aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anttasks/Android.mk3
-rw-r--r--anttasks/src/com/android/ant/AaptExecTask.java112
-rw-r--r--anttasks/src/com/android/ant/TaskHelper.java2
-rw-r--r--assetstudio/Android.mk16
-rw-r--r--assetstudio/src/com/android/assetstudiolib/ActionBarIconGenerator.java87
-rw-r--r--assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java292
-rw-r--r--assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java33
-rw-r--r--assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java198
-rw-r--r--assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java88
-rw-r--r--assetstudio/src/com/android/assetstudiolib/NotificationIconGenerator.java176
-rw-r--r--assetstudio/src/com/android/assetstudiolib/TabIconGenerator.java202
-rw-r--r--assetstudio/src/com/android/assetstudiolib/TextRenderUtil.java137
-rw-r--r--assetstudio/src/com/android/assetstudiolib/Util.java451
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-accept.pngbin1458 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-back.pngbin897 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-cancel.pngbin1758 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-collapse.pngbin1797 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-expand.pngbin1760 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-forward.pngbin895 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-next-item.pngbin1716 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-previous-item.pngbin1702 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/1-navigation-refresh.pngbin3502 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-accounts.pngbin2563 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-add-alarm.pngbin3828 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-alarms.pngbin5045 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-battery.pngbin653 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-bightness-low.pngbin4363 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-bluetooth-connected.pngbin3566 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-bluetooth-searching.pngbin4461 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-bluetooth.pngbin2748 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-brightness-auto.pngbin4356 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-brightness-high.pngbin5120 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-brightness-medium.pngbin4226 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-call.pngbin2783 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-camera.pngbin2982 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-data-usage.pngbin3887 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-dial-pad.pngbin739 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-end-call.pngbin2135 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-flash-automatic.pngbin2714 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-flash-off.pngbin2429 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-flash-on.pngbin1477 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-location-found.pngbin3992 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-location-off.pngbin3968 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-location-searching.pngbin3314 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-mic-muted.pngbin2947 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-mic.pngbin2608 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-network-cell.pngbin697 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-network-wifi.pngbin3739 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-new-account.pngbin2232 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-not-secure.pngbin1815 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-ring-volume.pngbin3769 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-landscape.pngbin1569 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-portrait.pngbin1649 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-screen-rotation.pngbin3589 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-sd-storage.pngbin1377 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-secure.pngbin1785 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-storage.pngbin601 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-switch-camera.pngbin4209 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-switch-video.pngbin3166 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-time.pngbin4432 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-usb.pngbin2589 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-video.pngbin1337 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-volume-muted.pngbin4406 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/10-device-access-volume-on.pngbin4983 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-off.pngbin3330 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-on.pngbin3121 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/11-alerts-and-states-error.pngbin1425 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/11-alerts-and-states-warning.pngbin2627 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-computer.pngbin1009 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-dock.pngbin1130 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-gamepad.pngbin2682 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-headphones.pngbin3389 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-headset.pngbin3544 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-keyboard.pngbin689 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-mouse.pngbin2551 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/12-hardware-phone.pngbin1726 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/2-action-about.pngbin4047 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/2-action-help.pngbin2193 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/2-action-search.pngbin3302 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/2-action-settings.pngbin1977 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-bad.pngbin1999 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-favorite.pngbin2282 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-good.pngbin2099 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-half-important.pngbin3748 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-important.pngbin3066 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/3-rating-not-important.pngbin3746 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-cloud.pngbin1716 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-collection.pngbin2064 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-go-to-today.pngbin1243 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-labels.pngbin2525 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-new-label.pngbin2338 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-sort-by-size.pngbin485 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-view-as-grid.pngbin338 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/4-collections-view-as-list.pngbin714 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-attachment.pngbin2235 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-backspace.pngbin2149 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-copy.pngbin773 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-cut.pngbin3947 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-discard.pngbin2301 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-edit.pngbin3893 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-email.pngbin1337 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-event.pngbin948 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-import-export.pngbin2017 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-merge.pngbin2574 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-new-attachment.pngbin2867 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-new-email.pngbin1501 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-new-event.pngbin802 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-new-picture.pngbin1759 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-new.pngbin412 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-paste.pngbin1982 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-picture.pngbin1725 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-read.pngbin2481 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-remove.pngbin1758 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-save.pngbin1072 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-select-all.pngbin872 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-split.pngbin2441 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-undo.pngbin2358 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/5-content-unread.pngbin2365 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-add-group.pngbin4911 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-add-person.pngbin2979 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-cc-bcc.pngbin3714 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-chat.pngbin848 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-forward.pngbin2046 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-group.pngbin4533 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-person.pngbin2569 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-reply-all.pngbin2995 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-reply.pngbin2043 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-send-now.pngbin1691 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/6-social-share.pngbin2890 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/7-location-directions.pngbin2130 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/7-location-map.pngbin4653 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/7-location-place.pngbin2684 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/7-location-web-site.pngbin7855 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/8-images-crop.pngbin1481 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/8-images-rotate-left.pngbin3802 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/8-images-rotate-right.pngbin3803 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/8-images-slideshow.pngbin1949 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-add-to-queue.pngbin719 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-download.pngbin1375 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-fast-forward.pngbin1835 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-full-screen.pngbin3549 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-make-available-offline.pngbin2489 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-next.pngbin1827 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-pause-over-video.pngbin4451 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-pause.pngbin372 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-play-over-video.pngbin4941 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-play.pngbin1817 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-previous.pngbin1821 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-repeat.pngbin3099 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-replay.pngbin3848 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-return-from-full-screen.pngbin3364 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-rewind.pngbin1974 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-shuffle.pngbin3832 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-stop.pngbin352 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/9-av-upload.pngbin1500 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/big/android.pngbin4156 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-accept.pngbin530 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-back.pngbin461 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-cancel.pngbin438 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-collapse.pngbin511 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-expand.pngbin531 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-forward.pngbin461 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-next-item.pngbin486 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-previous-item.pngbin507 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/1-navigation-refresh.pngbin796 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-accounts.pngbin694 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-add-alarm.pngbin745 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-alarms.pngbin820 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-battery.pngbin486 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-bightness-low.pngbin752 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-bluetooth-connected.pngbin664 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-bluetooth-searching.pngbin772 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-bluetooth.pngbin609 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-brightness-auto.pngbin765 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-brightness-high.pngbin731 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-brightness-medium.pngbin700 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-call.pngbin659 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-camera.pngbin709 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-data-usage.pngbin716 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-dial-pad.pngbin667 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-end-call.pngbin613 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-flash-automatic.pngbin645 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-flash-off.pngbin645 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-flash-on.pngbin555 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-location-found.pngbin725 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-location-off.pngbin732 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-location-searching.pngbin668 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-mic-muted.pngbin711 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-mic.pngbin650 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-network-cell.pngbin528 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-network-wifi.pngbin753 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-new-account.pngbin697 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-not-secure.pngbin562 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-ring-volume.pngbin710 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-landscape.pngbin619 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-portrait.pngbin630 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-screen-rotation.pngbin686 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-sd-storage.pngbin564 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-secure.pngbin555 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-storage.pngbin575 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-switch-camera.pngbin819 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-switch-video.pngbin721 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-time.pngbin701 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-usb.pngbin670 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-video.pngbin486 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-volume-muted.pngbin801 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/10-device-access-volume-on.pngbin827 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-off.pngbin732 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-on.pngbin729 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/11-alerts-and-states-error.pngbin507 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/11-alerts-and-states-warning.pngbin617 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-computer.pngbin464 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-dock.pngbin499 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-gamepad.pngbin655 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-headphones.pngbin766 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-headset.pngbin854 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-keyboard.pngbin829 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-mouse.pngbin654 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/12-hardware-phone.pngbin525 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/2-action-about.pngbin630 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/2-action-help.pngbin626 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/2-action-search.pngbin706 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/2-action-settings.pngbin566 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-bad.pngbin596 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-favorite.pngbin591 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-good.pngbin606 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-half-important.pngbin729 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-important.pngbin673 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/3-rating-not-important.pngbin748 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-cloud.pngbin541 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-collection.pngbin588 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-go-to-today.pngbin740 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-labels.pngbin684 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-new-label.pngbin706 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-sort-by-size.pngbin475 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-view-as-grid.pngbin484 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/4-collections-view-as-list.pngbin571 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-attachment.pngbin644 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-backspace.pngbin603 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-copy.pngbin615 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-cut.pngbin800 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-discard.pngbin646 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-edit.pngbin710 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-email.pngbin559 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-event.pngbin557 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-import-export.pngbin589 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-merge.pngbin599 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-new-attachment.pngbin715 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-new-email.pngbin691 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-new-event.pngbin657 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-new-picture.pngbin676 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-new.pngbin427 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-paste.pngbin677 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-picture.pngbin576 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-read.pngbin706 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-remove.pngbin438 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-save.pngbin650 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-select-all.pngbin697 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-split.pngbin621 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-undo.pngbin657 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/5-content-unread.pngbin624 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-add-group.pngbin938 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-add-person.pngbin745 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-cc-bcc.pngbin755 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-chat.pngbin508 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-forward.pngbin582 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-group.pngbin816 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-person.pngbin637 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-reply-all.pngbin712 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-reply.pngbin616 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-send-now.pngbin545 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/6-social-share.pngbin623 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/7-location-directions.pngbin528 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/7-location-map.pngbin895 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/7-location-place.pngbin604 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/7-location-web-site.pngbin1030 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/8-images-crop.pngbin616 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/8-images-rotate-left.pngbin783 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/8-images-rotate-right.pngbin776 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/8-images-slideshow.pngbin590 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-add-to-queue.pngbin649 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-download.pngbin555 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-fast-forward.pngbin532 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-full-screen.pngbin702 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-make-available-offline.pngbin594 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-next.pngbin589 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-pause-over-video.pngbin699 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-pause.pngbin402 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-play-over-video.pngbin748 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-play.pngbin557 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-previous.pngbin613 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-repeat.pngbin703 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-replay.pngbin791 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-return-from-full-screen.pngbin726 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-rewind.pngbin530 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-shuffle.pngbin694 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-stop.pngbin397 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/9-av-upload.pngbin546 -> 0 bytes
-rw-r--r--assetstudio/src/images/clipart/small/android.pngbin577 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/back.pngbin1185 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.pngbin4198 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/mask.pngbin1049 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/hdpi/mask_inner.pngbin888 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/back.pngbin877 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.pngbin2259 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/mask.pngbin591 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/mdpi/mask_inner.pngbin586 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/back.pngbin15543 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/fore1.pngbin43237 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/mask.pngbin8870 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/web/mask_inner.pngbin9061 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/back.pngbin1721 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.pngbin5891 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.pngbin1295 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xhdpi/mask_inner.pngbin1245 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xxhdpi/back.pngbin3103 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xxhdpi/fore1.pngbin10320 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask.pngbin2123 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask_inner.pngbin2037 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/back.pngbin487 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/fore1.pngbin1956 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/mask.pngbin278 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/hdpi/mask_inner.pngbin234 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/back.pngbin358 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/fore1.pngbin1065 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/mask.pngbin222 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/mdpi/mask_inner.pngbin194 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/back.pngbin4968 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/fore1.pngbin21368 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/mask.pngbin2640 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/web/mask_inner.pngbin2457 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/back.pngbin626 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.pngbin2647 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/mask.pngbin320 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xhdpi/mask_inner.pngbin288 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xxhdpi/back.pngbin1035 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xxhdpi/fore1.pngbin4275 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xxhdpi/mask.pngbin447 -> 0 bytes
-rw-r--r--assetstudio/src/images/launcher_stencil/square/xxhdpi/mask_inner.pngbin402 -> 0 bytes
-rw-r--r--assetstudio/src/images/notification_stencil/hdpi.pngbin519 -> 0 bytes
-rw-r--r--assetstudio/src/images/notification_stencil/mdpi.pngbin491 -> 0 bytes
-rw-r--r--assetstudio/src/images/notification_stencil/xhdpi.pngbin1534 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/ActionBarIconGeneratorTest.java41
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/GeneratorTest.java226
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/LauncherIconGeneratorTest.java50
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/MenuIconGeneratorTest.java31
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/NotificationIconGeneratorTest.java49
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/TabIconGeneratorTest.java38
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_dark.pngbin537 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_light.pngbin625 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_dark.pngbin394 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_light.pngbin482 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_dark.pngbin729 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_light.pngbin838 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/red_simple_circle-web.pngbin61650 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-hdpi/red_simple_circle.pngbin5881 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-mdpi/red_simple_circle.pngbin3447 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xhdpi/red_simple_circle.pngbin8118 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xxhdpi/red_simple_circle.pngbin13579 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-hdpi/ic_menu_1.pngbin1888 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-mdpi/ic_menu_1.pngbin1186 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-xhdpi/ic_menu_1.pngbin2525 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-hdpi/ic_stat_1.pngbin501 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-mdpi/ic_stat_1.pngbin340 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-xhdpi/ic_stat_1.pngbin621 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi-v11/ic_stat_1.pngbin501 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi/ic_stat_1.pngbin613 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi-v11/ic_stat_1.pngbin340 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi/ic_stat_1.pngbin410 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi-v11/ic_stat_1.pngbin621 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi/ic_stat_1.pngbin726 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v11/ic_stat_1.pngbin501 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v9/ic_stat_1.pngbin613 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi/ic_stat_1.pngbin1066 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v11/ic_stat_1.pngbin340 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v9/ic_stat_1.pngbin410 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi/ic_stat_1.pngbin687 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v11/ic_stat_1.pngbin621 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v9/ic_stat_1.pngbin726 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi/ic_stat_1.pngbin1506 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_selected.pngbin1540 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_unselected.pngbin724 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_selected.pngbin683 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_unselected.pngbin404 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_selected.pngbin941 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_unselected.pngbin501 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_selected.pngbin2203 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_unselected.pngbin978 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_selected.pngbin1540 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_unselected.pngbin724 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_selected.pngbin1667 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_unselected.pngbin1560 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_selected.pngbin941 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_unselected.pngbin501 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_selected.pngbin1003 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_unselected.pngbin968 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_selected.pngbin2203 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_unselected.pngbin978 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_selected.pngbin2289 -> 0 bytes
-rw-r--r--assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_unselected.pngbin2159 -> 0 bytes
-rw-r--r--build/product_sdk.mk2
-rw-r--r--build/tools.atree70
-rwxr-xr-xbuild/tools.windows.atree4
-rw-r--r--chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java3
-rw-r--r--chimpchat/src/com/android/chimpchat/core/TouchPressType.java2
-rw-r--r--common/Android.mk25
-rw-r--r--common/src/main/java/com/android/SdkConstants.java1168
-rw-r--r--common/src/main/java/com/android/annotations/NonNull.java38
-rw-r--r--common/src/main/java/com/android/annotations/NonNullByDefault.java47
-rwxr-xr-xcommon/src/main/java/com/android/annotations/Nullable.java49
-rwxr-xr-xcommon/src/main/java/com/android/annotations/VisibleForTesting.java50
-rw-r--r--common/src/main/java/com/android/io/FileWrapper.java158
-rw-r--r--common/src/main/java/com/android/io/FolderWrapper.java162
-rw-r--r--common/src/main/java/com/android/io/IAbstractFile.java58
-rw-r--r--common/src/main/java/com/android/io/IAbstractFolder.java77
-rw-r--r--common/src/main/java/com/android/io/IAbstractResource.java50
-rw-r--r--common/src/main/java/com/android/io/StreamException.java50
-rw-r--r--common/src/main/java/com/android/prefs/AndroidLocation.java128
-rw-r--r--common/src/main/java/com/android/utils/ILogger.java77
-rw-r--r--common/src/main/java/com/android/utils/NullLogger.java54
-rw-r--r--common/src/main/java/com/android/utils/Pair.java107
-rw-r--r--common/src/main/java/com/android/utils/PositionXmlParser.java729
-rw-r--r--common/src/main/java/com/android/utils/SdkUtils.java216
-rw-r--r--common/src/main/java/com/android/utils/StdLogger.java177
-rw-r--r--common/src/main/java/com/android/utils/XmlUtils.java416
-rw-r--r--common/src/main/java/com/android/xml/AndroidManifest.java361
-rw-r--r--common/src/main/java/com/android/xml/AndroidXPathFactory.java113
-rw-r--r--common/src/test/.classpath9
-rw-r--r--common/src/test/.project17
-rw-r--r--common/src/test/.settings/org.moreunit.prefs4
-rw-r--r--common/src/test/java/com/android/utils/PositionXmlParserTest.java322
-rw-r--r--common/src/test/java/com/android/utils/SdkUtilsTest.java133
-rw-r--r--common/src/test/java/com/android/utils/XmlUtilsTest.java170
-rw-r--r--ddms/app/etc/manifest.txt2
-rw-r--r--ddms/libs/ddmlib/Android.mk2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilter.java279
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java81
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java17
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java9
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessage.java96
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java2
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageParser.java94
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java65
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPidToNameMapper.java133
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java113
-rw-r--r--ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializerTest.java13
-rw-r--r--ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterTest.java163
-rw-r--r--ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatMessageParserTest.java99
-rw-r--r--device_validator/dvlib/Android.mk25
-rw-r--r--device_validator/dvlib/src/main/java/com/android/dvlib/DeviceSchema.java348
-rw-r--r--device_validator/dvlib/src/main/resources/com/android/dvlib/devices.xsd892
-rw-r--r--device_validator/dvlib/src/test/java/com/android/dvlib/DeviceSchemaTest.java297
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices.xml273
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_minimal.xml135
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_default.xml134
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_hardware.xml81
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_software.xml80
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_states.xml129
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/devices_too_many_defaults.xml141
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.jpeg0
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.png0
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.jpeg0
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.png0
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.jpeg0
-rw-r--r--device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.png0
-rw-r--r--draw9patch/Android.mk3
-rw-r--r--draw9patch/etc/manifest.txt1
-rw-r--r--draw9patch/src/com/android/draw9patch/ui/ImageEditorPanel.java165
-rw-r--r--draw9patch/src/com/android/draw9patch/ui/MainFrame.java18
-rw-r--r--draw9patch/src/com/android/draw9patch/ui/action/BackgroundAction.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java120
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAnnotation.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFix.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java11
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintJob.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java11
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/renamepackage/ApplicationPackageNameRefactoring.java8
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/META-INF/MANIFEST.MF3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.ndk/.classpath2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/.classpath2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandlerTest.java18
-rw-r--r--eclipse/scripts/build.xml133
-rwxr-xr-xeclipse/scripts/create_all_symlinks.sh24
-rw-r--r--hierarchyviewer/etc/manifest.txt2
-rw-r--r--hierarchyviewer/src/Android.mk1
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/ui/ScreenViewer.java63
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java106
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/ui/action/BackgroundAction.java3
-rw-r--r--hierarchyviewer2/app/etc/manifest.txt2
-rw-r--r--hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java14
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/.classpath2
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/manifest.txt2
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk4
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java15
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java48
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java17
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java6
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java20
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java302
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java166
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java108
-rw-r--r--hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.pngbin0 -> 370 bytes
-rw-r--r--jobb/Android.mk2
-rw-r--r--layoutlib_api/Android.mk21
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AdapterBinding.java82
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AttrResourceValue.java56
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Bridge.java161
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Capability.java69
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DataBindingItem.java97
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java71
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DensityBasedResourceValue.java87
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DrawableParams.java63
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/HardwareConfig.java91
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IAnimationListener.java48
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IImageFactory.java42
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ILayoutPullParser.java46
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IProjectCallback.java154
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/LayoutLog.java164
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/MergeCookie.java42
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderParams.java236
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderResources.java221
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderSession.java269
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceReference.java103
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceValue.java121
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Result.java189
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/SessionParams.java137
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/StyleResourceValue.java96
-rw-r--r--layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ViewInfo.java184
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/IDensityBasedResourceValue.java73
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutBridge.java230
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutLog.java46
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutResult.java109
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/IProjectCallback.java73
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/IResourceValue.java48
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/IStyleResourceValue.java40
-rw-r--r--layoutlib_api/src/main/java/com/android/layoutlib/api/IXmlPullParser.java34
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/Density.java142
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/FolderTypeRelationship.java166
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/Keyboard.java104
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/KeyboardState.java102
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/LayoutDirection.java100
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/Navigation.java103
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/NavigationState.java101
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/NightMode.java101
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ResourceConstants.java50
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ResourceEnum.java60
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ResourceFolderType.java77
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ResourceType.java111
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ScreenOrientation.java103
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ScreenRatio.java103
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/ScreenSize.java104
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/TouchScreen.java103
-rw-r--r--layoutlib_api/src/main/java/com/android/resources/UiMode.java100
-rw-r--r--layoutlib_api/src/main/java/com/android/util/Pair.java116
-rw-r--r--layoutlib_api/src/test/.classpath9
-rw-r--r--layoutlib_api/src/test/.project17
-rw-r--r--layoutlib_api/src/test/java/com/android/resources/FolderTypeRelationShipTest.java44
-rw-r--r--layoutlib_api/src/test/java/com/android/resources/ResourceFolderTypeTest.java30
-rw-r--r--lint/cli/Android.mk41
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java23
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/ManifestTypoDetectorTest.java184
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.class.databin0 -> 512 bytes
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.java.txt15
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/android-support-v4.jar.databin0 -> 385685 bytes
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_not_found.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature2.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library2.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission2.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk.xml28
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk2.xml28
-rw-r--r--lint/libs/lint_api/Android.mk17
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/AsmVisitor.java202
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java81
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/Configuration.java130
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultConfiguration.java453
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultSdkInfo.java288
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IDomParser.java93
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IJavaParser.java76
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IssueRegistry.java304
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/JavaVisitor.java1195
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java691
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java2227
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintListener.java70
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/OtherFileVisitor.java208
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/SdkInfo.java90
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/XmlVisitor.java221
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Category.java152
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ClassContext.java682
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Context.java377
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/DefaultPosition.java68
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Detector.java611
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Issue.java553
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/JavaContext.java127
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LayoutDetector.java70
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java798
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Location.java722
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Position.java50
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java929
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ResourceXmlDetector.java60
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Scope.java152
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Severity.java78
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Speed.java55
-rw-r--r--lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/XmlContext.java154
-rw-r--r--lint/libs/lint_checks/Android.mk25
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AccessibilityDetector.java130
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AlwaysShowActionDetector.java239
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java205
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Api.java87
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiClass.java424
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java1562
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiLookup.java971
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiParser.java122
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ArraySizeDetector.java259
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java381
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ButtonDetector.java782
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ChildCountDetector.java128
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CleanupDetector.java540
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java105
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CommentDetector.java197
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ControlFlowGraph.java329
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CutPasteDetector.java240
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.java175
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DetectMissingPrefix.java171
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DosLineEndingDetector.java115
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateIdDetector.java673
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateResourceDetector.java167
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ExtraTextDetector.java143
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FieldGetterDetector.java267
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FragmentDetector.java164
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/GridLayoutDetector.java117
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HandlerDetector.java83
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedDebugModeDetector.java95
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedValuesDetector.java114
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java1906
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InefficientWeightDetector.java349
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InvalidPackageDetector.java280
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/JavaPerformanceDetector.java565
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LabelForDetector.java168
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LocaleDetector.java225
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java557
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MathDetector.java97
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java213
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingClassDetector.java406
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingIdDetector.java91
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NamespaceDetector.java241
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java155
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java103
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java424
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OnClickDetector.java243
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverdrawDetector.java566
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverrideDetector.java278
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java107
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateResourceDetector.java75
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ProguardDetector.java164
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PxUsageDetector.java297
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RegistrationDetector.java255
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RequiredAttributeDetector.java618
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ScrollViewChildDetector.java100
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SdCardDetector.java127
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecureRandomDetector.java161
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecurityDetector.java402
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java74
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SharedPrefsDetector.java234
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StateListDetector.java145
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java1299
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StyleCycleDetector.java97
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SystemPermissionsDetector.java187
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextFieldDetector.java315
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextViewDetector.java230
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TitleDetector.java111
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java156
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TooManyViewsDetector.java150
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java581
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoDetector.java418
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoLookup.java785
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypographyDetector.java529
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java594
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UseCompoundDrawableDetector.java118
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UselessViewDetector.java246
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Utf8Detector.java106
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java148
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTagDetector.java175
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTypeDetector.java209
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WakelockDetector.java429
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCallDetector.java97
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCaseDetector.java83
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongIdDetector.java353
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongImportDetector.java109
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongLocationDetector.java69
-rw-r--r--manifmerger/Android.mk4
-rw-r--r--monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java3
-rw-r--r--sdk_common/.classpath2
-rw-r--r--sdk_common/Android.mk13
-rw-r--r--sdk_common/src/com/android/ide/common/rendering/HardwareConfigHelper.java158
-rw-r--r--sdk_common/src/com/android/ide/common/rendering/LayoutLibrary.java755
-rw-r--r--sdk_common/src/com/android/ide/common/rendering/StaticRenderSession.java63
-rw-r--r--sdk_common/src/com/android/ide/common/rendering/legacy/ILegacyPullParser.java31
-rw-r--r--sdk_common/src/com/android/ide/common/rendering/legacy/LegacyCallback.java59
-rw-r--r--sdk_common/src/com/android/ide/common/resources/FrameworkResourceItem.java40
-rwxr-xr-xsdk_common/src/com/android/ide/common/resources/FrameworkResources.java238
-rw-r--r--sdk_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java240
-rw-r--r--sdk_common/src/com/android/ide/common/resources/IdResourceParser.java150
-rw-r--r--sdk_common/src/com/android/ide/common/resources/InlineResourceItem.java71
-rw-r--r--sdk_common/src/com/android/ide/common/resources/IntArrayWrapper.java53
-rw-r--r--sdk_common/src/com/android/ide/common/resources/MultiResourceFile.java223
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ResourceDeltaKind.java26
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ResourceFile.java98
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ResourceFolder.java353
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ResourceItem.java239
-rwxr-xr-xsdk_common/src/com/android/ide/common/resources/ResourceRepository.java960
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ResourceResolver.java590
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ScanningContext.java110
-rw-r--r--sdk_common/src/com/android/ide/common/resources/SingleResourceFile.java171
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ValidatingResourceParser.java141
-rw-r--r--sdk_common/src/com/android/ide/common/resources/ValueResourceParser.java480
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/Configurable.java28
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/CountryCodeQualifier.java158
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/DensityQualifier.java130
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/DeviceConfigHelper.java112
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/EnumBasedResourceQualifier.java92
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/FolderConfiguration.java946
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/KeyboardStateQualifier.java112
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/LanguageQualifier.java165
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/LayoutDirectionQualifier.java74
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/NavigationMethodQualifier.java74
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/NavigationStateQualifier.java75
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/NetworkCodeQualifier.java169
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/NightModeQualifier.java74
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/RegionQualifier.java166
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ResourceQualifier.java134
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifier.java172
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenHeightQualifier.java181
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifier.java73
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenRatioQualifier.java70
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenSizeQualifier.java74
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/ScreenWidthQualifier.java180
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/SmallestScreenWidthQualifier.java180
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/TextInputMethodQualifier.java76
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/TouchScreenQualifier.java76
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/UiModeQualifier.java108
-rw-r--r--sdk_common/src/com/android/ide/common/resources/configuration/VersionQualifier.java194
-rw-r--r--sdk_common/src/com/android/ide/common/sdk/LoadStatus.java24
-rw-r--r--sdk_common/src/com/android/ide/common/xml/AndroidManifestParser.java672
-rw-r--r--sdk_common/src/com/android/ide/common/xml/ManifestData.java747
-rw-r--r--sdk_common/tests/.classpath10
-rw-r--r--sdk_common/tests/.project17
-rw-r--r--sdk_common/tests/.settings/org.moreunit.prefs4
-rw-r--r--sdk_common/tests/Android.mk27
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/ResourceRepositoryTest.java45
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/ValueResourceParserTest.java148
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/CountryCodeQualifierTest.java55
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/DockModeQualifierTest.java83
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/FolderConfigurationTest.java127
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/KeyboardStateQualifierTest.java61
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/LanguageQualifierTest.java53
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/NavigationMethodQualifierTest.java68
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/NetworkCodeQualifierTest.java55
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/PixelDensityQualifierTest.java118
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/RegionQualifierTest.java54
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifierTest.java57
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifierTest.java72
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenSizeQualifierTest.java69
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/TextInputMethodQualifierTest.java70
-rw-r--r--sdk_common/tests/src/com/android/ide/common/resources/configuration/TouchScreenQualifierTest.java68
-rw-r--r--sdk_common/tests/src/com/android/ide/common/xml/AndroidManifestParserTest.java175
-rw-r--r--sdk_common/tests/src/com/android/ide/common/xml/SupportsScreensTest.java148
-rw-r--r--sdkmanager/app/.classpath5
-rw-r--r--sdkmanager/app/Android.mk42
-rw-r--r--sdkmanager/app/etc/Android.mk2
-rw-r--r--sdkmanager/app/etc/manifest.txt2
-rw-r--r--sdkmanager/app/src/main/java/com/android/sdkmanager/Main.java (renamed from sdkmanager/app/src/com/android/sdkmanager/Main.java)3
-rw-r--r--sdkmanager/app/src/main/java/com/android/sdkmanager/SdkCommandLine.java (renamed from sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java)0
-rwxr-xr-xsdkmanager/app/src/test/java/com/android/sdklib/SdkManagerTestCase.java (renamed from sdkmanager/app/tests/com/android/sdklib/SdkManagerTestCase.java)0
-rw-r--r--sdkmanager/app/src/test/java/com/android/sdklib/mock/MockLog.java (renamed from sdkmanager/app/tests/com/android/sdklib/mock/MockLog.java)0
-rw-r--r--sdkmanager/app/src/test/java/com/android/sdkmanager/AvdManagerTest.java (renamed from sdkmanager/app/tests/com/android/sdkmanager/AvdManagerTest.java)0
-rw-r--r--sdkmanager/app/src/test/java/com/android/sdkmanager/MainTest.java (renamed from sdkmanager/app/tests/com/android/sdkmanager/MainTest.java)0
-rw-r--r--sdkmanager/app/src/test/java/com/android/sdkmanager/SdkCommandLineTest.java (renamed from sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java)0
-rw-r--r--sdkmanager/app/tests/Android.mk34
-rw-r--r--sdkmanager/libs/sdklib/Android.mk7
-rw-r--r--sdkmanager/libs/sdkuilib/Android.mk7
-rw-r--r--swtmenubar/Android.mk2
-rw-r--r--traceview/etc/manifest.txt2
800 files changed, 2097 insertions, 66832 deletions
diff --git a/anttasks/Android.mk b/anttasks/Android.mk
index 9922f53..ae0c3a9 100644
--- a/anttasks/Android.mk
+++ b/anttasks/Android.mk
@@ -25,7 +25,8 @@ LOCAL_JAVA_LIBRARIES := \
common \
sdklib \
manifmerger \
- ant
+ ant \
+ guava-tools
LOCAL_MODULE := anttasks
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java
index 257d1b9..a1d44c4 100644
--- a/anttasks/src/com/android/ant/AaptExecTask.java
+++ b/anttasks/src/com/android/ant/AaptExecTask.java
@@ -20,8 +20,8 @@ import com.android.SdkConstants;
import com.android.sdklib.internal.build.SymbolLoader;
import com.android.sdklib.internal.build.SymbolWriter;
import com.android.xml.AndroidXPathFactory;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -32,12 +32,10 @@ import org.xml.sax.InputSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
import javax.xml.xpath.XPath;
@@ -401,6 +399,7 @@ public final class AaptExecTask extends SingleDependencyTask {
*
* @see org.apache.tools.ant.Task#execute()
*/
+ @SuppressWarnings("deprecation")
@Override
public void execute() throws BuildException {
if (mLibraryResFolderPathRefid == null) {
@@ -706,8 +705,8 @@ public final class AaptExecTask extends SingleDependencyTask {
File rFile = new File(mBinFolder, SdkConstants.FN_RESOURCE_TEXT);
if (rFile.isFile()) {
// Load the full symbols from the full R.txt file.
- SymbolLoader fullSymbols = new SymbolLoader(rFile);
- fullSymbols.load();
+ SymbolLoader fullSymbolValues = new SymbolLoader(rFile);
+ fullSymbolValues.load();
// we have two props which contains list of items. Both items represent
// 2 data of a single property.
@@ -729,66 +728,41 @@ public final class AaptExecTask extends SingleDependencyTask {
mOriginalManifestPackage = getPackageName(mManifestFile);
}
- // simpler case of a single library
- if (packages.length == 1) {
- if (!mOriginalManifestPackage.equals(packages[0])) {
- createRClass(fullSymbols, rFiles[0], packages[0]);
+ Multimap<String, SymbolLoader> libMap = ArrayListMultimap.create();
+
+ // First pass processing the libraries, collecting them by packageName,
+ // and ignoring the ones that have the same package name as the application
+ // (since that R class was already created).
+ for (int i = 0 ; i < packages.length ; i++) {
+ String libPackage = packages[i];
+
+ // skip libraries that have the same package name as the application.
+ if (mOriginalManifestPackage.equals(libPackage)) {
+ continue;
}
- } else {
-
- Map<String, String> libPackages = Maps.newHashMapWithExpectedSize(
- packages.length);
- Set<String> duplicatePackages = Sets.newHashSet();
-
- // preprocessing to figure out if there are dups in the package names of
- // the libraries
- for (int i = 0 ; i < packages.length ; i++) {
- String libPackage = packages[i];
- if (mOriginalManifestPackage.equals(libPackage)) {
- // skip libraries that have the same package name as the application.
- continue;
- }
-
- String 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, rFiles[i]);
+
+ File rText = new File(rFiles[i]);
+ if (rText.isFile()) {
+ // load the lib symbols
+ SymbolLoader libSymbols = new SymbolLoader(rText);
+ libSymbols.load();
+
+ // store these symbols by associating them with the package name.
+ libMap.put(libPackage, libSymbols);
}
+ }
- // 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(mRFolder,
- 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.");
- throw new BuildException(sb.toString());
- }
- } else {
- // no dups, all libraries have different packages.
- // Conflicts with the main package have been removed already.
- // Just process all the libraries from the list where we removed
- // libs that had the same package as the app.
- for (Entry<String, String> lib : libPackages.entrySet()) {
- createRClass(fullSymbols, lib.getValue(), lib.getKey());
- }
+ // now loop on all the package names, merge all the symbols to write,
+ // and write them
+ for (String packageName : libMap.keySet()) {
+ Collection<SymbolLoader> symbols = libMap.get(packageName);
+
+ SymbolWriter writer = new SymbolWriter(mRFolder, packageName,
+ fullSymbolValues);
+ for (SymbolLoader symbolLoader : symbols) {
+ writer.addSymbolsToWrite(symbolLoader);
}
+ writer.write();
}
}
}
@@ -803,18 +777,6 @@ public final class AaptExecTask extends SingleDependencyTask {
}
}
- private void createRClass(SymbolLoader fullSymbols, String libRTxtFile, String libPackage)
- throws IOException {
- File libSymbolFile = new File(libRTxtFile);
- if (libSymbolFile.isFile()) {
- SymbolLoader libSymbols = new SymbolLoader(libSymbolFile);
- libSymbols.load();
-
- SymbolWriter writer = new SymbolWriter(mRFolder, libPackage, libSymbols, fullSymbols);
- writer.write();
- }
- }
-
private String getPackageName(String manifest) {
XPath xpath = AndroidXPathFactory.newXPath();
diff --git a/anttasks/src/com/android/ant/TaskHelper.java b/anttasks/src/com/android/ant/TaskHelper.java
index 43ea33a..c93b193 100644
--- a/anttasks/src/com/android/ant/TaskHelper.java
+++ b/anttasks/src/com/android/ant/TaskHelper.java
@@ -22,7 +22,7 @@ import com.android.annotations.Nullable;
import com.android.sdklib.internal.project.ProjectProperties;
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy;
-import com.android.sdklib.internal.repository.packages.FullRevision;
+import com.android.sdklib.repository.FullRevision;
import com.android.sdklib.repository.PkgProps;
import org.apache.tools.ant.BuildException;
diff --git a/assetstudio/Android.mk b/assetstudio/Android.mk
index 88f4987..17f9415 100644
--- a/assetstudio/Android.mk
+++ b/assetstudio/Android.mk
@@ -16,8 +16,14 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_JAVA_RESOURCE_DIRS := src
+# The assetstudio code has moved to tools/base/assetstudio.
+# The rule below uses the prebuilt assetstudio.jar.
+#
+# If you want to run the tests, cd to tools/base/assetstudio
+# and run ./gradlew :assetstudio:test
+
+LOCAL_MODULE := assetstudio
+LOCAL_MODULE_TAGS := optional
# TODO: Replace common with the batik stuff
LOCAL_JAVA_LIBRARIES := \
@@ -27,8 +33,8 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_JAR_MANIFEST := etc/manifest.txt
-LOCAL_MODULE := assetstudio
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_PREBUILT)
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/assetstudio/src/com/android/assetstudiolib/ActionBarIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/ActionBarIconGenerator.java
deleted file mode 100644
index 3cd6f11..0000000
--- a/assetstudio/src/com/android/assetstudiolib/ActionBarIconGenerator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.Util.Effect;
-import com.android.assetstudiolib.Util.FillEffect;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-
-/**
- * Generate icons for the action bar
- */
-public class ActionBarIconGenerator extends GraphicGenerator {
-
- /** Creates a new {@link ActionBarIconGenerator} */
- public ActionBarIconGenerator() {
- }
-
- @Override
- public BufferedImage generate(GraphicGeneratorContext context, Options options) {
- ActionBarOptions actionBarOptions = (ActionBarOptions) options;
- Rectangle iconSizeMdpi = new Rectangle(0, 0, 32, 32);
- Rectangle targetRectMdpi = actionBarOptions.sourceIsClipart
- ? new Rectangle(0, 0, 32, 32)
- : new Rectangle(4, 4, 24, 24);
- final float scaleFactor = GraphicGenerator.getMdpiScaleFactor(options.density);
- Rectangle imageRect = Util.scaleRectangle(iconSizeMdpi, scaleFactor);
- Rectangle targetRect = Util.scaleRectangle(targetRectMdpi, scaleFactor);
- BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g = (Graphics2D) outImage.getGraphics();
-
- BufferedImage tempImage = Util.newArgbBufferedImage(
- imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
- Util.drawCenterInside(g2, options.sourceImage, targetRect);
-
- if (actionBarOptions.theme == Theme.HOLO_LIGHT) {
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(new Color(0x333333), 0.6),
- });
- } else {
- assert actionBarOptions.theme == Theme.HOLO_DARK;
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(new Color(0xFFFFFF), 0.8)
- });
- }
-
- g.dispose();
- g2.dispose();
-
- return outImage;
- }
-
- /** Options specific to generating action bar icons */
- public static class ActionBarOptions extends GraphicGenerator.Options {
- /** The theme to generate icons for */
- public Theme theme = Theme.HOLO_LIGHT;
-
- /** Whether or not the source image is a clipart source */
- public boolean sourceIsClipart = false;
- }
-
- /** The themes to generate action bar icons for */
- public enum Theme {
- /** Theme.Holo - a dark (and default) version of the Honeycomb theme */
- HOLO_DARK,
-
- /** Theme.HoloLight - a light version of the Honeycomb theme */
- HOLO_LIGHT;
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java b/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java
deleted file mode 100644
index 706adc8..0000000
--- a/assetstudio/src/com/android/assetstudiolib/GraphicGenerator.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import com.android.resources.Density;
-import com.google.common.io.Closeables;
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import javax.imageio.ImageIO;
-
-/**
- * The base Generator class.
- */
-public abstract class GraphicGenerator {
- /**
- * Options used for all generators.
- */
- public static class Options {
- /** Minimum version (API level) of the SDK to generate icons for */
- public int minSdk = 1;
-
- /** Source image to use as a basis for the icon */
- public BufferedImage sourceImage;
-
- /** The density to generate the icon with */
- public Density density = Density.XHIGH;
- }
-
- /** Shapes that can be used for icon backgrounds */
- public static enum Shape {
- /** No background */
- NONE("none"),
- /** Circular background */
- CIRCLE("circle"),
- /** Square background */
- SQUARE("square");
-
- /** Id, used in filenames to identify associated stencils */
- public final String id;
-
- Shape(String id) {
- this.id = id;
- }
- }
-
- /** Foreground effects styles */
- public static enum Style {
- /** No effects */
- SIMPLE("fore1");
-
- /** Id, used in filenames to identify associated stencils */
- public final String id;
-
- Style(String id) {
- this.id = id;
- }
- }
-
- /**
- * Generate a single icon using the given options
- *
- * @param context render context to use for looking up resources etc
- * @param options options controlling the appearance of the icon
- * @return a {@link BufferedImage} with the generated icon
- */
- public abstract BufferedImage generate(GraphicGeneratorContext context, Options options);
-
- /**
- * Computes the target filename (relative to the Android project folder)
- * where an icon rendered with the given options should be stored. This is
- * also used as the map keys in the result map used by
- * {@link #generate(String, Map, GraphicGeneratorContext, Options, String)}.
- *
- * @param options the options object used by the generator for the current
- * image
- * @param name the base name to use when creating the path
- * @return a path relative to the res/ folder where the image should be
- * stored (will always use / as a path separator, not \ on Windows)
- */
- protected String getIconPath(Options options, String name) {
- return getIconFolder(options) + '/' + getIconName(options, name);
- }
-
- /**
- * Gets name of the file itself. It is sometimes modified by options, for
- * example in unselected tabs we change foo.png to foo-unselected.png
- */
- protected String getIconName(Options options, String name) {
- return name + ".png"; //$NON-NLS-1$
- }
-
- /**
- * Gets name of the folder to contain the resource. It usually includes the
- * density, but is also sometimes modified by options. For example, in some
- * notification icons we add in -v9 or -v11.
- */
- protected String getIconFolder(Options options) {
- return "res/drawable-" + options.density.getResourceValue(); //$NON-NLS-1$
- }
-
- /**
- * Generates a full set of icons into the given map. The values in the map
- * will be the generated images, and each value is keyed by the
- * corresponding relative path of the image, which is determined by the
- * {@link #getIconPath(Options, String)} method.
- *
- * @param category the current category to place images into (if null the
- * density name will be used)
- * @param categoryMap the map to put images into, should not be null. The
- * map is a map from a category name, to a map from file path to
- * image.
- * @param context a generator context which for example can load resources
- * @param options options to apply to this generator
- * @param name the base name of the icons to generate
- */
- public void generate(String category, Map<String, Map<String, BufferedImage>> categoryMap,
- GraphicGeneratorContext context, Options options, String name) {
- Density[] densityValues = Density.values();
- // Sort density values into ascending order
- Arrays.sort(densityValues, new Comparator<Density>() {
- @Override
- public int compare(Density d1, Density d2) {
- return d1.getDpiValue() - d2.getDpiValue();
- }
- });
-
- for (Density density : densityValues) {
- if (!density.isValidValueForDevice()) {
- continue;
- }
- if (density == Density.LOW || density == Density.TV ||
- (density == Density.XXHIGH && !(this instanceof LauncherIconGenerator))) {
- // TODO don't manually check and instead gracefully handle missing stencils.
- // Not yet supported -- missing stencil image
- continue;
- }
- options.density = density;
- BufferedImage image = generate(context, options);
- if (image != null) {
- String mapCategory = category;
- if (mapCategory == null) {
- mapCategory = options.density.getResourceValue();
- }
- Map<String, BufferedImage> imageMap = categoryMap.get(mapCategory);
- if (imageMap == null) {
- imageMap = new LinkedHashMap<String, BufferedImage>();
- categoryMap.put(mapCategory, imageMap);
- }
- imageMap.put(getIconPath(options, name), image);
- }
- }
- }
-
- /**
- * Returns the scale factor to apply for a given MDPI density to compute the
- * absolute pixel count to use to draw an icon of the given target density
- *
- * @param density the density
- * @return a factor to multiple mdpi distances with to compute the target density
- */
- public static float getMdpiScaleFactor(Density density) {
- return density.getDpiValue() / (float) Density.MEDIUM.getDpiValue();
- }
-
- /**
- * Returns one of the built in stencil images, or null
- *
- * @param relativePath stencil path such as "launcher-stencil/square/web/back.png"
- * @return the image, or null
- * @throws IOException if an unexpected I/O error occurs
- */
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables#closeQuietly yet
- public static BufferedImage getStencilImage(String relativePath) throws IOException {
- InputStream is = GraphicGenerator.class.getResourceAsStream(relativePath);
- try {
- return ImageIO.read(is);
- } finally {
- Closeables.closeQuietly(is);
- }
- }
-
- /**
- * Returns the icon (32x32) for a given clip art image.
- *
- * @param name the name of the image to be loaded (which can be looked up via
- * {@link #getClipartNames()})
- * @return the icon image
- * @throws IOException if the image cannot be loaded
- */
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables#closeQuietly yet
- public static BufferedImage getClipartIcon(String name) throws IOException {
- InputStream is = GraphicGenerator.class.getResourceAsStream(
- "/images/clipart/small/" + name);
- try {
- return ImageIO.read(is);
- } finally {
- Closeables.closeQuietly(is);
- }
- }
-
- /**
- * Returns the full size clip art image for a given image name.
- *
- * @param name the name of the image to be loaded (which can be looked up via
- * {@link #getClipartNames()})
- * @return the clip art image
- * @throws IOException if the image cannot be loaded
- */
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables#closeQuietly yet
- public static BufferedImage getClipartImage(String name) throws IOException {
- InputStream is = GraphicGenerator.class.getResourceAsStream(
- "/images/clipart/big/" + name);
- try {
- return ImageIO.read(is);
- } finally {
- Closeables.closeQuietly(is);
- }
- }
-
- /**
- * Returns the names of available clip art images which can be obtained by passing the
- * name to {@link #getClipartIcon(String)} or
- * {@link GraphicGenerator#getClipartImage(String)}
- *
- * @return an iterator for the available image names
- */
- public static Iterator<String> getClipartNames() {
- List<String> names = new ArrayList<String>(80);
- try {
- String pathPrefix = "images/clipart/big/"; //$NON-NLS-1$
- ProtectionDomain protectionDomain = GraphicGenerator.class.getProtectionDomain();
- URL url = protectionDomain.getCodeSource().getLocation();
- File file;
- try {
- file = new File(url.toURI());
- } catch (URISyntaxException e) {
- file = new File(url.getPath());
- }
- final ZipFile zipFile = new JarFile(file);
- Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
- while (enumeration.hasMoreElements()) {
- ZipEntry zipEntry = enumeration.nextElement();
- String name = zipEntry.getName();
- if (!name.startsWith(pathPrefix) || !name.endsWith(".png")) { //$NON-NLS-1$
- continue;
- }
-
- int lastSlash = name.lastIndexOf('/');
- if (lastSlash != -1) {
- name = name.substring(lastSlash + 1);
- }
- names.add(name);
- }
- } catch (final Exception e) {
- e.printStackTrace();
- }
-
- return names.iterator();
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java b/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java
deleted file mode 100644
index e0b00a6..0000000
--- a/assetstudio/src/com/android/assetstudiolib/GraphicGeneratorContext.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import java.awt.image.BufferedImage;
-
-/**
- * The context used during graphic generation.
- */
-public interface GraphicGeneratorContext {
- /**
- * Loads the given image resource, as requested by the graphic generator.
- *
- * @param path The path to the resource, relative to the general "resources" path, as defined by
- * the context implementor.
- * @return The loaded image resource, or null if there was an error.
- */
- public BufferedImage loadImageResource(String path);
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java
deleted file mode 100644
index 8902774..0000000
--- a/assetstudio/src/com/android/assetstudiolib/LauncherIconGenerator.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import com.android.resources.Density;
-import com.android.utils.Pair;
-
-import java.awt.AlphaComposite;
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A {@link GraphicGenerator} that generates Android "launcher" icons.
- */
-public class LauncherIconGenerator extends GraphicGenerator {
- private static final Rectangle IMAGE_SIZE_WEB = new Rectangle(0, 0, 512, 512);
- private static final Rectangle IMAGE_SIZE_MDPI = new Rectangle(0, 0, 48, 48);
-
- private static final Map<Pair<Shape, Density>, Rectangle> TARGET_RECTS
- = new HashMap<Pair<Shape, Density>, Rectangle>();
-
- static {
- // None, Web
- TARGET_RECTS.put(Pair.of(Shape.NONE, (Density) null), new Rectangle(32, 32, 448, 448));
- // None, HDPI
- TARGET_RECTS.put(Pair.of(Shape.NONE, Density.HIGH), new Rectangle(4, 4, 64, 64));
- // None, MDPI
- TARGET_RECTS.put(Pair.of(Shape.NONE, Density.MEDIUM), new Rectangle(3, 3, 42, 42));
-
- // Circle, Web
- TARGET_RECTS.put(Pair.of(Shape.CIRCLE, (Density) null), new Rectangle(32, 43, 448, 448));
- // Circle, HDPI
- TARGET_RECTS.put(Pair.of(Shape.CIRCLE, Density.HIGH), new Rectangle(4, 6, 64, 64));
- // Circle, MDPI
- TARGET_RECTS.put(Pair.of(Shape.CIRCLE, Density.MEDIUM), new Rectangle(3, 4, 42, 42));
-
- // Square, Web
- TARGET_RECTS.put(Pair.of(Shape.SQUARE, (Density) null), new Rectangle(32, 53, 448, 427));
- // Square, HDPI
- TARGET_RECTS.put(Pair.of(Shape.SQUARE, Density.HIGH), new Rectangle(4, 8, 64, 60));
- // Square, MDPI
- TARGET_RECTS.put(Pair.of(Shape.SQUARE, Density.MEDIUM), new Rectangle(3, 5, 42, 40));
- }
-
- @Override
- public BufferedImage generate(GraphicGeneratorContext context, Options options) {
- LauncherOptions launcherOptions = (LauncherOptions) options;
-
- String density;
- if (launcherOptions.isWebGraphic) {
- density = "web";
- } else {
- density = launcherOptions.density.getResourceValue();
- }
-
- BufferedImage backImage = null, foreImage = null, maskImage = null, maskInnerImage = null;
- if (launcherOptions.shape != Shape.NONE && launcherOptions.shape != null) {
- String shape = launcherOptions.shape.id;
- backImage = context.loadImageResource("/images/launcher_stencil/"
- + shape + "/" + density + "/back.png");
- foreImage = context.loadImageResource("/images/launcher_stencil/"
- + shape + "/" + density + "/" + launcherOptions.style.id + ".png");
- maskImage = context.loadImageResource("/images/launcher_stencil/"
- + shape + "/" + density + "/mask.png");
- maskInnerImage = context.loadImageResource("/images/launcher_stencil/"
- + shape + "/" + density + "/mask_inner.png");
- }
-
- Rectangle imageRect = IMAGE_SIZE_WEB;
- if (!launcherOptions.isWebGraphic) {
- imageRect = Util.scaleRectangle(IMAGE_SIZE_MDPI,
- GraphicGenerator.getMdpiScaleFactor(launcherOptions.density));
- }
-
- Rectangle targetRect = TARGET_RECTS.get(
- Pair.of(launcherOptions.shape, launcherOptions.density));
- if (targetRect == null) {
- // Scale up from MDPI if no density-specific target rectangle is defined.
- targetRect = Util.scaleRectangle(
- TARGET_RECTS.get(Pair.of(launcherOptions.shape, Density.MEDIUM)),
- GraphicGenerator.getMdpiScaleFactor(launcherOptions.density));
- }
-
- BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g = (Graphics2D) outImage.getGraphics();
- if (backImage != null) {
- g.drawImage(backImage, 0, 0, null);
- }
-
- BufferedImage tempImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
- if (maskImage != null) {
- g2.drawImage(maskImage, 0, 0, null);
- g2.setComposite(AlphaComposite.SrcAtop);
- g2.setPaint(new Color(launcherOptions.backgroundColor));
- g2.fillRect(0, 0, imageRect.width, imageRect.height);
- }
-
- BufferedImage tempImage2 = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g3 = (Graphics2D) tempImage2.getGraphics();
- if (maskInnerImage != null) {
- g3.drawImage(maskInnerImage, 0, 0, null);
- g3.setComposite(AlphaComposite.SrcAtop);
- g3.setPaint(new Color(launcherOptions.backgroundColor));
- g3.fillRect(0, 0, imageRect.width, imageRect.height);
- }
-
- if (launcherOptions.crop) {
- Util.drawCenterCrop(g3, launcherOptions.sourceImage, targetRect);
- } else {
- Util.drawCenterInside(g3, launcherOptions.sourceImage, targetRect);
- }
-
- g2.drawImage(tempImage2, 0, 0, null);
- g.drawImage(tempImage, 0, 0, null);
- if (foreImage != null) {
- g.drawImage(foreImage, 0, 0, null);
- }
-
- g.dispose();
- g2.dispose();
-
- return outImage;
- }
-
- @Override
- public void generate(String category, Map<String, Map<String, BufferedImage>> categoryMap,
- GraphicGeneratorContext context, Options options, String name) {
- LauncherOptions launcherOptions = (LauncherOptions) options;
- boolean generateWebImage = launcherOptions.isWebGraphic;
- launcherOptions.isWebGraphic = false;
- super.generate(category, categoryMap, context, options, name);
-
- if (generateWebImage) {
- launcherOptions.isWebGraphic = true;
- launcherOptions.density = null;
- BufferedImage image = generate(context, options);
- if (image != null) {
- Map<String, BufferedImage> imageMap = new HashMap<String, BufferedImage>();
- categoryMap.put("Web", imageMap);
- imageMap.put(getIconPath(options, name), image);
- }
- }
- }
-
- @Override
- protected String getIconPath(Options options, String name) {
- if (((LauncherOptions) options).isWebGraphic) {
- return name + "-web.png"; // Store at the root of the project
- }
-
- return super.getIconPath(options, name);
- }
-
- /** Options specific to generating launcher icons */
- public static class LauncherOptions extends GraphicGenerator.Options {
- /** Background color, as an RRGGBB packed integer */
- public int backgroundColor = 0;
-
- /** Whether the image should be cropped or not */
- public boolean crop = true;
-
- /** The shape to use for the background */
- public Shape shape = Shape.SQUARE;
-
- /** The effects to apply to the foreground */
- public Style style = Style.SIMPLE;
-
- /**
- * Whether a web graphic should be generated (will ignore normal density
- * setting). The {@link #generate(GraphicGeneratorContext, Options)}
- * method will use this to decide whether to generate a normal density
- * icon or a high res web image. The
- * {@link GraphicGenerator#generate(String, Map, GraphicGeneratorContext, Options, String)}
- * method will use this flag to determine whether it should include a
- * web graphic in its iteration.
- */
- public boolean isWebGraphic;
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java
deleted file mode 100644
index 33b9c34..0000000
--- a/assetstudio/src/com/android/assetstudiolib/MenuIconGenerator.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.Util.Effect;
-import com.android.assetstudiolib.Util.FillEffect;
-import com.android.assetstudiolib.Util.ShadowEffect;
-
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-
-/**
- * A {@link GraphicGenerator} that generates Android "menu" icons.
- */
-public class MenuIconGenerator extends GraphicGenerator {
- /** Creates a menu icon generator */
- public MenuIconGenerator() {
- }
-
- @Override
- public BufferedImage generate(GraphicGeneratorContext context, Options options) {
- Rectangle imageSizeHdpi = new Rectangle(0, 0, 48, 48);
- Rectangle targetRectHdpi = new Rectangle(8, 8, 32, 32);
- float scaleFactor = GraphicGenerator.getMdpiScaleFactor(options.density);
- Rectangle imageRect = Util.scaleRectangle(imageSizeHdpi, scaleFactor);
- Rectangle targetRect = Util.scaleRectangle(targetRectHdpi, scaleFactor);
-
- BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g = (Graphics2D) outImage.getGraphics();
-
- BufferedImage tempImage = Util.newArgbBufferedImage(
- imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
- Util.drawCenterInside(g2, options.sourceImage, targetRect);
-
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(
- new GradientPaint(
- 0, 0,
- new Color(0xa3a3a3),
- 0, imageRect.height,
- new Color(0x787878))),
- new ShadowEffect(
- 0,
- 2 * scaleFactor,
- 2 * scaleFactor,
- Color.BLACK,
- 0.2,
- true),
- new ShadowEffect(
- 0,
- 1,
- 0,
- Color.BLACK,
- 0.35,
- true),
- new ShadowEffect(
- 0,
- -1,
- 0,
- Color.WHITE,
- 0.35,
- true),
- });
-
- g.dispose();
- g2.dispose();
-
- return outImage;
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/NotificationIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/NotificationIconGenerator.java
deleted file mode 100644
index b84af1b..0000000
--- a/assetstudio/src/com/android/assetstudiolib/NotificationIconGenerator.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.Util.Effect;
-import com.android.assetstudiolib.Util.FillEffect;
-import com.android.assetstudiolib.Util.ShadowEffect;
-
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-import java.util.Map;
-
-/**
- * Generate icons for the notifications bar
- */
-public class NotificationIconGenerator extends GraphicGenerator {
- /** Creates a new {@link NotificationIconGenerator} */
- public NotificationIconGenerator() {
- }
-
- @Override
- public BufferedImage generate(GraphicGeneratorContext context, Options options) {
- Rectangle iconSizeMdpi;
- Rectangle targetRectMdpi;
- NotificationOptions notificationOptions = (NotificationOptions) options;
- if (notificationOptions.version == Version.OLDER) {
- iconSizeMdpi = new Rectangle(0, 0, 25, 25);
- targetRectMdpi = new Rectangle(4, 4, 17, 17);
- } else if (notificationOptions.version == Version.V11) {
- iconSizeMdpi = new Rectangle(0, 0, 24, 24);
- targetRectMdpi = new Rectangle(1, 1, 22, 22);
- } else {
- assert notificationOptions.version == Version.V9;
- iconSizeMdpi = new Rectangle(0, 0, 16, 25);
- targetRectMdpi = new Rectangle(0, 5, 16, 16);
- }
-
- final float scaleFactor = GraphicGenerator.getMdpiScaleFactor(options.density);
- Rectangle imageRect = Util.scaleRectangle(iconSizeMdpi, scaleFactor);
- Rectangle targetRect = Util.scaleRectangle(targetRectMdpi, scaleFactor);
-
- BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g = (Graphics2D) outImage.getGraphics();
-
- BufferedImage tempImage = Util.newArgbBufferedImage(
- imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
-
- if (notificationOptions.version == Version.OLDER) {
- BufferedImage backImage = context.loadImageResource(
- "/images/notification_stencil/"
- + notificationOptions.density.getResourceValue()
- + ".png");
- g.drawImage(backImage, 0, 0, null);
- BufferedImage top = options.sourceImage;
- BufferedImage filled = Util.filledImage(top, Color.WHITE);
- Util.drawCenterInside(g, filled, targetRect);
- } else if (notificationOptions.version == Version.V11) {
- Util.drawCenterInside(g2, options.sourceImage, targetRect);
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(Color.WHITE),
- });
- } else {
- assert notificationOptions.version == Version.V9;
- Util.drawCenterInside(g2, options.sourceImage, targetRect);
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(
- new GradientPaint(
- 0, 0,
- new Color(0x919191),
- 0, imageRect.height,
- new Color(0x828282))),
- new ShadowEffect(
- 0,
- 1,
- 0,
- Color.WHITE,
- 0.10,
- true),
- });
- }
-
- g.dispose();
- g2.dispose();
-
- return outImage;
- }
-
- @Override
- public void generate(String category, Map<String, Map<String, BufferedImage>> categoryMap,
- GraphicGeneratorContext context, Options baseOptions, String name) {
- NotificationOptions options = (NotificationOptions) baseOptions;
- if (options.minSdk < 9) {
- options.version = Version.OLDER;
- super.generate(options.version.getDisplayName(), categoryMap, context, options, name);
- }
- if (options.minSdk < 11) {
- options.version = Version.V9;
- super.generate(options.version.getDisplayName(), categoryMap, context, options, name);
- }
- options.version = Version.V11;
- super.generate(options.minSdk < 11 ? options.version.getDisplayName() : null,
- categoryMap, context, options, name);
- }
-
- @Override
- protected String getIconFolder(Options options) {
- String folder = super.getIconFolder(options);
- Version version = ((NotificationOptions) options).version;
- if (version == Version.V11 && options.minSdk < 11) {
- return folder + "-v11"; //$NON-NLS-1$
- } else if (version == Version.V9 && options.minSdk < 9) {
- return folder + "-v9"; //$NON-NLS-1$
- } else {
- return folder;
- }
- }
-
- /**
- * Options specific to generating notification icons
- */
- public static class NotificationOptions extends GraphicGenerator.Options {
- /**
- * The version of the icon to generate - different styles are used for different
- * versions of Android
- */
- public Version version = Version.V9;
- }
-
- /**
- * The version of the icon to generate - different styles are used for different
- * versions of Android
- */
- public enum Version {
- /** Icon style used for -v9 and -v10 */
- V9("V9"),
-
- /** Icon style used for -v11 (Honeycomb) and later */
- V11("V11"),
-
- /** Icon style used for versions older than v9 */
- OLDER("Other");
-
- private final String mDisplayName;
-
- Version(String displayName) {
- mDisplayName = displayName;
- }
-
- /**
- * Returns the display name for this version, typically shown as a
- * category
- *
- * @return the display name, never null
- */
- public String getDisplayName() {
- return mDisplayName;
- }
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/TabIconGenerator.java b/assetstudio/src/com/android/assetstudiolib/TabIconGenerator.java
deleted file mode 100644
index 3d2ac30..0000000
--- a/assetstudio/src/com/android/assetstudiolib/TabIconGenerator.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.Util.Effect;
-import com.android.assetstudiolib.Util.FillEffect;
-import com.android.assetstudiolib.Util.ShadowEffect;
-
-import java.awt.Color;
-import java.awt.GradientPaint;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-import java.util.Map;
-
-
-/**
- * Generate icons for tabs
- */
-public class TabIconGenerator extends GraphicGenerator {
- /** Creates a new {@link TabIconGenerator} */
- public TabIconGenerator() {
- }
-
- @Override
- public BufferedImage generate(GraphicGeneratorContext context, Options options) {
- Rectangle iconSizeMdpi = new Rectangle(0, 0, 32, 32);
- Rectangle targetRectMdpi = new Rectangle(2, 2, 28, 28);
- final float scaleFactor = GraphicGenerator.getMdpiScaleFactor(options.density);
- Rectangle imageRect = Util.scaleRectangle(iconSizeMdpi, scaleFactor);
- Rectangle targetRect = Util.scaleRectangle(targetRectMdpi, scaleFactor);
- BufferedImage outImage = Util.newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g = (Graphics2D) outImage.getGraphics();
-
- BufferedImage tempImage = Util.newArgbBufferedImage(
- imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) tempImage.getGraphics();
- Util.drawCenterInside(g2, options.sourceImage, targetRect);
-
- TabOptions tabOptions = (TabOptions) options;
- if (tabOptions.selected) {
- if (tabOptions.oldStyle) {
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(
- new GradientPaint(
- 0, 0,
- new Color(0xa3a3a3),
- 0, imageRect.height,
- new Color(0x787878))),
- new ShadowEffect(
- 0,
- 2 * scaleFactor,
- 2 * scaleFactor,
- Color.BLACK,
- 0.2,
- true),
- new ShadowEffect(
- 0,
- 1,
- 0,
- Color.BLACK,
- 0.35,
- true),
- new ShadowEffect(
- 0,
- -1,
- 0,
- Color.WHITE,
- 0.35,
- true),
- });
- } else {
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(Color.WHITE),
- new ShadowEffect(
- 0,
- 0,
- 3 * scaleFactor,
- Color.BLACK,
- 0.25,
- false),
- });
- }
- } else {
- // Unselected
- if (tabOptions.oldStyle) {
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(
- new GradientPaint(
- 0, 0.25f * imageRect.height,
- new Color(0xf9f9f9),
- 0, imageRect.height,
- new Color(0xdfdfdf))),
- new ShadowEffect(
- 0,
- 2 * scaleFactor,
- 2 * scaleFactor,
- Color.BLACK,
- 0.1,
- true),
- new ShadowEffect(
- 0,
- 1,
- 0,
- Color.BLACK,
- 0.35,
- true),
- new ShadowEffect(
- 0,
- -1,
- 0,
- Color.WHITE,
- 0.35,
- true),
- });
- } else {
- Util.drawEffects(g, tempImage, 0, 0, new Effect[] {
- new FillEffect(new Color(0x808080)),
- });
- }
- }
-
- g.dispose();
- g2.dispose();
-
- return outImage;
- }
-
- @Override
- public void generate(String category, Map<String, Map<String, BufferedImage>> categoryMap,
- GraphicGeneratorContext context, Options baseOptions, String name) {
- TabOptions options = (TabOptions) baseOptions;
- // Generate all permutations of tabOptions.selected and tabOptions.oldStyle
- options.selected = true;
- options.oldStyle = false;
-
- String selectedLabelV5 = "Selected (v5+)";
- String unselectedLabelV5 = "Unselected (v5+)";
- String selectedLabel = "Selected";
- String unselectedLabel = "Unselected";
-
- boolean generateOldStyle = options.minSdk < 5;
- if (generateOldStyle) {
- options.oldStyle = true;
- options.selected = true;
- super.generate(selectedLabel, categoryMap, context, options, name);
- options.selected = false;
- super.generate(unselectedLabel, categoryMap, context, options, name);
- }
-
- options.oldStyle = false;
- options.selected = true;
- super.generate(generateOldStyle ? unselectedLabelV5 : unselectedLabel,
- categoryMap, context, options, name);
- options.selected = false;
- super.generate(generateOldStyle ? selectedLabelV5 : selectedLabel,
- categoryMap, context, options, name);
- }
-
- @Override
- protected String getIconFolder(Options options) {
- String folder = super.getIconFolder(options);
-
- TabOptions tabOptions = (TabOptions) options;
- if (tabOptions.oldStyle || options.minSdk >= 5) {
- return folder;
- } else {
- return folder + "-v5"; //$NON-NLS-1$
- }
- }
-
- @Override
- protected String getIconName(Options options, String name) {
- TabOptions tabOptions = (TabOptions) options;
- if (tabOptions.selected) {
- return name + "_selected.png"; //$NON-NLS-1$
- } else {
- return name + "_unselected.png"; //$NON-NLS-1$
- }
- }
-
- /** Options specific to generating tab icons */
- public static class TabOptions extends GraphicGenerator.Options {
- /** Generate icon in the style used prior to v5 */
- public boolean oldStyle;
- /** Generate "selected" icon if true, and "unselected" icon if false */
- public boolean selected = true;
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/TextRenderUtil.java b/assetstudio/src/com/android/assetstudiolib/TextRenderUtil.java
deleted file mode 100644
index e08a234..0000000
--- a/assetstudio/src/com/android/assetstudiolib/TextRenderUtil.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.RenderingHints;
-import java.awt.font.FontRenderContext;
-import java.awt.font.TextLayout;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-
-/**
- * A set of utility classes for rendering text to a {@link BufferedImage}, suitable for use as a
- * source image to {@link GraphicGenerator} objects.
- */
-public class TextRenderUtil {
- /**
- * Renders the given string with the provided {@link Options} to a
- * {@link BufferedImage}.
- *
- * @param text The text to render.
- * @param paddingPercentage If nonzero, a percentage of the width or height
- * (whichever is smaller) to add as padding around the text
- * @param options The optional parameters for rendering the text.
- * @return An image, suitable for use as an input to a
- * {@link GraphicGenerator}.
- */
- public static BufferedImage renderTextImage(String text, int paddingPercentage,
- Options options) {
- if (options == null) {
- options = new Options();
- }
-
- BufferedImage tempImage = Util.newArgbBufferedImage(1, 1);
- if (text == null || text.equals("")) {
- return tempImage;
- }
-
- Graphics2D tempG = (Graphics2D) tempImage.getGraphics();
-
- Font font = options.font;
- if (font == null) {
- font = new Font(options.fontName, options.fontStyle, options.fontSize);
- // Map<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();
- // map.put(TextAttribute.TRACKING, 0.3);
- // font = font.deriveFont(map);
- }
-
- FontRenderContext frc = tempG.getFontRenderContext();
-
- TextLayout layout = new TextLayout(text, font, frc);
- Rectangle2D bounds = layout.getBounds();
-
- // The padding is a percentage relative to the overall minimum of the width or height
- if (paddingPercentage != 0) {
- double minDimension = Math.min(bounds.getWidth(), bounds.getHeight());
- double delta = minDimension * paddingPercentage / 100;
- bounds.setRect(bounds.getMinX() - delta, bounds.getMinY() - delta,
- bounds.getWidth() + 2 * delta, bounds.getHeight() + 2 * delta);
- }
-
- BufferedImage image = Util.newArgbBufferedImage(
- Math.max(1, (int) bounds.getWidth()), Math.max(1, (int) bounds.getHeight()));
- Graphics2D g = (Graphics2D) image.getGraphics();
- g.setColor(new Color(options.foregroundColor, true));
- g.setFont(font);
-
- g.setRenderingHint(
- RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setRenderingHint(
- RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-
- g.drawString(text, (float) -bounds.getX(), (float) -bounds.getY());
-
- g.dispose();
- tempG.dispose();
-
- return image;
- }
-
- /**
- * The parameters for text rendering. There are no required values so a <code>new
- * Options()</code> object is considered valid.
- */
- public static class Options {
- // We use a large default font size to reduce the need to scale generated images up.
- // TODO: Instead, a graphic generator should use a different source image for each density.
- private static final int DEFAULT_FONT_SIZE = 512;
-
- /** Foreground color to render text with, as an AARRGGBB packed integer */
- public int foregroundColor = 0xFFFFFFFF;
-
- /**
- * The optional {@link Font} to use. If null, a {@link Font} object will be generated using
- * the other options.
- */
- public Font font = null;
-
- /**
- * The optional font name. Defaults to {@link Font#SERIF}.
- *
- * @see Font#Font(String, int, int)
- */
- public String fontName = Font.SERIF;
-
- /**
- * The optional font styling (bold and/or italic). Defaults to no styling.
- *
- * @see Font#Font(String, int, int)
- */
- public int fontStyle = 0;
-
- /**
- * The optional font size, in points. Defaults to a very large font size, to prevent
- * up-scaling rendered text.
- *
- * @see Font#Font(String, int, int)
- */
- public int fontSize = DEFAULT_FONT_SIZE;
- }
-}
diff --git a/assetstudio/src/com/android/assetstudiolib/Util.java b/assetstudio/src/com/android/assetstudiolib/Util.java
deleted file mode 100644
index ee2a5f7..0000000
--- a/assetstudio/src/com/android/assetstudiolib/Util.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.assetstudiolib;
-
-import java.awt.AlphaComposite;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Rectangle;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ConvolveOp;
-import java.awt.image.Kernel;
-import java.awt.image.Raster;
-import java.awt.image.RescaleOp;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A set of utility classes for manipulating {@link BufferedImage} objects and drawing them to
- * {@link Graphics2D} canvases.
- */
-public class Util {
- /**
- * Scales the given rectangle by the given scale factor.
- *
- * @param rect The rectangle to scale.
- * @param scaleFactor The factor to scale by.
- * @return The scaled rectangle.
- */
- public static Rectangle scaleRectangle(Rectangle rect, float scaleFactor) {
- return new Rectangle(
- (int) Math.round(rect.x * scaleFactor),
- (int) Math.round(rect.y * scaleFactor),
- (int) Math.round(rect.width * scaleFactor),
- (int) Math.round(rect.height * scaleFactor));
- }
-
- /**
- * Creates a new ARGB {@link BufferedImage} of the given width and height.
- *
- * @param width The width of the new image.
- * @param height The height of the new image.
- * @return The newly created image.
- */
- public static BufferedImage newArgbBufferedImage(int width, int height) {
- return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- }
-
- /**
- * Smoothly scales the given {@link BufferedImage} to the given width and height using the
- * {@link Image#SCALE_SMOOTH} algorithm (generally bicubic resampling or bilinear filtering).
- *
- * @param source The source image.
- * @param width The destination width to scale to.
- * @param height The destination height to scale to.
- * @return A new, scaled image.
- */
- public static BufferedImage scaledImage(BufferedImage source, int width, int height) {
- Image scaledImage = source.getScaledInstance(width, height, Image.SCALE_SMOOTH);
- BufferedImage scaledBufImage = new BufferedImage(width, height,
- BufferedImage.TYPE_INT_ARGB);
- Graphics g = scaledBufImage.createGraphics();
- g.drawImage(scaledImage, 0, 0, null);
- g.dispose();
- return scaledBufImage;
- }
-
- /**
- * Applies a gaussian blur of the given radius to the given {@link BufferedImage} using a kernel
- * convolution.
- *
- * @param source The source image.
- * @param radius The blur radius, in pixels.
- * @return A new, blurred image, or the source image if no blur is performed.
- */
- public static BufferedImage blurredImage(BufferedImage source, double radius) {
- if (radius == 0) {
- return source;
- }
-
- final int r = (int) Math.ceil(radius);
- final int rows = r * 2 + 1;
- final float[] kernelData = new float[rows * rows];
-
- final double sigma = radius / 3;
- final double sigma22 = 2 * sigma * sigma;
- final double sqrtPiSigma22 = Math.sqrt(Math.PI * sigma22);
- final double radius2 = radius * radius;
-
- double total = 0;
- int index = 0;
- double distance2;
-
- int x, y;
- for (y = -r; y <= r; y++) {
- for (x = -r; x <= r; x++) {
- distance2 = 1.0 * x * x + 1.0 * y * y;
- if (distance2 > radius2) {
- kernelData[index] = 0;
- } else {
- kernelData[index] = (float) (Math.exp(-distance2 / sigma22) / sqrtPiSigma22);
- }
- total += kernelData[index];
- ++index;
- }
- }
-
- for (index = 0; index < kernelData.length; index++) {
- kernelData[index] /= total;
- }
-
- // We first pad the image so the kernel can operate at the edges.
- BufferedImage paddedSource = paddedImage(source, r);
- BufferedImage blurredPaddedImage = operatedImage(paddedSource, new ConvolveOp(
- new Kernel(rows, rows, kernelData), ConvolveOp.EDGE_ZERO_FILL, null));
- return blurredPaddedImage.getSubimage(r, r, source.getWidth(), source.getHeight());
- }
-
- /**
- * Inverts the alpha channel of the given {@link BufferedImage}. RGB data for the inverted area
- * are undefined, so it's generally best to fill the resulting image with a color.
- *
- * @param source The source image.
- * @return A new image with an alpha channel inverted from the original.
- */
- public static BufferedImage invertedAlphaImage(BufferedImage source) {
- final float[] scaleFactors = new float[]{1, 1, 1, -1};
- final float[] offsets = new float[]{0, 0, 0, 255};
-
- return operatedImage(source, new RescaleOp(scaleFactors, offsets, null));
- }
-
- /**
- * Applies a {@link BufferedImageOp} on the given {@link BufferedImage}.
- *
- * @param source The source image.
- * @param op The operation to perform.
- * @return A new image with the operation performed.
- */
- public static BufferedImage operatedImage(BufferedImage source, BufferedImageOp op) {
- BufferedImage newImage = newArgbBufferedImage(source.getWidth(), source.getHeight());
- Graphics2D g = (Graphics2D) newImage.getGraphics();
- g.drawImage(source, op, 0, 0);
- return newImage;
- }
-
- /**
- * Fills the given {@link BufferedImage} with a {@link Paint}, preserving its alpha channel.
- *
- * @param source The source image.
- * @param paint The paint to fill with.
- * @return A new, painted/filled image.
- */
- public static BufferedImage filledImage(BufferedImage source, Paint paint) {
- BufferedImage newImage = newArgbBufferedImage(source.getWidth(), source.getHeight());
- Graphics2D g = (Graphics2D) newImage.getGraphics();
- g.drawImage(source, 0, 0, null);
- g.setComposite(AlphaComposite.SrcAtop);
- g.setPaint(paint);
- g.fillRect(0, 0, source.getWidth(), source.getHeight());
- return newImage;
- }
-
- /**
- * Pads the given {@link BufferedImage} on all sides by the given padding amount.
- *
- * @param source The source image.
- * @param padding The amount to pad on all sides, in pixels.
- * @return A new, padded image, or the source image if no padding is performed.
- */
- public static BufferedImage paddedImage(BufferedImage source, int padding) {
- if (padding == 0) {
- return source;
- }
-
- BufferedImage newImage = newArgbBufferedImage(
- source.getWidth() + padding * 2, source.getHeight() + padding * 2);
- Graphics2D g = (Graphics2D) newImage.getGraphics();
- g.drawImage(source, padding, padding, null);
- return newImage;
- }
-
- /**
- * Trims the transparent pixels from the given {@link BufferedImage} (returns a sub-image).
- *
- * @param source The source image.
- * @return A new, trimmed image, or the source image if no trim is performed.
- */
- public static BufferedImage trimmedImage(BufferedImage source) {
- final int minAlpha = 1;
- final int srcWidth = source.getWidth();
- final int srcHeight = source.getHeight();
- Raster raster = source.getRaster();
- int l = srcWidth, t = srcHeight, r = 0, b = 0;
-
- int alpha, x, y;
- int[] pixel = new int[4];
- for (y = 0; y < srcHeight; y++) {
- for (x = 0; x < srcWidth; x++) {
- raster.getPixel(x, y, pixel);
- alpha = pixel[3];
- if (alpha >= minAlpha) {
- l = Math.min(x, l);
- t = Math.min(y, t);
- r = Math.max(x, r);
- b = Math.max(y, b);
- }
- }
- }
-
- if (l > r || t > b) {
- // No pixels, couldn't trim
- return source;
- }
-
- return source.getSubimage(l, t, r - l + 1, b - t + 1);
- }
-
- /**
- * Draws the given {@link BufferedImage} to the canvas, at the given coordinates, with the given
- * {@link Effect}s applied. Note that drawn effects may be outside the bounds of the source
- * image.
- *
- * @param g The destination canvas.
- * @param source The source image.
- * @param x The x offset at which to draw the image.
- * @param y The y offset at which to draw the image.
- * @param effects The list of effects to apply.
- */
- public static void drawEffects(Graphics2D g, BufferedImage source, int x, int y,
- Effect[] effects) {
- List<ShadowEffect> shadowEffects = new ArrayList<ShadowEffect>();
- List<FillEffect> fillEffects = new ArrayList<FillEffect>();
-
- for (Effect effect : effects) {
- if (effect instanceof ShadowEffect) {
- shadowEffects.add((ShadowEffect) effect);
- } else if (effect instanceof FillEffect) {
- fillEffects.add((FillEffect) effect);
- }
- }
-
- Composite oldComposite = g.getComposite();
- for (ShadowEffect effect : shadowEffects) {
- if (effect.inner) {
- continue;
- }
-
- // Outer shadow
- g.setComposite(AlphaComposite.getInstance(
- AlphaComposite.SRC_OVER, (float) effect.opacity));
- g.drawImage(
- filledImage(
- blurredImage(source, effect.radius),
- effect.color),
- (int) effect.xOffset, (int) effect.yOffset, null);
- }
- g.setComposite(oldComposite);
-
- // Inner shadow & fill effects.
- final Rectangle imageRect = new Rectangle(0, 0, source.getWidth(), source.getHeight());
- BufferedImage out = newArgbBufferedImage(imageRect.width, imageRect.height);
- Graphics2D g2 = (Graphics2D) out.getGraphics();
- double fillOpacity = 1.0;
-
- g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
- g2.drawImage(source, 0, 0, null);
- g2.setComposite(AlphaComposite.SrcAtop);
-
- // Gradient fill
- for (FillEffect effect : fillEffects) {
- g2.setPaint(effect.paint);
- g2.fillRect(0, 0, imageRect.width, imageRect.height);
- fillOpacity = Math.max(0, Math.min(1, effect.opacity));
- }
-
- // Inner shadows
- for (ShadowEffect effect : shadowEffects) {
- if (!effect.inner) {
- continue;
- }
-
- BufferedImage innerShadowImage = newArgbBufferedImage(
- imageRect.width, imageRect.height);
- Graphics2D g3 = (Graphics2D) innerShadowImage.getGraphics();
- g3.drawImage(source, (int) effect.xOffset, (int) effect.yOffset, null);
- g2.setComposite(AlphaComposite.getInstance(
- AlphaComposite.SRC_ATOP, (float) effect.opacity));
- g2.drawImage(
- filledImage(
- blurredImage(invertedAlphaImage(innerShadowImage), effect.radius),
- effect.color),
- 0, 0, null);
- }
-
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) fillOpacity));
- g.drawImage(out, x, y, null);
- g.setComposite(oldComposite);
- }
-
- /**
- * Draws the given {@link BufferedImage} to the canvas, centered, wholly contained within the
- * bounds defined by the destination rectangle, and with preserved aspect ratio.
- *
- * @param g The destination canvas.
- * @param source The source image.
- * @param dstRect The destination rectangle in the destination canvas into which to draw the
- * image.
- */
- public static void drawCenterInside(Graphics2D g, BufferedImage source, Rectangle dstRect) {
- final int srcWidth = source.getWidth();
- final int srcHeight = source.getHeight();
- if (srcWidth * 1.0 / srcHeight > dstRect.width * 1.0 / dstRect.height) {
- final int scaledWidth = Math.max(1, dstRect.width);
- final int scaledHeight = Math.max(1, dstRect.width * srcHeight / srcWidth);
- Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
- g.drawImage(scaledImage,
- dstRect.x,
- dstRect.y + (dstRect.height - scaledHeight) / 2,
- dstRect.x + dstRect.width,
- dstRect.y + (dstRect.height - scaledHeight) / 2 + scaledHeight,
- 0,
- 0,
- 0 + scaledWidth,
- 0 + scaledHeight,
- null);
- } else {
- final int scaledWidth = Math.max(1, dstRect.height * srcWidth / srcHeight);
- final int scaledHeight = Math.max(1, dstRect.height);
- Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
- g.drawImage(scaledImage,
- dstRect.x + (dstRect.width - scaledWidth) / 2,
- dstRect.y,
- dstRect.x + (dstRect.width - scaledWidth) / 2 + scaledWidth,
- dstRect.y + dstRect.height,
- 0,
- 0,
- 0 + scaledWidth,
- 0 + scaledHeight,
- null);
- }
- }
-
- /**
- * Draws the given {@link BufferedImage} to the canvas, centered and cropped to fill the
- * bounds defined by the destination rectangle, and with preserved aspect ratio.
- *
- * @param g The destination canvas.
- * @param source The source image.
- * @param dstRect The destination rectangle in the destination canvas into which to draw the
- * image.
- */
- public static void drawCenterCrop(Graphics2D g, BufferedImage source, Rectangle dstRect) {
- final int srcWidth = source.getWidth();
- final int srcHeight = source.getHeight();
- if (srcWidth * 1.0 / srcHeight > dstRect.width * 1.0 / dstRect.height) {
- final int scaledWidth = dstRect.height * srcWidth / srcHeight;
- final int scaledHeight = dstRect.height;
- Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
- g.drawImage(scaledImage,
- dstRect.x,
- dstRect.y,
- dstRect.x + dstRect.width,
- dstRect.y + dstRect.height,
- 0 + (scaledWidth - dstRect.width) / 2,
- 0,
- 0 + (scaledWidth - dstRect.width) / 2 + dstRect.width,
- 0 + dstRect.height,
- null);
- } else {
- final int scaledWidth = dstRect.width;
- final int scaledHeight = dstRect.width * srcHeight / srcWidth;
- Image scaledImage = scaledImage(source, scaledWidth, scaledHeight);
- g.drawImage(scaledImage,
- dstRect.x,
- dstRect.y,
- dstRect.x + dstRect.width,
- dstRect.y + dstRect.height,
- 0,
- 0 + (scaledHeight - dstRect.height) / 2,
- 0 + dstRect.width,
- 0 + (scaledHeight - dstRect.height) / 2 + dstRect.height,
- null);
- }
- }
-
- /**
- * An effect to apply in
- * {@link Util#drawEffects(java.awt.Graphics2D, java.awt.image.BufferedImage, int, int, Util.Effect[])}
- */
- public static abstract class Effect {
- }
-
- /**
- * An inner or outer shadow.
- */
- public static class ShadowEffect extends Effect {
- public double xOffset;
- public double yOffset;
- public double radius;
- public Color color;
- public double opacity;
- public boolean inner;
-
- public ShadowEffect(double xOffset, double yOffset, double radius, Color color,
- double opacity, boolean inner) {
- this.xOffset = xOffset;
- this.yOffset = yOffset;
- this.radius = radius;
- this.color = color;
- this.opacity = opacity;
- this.inner = inner;
- }
- }
-
- /**
- * A fill, defined by a paint.
- */
- public static class FillEffect extends Effect {
- public Paint paint;
- public double opacity;
-
- public FillEffect(Paint paint, double opacity) {
- this.paint = paint;
- this.opacity = opacity;
- }
-
- public FillEffect(Paint paint) {
- this.paint = paint;
- this.opacity = 1.0;
- }
- }
-}
diff --git a/assetstudio/src/images/clipart/big/1-navigation-accept.png b/assetstudio/src/images/clipart/big/1-navigation-accept.png
deleted file mode 100644
index 121b347..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-accept.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-back.png b/assetstudio/src/images/clipart/big/1-navigation-back.png
deleted file mode 100644
index 863074c..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-cancel.png b/assetstudio/src/images/clipart/big/1-navigation-cancel.png
deleted file mode 100644
index d968d34..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-cancel.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-collapse.png b/assetstudio/src/images/clipart/big/1-navigation-collapse.png
deleted file mode 100644
index e525983..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-collapse.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-expand.png b/assetstudio/src/images/clipart/big/1-navigation-expand.png
deleted file mode 100644
index f5b0728..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-expand.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-forward.png b/assetstudio/src/images/clipart/big/1-navigation-forward.png
deleted file mode 100644
index 4cae802..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-next-item.png b/assetstudio/src/images/clipart/big/1-navigation-next-item.png
deleted file mode 100644
index a1b8b83..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-next-item.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-previous-item.png b/assetstudio/src/images/clipart/big/1-navigation-previous-item.png
deleted file mode 100644
index 9312bf6..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-previous-item.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/1-navigation-refresh.png b/assetstudio/src/images/clipart/big/1-navigation-refresh.png
deleted file mode 100644
index b5202f9..0000000
--- a/assetstudio/src/images/clipart/big/1-navigation-refresh.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-accounts.png b/assetstudio/src/images/clipart/big/10-device-access-accounts.png
deleted file mode 100644
index 64544c5..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-accounts.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-add-alarm.png b/assetstudio/src/images/clipart/big/10-device-access-add-alarm.png
deleted file mode 100644
index bd4bcc3..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-add-alarm.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-alarms.png b/assetstudio/src/images/clipart/big/10-device-access-alarms.png
deleted file mode 100644
index a5b1ead..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-alarms.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-battery.png b/assetstudio/src/images/clipart/big/10-device-access-battery.png
deleted file mode 100644
index d86b2c1..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-battery.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-bightness-low.png b/assetstudio/src/images/clipart/big/10-device-access-bightness-low.png
deleted file mode 100644
index 738f203..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-bightness-low.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-bluetooth-connected.png b/assetstudio/src/images/clipart/big/10-device-access-bluetooth-connected.png
deleted file mode 100644
index 403a0b5..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-bluetooth-connected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-bluetooth-searching.png b/assetstudio/src/images/clipart/big/10-device-access-bluetooth-searching.png
deleted file mode 100644
index a99f65a..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-bluetooth-searching.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-bluetooth.png b/assetstudio/src/images/clipart/big/10-device-access-bluetooth.png
deleted file mode 100644
index 556499d..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-brightness-auto.png b/assetstudio/src/images/clipart/big/10-device-access-brightness-auto.png
deleted file mode 100644
index 46d2b8a..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-brightness-auto.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-brightness-high.png b/assetstudio/src/images/clipart/big/10-device-access-brightness-high.png
deleted file mode 100644
index 97e3f19..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-brightness-high.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-brightness-medium.png b/assetstudio/src/images/clipart/big/10-device-access-brightness-medium.png
deleted file mode 100644
index 5e361cb..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-brightness-medium.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-call.png b/assetstudio/src/images/clipart/big/10-device-access-call.png
deleted file mode 100644
index 940bcb6..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-call.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-camera.png b/assetstudio/src/images/clipart/big/10-device-access-camera.png
deleted file mode 100644
index ad8857a..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-camera.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-data-usage.png b/assetstudio/src/images/clipart/big/10-device-access-data-usage.png
deleted file mode 100644
index 9fa73a5..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-data-usage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-dial-pad.png b/assetstudio/src/images/clipart/big/10-device-access-dial-pad.png
deleted file mode 100644
index 81da080..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-dial-pad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-end-call.png b/assetstudio/src/images/clipart/big/10-device-access-end-call.png
deleted file mode 100644
index c28f284..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-end-call.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-flash-automatic.png b/assetstudio/src/images/clipart/big/10-device-access-flash-automatic.png
deleted file mode 100644
index e5c2c03..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-flash-automatic.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-flash-off.png b/assetstudio/src/images/clipart/big/10-device-access-flash-off.png
deleted file mode 100644
index dfcb747..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-flash-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-flash-on.png b/assetstudio/src/images/clipart/big/10-device-access-flash-on.png
deleted file mode 100644
index 1109aa0..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-flash-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-location-found.png b/assetstudio/src/images/clipart/big/10-device-access-location-found.png
deleted file mode 100644
index d829a3c..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-location-found.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-location-off.png b/assetstudio/src/images/clipart/big/10-device-access-location-off.png
deleted file mode 100644
index e58c258..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-location-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-location-searching.png b/assetstudio/src/images/clipart/big/10-device-access-location-searching.png
deleted file mode 100644
index 3de2f26..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-location-searching.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-mic-muted.png b/assetstudio/src/images/clipart/big/10-device-access-mic-muted.png
deleted file mode 100644
index 65b4ae6..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-mic-muted.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-mic.png b/assetstudio/src/images/clipart/big/10-device-access-mic.png
deleted file mode 100644
index 02c1ee8..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-mic.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-network-cell.png b/assetstudio/src/images/clipart/big/10-device-access-network-cell.png
deleted file mode 100644
index 9d60dbd..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-network-cell.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-network-wifi.png b/assetstudio/src/images/clipart/big/10-device-access-network-wifi.png
deleted file mode 100644
index 577abdb..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-network-wifi.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-new-account.png b/assetstudio/src/images/clipart/big/10-device-access-new-account.png
deleted file mode 100644
index d9707d8..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-new-account.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-not-secure.png b/assetstudio/src/images/clipart/big/10-device-access-not-secure.png
deleted file mode 100644
index 2ea293a..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-not-secure.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-ring-volume.png b/assetstudio/src/images/clipart/big/10-device-access-ring-volume.png
deleted file mode 100644
index 9d19f89..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-ring-volume.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-landscape.png b/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-landscape.png
deleted file mode 100644
index c702480..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-landscape.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-portrait.png b/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-portrait.png
deleted file mode 100644
index f66923c..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-screen-locked-to-portrait.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-screen-rotation.png b/assetstudio/src/images/clipart/big/10-device-access-screen-rotation.png
deleted file mode 100644
index 22e0fcb..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-screen-rotation.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-sd-storage.png b/assetstudio/src/images/clipart/big/10-device-access-sd-storage.png
deleted file mode 100644
index cbde363..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-sd-storage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-secure.png b/assetstudio/src/images/clipart/big/10-device-access-secure.png
deleted file mode 100644
index 83f4f7d..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-secure.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-storage.png b/assetstudio/src/images/clipart/big/10-device-access-storage.png
deleted file mode 100644
index 5addbad..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-storage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-switch-camera.png b/assetstudio/src/images/clipart/big/10-device-access-switch-camera.png
deleted file mode 100644
index 8b2a2e3..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-switch-camera.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-switch-video.png b/assetstudio/src/images/clipart/big/10-device-access-switch-video.png
deleted file mode 100644
index a2919f1..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-switch-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-time.png b/assetstudio/src/images/clipart/big/10-device-access-time.png
deleted file mode 100644
index aa21482..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-time.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-usb.png b/assetstudio/src/images/clipart/big/10-device-access-usb.png
deleted file mode 100644
index ba01983..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-usb.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-video.png b/assetstudio/src/images/clipart/big/10-device-access-video.png
deleted file mode 100644
index e18c6bd..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-volume-muted.png b/assetstudio/src/images/clipart/big/10-device-access-volume-muted.png
deleted file mode 100644
index 10433a7..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-volume-muted.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/10-device-access-volume-on.png b/assetstudio/src/images/clipart/big/10-device-access-volume-on.png
deleted file mode 100644
index bc86a7b..0000000
--- a/assetstudio/src/images/clipart/big/10-device-access-volume-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-off.png b/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-off.png
deleted file mode 100644
index f7db5e8..0000000
--- a/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-on.png b/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-on.png
deleted file mode 100644
index 7e8bf73..0000000
--- a/assetstudio/src/images/clipart/big/11-alerts-and-states-airplane-mode-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/11-alerts-and-states-error.png b/assetstudio/src/images/clipart/big/11-alerts-and-states-error.png
deleted file mode 100644
index 24335f9..0000000
--- a/assetstudio/src/images/clipart/big/11-alerts-and-states-error.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/11-alerts-and-states-warning.png b/assetstudio/src/images/clipart/big/11-alerts-and-states-warning.png
deleted file mode 100644
index be321f4..0000000
--- a/assetstudio/src/images/clipart/big/11-alerts-and-states-warning.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-computer.png b/assetstudio/src/images/clipart/big/12-hardware-computer.png
deleted file mode 100644
index 6170018..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-computer.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-dock.png b/assetstudio/src/images/clipart/big/12-hardware-dock.png
deleted file mode 100644
index c2fc8c8..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-dock.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-gamepad.png b/assetstudio/src/images/clipart/big/12-hardware-gamepad.png
deleted file mode 100644
index 3ddc322..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-gamepad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-headphones.png b/assetstudio/src/images/clipart/big/12-hardware-headphones.png
deleted file mode 100644
index e7bce69..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-headphones.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-headset.png b/assetstudio/src/images/clipart/big/12-hardware-headset.png
deleted file mode 100644
index 29f659b..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-headset.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-keyboard.png b/assetstudio/src/images/clipart/big/12-hardware-keyboard.png
deleted file mode 100644
index 4a2bf70..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-keyboard.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-mouse.png b/assetstudio/src/images/clipart/big/12-hardware-mouse.png
deleted file mode 100644
index 2bf8c05..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-mouse.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/12-hardware-phone.png b/assetstudio/src/images/clipart/big/12-hardware-phone.png
deleted file mode 100644
index 423fe65..0000000
--- a/assetstudio/src/images/clipart/big/12-hardware-phone.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/2-action-about.png b/assetstudio/src/images/clipart/big/2-action-about.png
deleted file mode 100644
index 6d43316..0000000
--- a/assetstudio/src/images/clipart/big/2-action-about.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/2-action-help.png b/assetstudio/src/images/clipart/big/2-action-help.png
deleted file mode 100644
index 16eb8ef..0000000
--- a/assetstudio/src/images/clipart/big/2-action-help.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/2-action-search.png b/assetstudio/src/images/clipart/big/2-action-search.png
deleted file mode 100644
index 9345a06..0000000
--- a/assetstudio/src/images/clipart/big/2-action-search.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/2-action-settings.png b/assetstudio/src/images/clipart/big/2-action-settings.png
deleted file mode 100644
index a049ca0..0000000
--- a/assetstudio/src/images/clipart/big/2-action-settings.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-bad.png b/assetstudio/src/images/clipart/big/3-rating-bad.png
deleted file mode 100644
index 1ab8c5b..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-bad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-favorite.png b/assetstudio/src/images/clipart/big/3-rating-favorite.png
deleted file mode 100644
index 9b68720..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-favorite.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-good.png b/assetstudio/src/images/clipart/big/3-rating-good.png
deleted file mode 100644
index c72826b..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-good.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-half-important.png b/assetstudio/src/images/clipart/big/3-rating-half-important.png
deleted file mode 100644
index 2110a0f..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-half-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-important.png b/assetstudio/src/images/clipart/big/3-rating-important.png
deleted file mode 100644
index dbad544..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/3-rating-not-important.png b/assetstudio/src/images/clipart/big/3-rating-not-important.png
deleted file mode 100644
index f7cf26f..0000000
--- a/assetstudio/src/images/clipart/big/3-rating-not-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-cloud.png b/assetstudio/src/images/clipart/big/4-collections-cloud.png
deleted file mode 100644
index a2cedbf..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-cloud.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-collection.png b/assetstudio/src/images/clipart/big/4-collections-collection.png
deleted file mode 100644
index dfb2508..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-collection.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-go-to-today.png b/assetstudio/src/images/clipart/big/4-collections-go-to-today.png
deleted file mode 100644
index b4971ca..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-go-to-today.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-labels.png b/assetstudio/src/images/clipart/big/4-collections-labels.png
deleted file mode 100644
index 16f35a8..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-labels.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-new-label.png b/assetstudio/src/images/clipart/big/4-collections-new-label.png
deleted file mode 100644
index cbf02af..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-new-label.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-sort-by-size.png b/assetstudio/src/images/clipart/big/4-collections-sort-by-size.png
deleted file mode 100644
index 10aec0d..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-sort-by-size.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-view-as-grid.png b/assetstudio/src/images/clipart/big/4-collections-view-as-grid.png
deleted file mode 100644
index 10a8fe3..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-view-as-grid.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/4-collections-view-as-list.png b/assetstudio/src/images/clipart/big/4-collections-view-as-list.png
deleted file mode 100644
index 5cf08e4..0000000
--- a/assetstudio/src/images/clipart/big/4-collections-view-as-list.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-attachment.png b/assetstudio/src/images/clipart/big/5-content-attachment.png
deleted file mode 100644
index 92e6726..0000000
--- a/assetstudio/src/images/clipart/big/5-content-attachment.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-backspace.png b/assetstudio/src/images/clipart/big/5-content-backspace.png
deleted file mode 100644
index 9a7e456..0000000
--- a/assetstudio/src/images/clipart/big/5-content-backspace.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-copy.png b/assetstudio/src/images/clipart/big/5-content-copy.png
deleted file mode 100644
index 284a5ce..0000000
--- a/assetstudio/src/images/clipart/big/5-content-copy.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-cut.png b/assetstudio/src/images/clipart/big/5-content-cut.png
deleted file mode 100644
index 18d1763..0000000
--- a/assetstudio/src/images/clipart/big/5-content-cut.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-discard.png b/assetstudio/src/images/clipart/big/5-content-discard.png
deleted file mode 100644
index e40e1fe..0000000
--- a/assetstudio/src/images/clipart/big/5-content-discard.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-edit.png b/assetstudio/src/images/clipart/big/5-content-edit.png
deleted file mode 100644
index f75157c..0000000
--- a/assetstudio/src/images/clipart/big/5-content-edit.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-email.png b/assetstudio/src/images/clipart/big/5-content-email.png
deleted file mode 100644
index 6bec626..0000000
--- a/assetstudio/src/images/clipart/big/5-content-email.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-event.png b/assetstudio/src/images/clipart/big/5-content-event.png
deleted file mode 100644
index dc4ed94..0000000
--- a/assetstudio/src/images/clipart/big/5-content-event.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-import-export.png b/assetstudio/src/images/clipart/big/5-content-import-export.png
deleted file mode 100644
index 7dcd6b0..0000000
--- a/assetstudio/src/images/clipart/big/5-content-import-export.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-merge.png b/assetstudio/src/images/clipart/big/5-content-merge.png
deleted file mode 100644
index 45ca498..0000000
--- a/assetstudio/src/images/clipart/big/5-content-merge.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-new-attachment.png b/assetstudio/src/images/clipart/big/5-content-new-attachment.png
deleted file mode 100644
index 3e441d8..0000000
--- a/assetstudio/src/images/clipart/big/5-content-new-attachment.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-new-email.png b/assetstudio/src/images/clipart/big/5-content-new-email.png
deleted file mode 100644
index fdcd64b..0000000
--- a/assetstudio/src/images/clipart/big/5-content-new-email.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-new-event.png b/assetstudio/src/images/clipart/big/5-content-new-event.png
deleted file mode 100644
index 29ef513..0000000
--- a/assetstudio/src/images/clipart/big/5-content-new-event.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-new-picture.png b/assetstudio/src/images/clipart/big/5-content-new-picture.png
deleted file mode 100644
index 1975219..0000000
--- a/assetstudio/src/images/clipart/big/5-content-new-picture.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-new.png b/assetstudio/src/images/clipart/big/5-content-new.png
deleted file mode 100644
index 9bb4337..0000000
--- a/assetstudio/src/images/clipart/big/5-content-new.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-paste.png b/assetstudio/src/images/clipart/big/5-content-paste.png
deleted file mode 100644
index f9393c0..0000000
--- a/assetstudio/src/images/clipart/big/5-content-paste.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-picture.png b/assetstudio/src/images/clipart/big/5-content-picture.png
deleted file mode 100644
index dc3251b..0000000
--- a/assetstudio/src/images/clipart/big/5-content-picture.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-read.png b/assetstudio/src/images/clipart/big/5-content-read.png
deleted file mode 100644
index 0a48d75..0000000
--- a/assetstudio/src/images/clipart/big/5-content-read.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-remove.png b/assetstudio/src/images/clipart/big/5-content-remove.png
deleted file mode 100644
index d968d34..0000000
--- a/assetstudio/src/images/clipart/big/5-content-remove.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-save.png b/assetstudio/src/images/clipart/big/5-content-save.png
deleted file mode 100644
index befe49a..0000000
--- a/assetstudio/src/images/clipart/big/5-content-save.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-select-all.png b/assetstudio/src/images/clipart/big/5-content-select-all.png
deleted file mode 100644
index 572b2b5..0000000
--- a/assetstudio/src/images/clipart/big/5-content-select-all.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-split.png b/assetstudio/src/images/clipart/big/5-content-split.png
deleted file mode 100644
index 7e5d059..0000000
--- a/assetstudio/src/images/clipart/big/5-content-split.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-undo.png b/assetstudio/src/images/clipart/big/5-content-undo.png
deleted file mode 100644
index 07fc7d8..0000000
--- a/assetstudio/src/images/clipart/big/5-content-undo.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/5-content-unread.png b/assetstudio/src/images/clipart/big/5-content-unread.png
deleted file mode 100644
index 41ba9e2..0000000
--- a/assetstudio/src/images/clipart/big/5-content-unread.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-add-group.png b/assetstudio/src/images/clipart/big/6-social-add-group.png
deleted file mode 100644
index 7822f4f..0000000
--- a/assetstudio/src/images/clipart/big/6-social-add-group.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-add-person.png b/assetstudio/src/images/clipart/big/6-social-add-person.png
deleted file mode 100644
index b335788..0000000
--- a/assetstudio/src/images/clipart/big/6-social-add-person.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-cc-bcc.png b/assetstudio/src/images/clipart/big/6-social-cc-bcc.png
deleted file mode 100644
index 4db30a7..0000000
--- a/assetstudio/src/images/clipart/big/6-social-cc-bcc.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-chat.png b/assetstudio/src/images/clipart/big/6-social-chat.png
deleted file mode 100644
index b0cccb3..0000000
--- a/assetstudio/src/images/clipart/big/6-social-chat.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-forward.png b/assetstudio/src/images/clipart/big/6-social-forward.png
deleted file mode 100644
index a5abbfc..0000000
--- a/assetstudio/src/images/clipart/big/6-social-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-group.png b/assetstudio/src/images/clipart/big/6-social-group.png
deleted file mode 100644
index 1b18678..0000000
--- a/assetstudio/src/images/clipart/big/6-social-group.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-person.png b/assetstudio/src/images/clipart/big/6-social-person.png
deleted file mode 100644
index 27ade22..0000000
--- a/assetstudio/src/images/clipart/big/6-social-person.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-reply-all.png b/assetstudio/src/images/clipart/big/6-social-reply-all.png
deleted file mode 100644
index c2a87c6..0000000
--- a/assetstudio/src/images/clipart/big/6-social-reply-all.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-reply.png b/assetstudio/src/images/clipart/big/6-social-reply.png
deleted file mode 100644
index 550aa80..0000000
--- a/assetstudio/src/images/clipart/big/6-social-reply.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-send-now.png b/assetstudio/src/images/clipart/big/6-social-send-now.png
deleted file mode 100644
index c3dad3c..0000000
--- a/assetstudio/src/images/clipart/big/6-social-send-now.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/6-social-share.png b/assetstudio/src/images/clipart/big/6-social-share.png
deleted file mode 100644
index b664970..0000000
--- a/assetstudio/src/images/clipart/big/6-social-share.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/7-location-directions.png b/assetstudio/src/images/clipart/big/7-location-directions.png
deleted file mode 100644
index c0e67e4..0000000
--- a/assetstudio/src/images/clipart/big/7-location-directions.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/7-location-map.png b/assetstudio/src/images/clipart/big/7-location-map.png
deleted file mode 100644
index e32dc26..0000000
--- a/assetstudio/src/images/clipart/big/7-location-map.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/7-location-place.png b/assetstudio/src/images/clipart/big/7-location-place.png
deleted file mode 100644
index fec173c..0000000
--- a/assetstudio/src/images/clipart/big/7-location-place.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/7-location-web-site.png b/assetstudio/src/images/clipart/big/7-location-web-site.png
deleted file mode 100644
index 4ef24a3..0000000
--- a/assetstudio/src/images/clipart/big/7-location-web-site.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/8-images-crop.png b/assetstudio/src/images/clipart/big/8-images-crop.png
deleted file mode 100644
index bd44bf9..0000000
--- a/assetstudio/src/images/clipart/big/8-images-crop.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/8-images-rotate-left.png b/assetstudio/src/images/clipart/big/8-images-rotate-left.png
deleted file mode 100644
index 0410adb..0000000
--- a/assetstudio/src/images/clipart/big/8-images-rotate-left.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/8-images-rotate-right.png b/assetstudio/src/images/clipart/big/8-images-rotate-right.png
deleted file mode 100644
index abcff9c..0000000
--- a/assetstudio/src/images/clipart/big/8-images-rotate-right.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/8-images-slideshow.png b/assetstudio/src/images/clipart/big/8-images-slideshow.png
deleted file mode 100644
index 94e47b4..0000000
--- a/assetstudio/src/images/clipart/big/8-images-slideshow.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-add-to-queue.png b/assetstudio/src/images/clipart/big/9-av-add-to-queue.png
deleted file mode 100644
index 57b2e61..0000000
--- a/assetstudio/src/images/clipart/big/9-av-add-to-queue.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-download.png b/assetstudio/src/images/clipart/big/9-av-download.png
deleted file mode 100644
index 46a1919..0000000
--- a/assetstudio/src/images/clipart/big/9-av-download.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-fast-forward.png b/assetstudio/src/images/clipart/big/9-av-fast-forward.png
deleted file mode 100644
index f820f5a..0000000
--- a/assetstudio/src/images/clipart/big/9-av-fast-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-full-screen.png b/assetstudio/src/images/clipart/big/9-av-full-screen.png
deleted file mode 100644
index 1dfd01a..0000000
--- a/assetstudio/src/images/clipart/big/9-av-full-screen.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-make-available-offline.png b/assetstudio/src/images/clipart/big/9-av-make-available-offline.png
deleted file mode 100644
index 2efcb11..0000000
--- a/assetstudio/src/images/clipart/big/9-av-make-available-offline.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-next.png b/assetstudio/src/images/clipart/big/9-av-next.png
deleted file mode 100644
index 871587c..0000000
--- a/assetstudio/src/images/clipart/big/9-av-next.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-pause-over-video.png b/assetstudio/src/images/clipart/big/9-av-pause-over-video.png
deleted file mode 100644
index a2665f2..0000000
--- a/assetstudio/src/images/clipart/big/9-av-pause-over-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-pause.png b/assetstudio/src/images/clipart/big/9-av-pause.png
deleted file mode 100644
index 506b1d4..0000000
--- a/assetstudio/src/images/clipart/big/9-av-pause.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-play-over-video.png b/assetstudio/src/images/clipart/big/9-av-play-over-video.png
deleted file mode 100644
index 3db3a1a..0000000
--- a/assetstudio/src/images/clipart/big/9-av-play-over-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-play.png b/assetstudio/src/images/clipart/big/9-av-play.png
deleted file mode 100644
index 0c12f86..0000000
--- a/assetstudio/src/images/clipart/big/9-av-play.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-previous.png b/assetstudio/src/images/clipart/big/9-av-previous.png
deleted file mode 100644
index 28f2596..0000000
--- a/assetstudio/src/images/clipart/big/9-av-previous.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-repeat.png b/assetstudio/src/images/clipart/big/9-av-repeat.png
deleted file mode 100644
index 9a7a79a..0000000
--- a/assetstudio/src/images/clipart/big/9-av-repeat.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-replay.png b/assetstudio/src/images/clipart/big/9-av-replay.png
deleted file mode 100644
index ce9df7f..0000000
--- a/assetstudio/src/images/clipart/big/9-av-replay.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-return-from-full-screen.png b/assetstudio/src/images/clipart/big/9-av-return-from-full-screen.png
deleted file mode 100644
index 24725c0..0000000
--- a/assetstudio/src/images/clipart/big/9-av-return-from-full-screen.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-rewind.png b/assetstudio/src/images/clipart/big/9-av-rewind.png
deleted file mode 100644
index b09f61a..0000000
--- a/assetstudio/src/images/clipart/big/9-av-rewind.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-shuffle.png b/assetstudio/src/images/clipart/big/9-av-shuffle.png
deleted file mode 100644
index 6e90f7c..0000000
--- a/assetstudio/src/images/clipart/big/9-av-shuffle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-stop.png b/assetstudio/src/images/clipart/big/9-av-stop.png
deleted file mode 100644
index 9ba88ee..0000000
--- a/assetstudio/src/images/clipart/big/9-av-stop.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/9-av-upload.png b/assetstudio/src/images/clipart/big/9-av-upload.png
deleted file mode 100644
index 41da601..0000000
--- a/assetstudio/src/images/clipart/big/9-av-upload.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/big/android.png b/assetstudio/src/images/clipart/big/android.png
deleted file mode 100644
index d966fae..0000000
--- a/assetstudio/src/images/clipart/big/android.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-accept.png b/assetstudio/src/images/clipart/small/1-navigation-accept.png
deleted file mode 100644
index f5069d9..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-accept.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-back.png b/assetstudio/src/images/clipart/small/1-navigation-back.png
deleted file mode 100644
index f35aec5..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-cancel.png b/assetstudio/src/images/clipart/small/1-navigation-cancel.png
deleted file mode 100644
index 4302320..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-cancel.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-collapse.png b/assetstudio/src/images/clipart/small/1-navigation-collapse.png
deleted file mode 100644
index 9c40e2c..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-collapse.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-expand.png b/assetstudio/src/images/clipart/small/1-navigation-expand.png
deleted file mode 100644
index 684fc5a..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-expand.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-forward.png b/assetstudio/src/images/clipart/small/1-navigation-forward.png
deleted file mode 100644
index beb6cf7..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-next-item.png b/assetstudio/src/images/clipart/small/1-navigation-next-item.png
deleted file mode 100644
index 932d787..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-next-item.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-previous-item.png b/assetstudio/src/images/clipart/small/1-navigation-previous-item.png
deleted file mode 100644
index 679b586..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-previous-item.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/1-navigation-refresh.png b/assetstudio/src/images/clipart/small/1-navigation-refresh.png
deleted file mode 100644
index b946402..0000000
--- a/assetstudio/src/images/clipart/small/1-navigation-refresh.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-accounts.png b/assetstudio/src/images/clipart/small/10-device-access-accounts.png
deleted file mode 100644
index 34b4d6a..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-accounts.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-add-alarm.png b/assetstudio/src/images/clipart/small/10-device-access-add-alarm.png
deleted file mode 100644
index 27c528a..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-add-alarm.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-alarms.png b/assetstudio/src/images/clipart/small/10-device-access-alarms.png
deleted file mode 100644
index 545a8fa..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-alarms.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-battery.png b/assetstudio/src/images/clipart/small/10-device-access-battery.png
deleted file mode 100644
index 52e08bf..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-battery.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-bightness-low.png b/assetstudio/src/images/clipart/small/10-device-access-bightness-low.png
deleted file mode 100644
index a34cdea..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-bightness-low.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-bluetooth-connected.png b/assetstudio/src/images/clipart/small/10-device-access-bluetooth-connected.png
deleted file mode 100644
index d04e9f4..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-bluetooth-connected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-bluetooth-searching.png b/assetstudio/src/images/clipart/small/10-device-access-bluetooth-searching.png
deleted file mode 100644
index 06d69ae..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-bluetooth-searching.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-bluetooth.png b/assetstudio/src/images/clipart/small/10-device-access-bluetooth.png
deleted file mode 100644
index 11ad6b3..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-brightness-auto.png b/assetstudio/src/images/clipart/small/10-device-access-brightness-auto.png
deleted file mode 100644
index cd50b9d..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-brightness-auto.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-brightness-high.png b/assetstudio/src/images/clipart/small/10-device-access-brightness-high.png
deleted file mode 100644
index b9d8501..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-brightness-high.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-brightness-medium.png b/assetstudio/src/images/clipart/small/10-device-access-brightness-medium.png
deleted file mode 100644
index 7145eee..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-brightness-medium.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-call.png b/assetstudio/src/images/clipart/small/10-device-access-call.png
deleted file mode 100644
index 732e551..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-call.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-camera.png b/assetstudio/src/images/clipart/small/10-device-access-camera.png
deleted file mode 100644
index f61ab27..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-camera.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-data-usage.png b/assetstudio/src/images/clipart/small/10-device-access-data-usage.png
deleted file mode 100644
index a78127f..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-data-usage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-dial-pad.png b/assetstudio/src/images/clipart/small/10-device-access-dial-pad.png
deleted file mode 100644
index cfbee88..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-dial-pad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-end-call.png b/assetstudio/src/images/clipart/small/10-device-access-end-call.png
deleted file mode 100644
index 2562d0d..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-end-call.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-flash-automatic.png b/assetstudio/src/images/clipart/small/10-device-access-flash-automatic.png
deleted file mode 100644
index 574219c..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-flash-automatic.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-flash-off.png b/assetstudio/src/images/clipart/small/10-device-access-flash-off.png
deleted file mode 100644
index 80e3d06..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-flash-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-flash-on.png b/assetstudio/src/images/clipart/small/10-device-access-flash-on.png
deleted file mode 100644
index c9c2fff..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-flash-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-location-found.png b/assetstudio/src/images/clipart/small/10-device-access-location-found.png
deleted file mode 100644
index 4221d83..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-location-found.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-location-off.png b/assetstudio/src/images/clipart/small/10-device-access-location-off.png
deleted file mode 100644
index ea0511d..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-location-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-location-searching.png b/assetstudio/src/images/clipart/small/10-device-access-location-searching.png
deleted file mode 100644
index ef9dc2e..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-location-searching.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-mic-muted.png b/assetstudio/src/images/clipart/small/10-device-access-mic-muted.png
deleted file mode 100644
index 87bc6b3..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-mic-muted.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-mic.png b/assetstudio/src/images/clipart/small/10-device-access-mic.png
deleted file mode 100644
index 7569d6a..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-mic.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-network-cell.png b/assetstudio/src/images/clipart/small/10-device-access-network-cell.png
deleted file mode 100644
index 7a2c443..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-network-cell.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-network-wifi.png b/assetstudio/src/images/clipart/small/10-device-access-network-wifi.png
deleted file mode 100644
index e25cc64..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-network-wifi.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-new-account.png b/assetstudio/src/images/clipart/small/10-device-access-new-account.png
deleted file mode 100644
index c537899..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-new-account.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-not-secure.png b/assetstudio/src/images/clipart/small/10-device-access-not-secure.png
deleted file mode 100644
index 89c732e..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-not-secure.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-ring-volume.png b/assetstudio/src/images/clipart/small/10-device-access-ring-volume.png
deleted file mode 100644
index 5bfe27a..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-ring-volume.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-landscape.png b/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-landscape.png
deleted file mode 100644
index a3b2bbb..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-landscape.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-portrait.png b/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-portrait.png
deleted file mode 100644
index 270c069..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-screen-locked-to-portrait.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-screen-rotation.png b/assetstudio/src/images/clipart/small/10-device-access-screen-rotation.png
deleted file mode 100644
index a5337e9..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-screen-rotation.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-sd-storage.png b/assetstudio/src/images/clipart/small/10-device-access-sd-storage.png
deleted file mode 100644
index fe09aca..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-sd-storage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-secure.png b/assetstudio/src/images/clipart/small/10-device-access-secure.png
deleted file mode 100644
index 9bf3627..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-secure.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-storage.png b/assetstudio/src/images/clipart/small/10-device-access-storage.png
deleted file mode 100644
index 1d38109..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-storage.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-switch-camera.png b/assetstudio/src/images/clipart/small/10-device-access-switch-camera.png
deleted file mode 100644
index 972e3b3..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-switch-camera.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-switch-video.png b/assetstudio/src/images/clipart/small/10-device-access-switch-video.png
deleted file mode 100644
index 2ae54f4..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-switch-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-time.png b/assetstudio/src/images/clipart/small/10-device-access-time.png
deleted file mode 100644
index f3d932e..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-time.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-usb.png b/assetstudio/src/images/clipart/small/10-device-access-usb.png
deleted file mode 100644
index 490d286..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-usb.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-video.png b/assetstudio/src/images/clipart/small/10-device-access-video.png
deleted file mode 100644
index d069de4..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-volume-muted.png b/assetstudio/src/images/clipart/small/10-device-access-volume-muted.png
deleted file mode 100644
index 283d621..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-volume-muted.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/10-device-access-volume-on.png b/assetstudio/src/images/clipart/small/10-device-access-volume-on.png
deleted file mode 100644
index a1d6670..0000000
--- a/assetstudio/src/images/clipart/small/10-device-access-volume-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-off.png b/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-off.png
deleted file mode 100644
index bfce2ee..0000000
--- a/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-off.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-on.png b/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-on.png
deleted file mode 100644
index fba67ae..0000000
--- a/assetstudio/src/images/clipart/small/11-alerts-and-states-airplane-mode-on.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/11-alerts-and-states-error.png b/assetstudio/src/images/clipart/small/11-alerts-and-states-error.png
deleted file mode 100644
index a32766b..0000000
--- a/assetstudio/src/images/clipart/small/11-alerts-and-states-error.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/11-alerts-and-states-warning.png b/assetstudio/src/images/clipart/small/11-alerts-and-states-warning.png
deleted file mode 100644
index 37af134..0000000
--- a/assetstudio/src/images/clipart/small/11-alerts-and-states-warning.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-computer.png b/assetstudio/src/images/clipart/small/12-hardware-computer.png
deleted file mode 100644
index 91c7cdf..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-computer.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-dock.png b/assetstudio/src/images/clipart/small/12-hardware-dock.png
deleted file mode 100644
index c4a20ae..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-dock.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-gamepad.png b/assetstudio/src/images/clipart/small/12-hardware-gamepad.png
deleted file mode 100644
index db62572..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-gamepad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-headphones.png b/assetstudio/src/images/clipart/small/12-hardware-headphones.png
deleted file mode 100644
index 9d3b020..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-headphones.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-headset.png b/assetstudio/src/images/clipart/small/12-hardware-headset.png
deleted file mode 100644
index d4efdf3..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-headset.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-keyboard.png b/assetstudio/src/images/clipart/small/12-hardware-keyboard.png
deleted file mode 100644
index 7b143d2..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-keyboard.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-mouse.png b/assetstudio/src/images/clipart/small/12-hardware-mouse.png
deleted file mode 100644
index 4f8d2df..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-mouse.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/12-hardware-phone.png b/assetstudio/src/images/clipart/small/12-hardware-phone.png
deleted file mode 100644
index b5f78e1..0000000
--- a/assetstudio/src/images/clipart/small/12-hardware-phone.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/2-action-about.png b/assetstudio/src/images/clipart/small/2-action-about.png
deleted file mode 100644
index 56a3a55..0000000
--- a/assetstudio/src/images/clipart/small/2-action-about.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/2-action-help.png b/assetstudio/src/images/clipart/small/2-action-help.png
deleted file mode 100644
index 9104862..0000000
--- a/assetstudio/src/images/clipart/small/2-action-help.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/2-action-search.png b/assetstudio/src/images/clipart/small/2-action-search.png
deleted file mode 100644
index 1d3f206..0000000
--- a/assetstudio/src/images/clipart/small/2-action-search.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/2-action-settings.png b/assetstudio/src/images/clipart/small/2-action-settings.png
deleted file mode 100644
index 1dd6bbb..0000000
--- a/assetstudio/src/images/clipart/small/2-action-settings.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-bad.png b/assetstudio/src/images/clipart/small/3-rating-bad.png
deleted file mode 100644
index 76060f7..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-bad.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-favorite.png b/assetstudio/src/images/clipart/small/3-rating-favorite.png
deleted file mode 100644
index b6ab63f..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-favorite.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-good.png b/assetstudio/src/images/clipart/small/3-rating-good.png
deleted file mode 100644
index 0e6f861..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-good.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-half-important.png b/assetstudio/src/images/clipart/small/3-rating-half-important.png
deleted file mode 100644
index d9aa154..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-half-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-important.png b/assetstudio/src/images/clipart/small/3-rating-important.png
deleted file mode 100644
index 0bc5c54..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/3-rating-not-important.png b/assetstudio/src/images/clipart/small/3-rating-not-important.png
deleted file mode 100644
index 6ea5892..0000000
--- a/assetstudio/src/images/clipart/small/3-rating-not-important.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-cloud.png b/assetstudio/src/images/clipart/small/4-collections-cloud.png
deleted file mode 100644
index 5d80291..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-cloud.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-collection.png b/assetstudio/src/images/clipart/small/4-collections-collection.png
deleted file mode 100644
index d4a7dcb..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-collection.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-go-to-today.png b/assetstudio/src/images/clipart/small/4-collections-go-to-today.png
deleted file mode 100644
index 3326ead..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-go-to-today.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-labels.png b/assetstudio/src/images/clipart/small/4-collections-labels.png
deleted file mode 100644
index e647488..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-labels.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-new-label.png b/assetstudio/src/images/clipart/small/4-collections-new-label.png
deleted file mode 100644
index f822806..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-new-label.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-sort-by-size.png b/assetstudio/src/images/clipart/small/4-collections-sort-by-size.png
deleted file mode 100644
index b097f67..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-sort-by-size.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-view-as-grid.png b/assetstudio/src/images/clipart/small/4-collections-view-as-grid.png
deleted file mode 100644
index 9f9e0c1..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-view-as-grid.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/4-collections-view-as-list.png b/assetstudio/src/images/clipart/small/4-collections-view-as-list.png
deleted file mode 100644
index 39a2f1f..0000000
--- a/assetstudio/src/images/clipart/small/4-collections-view-as-list.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-attachment.png b/assetstudio/src/images/clipart/small/5-content-attachment.png
deleted file mode 100644
index ae5dac4..0000000
--- a/assetstudio/src/images/clipart/small/5-content-attachment.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-backspace.png b/assetstudio/src/images/clipart/small/5-content-backspace.png
deleted file mode 100644
index f2743fe..0000000
--- a/assetstudio/src/images/clipart/small/5-content-backspace.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-copy.png b/assetstudio/src/images/clipart/small/5-content-copy.png
deleted file mode 100644
index 7efa0ec..0000000
--- a/assetstudio/src/images/clipart/small/5-content-copy.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-cut.png b/assetstudio/src/images/clipart/small/5-content-cut.png
deleted file mode 100644
index 4f113d6..0000000
--- a/assetstudio/src/images/clipart/small/5-content-cut.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-discard.png b/assetstudio/src/images/clipart/small/5-content-discard.png
deleted file mode 100644
index 9bbe70c..0000000
--- a/assetstudio/src/images/clipart/small/5-content-discard.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-edit.png b/assetstudio/src/images/clipart/small/5-content-edit.png
deleted file mode 100644
index dfef46d..0000000
--- a/assetstudio/src/images/clipart/small/5-content-edit.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-email.png b/assetstudio/src/images/clipart/small/5-content-email.png
deleted file mode 100644
index 0698571..0000000
--- a/assetstudio/src/images/clipart/small/5-content-email.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-event.png b/assetstudio/src/images/clipart/small/5-content-event.png
deleted file mode 100644
index 4fea671..0000000
--- a/assetstudio/src/images/clipart/small/5-content-event.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-import-export.png b/assetstudio/src/images/clipart/small/5-content-import-export.png
deleted file mode 100644
index 1b4ed11..0000000
--- a/assetstudio/src/images/clipart/small/5-content-import-export.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-merge.png b/assetstudio/src/images/clipart/small/5-content-merge.png
deleted file mode 100644
index 4f7451e..0000000
--- a/assetstudio/src/images/clipart/small/5-content-merge.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-new-attachment.png b/assetstudio/src/images/clipart/small/5-content-new-attachment.png
deleted file mode 100644
index 8028ea7..0000000
--- a/assetstudio/src/images/clipart/small/5-content-new-attachment.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-new-email.png b/assetstudio/src/images/clipart/small/5-content-new-email.png
deleted file mode 100644
index 699dca9..0000000
--- a/assetstudio/src/images/clipart/small/5-content-new-email.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-new-event.png b/assetstudio/src/images/clipart/small/5-content-new-event.png
deleted file mode 100644
index 4c4f674..0000000
--- a/assetstudio/src/images/clipart/small/5-content-new-event.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-new-picture.png b/assetstudio/src/images/clipart/small/5-content-new-picture.png
deleted file mode 100644
index 6b7b7ea..0000000
--- a/assetstudio/src/images/clipart/small/5-content-new-picture.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-new.png b/assetstudio/src/images/clipart/small/5-content-new.png
deleted file mode 100644
index 7ccce5b..0000000
--- a/assetstudio/src/images/clipart/small/5-content-new.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-paste.png b/assetstudio/src/images/clipart/small/5-content-paste.png
deleted file mode 100644
index 9c3d906..0000000
--- a/assetstudio/src/images/clipart/small/5-content-paste.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-picture.png b/assetstudio/src/images/clipart/small/5-content-picture.png
deleted file mode 100644
index 0676181..0000000
--- a/assetstudio/src/images/clipart/small/5-content-picture.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-read.png b/assetstudio/src/images/clipart/small/5-content-read.png
deleted file mode 100644
index 7c7186f..0000000
--- a/assetstudio/src/images/clipart/small/5-content-read.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-remove.png b/assetstudio/src/images/clipart/small/5-content-remove.png
deleted file mode 100644
index 97f11f7..0000000
--- a/assetstudio/src/images/clipart/small/5-content-remove.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-save.png b/assetstudio/src/images/clipart/small/5-content-save.png
deleted file mode 100644
index 4b38e6c..0000000
--- a/assetstudio/src/images/clipart/small/5-content-save.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-select-all.png b/assetstudio/src/images/clipart/small/5-content-select-all.png
deleted file mode 100644
index cfb2282..0000000
--- a/assetstudio/src/images/clipart/small/5-content-select-all.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-split.png b/assetstudio/src/images/clipart/small/5-content-split.png
deleted file mode 100644
index 779f650..0000000
--- a/assetstudio/src/images/clipart/small/5-content-split.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-undo.png b/assetstudio/src/images/clipart/small/5-content-undo.png
deleted file mode 100644
index 87b0129..0000000
--- a/assetstudio/src/images/clipart/small/5-content-undo.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/5-content-unread.png b/assetstudio/src/images/clipart/small/5-content-unread.png
deleted file mode 100644
index 69cb276..0000000
--- a/assetstudio/src/images/clipart/small/5-content-unread.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-add-group.png b/assetstudio/src/images/clipart/small/6-social-add-group.png
deleted file mode 100644
index cae89bb..0000000
--- a/assetstudio/src/images/clipart/small/6-social-add-group.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-add-person.png b/assetstudio/src/images/clipart/small/6-social-add-person.png
deleted file mode 100644
index ec95691..0000000
--- a/assetstudio/src/images/clipart/small/6-social-add-person.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-cc-bcc.png b/assetstudio/src/images/clipart/small/6-social-cc-bcc.png
deleted file mode 100644
index 92772f7..0000000
--- a/assetstudio/src/images/clipart/small/6-social-cc-bcc.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-chat.png b/assetstudio/src/images/clipart/small/6-social-chat.png
deleted file mode 100644
index 675c7e3..0000000
--- a/assetstudio/src/images/clipart/small/6-social-chat.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-forward.png b/assetstudio/src/images/clipart/small/6-social-forward.png
deleted file mode 100644
index f533b34..0000000
--- a/assetstudio/src/images/clipart/small/6-social-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-group.png b/assetstudio/src/images/clipart/small/6-social-group.png
deleted file mode 100644
index ee027a7..0000000
--- a/assetstudio/src/images/clipart/small/6-social-group.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-person.png b/assetstudio/src/images/clipart/small/6-social-person.png
deleted file mode 100644
index bb685c7..0000000
--- a/assetstudio/src/images/clipart/small/6-social-person.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-reply-all.png b/assetstudio/src/images/clipart/small/6-social-reply-all.png
deleted file mode 100644
index fc94679..0000000
--- a/assetstudio/src/images/clipart/small/6-social-reply-all.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-reply.png b/assetstudio/src/images/clipart/small/6-social-reply.png
deleted file mode 100644
index e413c9a..0000000
--- a/assetstudio/src/images/clipart/small/6-social-reply.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-send-now.png b/assetstudio/src/images/clipart/small/6-social-send-now.png
deleted file mode 100644
index 6fa79f0..0000000
--- a/assetstudio/src/images/clipart/small/6-social-send-now.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/6-social-share.png b/assetstudio/src/images/clipart/small/6-social-share.png
deleted file mode 100644
index fb74121..0000000
--- a/assetstudio/src/images/clipart/small/6-social-share.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/7-location-directions.png b/assetstudio/src/images/clipart/small/7-location-directions.png
deleted file mode 100644
index c3e821d..0000000
--- a/assetstudio/src/images/clipart/small/7-location-directions.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/7-location-map.png b/assetstudio/src/images/clipart/small/7-location-map.png
deleted file mode 100644
index 4893657..0000000
--- a/assetstudio/src/images/clipart/small/7-location-map.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/7-location-place.png b/assetstudio/src/images/clipart/small/7-location-place.png
deleted file mode 100644
index 2d41b57..0000000
--- a/assetstudio/src/images/clipart/small/7-location-place.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/7-location-web-site.png b/assetstudio/src/images/clipart/small/7-location-web-site.png
deleted file mode 100644
index fe15c10..0000000
--- a/assetstudio/src/images/clipart/small/7-location-web-site.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/8-images-crop.png b/assetstudio/src/images/clipart/small/8-images-crop.png
deleted file mode 100644
index ddca47f..0000000
--- a/assetstudio/src/images/clipart/small/8-images-crop.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/8-images-rotate-left.png b/assetstudio/src/images/clipart/small/8-images-rotate-left.png
deleted file mode 100644
index 0450f2b..0000000
--- a/assetstudio/src/images/clipart/small/8-images-rotate-left.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/8-images-rotate-right.png b/assetstudio/src/images/clipart/small/8-images-rotate-right.png
deleted file mode 100644
index a34d957..0000000
--- a/assetstudio/src/images/clipart/small/8-images-rotate-right.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/8-images-slideshow.png b/assetstudio/src/images/clipart/small/8-images-slideshow.png
deleted file mode 100644
index 5317cf7..0000000
--- a/assetstudio/src/images/clipart/small/8-images-slideshow.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-add-to-queue.png b/assetstudio/src/images/clipart/small/9-av-add-to-queue.png
deleted file mode 100644
index 544b8fc..0000000
--- a/assetstudio/src/images/clipart/small/9-av-add-to-queue.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-download.png b/assetstudio/src/images/clipart/small/9-av-download.png
deleted file mode 100644
index bbf910c..0000000
--- a/assetstudio/src/images/clipart/small/9-av-download.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-fast-forward.png b/assetstudio/src/images/clipart/small/9-av-fast-forward.png
deleted file mode 100644
index dc7e11f..0000000
--- a/assetstudio/src/images/clipart/small/9-av-fast-forward.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-full-screen.png b/assetstudio/src/images/clipart/small/9-av-full-screen.png
deleted file mode 100644
index c1dd576..0000000
--- a/assetstudio/src/images/clipart/small/9-av-full-screen.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-make-available-offline.png b/assetstudio/src/images/clipart/small/9-av-make-available-offline.png
deleted file mode 100644
index 8e9459c..0000000
--- a/assetstudio/src/images/clipart/small/9-av-make-available-offline.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-next.png b/assetstudio/src/images/clipart/small/9-av-next.png
deleted file mode 100644
index 01e6543..0000000
--- a/assetstudio/src/images/clipart/small/9-av-next.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-pause-over-video.png b/assetstudio/src/images/clipart/small/9-av-pause-over-video.png
deleted file mode 100644
index bac9ce4..0000000
--- a/assetstudio/src/images/clipart/small/9-av-pause-over-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-pause.png b/assetstudio/src/images/clipart/small/9-av-pause.png
deleted file mode 100644
index 6a17d65..0000000
--- a/assetstudio/src/images/clipart/small/9-av-pause.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-play-over-video.png b/assetstudio/src/images/clipart/small/9-av-play-over-video.png
deleted file mode 100644
index a3a68fc..0000000
--- a/assetstudio/src/images/clipart/small/9-av-play-over-video.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-play.png b/assetstudio/src/images/clipart/small/9-av-play.png
deleted file mode 100644
index 2092eca..0000000
--- a/assetstudio/src/images/clipart/small/9-av-play.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-previous.png b/assetstudio/src/images/clipart/small/9-av-previous.png
deleted file mode 100644
index cf10fbf..0000000
--- a/assetstudio/src/images/clipart/small/9-av-previous.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-repeat.png b/assetstudio/src/images/clipart/small/9-av-repeat.png
deleted file mode 100644
index 7638bea..0000000
--- a/assetstudio/src/images/clipart/small/9-av-repeat.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-replay.png b/assetstudio/src/images/clipart/small/9-av-replay.png
deleted file mode 100644
index 8f1dae0..0000000
--- a/assetstudio/src/images/clipart/small/9-av-replay.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-return-from-full-screen.png b/assetstudio/src/images/clipart/small/9-av-return-from-full-screen.png
deleted file mode 100644
index 96949cb..0000000
--- a/assetstudio/src/images/clipart/small/9-av-return-from-full-screen.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-rewind.png b/assetstudio/src/images/clipart/small/9-av-rewind.png
deleted file mode 100644
index 1811cd9..0000000
--- a/assetstudio/src/images/clipart/small/9-av-rewind.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-shuffle.png b/assetstudio/src/images/clipart/small/9-av-shuffle.png
deleted file mode 100644
index 6075afb..0000000
--- a/assetstudio/src/images/clipart/small/9-av-shuffle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-stop.png b/assetstudio/src/images/clipart/small/9-av-stop.png
deleted file mode 100644
index 3c95c99..0000000
--- a/assetstudio/src/images/clipart/small/9-av-stop.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/9-av-upload.png b/assetstudio/src/images/clipart/small/9-av-upload.png
deleted file mode 100644
index af9b895..0000000
--- a/assetstudio/src/images/clipart/small/9-av-upload.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/clipart/small/android.png b/assetstudio/src/images/clipart/small/android.png
deleted file mode 100644
index b2c6cd2..0000000
--- a/assetstudio/src/images/clipart/small/android.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png
deleted file mode 100644
index 5401258..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/hdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png
deleted file mode 100644
index 6295083..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/hdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png
deleted file mode 100644
index 7d10568..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/hdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/hdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/circle/hdpi/mask_inner.png
deleted file mode 100644
index 3cbd8de..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/hdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png
deleted file mode 100644
index 73a640f..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/mdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png
deleted file mode 100644
index 90a9e47..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/mdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png
deleted file mode 100644
index 107082b..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/mdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/mdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/circle/mdpi/mask_inner.png
deleted file mode 100644
index c44b167..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/mdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/back.png b/assetstudio/src/images/launcher_stencil/circle/web/back.png
deleted file mode 100644
index 2058604..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/web/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/fore1.png b/assetstudio/src/images/launcher_stencil/circle/web/fore1.png
deleted file mode 100644
index b80d804..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/web/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/mask.png b/assetstudio/src/images/launcher_stencil/circle/web/mask.png
deleted file mode 100644
index 709060e..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/web/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/web/mask_inner.png b/assetstudio/src/images/launcher_stencil/circle/web/mask_inner.png
deleted file mode 100644
index dca886c..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/web/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png
deleted file mode 100644
index 4fd8b7d..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xhdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png
deleted file mode 100644
index c0d752b..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xhdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png
deleted file mode 100644
index a0bfc98..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask_inner.png
deleted file mode 100644
index 02bc806..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xhdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/back.png b/assetstudio/src/images/launcher_stencil/circle/xxhdpi/back.png
deleted file mode 100644
index 8b62d02..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/circle/xxhdpi/fore1.png
deleted file mode 100644
index 2e4ab8c..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask.png b/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask.png
deleted file mode 100644
index 874aa5b..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask_inner.png
deleted file mode 100644
index 819c144..0000000
--- a/assetstudio/src/images/launcher_stencil/circle/xxhdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/back.png b/assetstudio/src/images/launcher_stencil/square/hdpi/back.png
deleted file mode 100644
index 284a785..0000000
--- a/assetstudio/src/images/launcher_stencil/square/hdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png
deleted file mode 100644
index e7faa71..0000000
--- a/assetstudio/src/images/launcher_stencil/square/hdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png
deleted file mode 100644
index fe1aa7a..0000000
--- a/assetstudio/src/images/launcher_stencil/square/hdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/hdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/square/hdpi/mask_inner.png
deleted file mode 100644
index 28df306..0000000
--- a/assetstudio/src/images/launcher_stencil/square/hdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/back.png b/assetstudio/src/images/launcher_stencil/square/mdpi/back.png
deleted file mode 100644
index 849a656..0000000
--- a/assetstudio/src/images/launcher_stencil/square/mdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png
deleted file mode 100644
index cef3e48..0000000
--- a/assetstudio/src/images/launcher_stencil/square/mdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png
deleted file mode 100644
index 8b3d0a2..0000000
--- a/assetstudio/src/images/launcher_stencil/square/mdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/mdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/square/mdpi/mask_inner.png
deleted file mode 100644
index 3f3ad9b..0000000
--- a/assetstudio/src/images/launcher_stencil/square/mdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/back.png b/assetstudio/src/images/launcher_stencil/square/web/back.png
deleted file mode 100644
index bb59979..0000000
--- a/assetstudio/src/images/launcher_stencil/square/web/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/fore1.png b/assetstudio/src/images/launcher_stencil/square/web/fore1.png
deleted file mode 100644
index 2a3be1c..0000000
--- a/assetstudio/src/images/launcher_stencil/square/web/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/mask.png b/assetstudio/src/images/launcher_stencil/square/web/mask.png
deleted file mode 100644
index e3f10a3..0000000
--- a/assetstudio/src/images/launcher_stencil/square/web/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/web/mask_inner.png b/assetstudio/src/images/launcher_stencil/square/web/mask_inner.png
deleted file mode 100644
index ea15b03..0000000
--- a/assetstudio/src/images/launcher_stencil/square/web/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png
deleted file mode 100644
index 1338f7c..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xhdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png
deleted file mode 100644
index 90c3430..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xhdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png
deleted file mode 100644
index 7291db1..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xhdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xhdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/square/xhdpi/mask_inner.png
deleted file mode 100644
index 388a4c2..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xhdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xxhdpi/back.png b/assetstudio/src/images/launcher_stencil/square/xxhdpi/back.png
deleted file mode 100644
index 068e28f..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xxhdpi/back.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xxhdpi/fore1.png b/assetstudio/src/images/launcher_stencil/square/xxhdpi/fore1.png
deleted file mode 100644
index 099b135..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xxhdpi/fore1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask.png b/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask.png
deleted file mode 100644
index be26125..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask_inner.png b/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask_inner.png
deleted file mode 100644
index 3f8c5ea..0000000
--- a/assetstudio/src/images/launcher_stencil/square/xxhdpi/mask_inner.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/notification_stencil/hdpi.png b/assetstudio/src/images/notification_stencil/hdpi.png
deleted file mode 100644
index f755f4f..0000000
--- a/assetstudio/src/images/notification_stencil/hdpi.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/notification_stencil/mdpi.png b/assetstudio/src/images/notification_stencil/mdpi.png
deleted file mode 100644
index 5f80247..0000000
--- a/assetstudio/src/images/notification_stencil/mdpi.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/src/images/notification_stencil/xhdpi.png b/assetstudio/src/images/notification_stencil/xhdpi.png
deleted file mode 100644
index 7c27d82..0000000
--- a/assetstudio/src/images/notification_stencil/xhdpi.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/ActionBarIconGeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/ActionBarIconGeneratorTest.java
deleted file mode 100644
index a097f0a..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/ActionBarIconGeneratorTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.ActionBarIconGenerator.ActionBarOptions;
-import com.android.assetstudiolib.ActionBarIconGenerator.Theme;
-
-import java.io.IOException;
-
-@SuppressWarnings("javadoc")
-public class ActionBarIconGeneratorTest extends GeneratorTest {
- private void checkGraphic(String baseName, Theme theme) throws IOException {
- ActionBarOptions options = new ActionBarOptions();
- options.theme = theme;
-
- ActionBarIconGenerator generator = new ActionBarIconGenerator();
- checkGraphic(3, "actions", baseName, generator, options);
- }
-
- public void testDark() throws Exception {
- checkGraphic("ic_action_dark", Theme.HOLO_DARK);
- }
-
- public void testLight() throws Exception {
- checkGraphic("ic_action_light", Theme.HOLO_LIGHT);
- }
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/GeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/GeneratorTest.java
deleted file mode 100644
index 4a96f30..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/GeneratorTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.imageio.ImageIO;
-
-import junit.framework.TestCase;
-
-/**
- * Shared test infrastructure for code generator
- */
-public abstract class GeneratorTest extends TestCase implements GraphicGeneratorContext {
- private static final String TEST_DATA_REL_PATH =
- "assetstudio/tests/src/com/android/assetstudiolib/testdata";
-
- protected void checkGraphic(int expectedFileCount, String folderName, String baseName,
- GraphicGenerator generator, GraphicGenerator.Options options)
- throws IOException {
- Map<String, Map<String, BufferedImage>> categoryMap =
- new HashMap<String, Map<String, BufferedImage>>();
- options.sourceImage = GraphicGenerator.getClipartImage("android.png");
- generator.generate(null, categoryMap, this, options, baseName);
-
- File targetDir = getTargetDir();
-
- List<String> errors = new ArrayList<String>();
- int fileCount = 0;
- for (Map<String, BufferedImage> previews : categoryMap.values()) {
- for (Map.Entry<String, BufferedImage> entry : previews.entrySet()) {
- String relativePath = entry.getKey();
- BufferedImage image = entry.getValue();
-
- String path = "testdata" + File.separator + folderName + File.separator
- + relativePath;
- InputStream is = GeneratorTest.class.getResourceAsStream(path);
- if (is == null) {
- if (targetDir == null) {
- fail("Did not find " + path
- + ". Set ADT_SDK_SOURCE_PATH to have it created automatically");
- }
- File fileName = new File(targetDir, folderName + File.separator
- + relativePath);
- assertFalse(fileName.exists());
- if (!fileName.getParentFile().exists()) {
- boolean mkdir = fileName.getParentFile().mkdirs();
- assertTrue(fileName.getParent(), mkdir);
- }
-
- ImageIO.write(image, "PNG", fileName);
- errors.add("File did not exist, created " + fileName.getPath());
- } else {
- BufferedImage goldenImage = ImageIO.read(is);
- assertImageSimilar(relativePath, goldenImage, image, 5.0f);
- }
- }
-
- fileCount += previews.values().size();
- }
- if (errors.size() > 0) {
- fail(errors.toString());
- }
-
- assertEquals("Wrong number of generated files", expectedFileCount, fileCount);
- }
-
- private void assertImageSimilar(String imageName, BufferedImage goldenImage,
- BufferedImage image, float maxPercentDifferent) throws IOException {
- assertTrue("Widths differ too much for " + imageName, Math.abs(goldenImage.getWidth()
- - image.getWidth()) < 2);
- assertTrue("Widths differ too much for " + imageName, Math.abs(goldenImage.getHeight()
- - image.getHeight()) < 2);
-
- assertEquals(BufferedImage.TYPE_INT_ARGB, image.getType());
-
- if (goldenImage.getType() != BufferedImage.TYPE_INT_ARGB) {
- BufferedImage temp = new BufferedImage(goldenImage.getWidth(), goldenImage.getHeight(),
- BufferedImage.TYPE_INT_ARGB);
- temp.getGraphics().drawImage(goldenImage, 0, 0, null);
- goldenImage = temp;
- }
- assertEquals(BufferedImage.TYPE_INT_ARGB, goldenImage.getType());
-
- int imageWidth = Math.min(goldenImage.getWidth(), image.getWidth());
- int imageHeight = Math.min(goldenImage.getHeight(), image.getHeight());
-
- // Blur the images to account for the scenarios where there are pixel
- // differences
- // in where a sharp edge occurs
- // goldenImage = blur(goldenImage, 6);
- // image = blur(image, 6);
-
- int width = 3 * imageWidth;
- int height = imageHeight;
- BufferedImage deltaImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- Graphics g = deltaImage.getGraphics();
-
- // Compute delta map
- long delta = 0;
- for (int y = 0; y < imageHeight; y++) {
- for (int x = 0; x < imageWidth; x++) {
- int goldenRgb = goldenImage.getRGB(x, y);
- int rgb = image.getRGB(x, y);
- if (goldenRgb == rgb) {
- deltaImage.setRGB(imageWidth + x, y, 0x00808080);
- continue;
- }
-
- // If the pixels have no opacity, don't delta colors at all
- if (((goldenRgb & 0xFF000000) == 0) && (rgb & 0xFF000000) == 0) {
- deltaImage.setRGB(imageWidth + x, y, 0x00808080);
- continue;
- }
-
- int deltaR = ((rgb & 0xFF0000) >>> 16) - ((goldenRgb & 0xFF0000) >>> 16);
- int newR = 128 + deltaR & 0xFF;
- int deltaG = ((rgb & 0x00FF00) >>> 8) - ((goldenRgb & 0x00FF00) >>> 8);
- int newG = 128 + deltaG & 0xFF;
- int deltaB = (rgb & 0x0000FF) - (goldenRgb & 0x0000FF);
- int newB = 128 + deltaB & 0xFF;
-
- int avgAlpha = ((((goldenRgb & 0xFF000000) >>> 24)
- + ((rgb & 0xFF000000) >>> 24)) / 2) << 24;
-
- int newRGB = avgAlpha | newR << 16 | newG << 8 | newB;
- deltaImage.setRGB(imageWidth + x, y, newRGB);
-
- delta += Math.abs(deltaR);
- delta += Math.abs(deltaG);
- delta += Math.abs(deltaB);
- }
- }
-
- // 3 different colors, 256 color levels
- long total = imageHeight * imageWidth * 3L * 256L;
- float percentDifference = (float) (delta * 100 / (double) total);
-
- if (percentDifference > maxPercentDifferent) {
- // Expected on the left
- // Golden on the right
- g.drawImage(goldenImage, 0, 0, null);
- g.drawImage(image, 2 * imageWidth, 0, null);
-
- // Labels
- if (imageWidth > 80) {
- g.setColor(Color.RED);
- g.drawString("Expected", 10, 20);
- g.drawString("Actual", 2 * imageWidth + 10, 20);
- }
-
- File output = new File(getTempDir(), "delta-"
- + imageName.replace(File.separatorChar, '_'));
- if (output.exists()) {
- output.delete();
- }
- ImageIO.write(deltaImage, "PNG", output);
- String message = String.format("Images differ (by %.1f%%) - see details in %s",
- percentDifference, output);
- System.out.println(message);
- fail(message);
- }
-
- g.dispose();
- }
-
- protected File getTempDir() {
- if (System.getProperty("os.name").equals("Mac OS X")) {
- return new File("/tmp"); //$NON-NLS-1$
- }
-
- return new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
- }
-
- @Override
- public BufferedImage loadImageResource(String path) {
- try {
- return GraphicGenerator.getStencilImage(path);
- } catch (IOException e) {
- fail(e.toString());
- }
-
- return null;
- }
-
- /** Get the location to write missing golden files to */
- protected File getTargetDir() {
- // Set $ADT_SDK_SOURCE_PATH to point to your git "sdk" directory
- String sdk = System.getenv("ADT_SDK_SOURCE_PATH");
- if (sdk != null) {
- File sdkPath = new File(sdk);
- if (sdkPath.exists()) {
- File testData = new File(sdkPath, TEST_DATA_REL_PATH.replace('/',
- File.separatorChar));
- if (testData.exists()) {
- return testData;
- }
- }
- }
-
- return null;
- }
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/LauncherIconGeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/LauncherIconGeneratorTest.java
deleted file mode 100644
index 2ab09b1..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/LauncherIconGeneratorTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.LauncherIconGenerator.LauncherOptions;
-
-import java.io.IOException;
-
-@SuppressWarnings("javadoc")
-public class LauncherIconGeneratorTest extends GeneratorTest {
- private void checkGraphic(String baseName,
- GraphicGenerator.Shape shape, GraphicGenerator.Style style,
- boolean crop, int background, boolean isWebGraphic) throws IOException {
- LauncherOptions options = new LauncherOptions();
- options.shape = shape;
- options.crop = crop;
- options.style = style;
- options.backgroundColor = background;
- options.isWebGraphic = isWebGraphic;
-
- LauncherIconGenerator generator = new LauncherIconGenerator();
- checkGraphic(4 + (isWebGraphic ? 1 : 0), "launcher", baseName, generator, options);
- }
-
- public void testLauncher_simpleCircle() throws Exception {
- checkGraphic("red_simple_circle", GraphicGenerator.Shape.CIRCLE,
- GraphicGenerator.Style.SIMPLE, true, 0xFF0000, true);
- }
-
- // The glossy rendering type is no longer included since it doesn't match the
- // style guide.
- //public void testLauncher_glossySquare() throws Exception {
- // checkGraphic("blue_glossy_square", GraphicGenerator.Shape.SQUARE,
- // GraphicGenerator.Style.GLOSSY, true, 0x0040FF, true);
- //}
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/MenuIconGeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/MenuIconGeneratorTest.java
deleted file mode 100644
index 544777d..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/MenuIconGeneratorTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import java.io.IOException;
-
-@SuppressWarnings("javadoc")
-public class MenuIconGeneratorTest extends GeneratorTest {
- private void checkGraphic(String baseName) throws IOException {
- MenuIconGenerator generator = new MenuIconGenerator();
- checkGraphic(3, "menus", baseName, generator, new GraphicGenerator.Options());
- }
-
- public void testMenu() throws Exception {
- checkGraphic("ic_menu_1");
- }
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/NotificationIconGeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/NotificationIconGeneratorTest.java
deleted file mode 100644
index 39fd7ac..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/NotificationIconGeneratorTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import com.android.assetstudiolib.NotificationIconGenerator.NotificationOptions;
-
-import java.io.IOException;
-
-@SuppressWarnings("javadoc")
-public class NotificationIconGeneratorTest extends GeneratorTest {
- private void checkGraphic(String baseName, int minSdk, String folderName,
- int expectedCount) throws IOException {
- NotificationOptions options = new NotificationOptions();
- options.minSdk = minSdk;
-
- NotificationIconGenerator generator = new NotificationIconGenerator();
- checkGraphic(expectedCount, folderName, baseName, generator, options);
- }
-
- private void checkGraphic(String baseName) throws IOException {
- checkGraphic(baseName, 1, "notification", 9);
- }
-
- public void testNotification1() throws Exception {
- checkGraphic("ic_stat_1");
- }
-
- public void testNotification2() throws Exception {
- checkGraphic("ic_stat_1", 9 /* minSdk */, "notification-v9+", 6 /* fileCount */);
- }
-
- public void testNotification3() throws Exception {
- checkGraphic("ic_stat_1", 11, "notification-v11+", 3);
- }
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/TabIconGeneratorTest.java b/assetstudio/tests/src/com/android/assetstudiolib/TabIconGeneratorTest.java
deleted file mode 100644
index fb7849c..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/TabIconGeneratorTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.assetstudiolib;
-
-import java.io.IOException;
-
-@SuppressWarnings("javadoc")
-public class TabIconGeneratorTest extends GeneratorTest {
- private void checkGraphic(String folderName, String baseName, int minSdk,
- int expectedFileCount) throws IOException {
- TabIconGenerator generator = new TabIconGenerator();
- TabIconGenerator.TabOptions options = new TabIconGenerator.TabOptions();
- options.minSdk = minSdk;
- checkGraphic(expectedFileCount, folderName, baseName, generator, options);
- }
-
- public void testTabs1() throws Exception {
- checkGraphic("tabs", "ic_tab_1", 1 /* minSdk */, 12 /* expectedFileCount */);
- }
-
- public void testTabs2() throws Exception {
- checkGraphic("tabs-v5+", "ic_tab_1", 5, 6);
- }
-}
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_dark.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_dark.png
deleted file mode 100644
index f8950e9..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_dark.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_light.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_light.png
deleted file mode 100644
index 0904e2f..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-hdpi/ic_action_light.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_dark.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_dark.png
deleted file mode 100644
index 08a41b6..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_dark.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_light.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_light.png
deleted file mode 100644
index 11d4db7..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-mdpi/ic_action_light.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_dark.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_dark.png
deleted file mode 100644
index 7396c15..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_dark.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_light.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_light.png
deleted file mode 100644
index 941e377..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/actions/res/drawable-xhdpi/ic_action_light.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/red_simple_circle-web.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/red_simple_circle-web.png
deleted file mode 100644
index 7805116..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/red_simple_circle-web.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-hdpi/red_simple_circle.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-hdpi/red_simple_circle.png
deleted file mode 100644
index 6fdf98e..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-hdpi/red_simple_circle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-mdpi/red_simple_circle.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-mdpi/red_simple_circle.png
deleted file mode 100644
index 18a677f..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-mdpi/red_simple_circle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xhdpi/red_simple_circle.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xhdpi/red_simple_circle.png
deleted file mode 100644
index 85de4ee..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xhdpi/red_simple_circle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xxhdpi/red_simple_circle.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xxhdpi/red_simple_circle.png
deleted file mode 100644
index 5670c8c..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/launcher/res/drawable-xxhdpi/red_simple_circle.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-hdpi/ic_menu_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-hdpi/ic_menu_1.png
deleted file mode 100644
index 0d6d67f..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-hdpi/ic_menu_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-mdpi/ic_menu_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-mdpi/ic_menu_1.png
deleted file mode 100644
index de68199..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-mdpi/ic_menu_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-xhdpi/ic_menu_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-xhdpi/ic_menu_1.png
deleted file mode 100644
index dca9a75..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/menus/res/drawable-xhdpi/ic_menu_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-hdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-hdpi/ic_stat_1.png
deleted file mode 100644
index 4273bef..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-hdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-mdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-mdpi/ic_stat_1.png
deleted file mode 100644
index c8994f5..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-mdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-xhdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-xhdpi/ic_stat_1.png
deleted file mode 100644
index 1643eba..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v11+/res/drawable-xhdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi-v11/ic_stat_1.png
deleted file mode 100644
index 4273bef..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi/ic_stat_1.png
deleted file mode 100644
index 2fc269b..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-hdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi-v11/ic_stat_1.png
deleted file mode 100644
index c8994f5..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi/ic_stat_1.png
deleted file mode 100644
index 524e31a..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-mdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi-v11/ic_stat_1.png
deleted file mode 100644
index 1643eba..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi/ic_stat_1.png
deleted file mode 100644
index 8b24336..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification-v9+/res/drawable-xhdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v11/ic_stat_1.png
deleted file mode 100644
index 4273bef..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v9/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v9/ic_stat_1.png
deleted file mode 100644
index 2fc269b..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi-v9/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi/ic_stat_1.png
deleted file mode 100644
index a1c9285..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-hdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v11/ic_stat_1.png
deleted file mode 100644
index c8994f5..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v9/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v9/ic_stat_1.png
deleted file mode 100644
index 524e31a..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi-v9/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi/ic_stat_1.png
deleted file mode 100644
index 40b27af..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-mdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v11/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v11/ic_stat_1.png
deleted file mode 100644
index 1643eba..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v11/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v9/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v9/ic_stat_1.png
deleted file mode 100644
index 8b24336..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi-v9/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi/ic_stat_1.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi/ic_stat_1.png
deleted file mode 100644
index c7159ec..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/notification/res/drawable-xhdpi/ic_stat_1.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_selected.png
deleted file mode 100644
index 1e367dc..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_unselected.png
deleted file mode 100644
index 8d1ea96..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-hdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_selected.png
deleted file mode 100644
index 1d79c30..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_unselected.png
deleted file mode 100644
index 4ed95d7..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-ldpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_selected.png
deleted file mode 100644
index c741050..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_unselected.png
deleted file mode 100644
index c11de02..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-mdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_selected.png
deleted file mode 100644
index f61e1de..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_unselected.png
deleted file mode 100644
index 52852ee..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs-v5+/res/drawable-xhdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_selected.png
deleted file mode 100644
index 1e367dc..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_unselected.png
deleted file mode 100644
index 8d1ea96..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi-v5/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_selected.png
deleted file mode 100644
index 5a49be9..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_unselected.png
deleted file mode 100644
index d957240..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-hdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_selected.png
deleted file mode 100644
index c741050..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_unselected.png
deleted file mode 100644
index c11de02..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi-v5/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_selected.png
deleted file mode 100644
index 7c603b7..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_unselected.png
deleted file mode 100644
index 521bf60..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-mdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_selected.png
deleted file mode 100644
index f61e1de..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_unselected.png
deleted file mode 100644
index 52852ee..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi-v5/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_selected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_selected.png
deleted file mode 100644
index 317fc5a..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_selected.png
+++ /dev/null
Binary files differ
diff --git a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_unselected.png b/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_unselected.png
deleted file mode 100644
index 7a0ffc6..0000000
--- a/assetstudio/tests/src/com/android/assetstudiolib/testdata/tabs/res/drawable-xhdpi/ic_tab_1_unselected.png
+++ /dev/null
Binary files differ
diff --git a/build/product_sdk.mk b/build/product_sdk.mk
index 226dba3..cf4879e 100644
--- a/build/product_sdk.mk
+++ b/build/product_sdk.mk
@@ -33,13 +33,11 @@ PRODUCT_PACKAGES += \
anttasks \
archquery \
assetstudio \
- common-tests \
ddmlib \
ddms \
ddmuilib \
draw9patch \
dvlib \
- dvlib-tests \
hierarchyviewer \
sdk_common \
layoutlib_api \
diff --git a/build/tools.atree b/build/tools.atree
index a8c9da6..b5a7edd 100644
--- a/build/tools.atree
+++ b/build/tools.atree
@@ -69,9 +69,9 @@ bin/draw9patch tools/draw9patch
bin/traceview tools/traceview
bin/android tools/android
bin/monkeyrunner tools/monkeyrunner
-bin/lint tools/lint
bin/uiautomatorviewer tools/uiautomatorviewer
-prebuilts/devtools/jobb/etc/jobb tools/jobb
+prebuilts/devtools/etc/jobb tools/jobb
+prebuilts/devtools/etc/lint tools/lint
# sdk.git Ant templates for project build files
sdk/templates/build.template tools/lib/build.template
@@ -94,36 +94,36 @@ external/qemu/android/avd/hardware-properties.ini tools/lib/hardware-properties.
sdk/files/android.el tools/lib/android.el
# Java Libraries for the tools
-framework/common.jar tools/lib/common.jar
-framework/swtmenubar.jar tools/lib/swtmenubar.jar
-sdk/apkbuilder/etc/apkbuilder tools/apkbuilder
-framework/sdkstats.jar tools/lib/sdkstats.jar
-framework/archquery.jar tools/lib/archquery.jar
-framework/ddms.jar tools/lib/ddms.jar
-framework/ddmlib.jar tools/lib/ddmlib.jar
-framework/ddmuilib.jar tools/lib/ddmuilib.jar
-framework/hierarchyviewer2.jar tools/lib/hierarchyviewer2.jar
-framework/hierarchyviewerlib.jar tools/lib/hierarchyviewerlib.jar
-framework/draw9patch.jar tools/lib/draw9patch.jar
-framework/traceview.jar tools/lib/traceview.jar
-framework/anttasks.jar tools/lib/anttasks.jar
-framework/sdklib.jar tools/lib/sdklib.jar
-framework/sdkuilib.jar tools/lib/sdkuilib.jar
-framework/sdkmanager.jar tools/lib/sdkmanager.jar
-framework/monkeyrunner.jar tools/lib/monkeyrunner.jar
-framework/chimpchat.jar tools/lib/chimpchat.jar
-framework/guava-tools.jar tools/lib/guava-tools.jar
-framework/jsilver.jar tools/lib/jsilver.jar
-framework/jython.jar tools/lib/jython.jar
-framework/lint.jar tools/lib/lint.jar
-framework/lint_api.jar tools/lib/lint_api.jar
-framework/lint_checks.jar tools/lib/lint_checks.jar
-framework/manifmerger.jar tools/lib/manifmerger.jar
-framework/dvlib.jar tools/lib/dvlib.jar
-framework/layoutlib_api.jar tools/lib/layoutlib_api.jar
-framework/uiautomatorviewer.jar tools/lib/uiautomatorviewer.jar
-framework/jobb.jar tools/lib/jobb.jar
-framework/fat32lib.jar tools/lib/fat32lib.jar
+prebuilts/devtools/common.jar tools/lib/common.jar
+prebuilts/devtools/swtmenubar.jar tools/lib/swtmenubar.jar
+sdk/apkbuilder/etc/apkbuilder tools/apkbuilder
+framework/sdkstats.jar tools/lib/sdkstats.jar
+framework/archquery.jar tools/lib/archquery.jar
+framework/ddms.jar tools/lib/ddms.jar
+prebuilts/devtools/ddmlib.jar tools/lib/ddmlib.jar
+framework/ddmuilib.jar tools/lib/ddmuilib.jar
+framework/hierarchyviewer2.jar tools/lib/hierarchyviewer2.jar
+framework/hierarchyviewerlib.jar tools/lib/hierarchyviewerlib.jar
+framework/draw9patch.jar tools/lib/draw9patch.jar
+framework/traceview.jar tools/lib/traceview.jar
+framework/anttasks.jar tools/lib/anttasks.jar
+prebuilts/devtools/sdklib.jar tools/lib/sdklib.jar
+prebuilts/devtools/sdkuilib.jar tools/lib/sdkuilib.jar
+framework/sdkmanager.jar tools/lib/sdkmanager.jar
+framework/monkeyrunner.jar tools/lib/monkeyrunner.jar
+framework/chimpchat.jar tools/lib/chimpchat.jar
+framework/guava-tools.jar tools/lib/guava-tools.jar
+framework/jsilver.jar tools/lib/jsilver.jar
+framework/jython.jar tools/lib/jython.jar
+prebuilts/devtools/lint.jar tools/lib/lint.jar
+prebuilts/devtools/lint_api.jar tools/lib/lint_api.jar
+prebuilts/devtools/lint_checks.jar tools/lib/lint_checks.jar
+prebuilts/devtools/manifmerger.jar tools/lib/manifmerger.jar
+prebuilts/devtools/dvlib.jar tools/lib/dvlib.jar
+prebuilts/devtools/layoutlib_api.jar tools/lib/layoutlib_api.jar
+framework/uiautomatorviewer.jar tools/lib/uiautomatorviewer.jar
+prebuilts/devtools/jobb.jar tools/lib/jobb.jar
+framework/fat32lib.jar tools/lib/fat32lib.jar
prebuilts/tools/common/mkidentity/mkidentity-prebuilt.jar tools/lib/mkidentity.jar
# 3rd Party java libraries
@@ -135,7 +135,7 @@ prebuilts/tools/common/http-client/commons-logging-1.1.1.jar
prebuilts/tools/common/http-client/commons-codec-1.4.jar tools/lib/commons-codec-1.4.jar
framework/emmalib.jar tools/lib/emma_device.jar
external/emma/lib/emma.jar tools/lib/emma.jar
-external/emma/lib/emma_ant.jar tools/lib/emma_ant.jar
+external/emma/lib/emma_ant.jar tools/lib/emma_ant.jar
prebuilts/tools/common/jfreechart/jcommon-1.0.12.jar tools/lib/jcommon-1.0.12.jar
prebuilts/tools/common/jfreechart/jfreechart-1.0.9.jar tools/lib/jfreechart-1.0.9.jar
prebuilts/tools/common/jfreechart/jfreechart-1.0.9-swt.jar tools/lib/jfreechart-1.0.9-swt.jar
@@ -143,7 +143,6 @@ prebuilts/tools/common/eclipse/org.eclipse.core.commands_3.6.0.I20100512-1500.ja
prebuilts/tools/common/eclipse/org.eclipse.equinox.common_3.6.0.v20100503.jar tools/lib/org.eclipse.equinox.common_3.6.0.v20100503.jar
prebuilts/tools/common/eclipse/org.eclipse.jface_3.6.2.M20110210-1200.jar tools/lib/org.eclipse.jface_3.6.2.M20110210-1200.jar
prebuilts/tools/common/osgi/osgi.jar tools/lib/osgi.jar
-prebuilts/tools/common/swing-worker/swing-worker-1.1.jar tools/lib/swing-worker-1.1.jar
prebuilts/tools/common/asm-tools/asm-4.0.jar tools/lib/asm-4.0.jar
prebuilts/tools/common/asm-tools/asm-tree-4.0.jar tools/lib/asm-tree-4.0.jar
prebuilts/tools/common/asm-tools/asm-analysis-4.0.jar tools/lib/asm-analysis-4.0.jar
@@ -191,7 +190,4 @@ sdk/files/typos tools/support
sdk/testapps tests/testapps
framework/ninepatch-tests.jar tests/libtests/ninepatch-tests.jar
-framework/common-tests.jar tests/libtests/common-tests.jar
-framework/layoutlib_api.jar tests/libtests/layoutlib_api.jar
-framework/dvlib-tests.jar tests/libtests/dvlib-tests.jar
diff --git a/build/tools.windows.atree b/build/tools.windows.atree
index f936d96..3a84ff8 100755
--- a/build/tools.windows.atree
+++ b/build/tools.windows.atree
@@ -37,10 +37,10 @@ rm tools/draw9patch
sdk/draw9patch/etc/draw9patch.bat tools/draw9patch.bat
rm tools/lint
-sdk/lint/cli/etc/lint.bat tools/lint.bat
+prebuilts/devtools/etc/lint.bat tools/lint.bat
rm tools/jobb
-prebuilts/devtools/jobb/etc/jobb.bat tools/jobb.bat
+prebuilts/devtools/etc/jobb.bat tools/jobb.bat
rm tools/emulator
diff --git a/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java b/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java
index dadb017..af09efe 100644
--- a/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java
+++ b/chimpchat/src/com/android/chimpchat/adb/AdbChimpDevice.java
@@ -367,6 +367,9 @@ public class AdbChimpDevice implements IChimpDevice {
case DOWN_AND_UP:
manager.tap(x, y);
break;
+ case MOVE:
+ manager.touchMove(x, y);
+ break;
}
} catch (IOException e) {
LOG.log(Level.SEVERE, "Error sending touch event: " + x + " " + y + " " + type, e);
diff --git a/chimpchat/src/com/android/chimpchat/core/TouchPressType.java b/chimpchat/src/com/android/chimpchat/core/TouchPressType.java
index e5b92b7..7e1d4b6 100644
--- a/chimpchat/src/com/android/chimpchat/core/TouchPressType.java
+++ b/chimpchat/src/com/android/chimpchat/core/TouchPressType.java
@@ -23,7 +23,7 @@ import java.util.Map;
* When passed as a string, the "identifier" value is used.
*/
public enum TouchPressType {
- DOWN("down"), UP("up"), DOWN_AND_UP("downAndUp");
+ DOWN("down"), UP("up"), DOWN_AND_UP("downAndUp"), MOVE("move");
private static final Map<String,TouchPressType> identifierToEnum =
new HashMap<String,TouchPressType>();
diff --git a/common/Android.mk b/common/Android.mk
index 85bcd60..dc098fd 100644
--- a/common/Android.mk
+++ b/common/Android.mk
@@ -16,13 +16,12 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-
-LOCAL_JAR_MANIFEST := manifest.txt
+# The common code has moved to tools/base/common.
+# The rule below uses the prebuilt common.jar.
+#
+# If you want to run the tests, cd to tools/base/common
+# and run ./gradlew :common:test
-# IMPORTANT: if you add a new dependency here, please make sure
-# to also check the following files:
-# common/manifest.txt
LOCAL_JAVA_LIBRARIES := \
guava-tools
@@ -30,16 +29,8 @@ LOCAL_MODULE := common
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# build the tests
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
-
-LOCAL_MODULE := common-tests
-LOCAL_MODULE_TAGS := optional
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-LOCAL_JAVA_LIBRARIES := common junit
+include $(BUILD_HOST_PREBUILT)
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/src/main/java/com/android/SdkConstants.java b/common/src/main/java/com/android/SdkConstants.java
deleted file mode 100644
index a0fdc39..0000000
--- a/common/src/main/java/com/android/SdkConstants.java
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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;
-
-import java.io.File;
-
-/**
- * Constant definition class.<br>
- * <br>
- * Most constants have a prefix defining the content.
- * <ul>
- * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li>
- * <li><code>FN_</code> File name constant.</li>
- * <li><code>FD_</code> Folder name constant.</li>
- * <li><code>TAG_</code> XML element tag name</li>
- * <li><code>ATTR_</code> XML attribute name</li>
- * <li><code>VALUE_</code> XML attribute value</li>
- * <li><code>CLASS_</code> Class name</li>
- * <li><code>DOT_</code> File name extension, including the dot </li>
- * <li><code>EXT_</code> File name extension, without the dot </li>
- * </ul>
- */
-@SuppressWarnings("javadoc") // Not documenting all the fields here
-public final class SdkConstants {
- public static final int PLATFORM_UNKNOWN = 0;
- public static final int PLATFORM_LINUX = 1;
- public static final int PLATFORM_WINDOWS = 2;
- public static final int PLATFORM_DARWIN = 3;
-
- /**
- * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- public static final int CURRENT_PLATFORM = currentPlatform();
-
- /**
- * Charset for the ini file handled by the SDK.
- */
- public static final String INI_CHARSET = "UTF-8"; //$NON-NLS-1$
-
- /** An SDK Project's AndroidManifest.xml file */
- public static final String FN_ANDROID_MANIFEST_XML= "AndroidManifest.xml"; //$NON-NLS-1$
- /** pre-dex jar filename. i.e. "classes.jar" */
- public static final String FN_CLASSES_JAR = "classes.jar"; //$NON-NLS-1$
- /** Dex filename inside the APK. i.e. "classes.dex" */
- public static final String FN_APK_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$
-
- /** An SDK Project's build.xml file */
- public static final String FN_BUILD_XML = "build.xml"; //$NON-NLS-1$
-
- /** Name of the framework library, i.e. "android.jar" */
- public static final String FN_FRAMEWORK_LIBRARY = "android.jar"; //$NON-NLS-1$
- /** Name of the framework library, i.e. "uiautomator.jar" */
- public static final String FN_UI_AUTOMATOR_LIBRARY = "uiautomator.jar"; //$NON-NLS-1$
- /** Name of the layout attributes, i.e. "attrs.xml" */
- public static final String FN_ATTRS_XML = "attrs.xml"; //$NON-NLS-1$
- /** Name of the layout attributes, i.e. "attrs_manifest.xml" */
- public static final String FN_ATTRS_MANIFEST_XML = "attrs_manifest.xml"; //$NON-NLS-1$
- /** framework aidl import file */
- public static final String FN_FRAMEWORK_AIDL = "framework.aidl"; //$NON-NLS-1$
- /** framework renderscript folder */
- public static final String FN_FRAMEWORK_RENDERSCRIPT = "renderscript"; //$NON-NLS-1$
- /** framework include folder */
- public static final String FN_FRAMEWORK_INCLUDE = "include"; //$NON-NLS-1$
- /** framework include (clang) folder */
- public static final String FN_FRAMEWORK_INCLUDE_CLANG = "clang-include"; //$NON-NLS-1$
- /** layoutlib.jar file */
- public static final String FN_LAYOUTLIB_JAR = "layoutlib.jar"; //$NON-NLS-1$
- /** widget list file */
- public static final String FN_WIDGETS = "widgets.txt"; //$NON-NLS-1$
- /** Intent activity actions list file */
- public static final String FN_INTENT_ACTIONS_ACTIVITY = "activity_actions.txt"; //$NON-NLS-1$
- /** Intent broadcast actions list file */
- public static final String FN_INTENT_ACTIONS_BROADCAST = "broadcast_actions.txt"; //$NON-NLS-1$
- /** Intent service actions list file */
- public static final String FN_INTENT_ACTIONS_SERVICE = "service_actions.txt"; //$NON-NLS-1$
- /** Intent category list file */
- public static final String FN_INTENT_CATEGORIES = "categories.txt"; //$NON-NLS-1$
-
- /** annotations support jar */
- public static final String FN_ANNOTATIONS_JAR = "annotations.jar"; //$NON-NLS-1$
-
- /** platform build property file */
- public static final String FN_BUILD_PROP = "build.prop"; //$NON-NLS-1$
- /** plugin properties file */
- public static final String FN_PLUGIN_PROP = "plugin.prop"; //$NON-NLS-1$
- /** add-on manifest file */
- public static final String FN_MANIFEST_INI = "manifest.ini"; //$NON-NLS-1$
- /** add-on layout device XML file. */
- public static final String FN_DEVICES_XML = "devices.xml"; //$NON-NLS-1$
- /** hardware properties definition file */
- public static final String FN_HARDWARE_INI = "hardware-properties.ini"; //$NON-NLS-1$
-
- /** project property file */
- public static final String FN_PROJECT_PROPERTIES = "project.properties"; //$NON-NLS-1$
-
- /** project local property file */
- public static final String FN_LOCAL_PROPERTIES = "local.properties"; //$NON-NLS-1$
-
- /** project ant property file */
- public static final String FN_ANT_PROPERTIES = "ant.properties"; //$NON-NLS-1$
-
- /** Skin layout file */
- public static final String FN_SKIN_LAYOUT = "layout"; //$NON-NLS-1$
-
- /** dx.jar file */
- public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
-
- /** dx executable (with extension for the current OS) */
- public static final String FN_DX =
- "dx" + ext(".bat", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** aapt executable (with extension for the current OS) */
- public static final String FN_AAPT =
- "aapt" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** aidl executable (with extension for the current OS) */
- public static final String FN_AIDL =
- "aidl" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** renderscript executable (with extension for the current OS) */
- public static final String FN_RENDERSCRIPT =
- "llvm-rs-cc" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** adb executable (with extension for the current OS) */
- public static final String FN_ADB =
- "adb" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** emulator executable for the current OS */
- public static final String FN_EMULATOR =
- "emulator" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** zipalign executable (with extension for the current OS) */
- public static final String FN_ZIPALIGN =
- "zipalign" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** dexdump executable (with extension for the current OS) */
- public static final String FN_DEXDUMP =
- "dexdump" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** proguard executable (with extension for the current OS) */
- public static final String FN_PROGUARD =
- "proguard" + ext(".bat", ".sh"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** find_lock for Windows (with extension for the current OS) */
- public static final String FN_FIND_LOCK =
- "find_lock" + ext(".exe", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- /** properties file for SDK Updater packages */
- public static final String FN_SOURCE_PROP = "source.properties"; //$NON-NLS-1$
- /** properties file for content hash of installed packages */
- public static final String FN_CONTENT_HASH_PROP = "content_hash.properties"; //$NON-NLS-1$
- /** properties file for the SDK */
- public static final String FN_SDK_PROP = "sdk.properties"; //$NON-NLS-1$
-
- /**
- * filename for gdbserver.
- */
- public static final String FN_GDBSERVER = "gdbserver"; //$NON-NLS-1$
-
- /** global Android proguard config file */
- public static final String FN_ANDROID_PROGUARD_FILE = "proguard-android.txt"; //$NON-NLS-1$
- /** global Android proguard config file with optimization enabled */
- public static final String FN_ANDROID_OPT_PROGUARD_FILE = "proguard-android-optimize.txt"; //$NON-NLS-1$
- /** default proguard config file with new file extension (for project specific stuff) */
- public static final String FN_PROJECT_PROGUARD_FILE = "proguard-project.txt"; //$NON-NLS-1$
-
- /* Folder Names for Android Projects . */
-
- /** Resources folder name, i.e. "res". */
- public static final String FD_RESOURCES = "res"; //$NON-NLS-1$
- /** Assets folder name, i.e. "assets" */
- public static final String FD_ASSETS = "assets"; //$NON-NLS-1$
- /** Default source folder name in an SDK project, i.e. "src".
- * <p/>
- * Note: this is not the same as {@link #FD_PKG_SOURCES}
- * which is an SDK sources folder for packages. */
- public static final String FD_SOURCES = "src"; //$NON-NLS-1$
- /** Default generated source folder name, i.e. "gen" */
- public static final String FD_GEN_SOURCES = "gen"; //$NON-NLS-1$
- /** Default native library folder name inside the project, i.e. "libs"
- * While the folder inside the .apk is "lib", we call that one libs because
- * that's what we use in ant for both .jar and .so and we need to make the 2 development ways
- * compatible. */
- public static final String FD_NATIVE_LIBS = "libs"; //$NON-NLS-1$
- /** Native lib folder inside the APK: "lib" */
- public static final String FD_APK_NATIVE_LIBS = "lib"; //$NON-NLS-1$
- /** Default output folder name, i.e. "bin" */
- public static final String FD_OUTPUT = "bin"; //$NON-NLS-1$
- /** Classes output folder name, i.e. "classes" */
- public static final String FD_CLASSES_OUTPUT = "classes"; //$NON-NLS-1$
- /** proguard output folder for mapping, etc.. files */
- public static final String FD_PROGUARD = "proguard"; //$NON-NLS-1$
- /** aidl output folder for copied aidl files */
- public static final String FD_AIDL = "aidl"; //$NON-NLS-1$
-
- /* Folder Names for the Android SDK */
-
- /** Name of the SDK platforms folder. */
- public static final String FD_PLATFORMS = "platforms"; //$NON-NLS-1$
- /** Name of the SDK addons folder. */
- public static final String FD_ADDONS = "add-ons"; //$NON-NLS-1$
- /** Name of the SDK system-images folder. */
- public static final String FD_SYSTEM_IMAGES = "system-images"; //$NON-NLS-1$
- /** Name of the SDK sources folder where source packages are installed.
- * <p/>
- * Note this is not the same as {@link #FD_SOURCES} which is the folder name where sources
- * are installed inside a project. */
- public static final String FD_PKG_SOURCES = "sources"; //$NON-NLS-1$
- /** Name of the SDK tools folder. */
- public static final String FD_TOOLS = "tools"; //$NON-NLS-1$
- /** Name of the SDK tools/support folder. */
- public static final String FD_SUPPORT = "support"; //$NON-NLS-1$
- /** Name of the SDK platform tools folder. */
- public static final String FD_PLATFORM_TOOLS = "platform-tools"; //$NON-NLS-1$
- /** Name of the SDK tools/lib folder. */
- public static final String FD_LIB = "lib"; //$NON-NLS-1$
- /** Name of the SDK docs folder. */
- public static final String FD_DOCS = "docs"; //$NON-NLS-1$
- /** Name of the doc folder containing API reference doc (javadoc) */
- public static final String FD_DOCS_REFERENCE = "reference"; //$NON-NLS-1$
- /** Name of the SDK images folder. */
- public static final String FD_IMAGES = "images"; //$NON-NLS-1$
- /** Name of the ABI to support. */
- public static final String ABI_ARMEABI = "armeabi"; //$NON-NLS-1$
- public static final String ABI_ARMEABI_V7A = "armeabi-v7a"; //$NON-NLS-1$
- public static final String ABI_INTEL_ATOM = "x86"; //$NON-NLS-1$
- public static final String ABI_MIPS = "mips"; //$NON-NLS-1$
- /** Name of the CPU arch to support. */
- public static final String CPU_ARCH_ARM = "arm"; //$NON-NLS-1$
- public static final String CPU_ARCH_INTEL_ATOM = "x86"; //$NON-NLS-1$
- public static final String CPU_ARCH_MIPS = "mips"; //$NON-NLS-1$
- /** Name of the CPU model to support. */
- public static final String CPU_MODEL_CORTEX_A8 = "cortex-a8"; //$NON-NLS-1$
-
- /** Name of the SDK skins folder. */
- public static final String FD_SKINS = "skins"; //$NON-NLS-1$
- /** Name of the SDK samples folder. */
- public static final String FD_SAMPLES = "samples"; //$NON-NLS-1$
- /** Name of the SDK extras folder. */
- public static final String FD_EXTRAS = "extras"; //$NON-NLS-1$
- /**
- * Name of an extra's sample folder.
- * Ideally extras should have one {@link #FD_SAMPLES} folder containing
- * one or more sub-folders (one per sample). However some older extras
- * might contain a single "sample" folder with directly the samples files
- * in it. When possible we should encourage extras' owners to move to the
- * multi-samples format.
- */
- public static final String FD_SAMPLE = "sample"; //$NON-NLS-1$
- /** Name of the SDK templates folder, i.e. "templates" */
- public static final String FD_TEMPLATES = "templates"; //$NON-NLS-1$
- /** Name of the SDK Ant folder, i.e. "ant" */
- public static final String FD_ANT = "ant"; //$NON-NLS-1$
- /** Name of the SDK data folder, i.e. "data" */
- public static final String FD_DATA = "data"; //$NON-NLS-1$
- /** Name of the SDK renderscript folder, i.e. "rs" */
- public static final String FD_RENDERSCRIPT = "rs"; //$NON-NLS-1$
- /** Name of the SDK resources folder, i.e. "res" */
- public static final String FD_RES = "res"; //$NON-NLS-1$
- /** Name of the SDK font folder, i.e. "fonts" */
- public static final String FD_FONTS = "fonts"; //$NON-NLS-1$
- /** Name of the android sources directory */
- public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
- /** Name of the addon libs folder. */
- public static final String FD_ADDON_LIBS = "libs"; //$NON-NLS-1$
-
- /** Name of the cache folder in the $HOME/.android. */
- public static final String FD_CACHE = "cache"; //$NON-NLS-1$
-
- /** API codename of a release (non preview) system image or platform. **/
- public static final String CODENAME_RELEASE = "REL"; //$NON-NLS-1$
-
- /** Namespace for the resource XML, i.e. "http://schemas.android.com/apk/res/android" */
- public static final String NS_RESOURCES =
- "http://schemas.android.com/apk/res/android"; //$NON-NLS-1$
-
- /** Namespace for the device schema, i.e. "http://schemas.android.com/sdk/devices/1" */
- public static final String NS_DEVICES_XSD =
- "http://schemas.android.com/sdk/devices/1"; //$NON-NLS-1$
-
-
- /** The name of the uses-library that provides "android.test.runner" */
- public static final String ANDROID_TEST_RUNNER_LIB =
- "android.test.runner"; //$NON-NLS-1$
-
- /* Folder path relative to the SDK root */
- /** Path of the documentation directory relative to the sdk folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_DOCS_FOLDER = FD_DOCS + File.separator;
-
- /** Path of the tools directory relative to the sdk folder, or to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_TOOLS_FOLDER = FD_TOOLS + File.separator;
-
- /** Path of the lib directory relative to the sdk folder, or to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_TOOLS_LIB_FOLDER =
- OS_SDK_TOOLS_FOLDER + FD_LIB + File.separator;
-
- /**
- * Path of the lib directory relative to the sdk folder, or to a platform
- * folder. This is an OS path, ending with a separator.
- */
- public static final String OS_SDK_TOOLS_LIB_EMULATOR_FOLDER = OS_SDK_TOOLS_LIB_FOLDER
- + "emulator" + File.separator; //$NON-NLS-1$
-
- /** Path of the platform tools directory relative to the sdk folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_PLATFORM_TOOLS_FOLDER = FD_PLATFORM_TOOLS + File.separator;
-
- /** Path of the Platform tools Lib directory relative to the sdk folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_PLATFORM_TOOLS_LIB_FOLDER =
- OS_SDK_PLATFORM_TOOLS_FOLDER + FD_LIB + File.separator;
-
- /** Path of the bin folder of proguard folder relative to the sdk folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SDK_TOOLS_PROGUARD_BIN_FOLDER =
- SdkConstants.OS_SDK_TOOLS_FOLDER +
- "proguard" + File.separator + //$NON-NLS-1$
- "bin" + File.separator; //$NON-NLS-1$
-
- /* Folder paths relative to a platform or add-on folder */
-
- /** Path of the images directory relative to a platform or addon folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_IMAGES_FOLDER = FD_IMAGES + File.separator;
-
- /** Path of the skin directory relative to a platform or addon folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_SKINS_FOLDER = FD_SKINS + File.separator;
-
- /* Folder paths relative to a Platform folder */
-
- /** Path of the data directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_DATA_FOLDER = FD_DATA + File.separator;
-
- /** Path of the renderscript directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_RENDERSCRIPT_FOLDER = FD_RENDERSCRIPT + File.separator;
-
-
- /** Path of the samples directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_SAMPLES_FOLDER = FD_SAMPLES + File.separator;
-
- /** Path of the resources directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_RESOURCES_FOLDER =
- OS_PLATFORM_DATA_FOLDER + FD_RES + File.separator;
-
- /** Path of the fonts directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_FONTS_FOLDER =
- OS_PLATFORM_DATA_FOLDER + FD_FONTS + File.separator;
-
- /** Path of the android source directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_SOURCES_FOLDER = FD_ANDROID_SOURCES + File.separator;
-
- /** Path of the android templates directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_TEMPLATES_FOLDER = FD_TEMPLATES + File.separator;
-
- /** Path of the Ant build rules directory relative to a platform folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_PLATFORM_ANT_FOLDER = FD_ANT + File.separator;
-
- /** Path of the attrs.xml file relative to a platform folder. */
- public static final String OS_PLATFORM_ATTRS_XML =
- OS_PLATFORM_RESOURCES_FOLDER + SdkConstants.FD_RES_VALUES + File.separator +
- FN_ATTRS_XML;
-
- /** Path of the attrs_manifest.xml file relative to a platform folder. */
- public static final String OS_PLATFORM_ATTRS_MANIFEST_XML =
- OS_PLATFORM_RESOURCES_FOLDER + SdkConstants.FD_RES_VALUES + File.separator +
- FN_ATTRS_MANIFEST_XML;
-
- /** Path of the layoutlib.jar file relative to a platform folder. */
- public static final String OS_PLATFORM_LAYOUTLIB_JAR =
- OS_PLATFORM_DATA_FOLDER + FN_LAYOUTLIB_JAR;
-
- /** Path of the renderscript include folder relative to a platform folder. */
- public static final String OS_FRAMEWORK_RS =
- FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE;
- /** Path of the renderscript (clang) include folder relative to a platform folder. */
- public static final String OS_FRAMEWORK_RS_CLANG =
- FN_FRAMEWORK_RENDERSCRIPT + File.separator + FN_FRAMEWORK_INCLUDE_CLANG;
-
- /* Folder paths relative to a addon folder */
- /** Path of the images directory relative to a folder folder.
- * This is an OS path, ending with a separator. */
- public static final String OS_ADDON_LIBS_FOLDER = FD_ADDON_LIBS + File.separator;
-
- /** Skin default **/
- public static final String SKIN_DEFAULT = "default"; //$NON-NLS-1$
-
- /** SDK property: ant templates revision */
- public static final String PROP_SDK_ANT_TEMPLATES_REVISION =
- "sdk.ant.templates.revision"; //$NON-NLS-1$
-
- /** SDK property: default skin */
- public static final String PROP_SDK_DEFAULT_SKIN = "sdk.skin.default"; //$NON-NLS-1$
-
- /* Android Class Constants */
- public static final String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$
- public static final String CLASS_APPLICATION = "android.app.Application"; //$NON-NLS-1$
- public static final String CLASS_SERVICE = "android.app.Service"; //$NON-NLS-1$
- public static final String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$
- public static final String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
- public static final String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
- public static final String CLASS_INSTRUMENTATION_RUNNER =
- "android.test.InstrumentationTestRunner"; //$NON-NLS-1$
- public static final String CLASS_BUNDLE = "android.os.Bundle"; //$NON-NLS-1$
- public static final String CLASS_R = "android.R"; //$NON-NLS-1$
- public static final String CLASS_MANIFEST_PERMISSION = "android.Manifest$permission"; //$NON-NLS-1$
- public static final String CLASS_INTENT = "android.content.Intent"; //$NON-NLS-1$
- public static final String CLASS_CONTEXT = "android.content.Context"; //$NON-NLS-1$
- public static final String CLASS_VIEW = "android.view.View"; //$NON-NLS-1$
- public static final String CLASS_VIEWGROUP = "android.view.ViewGroup"; //$NON-NLS-1$
- public static final String CLASS_NAME_LAYOUTPARAMS = "LayoutParams"; //$NON-NLS-1$
- public static final String CLASS_VIEWGROUP_LAYOUTPARAMS =
- CLASS_VIEWGROUP + "$" + CLASS_NAME_LAYOUTPARAMS; //$NON-NLS-1$
- public static final String CLASS_NAME_FRAMELAYOUT = "FrameLayout"; //$NON-NLS-1$
- public static final String CLASS_FRAMELAYOUT =
- "android.widget." + CLASS_NAME_FRAMELAYOUT; //$NON-NLS-1$
- public static final String CLASS_PREFERENCE = "android.preference.Preference"; //$NON-NLS-1$
- public static final String CLASS_NAME_PREFERENCE_SCREEN = "PreferenceScreen"; //$NON-NLS-1$
- public static final String CLASS_PREFERENCES =
- "android.preference." + CLASS_NAME_PREFERENCE_SCREEN; //$NON-NLS-1$
- public static final String CLASS_PREFERENCEGROUP = "android.preference.PreferenceGroup"; //$NON-NLS-1$
- public static final String CLASS_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$
- public static final String CLASS_FRAGMENT = "android.app.Fragment"; //$NON-NLS-1$
- public static final String CLASS_V4_FRAGMENT = "android.support.v4.app.Fragment"; //$NON-NLS-1$
- /** MockView is part of the layoutlib bridge and used to display classes that have
- * no rendering in the graphical layout editor. */
- public static final String CLASS_MOCK_VIEW = "com.android.layoutlib.bridge.MockView"; //$NON-NLS-1$
-
- /** Returns the appropriate name for the 'android' command, which is 'android.exe' for
- * Windows and 'android' for all other platforms. */
- public static String androidCmdName() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- String cmd = "android"; //$NON-NLS-1$
- if (os.startsWith("Windows")) { //$NON-NLS-1$
- cmd += ".bat"; //$NON-NLS-1$
- }
- return cmd;
- }
-
- /** Returns the appropriate name for the 'mksdcard' command, which is 'mksdcard.exe' for
- * Windows and 'mkdsdcard' for all other platforms. */
- public static String mkSdCardCmdName() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- String cmd = "mksdcard"; //$NON-NLS-1$
- if (os.startsWith("Windows")) { //$NON-NLS-1$
- cmd += ".exe"; //$NON-NLS-1$
- }
- return cmd;
- }
-
- /**
- * Returns current platform
- *
- * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
- * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
- */
- public static int currentPlatform() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- if (os.startsWith("Mac OS")) { //$NON-NLS-1$
- return PLATFORM_DARWIN;
- } else if (os.startsWith("Windows")) { //$NON-NLS-1$
- return PLATFORM_WINDOWS;
- } else if (os.startsWith("Linux")) { //$NON-NLS-1$
- return PLATFORM_LINUX;
- }
-
- return PLATFORM_UNKNOWN;
- }
-
- /**
- * Returns current platform's UI name
- *
- * @return one of "Windows", "Mac OS X", "Linux" or "other".
- */
- public static String currentPlatformName() {
- String os = System.getProperty("os.name"); //$NON-NLS-1$
- if (os.startsWith("Mac OS")) { //$NON-NLS-1$
- return "Mac OS X"; //$NON-NLS-1$
- } else if (os.startsWith("Windows")) { //$NON-NLS-1$
- return "Windows"; //$NON-NLS-1$
- } else if (os.startsWith("Linux")) { //$NON-NLS-1$
- return "Linux"; //$NON-NLS-1$
- }
-
- return "Other";
- }
-
- private static String ext(String windowsExtension, String nonWindowsExtension) {
- if (CURRENT_PLATFORM == PLATFORM_WINDOWS) {
- return windowsExtension;
- } else {
- return nonWindowsExtension;
- }
- }
-
- /** Default anim resource folder name, i.e. "anim" */
- public static final String FD_RES_ANIM = "anim"; //$NON-NLS-1$
- /** Default animator resource folder name, i.e. "animator" */
- public static final String FD_RES_ANIMATOR = "animator"; //$NON-NLS-1$
- /** Default color resource folder name, i.e. "color" */
- public static final String FD_RES_COLOR = "color"; //$NON-NLS-1$
- /** Default drawable resource folder name, i.e. "drawable" */
- public static final String FD_RES_DRAWABLE = "drawable"; //$NON-NLS-1$
- /** Default interpolator resource folder name, i.e. "interpolator" */
- public static final String FD_RES_INTERPOLATOR = "interpolator"; //$NON-NLS-1$
- /** Default layout resource folder name, i.e. "layout" */
- public static final String FD_RES_LAYOUT = "layout"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "menu" */
- public static final String FD_RES_MENU = "menu"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "mipmap" */
- public static final String FD_RES_MIPMAP = "mipmap"; //$NON-NLS-1$
- /** Default values resource folder name, i.e. "values" */
- public static final String FD_RES_VALUES = "values"; //$NON-NLS-1$
- /** Default xml resource folder name, i.e. "xml" */
- public static final String FD_RES_XML = "xml"; //$NON-NLS-1$
- /** Default raw resource folder name, i.e. "raw" */
- public static final String FD_RES_RAW = "raw"; //$NON-NLS-1$
- /** Separator between the resource folder qualifier. */
- public static final String RES_QUALIFIER_SEP = "-"; //$NON-NLS-1$
- /** Namespace used in XML files for Android attributes */
-
- // ---- XML ----
-
- /** URI of the reserved "xmlns" prefix */
- public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; //$NON-NLS-1$
- /** The "xmlns" attribute name */
- public static final String XMLNS = "xmlns"; //$NON-NLS-1$
- /** The default prefix used for the {@link #XMLNS_URI} */
- public static final String XMLNS_PREFIX = "xmlns:"; //$NON-NLS-1$
- /** Qualified name of the xmlns android declaration element */
- public static final String XMLNS_ANDROID = "xmlns:android"; //$NON-NLS-1$
- /** The default prefix used for the {@link #ANDROID_URI} name space */
- public static final String ANDROID_NS_NAME = "android"; //$NON-NLS-1$
- /** The default prefix used for the {@link #ANDROID_URI} name space including the colon */
- public static final String ANDROID_NS_NAME_PREFIX = "android:"; //$NON-NLS-1$
- /** The default prefix used for the app */
- public static final String APP_PREFIX = "app"; //$NON-NLS-1$
- /** The entity for the ampersand character */
- public static final String AMP_ENTITY = "&amp;"; //$NON-NLS-1$
- /** The entity for the quote character */
- public static final String QUOT_ENTITY = "&quot;"; //$NON-NLS-1$
- /** The entity for the apostrophe character */
- public static final String APOS_ENTITY = "&apos;"; //$NON-NLS-1$
- /** The entity for the less than character */
- public static final String LT_ENTITY = "&lt;"; //$NON-NLS-1$
- /** The entity for the greater than character */
- public static final String GT_ENTITY = "&gt;"; //$NON-NLS-1$
-
- // ---- Elements and Attributes ----
-
- /** Namespace prefix used for all resources */
- public static final String URI_PREFIX =
- "http://schemas.android.com/apk/res/"; //$NON-NLS-1$
- /** Namespace used in XML files for Android attributes */
- public static final String ANDROID_URI =
- "http://schemas.android.com/apk/res/android"; //$NON-NLS-1$
- /** Namespace used in XML files for Android Tooling attributes */
- public static final String TOOLS_URI =
- "http://schemas.android.com/tools"; //$NON-NLS-1$
- /** Namespace used for auto-adjusting namespaces */
- public static final String AUTO_URI =
- "http://schemas.android.com/apk/res-auto"; //$NON-NLS-1$
- /** Default prefix used for tools attributes */
- public static final String TOOLS_PREFIX = "tools"; //$NON-NLS-1$
- public static final String R_CLASS = "R"; //$NON-NLS-1$
- public static final String ANDROID_PKG = "android"; //$NON-NLS-1$
-
- // Tags: Manifest
- public static final String TAG_SERVICE = "service"; //$NON-NLS-1$
- public static final String TAG_PERMISSION = "permission"; //$NON-NLS-1$
- public static final String TAG_USES_PERMISSION = "uses-permission";//$NON-NLS-1$
- public static final String TAG_USES_LIBRARY = "uses-library"; //$NON-NLS-1$
- public static final String TAG_APPLICATION = "application"; //$NON-NLS-1$
- public static final String TAG_INTENT_FILTER = "intent-filter"; //$NON-NLS-1$
- public static final String TAG_USES_SDK = "uses-sdk"; //$NON-NLS-1$
- public static final String TAG_ACTIVITY = "activity"; //$NON-NLS-1$
- public static final String TAG_RECEIVER = "receiver"; //$NON-NLS-1$
- public static final String TAG_PROVIDER = "provider"; //$NON-NLS-1$
- public static final String TAG_GRANT_PERMISSION = "grant-uri-permission"; //$NON-NLS-1$
- public static final String TAG_PATH_PERMISSION = "path-permission"; //$NON-NLS-1$
-
- // Tags: Resources
- public static final String TAG_RESOURCES = "resources"; //$NON-NLS-1$
- public static final String TAG_STRING = "string"; //$NON-NLS-1$
- public static final String TAG_ARRAY = "array"; //$NON-NLS-1$
- public static final String TAG_STYLE = "style"; //$NON-NLS-1$
- public static final String TAG_ITEM = "item"; //$NON-NLS-1$
- public static final String TAG_STRING_ARRAY = "string-array"; //$NON-NLS-1$
- public static final String TAG_PLURALS = "plurals"; //$NON-NLS-1$
- public static final String TAG_INTEGER_ARRAY = "integer-array"; //$NON-NLS-1$
- public static final String TAG_COLOR = "color"; //$NON-NLS-1$
- public static final String TAG_DIMEN = "dimen"; //$NON-NLS-1$
- public static final String TAG_DRAWABLE = "drawable"; //$NON-NLS-1$
- public static final String TAG_MENU = "menu"; //$NON-NLS-1$
-
- // Tags: Layouts
- public static final String VIEW_TAG = "view"; //$NON-NLS-1$
- public static final String VIEW_INCLUDE = "include"; //$NON-NLS-1$
- public static final String VIEW_MERGE = "merge"; //$NON-NLS-1$
- public static final String VIEW_FRAGMENT = "fragment"; //$NON-NLS-1$
- public static final String REQUEST_FOCUS = "requestFocus"; //$NON-NLS-1$
-
- public static final String VIEW = "View"; //$NON-NLS-1$
- public static final String VIEW_GROUP = "ViewGroup"; //$NON-NLS-1$
- public static final String FRAME_LAYOUT = "FrameLayout"; //$NON-NLS-1$
- public static final String LINEAR_LAYOUT = "LinearLayout"; //$NON-NLS-1$
- public static final String RELATIVE_LAYOUT = "RelativeLayout"; //$NON-NLS-1$
- public static final String GRID_LAYOUT = "GridLayout"; //$NON-NLS-1$
- public static final String SCROLL_VIEW = "ScrollView"; //$NON-NLS-1$
- public static final String BUTTON = "Button"; //$NON-NLS-1$
- public static final String COMPOUND_BUTTON = "CompoundButton"; //$NON-NLS-1$
- public static final String ADAPTER_VIEW = "AdapterView"; //$NON-NLS-1$
- public static final String GALLERY = "Gallery"; //$NON-NLS-1$
- public static final String GRID_VIEW = "GridView"; //$NON-NLS-1$
- public static final String TAB_HOST = "TabHost"; //$NON-NLS-1$
- public static final String RADIO_GROUP = "RadioGroup"; //$NON-NLS-1$
- public static final String RADIO_BUTTON = "RadioButton"; //$NON-NLS-1$
- public static final String SWITCH = "Switch"; //$NON-NLS-1$
- public static final String EDIT_TEXT = "EditText"; //$NON-NLS-1$
- public static final String LIST_VIEW = "ListView"; //$NON-NLS-1$
- public static final String TEXT_VIEW = "TextView"; //$NON-NLS-1$
- public static final String CHECKED_TEXT_VIEW = "CheckedTextView"; //$NON-NLS-1$
- public static final String IMAGE_VIEW = "ImageView"; //$NON-NLS-1$
- public static final String SURFACE_VIEW = "SurfaceView"; //$NON-NLS-1$
- public static final String ABSOLUTE_LAYOUT = "AbsoluteLayout"; //$NON-NLS-1$
- public static final String TABLE_LAYOUT = "TableLayout"; //$NON-NLS-1$
- public static final String TABLE_ROW = "TableRow"; //$NON-NLS-1$
- public static final String TAB_WIDGET = "TabWidget"; //$NON-NLS-1$
- public static final String IMAGE_BUTTON = "ImageButton"; //$NON-NLS-1$
- public static final String SEEK_BAR = "SeekBar"; //$NON-NLS-1$
- public static final String VIEW_STUB = "ViewStub"; //$NON-NLS-1$
- public static final String SPINNER = "Spinner"; //$NON-NLS-1$
- public static final String WEB_VIEW = "WebView"; //$NON-NLS-1$
- public static final String TOGGLE_BUTTON = "ToggleButton"; //$NON-NLS-1$
- public static final String CHECK_BOX = "CheckBox"; //$NON-NLS-1$
- public static final String ABS_LIST_VIEW = "AbsListView"; //$NON-NLS-1$
- public static final String PROGRESS_BAR = "ProgressBar"; //$NON-NLS-1$
- public static final String ABS_SPINNER = "AbsSpinner"; //$NON-NLS-1$
- public static final String ABS_SEEK_BAR = "AbsSeekBar"; //$NON-NLS-1$
- public static final String VIEW_ANIMATOR = "ViewAnimator"; //$NON-NLS-1$
- public static final String VIEW_SWITCHER = "ViewSwitcher"; //$NON-NLS-1$
- public static final String EXPANDABLE_LIST_VIEW = "ExpandableListView"; //$NON-NLS-1$
- public static final String HORIZONTAL_SCROLL_VIEW = "HorizontalScrollView"; //$NON-NLS-1$
- public static final String MULTI_AUTO_COMPLETE_TEXT_VIEW = "MultiAutoCompleteTextView"; //$NON-NLS-1$
- public static final String AUTO_COMPLETE_TEXT_VIEW = "AutoCompleteTextView"; //$NON-NLS-1$
- public static final String CHECKABLE = "Checkable"; //$NON-NLS-1$
-
- // Tags: Drawables
- public static final String TAG_BITMAP = "bitmap"; //$NON-NLS-1$
-
- // Attributes: Manifest
- public static final String ATTR_EXPORTED = "exported"; //$NON-NLS-1$
- public static final String ATTR_PERMISSION = "permission"; //$NON-NLS-1$
- public static final String ATTR_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-1$
- public static final String ATTR_TARGET_SDK_VERSION = "targetSdkVersion"; //$NON-NLS-1$
- public static final String ATTR_ICON = "icon"; //$NON-NLS-1$
- public static final String ATTR_PACKAGE = "package"; //$NON-NLS-1$
- public static final String ATTR_CORE_APP = "coreApp"; //$NON-NLS-1$
- public static final String ATTR_THEME = "theme"; //$NON-NLS-1$
- public static final String ATTR_PATH = "path"; //$NON-NLS-1$
- public static final String ATTR_PATH_PREFIX = "pathPrefix"; //$NON-NLS-1$
- public static final String ATTR_PATH_PATTERN = "pathPattern"; //$NON-NLS-1$
- public static final String ATTR_ALLOW_BACKUP = "allowBackup"; //$NON_NLS-1$
- public static final String ATTR_DEBUGGABLE = "debuggable"; //$NON-NLS-1$
- public static final String ATTR_READ_PERMISSION = "readPermission"; //$NON_NLS-1$
- public static final String ATTR_WRITE_PERMISSION = "writePermission"; //$NON_NLS-1$
-
- // Attributes: Resources
- public static final String ATTR_NAME = "name"; //$NON-NLS-1$
- public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
- public static final String ATTR_PARENT = "parent"; //$NON-NLS-1$
- public static final String ATTR_TRANSLATABLE = "translatable"; //$NON-NLS-1$
- public static final String ATTR_COLOR = "color"; //$NON-NLS-1$
-
- // Attributes: Layout
- public static final String ATTR_LAYOUT_RESOURCE_PREFIX = "layout_";//$NON-NLS-1$
- public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
- public static final String ATTR_STYLE = "style"; //$NON-NLS-1$
- public static final String ATTR_CONTEXT = "context"; //$NON-NLS-1$
- public static final String ATTR_ID = "id"; //$NON-NLS-1$
- public static final String ATTR_TEXT = "text"; //$NON-NLS-1$
- public static final String ATTR_TEXT_SIZE = "textSize"; //$NON-NLS-1$
- public static final String ATTR_LABEL = "label"; //$NON-NLS-1$
- public static final String ATTR_HINT = "hint"; //$NON-NLS-1$
- public static final String ATTR_PROMPT = "prompt"; //$NON-NLS-1$
- public static final String ATTR_ON_CLICK = "onClick"; //$NON-NLS-1$
- public static final String ATTR_INPUT_TYPE = "inputType"; //$NON-NLS-1$
- public static final String ATTR_INPUT_METHOD = "inputMethod"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_GRAVITY = "layout_gravity"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_WIDTH = "layout_width"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_HEIGHT = "layout_height"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_WEIGHT = "layout_weight"; //$NON-NLS-1$
- public static final String ATTR_PADDING = "padding"; //$NON-NLS-1$
- public static final String ATTR_PADDING_BOTTOM = "paddingBottom"; //$NON-NLS-1$
- public static final String ATTR_PADDING_TOP = "paddingTop"; //$NON-NLS-1$
- public static final String ATTR_PADDING_RIGHT = "paddingRight"; //$NON-NLS-1$
- public static final String ATTR_PADDING_LEFT = "paddingLeft"; //$NON-NLS-1$
- public static final String ATTR_FOREGROUND = "foreground"; //$NON-NLS-1$
- public static final String ATTR_BACKGROUND = "background"; //$NON-NLS-1$
- public static final String ATTR_ORIENTATION = "orientation"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT = "layout"; //$NON-NLS-1$
- public static final String ATTR_ROW_COUNT = "rowCount"; //$NON-NLS-1$
- public static final String ATTR_COLUMN_COUNT = "columnCount"; //$NON-NLS-1$
- public static final String ATTR_LABEL_FOR = "labelFor"; //$NON-NLS-1$
- public static final String ATTR_BASELINE_ALIGNED = "baselineAligned"; //$NON-NLS-1$
- public static final String ATTR_CONTENT_DESCRIPTION = "contentDescription"; //$NON-NLS-1$
- public static final String ATTR_IME_ACTION_LABEL = "imeActionLabel"; //$NON-NLS-1$
- public static final String ATTR_PRIVATE_IME_OPTIONS = "privateImeOptions"; //$NON-NLS-1$
- public static final String VALUE_NONE = "none"; //$NON-NLS-1$
- public static final String VALUE_NO = "no"; //$NON-NLS-1$
- public static final String ATTR_NUMERIC = "numeric"; //$NON-NLS-1$
- public static final String ATTR_IME_ACTION_ID = "imeActionId"; //$NON-NLS-1$
- public static final String ATTR_IME_OPTIONS = "imeOptions"; //$NON-NLS-1$
- public static final String ATTR_FREEZES_TEXT = "freezesText"; //$NON-NLS-1$
- public static final String ATTR_EDITOR_EXTRAS = "editorExtras"; //$NON-NLS-1$
- public static final String ATTR_EDITABLE = "editable"; //$NON-NLS-1$
- public static final String ATTR_DIGITS = "digits"; //$NON-NLS-1$
- public static final String ATTR_CURSOR_VISIBLE = "cursorVisible"; //$NON-NLS-1$
- public static final String ATTR_CAPITALIZE = "capitalize"; //$NON-NLS-1$
- public static final String ATTR_PHONE_NUMBER = "phoneNumber"; //$NON-NLS-1$
- public static final String ATTR_PASSWORD = "password"; //$NON-NLS-1$
- public static final String ATTR_BUFFER_TYPE = "bufferType"; //$NON-NLS-1$
- public static final String ATTR_AUTO_TEXT = "autoText"; //$NON-NLS-1$
- public static final String ATTR_ENABLED = "enabled"; //$NON-NLS-1$
- public static final String ATTR_SINGLE_LINE = "singleLine"; //$NON-NLS-1$
- public static final String ATTR_SCALE_TYPE = "scaleType"; //$NON-NLS-1$
- public static final String ATTR_VISIBILITY = "visibility"; //$NON-NLS-1$
- public static final String ATTR_TEXT_IS_SELECTABLE =
- "textIsSelectable"; //$NON-NLS-1$
- public static final String ATTR_IMPORTANT_FOR_ACCESSIBILITY =
- "importantForAccessibility"; //$NON-NLS-1$
-
- // AbsoluteLayout layout params
- public static final String ATTR_LAYOUT_Y = "layout_y"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_X = "layout_x"; //$NON-NLS-1$
-
- // GridLayout layout params
- public static final String ATTR_LAYOUT_ROW = "layout_row"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ROW_SPAN = "layout_rowSpan";//$NON-NLS-1$
- public static final String ATTR_LAYOUT_COLUMN = "layout_column"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_COLUMN_SPAN = "layout_columnSpan"; //$NON-NLS-1$
-
- // TableRow
- public static final String ATTR_LAYOUT_SPAN = "layout_span"; //$NON-NLS-1$
-
- // RelativeLayout layout params:
- public static final String ATTR_LAYOUT_ALIGN_LEFT = "layout_alignLeft"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_RIGHT = "layout_alignRight"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_TOP = "layout_alignTop"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_BOTTOM = "layout_alignBottom"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_PARENT_TOP = "layout_alignParentTop"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_PARENT_BOTTOM = "layout_alignParentBottom"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_PARENT_LEFT = "layout_alignParentLeft";//$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_PARENT_RIGHT = "layout_alignParentRight"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING = "layout_alignWithParentIfMissing"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ALIGN_BASELINE = "layout_alignBaseline"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_CENTER_IN_PARENT = "layout_centerInParent"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_CENTER_VERTICAL = "layout_centerVertical"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_CENTER_HORIZONTAL = "layout_centerHorizontal"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_TO_RIGHT_OF = "layout_toRightOf"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_TO_LEFT_OF = "layout_toLeftOf"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_BELOW = "layout_below"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_ABOVE = "layout_above"; //$NON-NLS-1$
-
- // Margins
- public static final String ATTR_LAYOUT_MARGIN = "layout_margin"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_MARGIN_LEFT = "layout_marginLeft"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_MARGIN_RIGHT = "layout_marginRight"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_MARGIN_TOP = "layout_marginTop"; //$NON-NLS-1$
- public static final String ATTR_LAYOUT_MARGIN_BOTTOM = "layout_marginBottom"; //$NON-NLS-1$
-
- // Attributes: Drawables
- public static final String ATTR_TILE_MODE = "tileMode"; //$NON-NLS-1$
-
- // Values: Layouts
- public static final String VALUE_FILL_PARENT = "fill_parent"; //$NON-NLS-1$
- public static final String VALUE_MATCH_PARENT = "match_parent"; //$NON-NLS-1$
- public static final String VALUE_VERTICAL = "vertical"; //$NON-NLS-1$
- public static final String VALUE_TRUE = "true"; //$NON-NLS-1$
- public static final String VALUE_EDITABLE = "editable"; //$NON-NLS-1$
- public static final String VALUE_AUTO_FIT = "auto_fit"; //$NON-NLS-1$
- public static final String VALUE_SELECTABLE_ITEM_BACKGROUND =
- "?android:attr/selectableItemBackground"; //$NON-NLS-1$
-
-
- // Values: Resources
- public static final String VALUE_ID = "id"; //$NON-NLS-1$
-
- // Values: Drawables
- public static final String VALUE_DISABLED = "disabled"; //$NON-NLS-1$
- public static final String VALUE_CLAMP = "clamp"; //$NON-NLS-1$
-
- // Menus
- public static final String ATTR_SHOW_AS_ACTION = "showAsAction"; //$NON-NLS-1$
- public static final String ATTR_TITLE = "title"; //$NON-NLS-1$
- public static final String ATTR_VISIBLE = "visible"; //$NON-NLS-1$
- public static final String VALUE_IF_ROOM = "ifRoom"; //$NON-NLS-1$
- public static final String VALUE_ALWAYS = "always"; //$NON-NLS-1$
-
- // Units
- public static final String UNIT_DP = "dp"; //$NON-NLS-1$
- public static final String UNIT_DIP = "dip"; //$NON-NLS-1$
- public static final String UNIT_SP = "sp"; //$NON-NLS-1$
- public static final String UNIT_PX = "px"; //$NON-NLS-1$
- public static final String UNIT_IN = "in"; //$NON-NLS-1$
- public static final String UNIT_MM = "mm"; //$NON-NLS-1$
- public static final String UNIT_PT = "pt"; //$NON-NLS-1$
-
- // Filenames and folder names
- public static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; //$NON-NLS-1$
- public static final String OLD_PROGUARD_FILE = "proguard.cfg"; //$NON-NLS-1$
- public static final String CLASS_FOLDER =
- "bin" + File.separator + "classes"; //$NON-NLS-1$ //$NON-NLS-2$
- public static final String GEN_FOLDER = "gen"; //$NON-NLS-1$
- public static final String SRC_FOLDER = "src"; //$NON-NLS-1$
- public static final String LIBS_FOLDER = "libs"; //$NON-NLS-1$
- public static final String BIN_FOLDER = "bin"; //$NON-NLS-1$
-
- public static final String RES_FOLDER = "res"; //$NON-NLS-1$
- public static final String DOT_XML = ".xml"; //$NON-NLS-1$
- public static final String DOT_GIF = ".gif"; //$NON-NLS-1$
- public static final String DOT_JPG = ".jpg"; //$NON-NLS-1$
- public static final String DOT_JPEG = ".jpeg"; //$NON-NLS-1$
- public static final String DOT_PNG = ".png"; //$NON-NLS-1$
- public static final String DOT_9PNG = ".9.png"; //$NON-NLS-1$
- public static final String DOT_JAVA = ".java"; //$NON-NLS-1$
- public static final String DOT_CLASS = ".class"; //$NON-NLS-1$
- public static final String DOT_JAR = ".jar"; //$NON-NLS-1$
-
-
- /** Extension of the Application package Files, i.e. "apk". */
- public static final String EXT_ANDROID_PACKAGE = "apk"; //$NON-NLS-1$
- /** Extension of java files, i.e. "java" */
- public static final String EXT_JAVA = "java"; //$NON-NLS-1$
- /** Extension of compiled java files, i.e. "class" */
- public static final String EXT_CLASS = "class"; //$NON-NLS-1$
- /** Extension of xml files, i.e. "xml" */
- public static final String EXT_XML = "xml"; //$NON-NLS-1$
- /** Extension of jar files, i.e. "jar" */
- public static final String EXT_JAR = "jar"; //$NON-NLS-1$
- /** Extension of aidl files, i.e. "aidl" */
- public static final String EXT_AIDL = "aidl"; //$NON-NLS-1$
- /** Extension of Renderscript files, i.e. "rs" */
- public static final String EXT_RS = "rs"; //$NON-NLS-1$
- /** Extension of FilterScript files, i.e. "fs" */
- public static final String EXT_FS = "fs"; //$NON-NLS-1$
- /** Extension of dependency files, i.e. "d" */
- public static final String EXT_DEP = "d"; //$NON-NLS-1$
- /** Extension of native libraries, i.e. "so" */
- public static final String EXT_NATIVE_LIB = "so"; //$NON-NLS-1$
- /** Extension of dex files, i.e. "dex" */
- public static final String EXT_DEX = "dex"; //$NON-NLS-1$
- /** Extension for temporary resource files, ie "ap_ */
- public static final String EXT_RES = "ap_"; //$NON-NLS-1$
- /** Extension for pre-processable images. Right now pngs */
- public static final String EXT_PNG = "png"; //$NON-NLS-1$
-
- private final static String DOT = "."; //$NON-NLS-1$
-
- /** Dot-Extension of the Application package Files, i.e. ".apk". */
- public static final String DOT_ANDROID_PACKAGE = DOT + EXT_ANDROID_PACKAGE;
- /** Dot-Extension of aidl files, i.e. ".aidl" */
- public static final String DOT_AIDL = DOT + EXT_AIDL;
- /** Dot-Extension of renderscript files, i.e. ".rs" */
- public static final String DOT_RS = DOT + EXT_RS;
- /** Dot-Extension of FilterScript files, i.e. ".fs" */
- public static final String DOT_FS = DOT + EXT_FS;
- /** Dot-Extension of dependency files, i.e. ".d" */
- public static final String DOT_DEP = DOT + EXT_DEP;
- /** Dot-Extension of dex files, i.e. ".dex" */
- public static final String DOT_DEX = DOT + EXT_DEX;
- /** Dot-Extension for temporary resource files, ie "ap_ */
- public static final String DOT_RES = DOT + EXT_RES;
- /** Dot-Extension for BMP files, i.e. ".bmp" */
- public static final String DOT_BMP = ".bmp"; //$NON-NLS-1$
- /** Dot-Extension for SVG files, i.e. ".svg" */
- public static final String DOT_SVG = ".svg"; //$NON-NLS-1$
- /** Dot-Extension for template files */
- public static final String DOT_FTL = ".ftl"; //$NON-NLS-1$
- /** Dot-Extension of text files, i.e. ".txt" */
- public static final String DOT_TXT = ".txt"; //$NON-NLS-1$
-
- /** Resource base name for java files and classes */
- public static final String FN_RESOURCE_BASE = "R"; //$NON-NLS-1$
- /** Resource java class filename, i.e. "R.java" */
- public static final String FN_RESOURCE_CLASS = FN_RESOURCE_BASE + DOT_JAVA;
- /** Resource class file filename, i.e. "R.class" */
- public static final String FN_COMPILED_RESOURCE_CLASS = FN_RESOURCE_BASE + DOT_CLASS;
- /** Resource text filename, i.e. "R.txt" */
- public static final String FN_RESOURCE_TEXT = FN_RESOURCE_BASE + DOT_TXT;
- /** Generated manifest class name */
- public static final String FN_MANIFEST_BASE = "Manifest"; //$NON-NLS-1$
- /** Generated BuildConfig class name */
- public static final String FN_BUILD_CONFIG_BASE = "BuildConfig"; //$NON-NLS-1$
- /** Manifest java class filename, i.e. "Manifest.java" */
- public static final String FN_MANIFEST_CLASS = FN_MANIFEST_BASE + DOT_JAVA;
- /** BuildConfig java class filename, i.e. "BuildConfig.java" */
- public static final String FN_BUILD_CONFIG = FN_BUILD_CONFIG_BASE + DOT_JAVA;
-
- public static final String DRAWABLE_FOLDER = "drawable"; //$NON-NLS-1$
- public static final String DRAWABLE_XHDPI = "drawable-xhdpi"; //$NON-NLS-1$
- public static final String DRAWABLE_HDPI = "drawable-hdpi"; //$NON-NLS-1$
- public static final String DRAWABLE_MDPI = "drawable-mdpi"; //$NON-NLS-1$
- public static final String DRAWABLE_LDPI = "drawable-ldpi"; //$NON-NLS-1$
-
- // Resources
- public static final String PREFIX_RESOURCE_REF = "@"; //$NON-NLS-1$
- public static final String PREFIX_THEME_REF = "?"; //$NON-NLS-1$
- public static final String ANDROID_PREFIX = "@android:"; //$NON-NLS-1$
- public static final String ANDROID_THEME_PREFIX = "?android:"; //$NON-NLS-1$
- public static final String LAYOUT_RESOURCE_PREFIX = "@layout/"; //$NON-NLS-1$
- public static final String STYLE_RESOURCE_PREFIX = "@style/"; //$NON-NLS-1$
- public static final String NEW_ID_PREFIX = "@+id/"; //$NON-NLS-1$
- public static final String ID_PREFIX = "@id/"; //$NON-NLS-1$
- public static final String DRAWABLE_PREFIX = "@drawable/"; //$NON-NLS-1$
- public static final String STRING_PREFIX = "@string/"; //$NON-NLS-1$
- public static final String ANDROID_STRING_PREFIX = "@android:string/"; //$NON-NLS-1$
- public static final String ANDROID_LAYOUT_RESOURCE_PREFIX = "@android:layout/"; //$NON-NLS-1$
-
- public static final String RESOURCE_CLZ_ID = "id"; //$NON-NLS-1$
- public static final String RESOURCE_CLZ_COLOR = "color"; //$NON-NLS-1$
- public static final String RESOURCE_CLZ_ARRAY = "array"; //$NON-NLS-1$
- public static final String RESOURCE_CLZ_ATTR = "attr"; //$NON-NLS-1$
- public static final String RESOURCE_CLR_STYLEABLE = "styleable"; //$NON-NLS-1$
- public static final String NULL_RESOURCE = "@null"; //$NON-NLS-1$
- public static final String TRANSPARENT_COLOR = "@android:color/transparent"; //$NON-NLS-1$
- public static final String ANDROID_STYLE_RESOURCE_PREFIX = "@android:style/"; //$NON-NLS-1$
- public static final String REFERENCE_STYLE = "style/"; //$NON-NLS-1$
- public static final String PREFIX_ANDROID = "android:"; //$NON-NLS-1$
-
- // Resource Types
- public static final String DRAWABLE_TYPE = "drawable"; //$NON-NLS-1$
- public static final String MENU_TYPE = "menu"; //$NON-NLS-1$
-
- // Packages
- public static final String ANDROID_PKG_PREFIX = "android."; //$NON-NLS-1$
- public static final String WIDGET_PKG_PREFIX = "android.widget."; //$NON-NLS-1$
- public static final String VIEW_PKG_PREFIX = "android.view."; //$NON-NLS-1$
-
- // Project properties
- public static final String ANDROID_LIBRARY = "android.library"; //$NON-NLS-1$
- public static final String PROGUARD_CONFIG = "proguard.config"; //$NON-NLS-1$
- public static final String ANDROID_LIBRARY_REFERENCE_FORMAT = "android.library.reference.%1$d";//$NON-NLS-1$
- public static final String PROJECT_PROPERTIES = "project.properties";//$NON-NLS-1$
-
- // Java References
- public static final String ATTR_REF_PREFIX = "?attr/"; //$NON-NLS-1$
- public static final String R_PREFIX = "R."; //$NON-NLS-1$
- public static final String R_ID_PREFIX = "R.id."; //$NON-NLS-1$
- public static final String R_LAYOUT_RESOURCE_PREFIX = "R.layout."; //$NON-NLS-1$
- public static final String R_DRAWABLE_PREFIX = "R.drawable."; //$NON-NLS-1$
- public static final String R_ATTR_PREFIX = "R.attr."; //$NON-NLS-1$
-
- // Attributes related to tools
- public static final String ATTR_IGNORE = "ignore"; //$NON-NLS-1$
- public static final String ATTR_LOCALE = "locale"; //$NON-NLS-1$
-
- // SuppressLint
- public static final String SUPPRESS_ALL = "all"; //$NON-NLS-1$
- public static final String SUPPRESS_LINT = "SuppressLint"; //$NON-NLS-1$
- public static final String TARGET_API = "TargetApi"; //$NON-NLS-1$
- public static final String ATTR_TARGET_API = "targetApi"; //$NON-NLS-1$
- public static final String FQCN_SUPPRESS_LINT = "android.annotation." + SUPPRESS_LINT; //$NON-NLS-1$
- public static final String FQCN_TARGET_API = "android.annotation." + TARGET_API; //$NON-NLS-1$
-
- // Class Names
- public static final String CONSTRUCTOR_NAME = "<init>"; //$NON-NLS-1$
- public static final String CLASS_CONSTRUCTOR = "<clinit>"; //$NON-NLS-1$
- public static final String FRAGMENT = "android/app/Fragment"; //$NON-NLS-1$
- public static final String FRAGMENT_V4 = "android/support/v4/app/Fragment"; //$NON-NLS-1$
- public static final String ANDROID_APP_ACTIVITY = "android/app/Activity"; //$NON-NLS-1$
- public static final String ANDROID_APP_SERVICE = "android/app/Service"; //$NON-NLS-1$
- public static final String ANDROID_CONTENT_CONTENT_PROVIDER =
- "android/content/ContentProvider"; //$NON-NLS-1$
- public static final String ANDROID_CONTENT_BROADCAST_RECEIVER =
- "android/content/BroadcastReceiver"; //$NON-NLS-1$
-
- // Method Names
- public static final String FORMAT_METHOD = "format"; //$NON-NLS-1$
- public static final String GET_STRING_METHOD = "getString"; //$NON-NLS-1$
-
-
-
-
- public static final String ATTR_TAG = "tag"; //$NON-NLS-1$
- public static final String ATTR_NUM_COLUMNS = "numColumns"; //$NON-NLS-1$
-
- // Some common layout element names
- public static final String CALENDAR_VIEW = "CalendarView"; //$NON-NLS-1$
- public static final String SPACE = "Space"; //$NON-NLS-1$
- public static final String GESTURE_OVERLAY_VIEW = "GestureOverlayView";//$NON-NLS-1$
-
- public static final String ATTR_HANDLE = "handle"; //$NON-NLS-1$
- public static final String ATTR_CONTENT = "content"; //$NON-NLS-1$
- public static final String ATTR_CHECKED = "checked"; //$NON-NLS-1$
-
- // TextView
- public static final String ATTR_DRAWABLE_RIGHT = "drawableRight"; //$NON-NLS-1$
- public static final String ATTR_DRAWABLE_LEFT = "drawableLeft"; //$NON-NLS-1$
- public static final String ATTR_DRAWABLE_BOTTOM = "drawableBottom"; //$NON-NLS-1$
- public static final String ATTR_DRAWABLE_TOP = "drawableTop"; //$NON-NLS-1$
- public static final String ATTR_DRAWABLE_PADDING = "drawablePadding"; //$NON-NLS-1$
-
- public static final String ATTR_USE_DEFAULT_MARGINS = "useDefaultMargins"; //$NON-NLS-1$
- public static final String ATTR_MARGINS_INCLUDED_IN_ALIGNMENT = "marginsIncludedInAlignment"; //$NON-NLS-1$
-
- public static final String VALUE_WRAP_CONTENT = "wrap_content"; //$NON-NLS-1$
- public static final String VALUE_FALSE= "false"; //$NON-NLS-1$
- public static final String VALUE_N_DP = "%ddp"; //$NON-NLS-1$
- public static final String VALUE_ZERO_DP = "0dp"; //$NON-NLS-1$
- public static final String VALUE_ONE_DP = "1dp"; //$NON-NLS-1$
- public static final String VALUE_TOP = "top"; //$NON-NLS-1$
- public static final String VALUE_LEFT = "left"; //$NON-NLS-1$
- public static final String VALUE_RIGHT = "right"; //$NON-NLS-1$
- public static final String VALUE_BOTTOM = "bottom"; //$NON-NLS-1$
- public static final String VALUE_CENTER_VERTICAL = "center_vertical"; //$NON-NLS-1$
- public static final String VALUE_CENTER_HORIZONTAL = "center_horizontal"; //$NON-NLS-1$
- public static final String VALUE_FILL_HORIZONTAL = "fill_horizontal"; //$NON-NLS-1$
- public static final String VALUE_FILL_VERTICAL = "fill_vertical"; //$NON-NLS-1$
- public static final String VALUE_0 = "0"; //$NON-NLS-1$
- public static final String VALUE_1 = "1"; //$NON-NLS-1$
-
- // Gravity values. These have the GRAVITY_ prefix in front of value because we already
- // have VALUE_CENTER_HORIZONTAL defined for layouts, and its definition conflicts
- // (centerHorizontal versus center_horizontal)
- public static final String GRAVITY_VALUE_ = "center"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_CENTER = "center"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_RIGHT = "right"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_LEFT = "left"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_BOTTOM = "bottom"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_TOP = "top"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_FILL_HORIZONTAL = "fill_horizontal"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_FILL_VERTICAL = "fill_vertical"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_CENTER_HORIZONTAL = "center_horizontal"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_CENTER_VERTICAL = "center_vertical"; //$NON-NLS-1$
- public static final String GRAVITY_VALUE_FILL = "fill"; //$NON-NLS-1$
-
- /**
- * The top level android package as a prefix, "android.".
- */
- public static final String ANDROID_SUPPORT_PKG_PREFIX = ANDROID_PKG_PREFIX + "support."; //$NON-NLS-1$
-
- /** The android.view. package prefix */
- public static final String ANDROID_VIEW_PKG = ANDROID_PKG_PREFIX + "view."; //$NON-NLS-1$
-
- /** The android.widget. package prefix */
- public static final String ANDROID_WIDGET_PREFIX = ANDROID_PKG_PREFIX + "widget."; //$NON-NLS-1$
-
- /** The android.webkit. package prefix */
- public static final String ANDROID_WEBKIT_PKG = ANDROID_PKG_PREFIX + "webkit."; //$NON-NLS-1$
-
- /** The LayoutParams inner-class name suffix, .LayoutParams */
- public static final String DOT_LAYOUT_PARAMS = ".LayoutParams"; //$NON-NLS-1$
-
- /** The fully qualified class name of an EditText view */
- public static final String FQCN_EDIT_TEXT = "android.widget.EditText"; //$NON-NLS-1$
-
- /** The fully qualified class name of a LinearLayout view */
- public static final String FQCN_LINEAR_LAYOUT = "android.widget.LinearLayout"; //$NON-NLS-1$
-
- /** The fully qualified class name of a RelativeLayout view */
- public static final String FQCN_RELATIVE_LAYOUT = "android.widget.RelativeLayout"; //$NON-NLS-1$
-
- /** The fully qualified class name of a RelativeLayout view */
- public static final String FQCN_GRID_LAYOUT = "android.widget.GridLayout"; //$NON-NLS-1$
- public static final String FQCN_GRID_LAYOUT_V7 = "android.support.v7.widget.GridLayout"; //$NON-NLS-1$
-
- /** The fully qualified class name of a FrameLayout view */
- public static final String FQCN_FRAME_LAYOUT = "android.widget.FrameLayout"; //$NON-NLS-1$
-
- /** The fully qualified class name of a TableRow view */
- public static final String FQCN_TABLE_ROW = "android.widget.TableRow"; //$NON-NLS-1$
-
- /** The fully qualified class name of a TableLayout view */
- public static final String FQCN_TABLE_LAYOUT = "android.widget.TableLayout"; //$NON-NLS-1$
-
- /** The fully qualified class name of a GridView view */
- public static final String FQCN_GRID_VIEW = "android.widget.GridView"; //$NON-NLS-1$
-
- /** The fully qualified class name of a TabWidget view */
- public static final String FQCN_TAB_WIDGET = "android.widget.TabWidget"; //$NON-NLS-1$
-
- /** The fully qualified class name of a Button view */
- public static final String FQCN_BUTTON = "android.widget.Button"; //$NON-NLS-1$
-
- /** The fully qualified class name of a RadioButton view */
- public static final String FQCN_RADIO_BUTTON = "android.widget.RadioButton"; //$NON-NLS-1$
-
- /** The fully qualified class name of a ToggleButton view */
- public static final String FQCN_TOGGLE_BUTTON = "android.widget.ToggleButton"; //$NON-NLS-1$
-
- /** The fully qualified class name of a Spinner view */
- public static final String FQCN_SPINNER = "android.widget.Spinner"; //$NON-NLS-1$
-
- /** The fully qualified class name of an AdapterView */
- public static final String FQCN_ADAPTER_VIEW = "android.widget.AdapterView"; //$NON-NLS-1$
-
- /** The fully qualified class name of a ListView */
- public static final String FQCN_LIST_VIEW = "android.widget.ListView"; //$NON-NLS-1$
-
- /** The fully qualified class name of an ExpandableListView */
- public static final String FQCN_EXPANDABLE_LIST_VIEW = "android.widget.ExpandableListView"; //$NON-NLS-1$
-
- /** The fully qualified class name of a GestureOverlayView */
- public static final String FQCN_GESTURE_OVERLAY_VIEW = "android.gesture.GestureOverlayView"; //$NON-NLS-1$
-
- /** The fully qualified class name of a DatePicker */
- public static final String FQCN_DATE_PICKER = "android.widget.DatePicker"; //$NON-NLS-1$
-
- /** The fully qualified class name of a TimePicker */
- public static final String FQCN_TIME_PICKER = "android.widget.TimePicker"; //$NON-NLS-1$
-
- /** The fully qualified class name of a RadioGroup */
- public static final String FQCN_RADIO_GROUP = "android.widgets.RadioGroup"; //$NON-NLS-1$
-
- /** The fully qualified class name of a Space */
- public static final String FQCN_SPACE = "android.widget.Space"; //$NON-NLS-1$
- public static final String FQCN_SPACE_V7 = "android.support.v7.widget.Space"; //$NON-NLS-1$
-
- /** The fully qualified class name of a TextView view */
- public static final String FQCN_TEXT_VIEW = "android.widget.TextView"; //$NON-NLS-1$
-
- /** The fully qualified class name of an ImageView view */
- public static final String FQCN_IMAGE_VIEW = "android.widget.ImageView"; //$NON-NLS-1$
-
- public static final String ATTR_SRC = "src"; //$NON-NLS-1$
-
- public static final String ATTR_GRAVITY = "gravity"; //$NON-NLS-1$
- public static final String ATTR_WEIGHT_SUM = "weightSum"; //$NON-NLS-1$
- public static final String ATTR_EMS = "ems"; //$NON-NLS-1$
-
- public static final String VALUE_HORIZONTAL = "horizontal"; //$NON-NLS-1$
-
- /**
- * The highest known API level. Note that the tools may also look at the
- * installed platforms to see if they can find more recently released
- * platforms, e.g. when the tools have not yet been updated for a new
- * release. This number is used as a baseline and any more recent platforms
- * found can be used to increase the highest known number.
- */
- public static final int HIGHEST_KNOWN_API = 17;
-}
diff --git a/common/src/main/java/com/android/annotations/NonNull.java b/common/src/main/java/com/android/annotations/NonNull.java
deleted file mode 100644
index 973ebb6..0000000
--- a/common/src/main/java/com/android/annotations/NonNull.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Denotes that a parameter, field or method return value can never be null.
- * <p/>
- * This is a marker annotation and it has no specific attributes.
- */
-@Documented
-@Retention(RetentionPolicy.CLASS)
-@Target({METHOD,PARAMETER,LOCAL_VARIABLE,FIELD})
-public @interface NonNull {
-}
diff --git a/common/src/main/java/com/android/annotations/NonNullByDefault.java b/common/src/main/java/com/android/annotations/NonNullByDefault.java
deleted file mode 100644
index 3db891c..0000000
--- a/common/src/main/java/com/android/annotations/NonNullByDefault.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.annotations;
-
-import static java.lang.annotation.ElementType.PACKAGE;
-import static java.lang.annotation.ElementType.TYPE;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Denotes that all parameters, fields or methods within a class or method by
- * default can not be null. This can be overridden by adding specific
- * {@link com.android.annotations.Nullable} annotations on fields, parameters or
- * methods that should not use the default.
- * <p/>
- * NOTE: Eclipse does not yet handle defaults well (in particular, if
- * you add this on a class which implements Comparable, then it will insist
- * that your compare method is changing the nullness of the compare parameter,
- * so you'll need to add @Nullable on it, which also is not right (since
- * the method should have implied @NonNull and you do not need to check
- * the parameter.). For now, it's best to individually annotate methods,
- * parameters and fields.
- * <p/>
- * This is a marker annotation and it has no specific attributes.
- */
-@Documented
-@Retention(RetentionPolicy.CLASS)
-@Target({PACKAGE, TYPE})
-public @interface NonNullByDefault {
-}
diff --git a/common/src/main/java/com/android/annotations/Nullable.java b/common/src/main/java/com/android/annotations/Nullable.java
deleted file mode 100755
index d9c3861..0000000
--- a/common/src/main/java/com/android/annotations/Nullable.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Denotes that a parameter, field or method return value can be null.
- * <b>Note</b>: this is the default assumption for most Java APIs and the
- * default assumption made by most static code checking tools, so usually you
- * don't need to use this annotation; its primary use is to override a default
- * wider annotation like {@link NonNullByDefault}.
- * <p/>
- * When decorating a method call parameter, this denotes the parameter can
- * legitimately be null and the method will gracefully deal with it. Typically
- * used on optional parameters.
- * <p/>
- * When decorating a method, this denotes the method might legitimately return
- * null.
- * <p/>
- * This is a marker annotation and it has no specific attributes.
- */
-@Documented
-@Retention(RetentionPolicy.CLASS)
-@Target({METHOD, PARAMETER, LOCAL_VARIABLE, FIELD})
-public @interface Nullable {
-}
diff --git a/common/src/main/java/com/android/annotations/VisibleForTesting.java b/common/src/main/java/com/android/annotations/VisibleForTesting.java
deleted file mode 100755
index 7f41d70..0000000
--- a/common/src/main/java/com/android/annotations/VisibleForTesting.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.annotations;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Denotes that the class, method or field has its visibility relaxed so
- * that unit tests can access it.
- * <p/>
- * The <code>visibility</code> argument can be used to specific what the original
- * visibility should have been if it had not been made public or package-private for testing.
- * The default is to consider the element private.
- */
-@Retention(RetentionPolicy.SOURCE)
-public @interface VisibleForTesting {
- /**
- * Intended visibility if the element had not been made public or package-private for
- * testing.
- */
- enum Visibility {
- /** The element should be considered protected. */
- PROTECTED,
- /** The element should be considered package-private. */
- PACKAGE,
- /** The element should be considered private. */
- PRIVATE
- }
-
- /**
- * Intended visibility if the element had not been made public or package-private for testing.
- * If not specified, one should assume the element originally intended to be private.
- */
- Visibility visibility() default Visibility.PRIVATE;
-}
diff --git a/common/src/main/java/com/android/io/FileWrapper.java b/common/src/main/java/com/android/io/FileWrapper.java
deleted file mode 100644
index 8be7859..0000000
--- a/common/src/main/java/com/android/io/FileWrapper.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-
-/**
- * An implementation of {@link IAbstractFile} extending {@link File}.
- */
-public class FileWrapper extends File implements IAbstractFile {
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates a new File instance matching a given {@link File} object.
- * @param file the file to match
- */
- public FileWrapper(File file) {
- super(file.getAbsolutePath());
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(File, String)
- */
- public FileWrapper(File parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given pathname string into an abstract
- * pathname.
- * @param osPathname the OS pathname
- *
- * @see File#File(String)
- */
- public FileWrapper(String osPathname) {
- super(osPathname);
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(String, String)
- */
- public FileWrapper(String parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given <code>file:</code> URI into an
- * abstract pathname.
- * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path
- * component, and undefined authority, query, and fragment components
- *
- * @see File#File(URI)
- */
- public FileWrapper(URI uri) {
- super(uri);
- }
-
- @Override
- public InputStream getContents() throws StreamException {
- try {
- return new FileInputStream(this);
- } catch (FileNotFoundException e) {
- throw new StreamException(e, this, StreamException.Error.FILENOTFOUND);
- }
- }
-
- @Override
- public void setContents(InputStream source) throws StreamException {
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(this);
-
- byte[] buffer = new byte[1024];
- int count = 0;
- while ((count = source.read(buffer)) != -1) {
- fos.write(buffer, 0, count);
- }
- } catch (IOException e) {
- throw new StreamException(e, this);
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- throw new StreamException(e, this);
- }
- }
- }
- }
-
- @Override
- public OutputStream getOutputStream() throws StreamException {
- try {
- return new FileOutputStream(this);
- } catch (FileNotFoundException e) {
- throw new StreamException(e, this);
- }
- }
-
- @Override
- public PreferredWriteMode getPreferredWriteMode() {
- return PreferredWriteMode.OUTPUTSTREAM;
- }
-
- @Override
- public String getOsLocation() {
- return getAbsolutePath();
- }
-
- @Override
- public boolean exists() {
- return isFile();
- }
-
- @Override
- public long getModificationStamp() {
- return lastModified();
- }
-
- @Override
- public IAbstractFolder getParentFolder() {
- String p = this.getParent();
- if (p == null) {
- return null;
- }
- return new FolderWrapper(p);
- }
-}
diff --git a/common/src/main/java/com/android/io/FolderWrapper.java b/common/src/main/java/com/android/io/FolderWrapper.java
deleted file mode 100644
index c29c934..0000000
--- a/common/src/main/java/com/android/io/FolderWrapper.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-
-import java.io.File;
-import java.net.URI;
-import java.util.ArrayList;
-
-/**
- * An implementation of {@link IAbstractFolder} extending {@link File}.
- */
-public class FolderWrapper extends File implements IAbstractFolder {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(File, String)
- */
- public FolderWrapper(File parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given pathname string into an abstract
- * pathname.
- * @param pathname the pathname
- *
- * @see File#File(String)
- */
- public FolderWrapper(String pathname) {
- super(pathname);
- }
-
- /**
- * Creates a new File instance from a parent abstract pathname and a child pathname string.
- * @param parent the parent pathname
- * @param child the child name
- *
- * @see File#File(String, String)
- */
- public FolderWrapper(String parent, String child) {
- super(parent, child);
- }
-
- /**
- * Creates a new File instance by converting the given <code>file:</code> URI into an
- * abstract pathname.
- * @param uri An absolute, hierarchical URI with a scheme equal to "file", a non-empty path
- * component, and undefined authority, query, and fragment components
- *
- * @see File#File(URI)
- */
- public FolderWrapper(URI uri) {
- super(uri);
- }
-
- /**
- * Creates a new File instance matching a give {@link File} object.
- * @param file the file to match
- */
- public FolderWrapper(File file) {
- super(file.getAbsolutePath());
- }
-
- @Override
- public IAbstractResource[] listMembers() {
- File[] files = listFiles();
- final int count = files == null ? 0 : files.length;
- IAbstractResource[] afiles = new IAbstractResource[count];
-
- if (files != null) {
- for (int i = 0 ; i < count ; i++) {
- File f = files[i];
- if (f.isFile()) {
- afiles[i] = new FileWrapper(f);
- } else if (f.isDirectory()) {
- afiles[i] = new FolderWrapper(f);
- }
- }
- }
-
- return afiles;
- }
-
- @Override
- public boolean hasFile(final String name) {
- String[] match = list(new FilenameFilter() {
- @Override
- public boolean accept(IAbstractFolder dir, String filename) {
- return name.equals(filename);
- }
- });
-
- return match.length > 0;
- }
-
- @Override
- public IAbstractFile getFile(String name) {
- return new FileWrapper(this, name);
- }
-
- @Override
- public IAbstractFolder getFolder(String name) {
- return new FolderWrapper(this, name);
- }
-
- @Override
- public IAbstractFolder getParentFolder() {
- String p = this.getParent();
- if (p == null) {
- return null;
- }
- return new FolderWrapper(p);
- }
-
- @Override
- public String getOsLocation() {
- return getAbsolutePath();
- }
-
- @Override
- public boolean exists() {
- return isDirectory();
- }
-
- @Override
- public String[] list(FilenameFilter filter) {
- File[] files = listFiles();
- if (files != null && files.length > 0) {
- ArrayList<String> list = new ArrayList<String>();
-
- for (File file : files) {
- if (filter.accept(this, file.getName())) {
- list.add(file.getName());
- }
- }
-
- return list.toArray(new String[list.size()]);
- }
-
- return new String[0];
- }
-}
diff --git a/common/src/main/java/com/android/io/IAbstractFile.java b/common/src/main/java/com/android/io/IAbstractFile.java
deleted file mode 100644
index 6dfc8d8..0000000
--- a/common/src/main/java/com/android/io/IAbstractFile.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A file.
- */
-public interface IAbstractFile extends IAbstractResource {
- public static enum PreferredWriteMode {
- INPUTSTREAM, OUTPUTSTREAM;
- }
-
- /**
- * Returns an {@link InputStream} object on the file content.
- * @throws StreamException
- */
- InputStream getContents() throws StreamException;
-
- /**
- * Sets the content of the file.
- * @param source the content
- * @throws StreamException
- */
- void setContents(InputStream source) throws StreamException;
-
- /**
- * Returns an {@link OutputStream} to write into the file.
- * @throws StreamException
- */
- OutputStream getOutputStream() throws StreamException;
-
- /**
- * Returns the preferred mode to write into the file.
- */
- PreferredWriteMode getPreferredWriteMode();
-
- /**
- * Returns the last modification timestamp
- */
- long getModificationStamp();
-}
diff --git a/common/src/main/java/com/android/io/IAbstractFolder.java b/common/src/main/java/com/android/io/IAbstractFolder.java
deleted file mode 100644
index 8335ef9..0000000
--- a/common/src/main/java/com/android/io/IAbstractFolder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-import java.io.File;
-
-/**
- * A folder.
- */
-public interface IAbstractFolder extends IAbstractResource {
- /**
- * Instances of classes that implement this interface are used to
- * filter filenames.
- */
- public interface FilenameFilter {
- /**
- * Tests if a specified file should be included in a file list.
- *
- * @param dir the directory in which the file was found.
- * @param name the name of the file.
- * @return <code>true</code> if and only if the name should be
- * included in the file list; <code>false</code> otherwise.
- */
- boolean accept(IAbstractFolder dir, String name);
- }
-
- /**
- * Returns true if the receiver contains a file with a given name
- * @param name the name of the file. This is the name without the path leading to the
- * parent folder.
- */
- boolean hasFile(String name);
-
- /**
- * Returns an {@link IAbstractFile} representing a child of the current folder with the
- * given name. The file may not actually exist.
- * @param name the name of the file.
- */
- IAbstractFile getFile(String name);
-
- /**
- * Returns an {@link IAbstractFolder} representing a child of the current folder with the
- * given name. The folder may not actually exist.
- * @param name the name of the folder.
- */
- IAbstractFolder getFolder(String name);
-
- /**
- * Returns a list of all existing file and directory members in this folder.
- * The returned array can be empty but is never null.
- */
- IAbstractResource[] listMembers();
-
- /**
- * Returns a list of all existing file and directory members in this folder
- * that satisfy the specified filter.
- *
- * @param filter A filename filter instance. Must not be null.
- * @return An array of file names (generated using {@link File#getName()}).
- * The array can be empty but is never null.
- */
- String[] list(FilenameFilter filter);
-}
diff --git a/common/src/main/java/com/android/io/IAbstractResource.java b/common/src/main/java/com/android/io/IAbstractResource.java
deleted file mode 100644
index e6358ec..0000000
--- a/common/src/main/java/com/android/io/IAbstractResource.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-/**
- * Base representation of a file system resource.<p/>
- * This somewhat limited interface is designed to let classes use file-system resources, without
- * having the manually handle either the standard Java file or the Eclipse file API..
- */
-public interface IAbstractResource {
-
- /**
- * Returns the name of the resource.
- */
- String getName();
-
- /**
- * Returns the OS path of the folder location.
- */
- String getOsLocation();
-
- /**
- * Returns whether the resource actually exists.
- */
- boolean exists();
-
- /**
- * Returns the parent folder or null if there is no parent.
- */
- IAbstractFolder getParentFolder();
-
- /**
- * Deletes the resource.
- */
- boolean delete();
-}
diff --git a/common/src/main/java/com/android/io/StreamException.java b/common/src/main/java/com/android/io/StreamException.java
deleted file mode 100644
index 9f632f4..0000000
--- a/common/src/main/java/com/android/io/StreamException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.io;
-
-
-/**
- * Exception thrown when {@link IAbstractFile#getContents()} fails.
- */
-public class StreamException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public static enum Error {
- DEFAULT, OUTOFSYNC, FILENOTFOUND;
- }
-
- private final Error mError;
- private final IAbstractFile mFile;
-
- public StreamException(Exception e, IAbstractFile file) {
- this(e, file, Error.DEFAULT);
- }
-
- public StreamException(Exception e, IAbstractFile file, Error error) {
- super(e);
- mFile = file;
- mError = error;
- }
-
- public Error getError() {
- return mError;
- }
-
- public IAbstractFile getFile() {
- return mFile;
- }
-}
diff --git a/common/src/main/java/com/android/prefs/AndroidLocation.java b/common/src/main/java/com/android/prefs/AndroidLocation.java
deleted file mode 100644
index 6af8e9b..0000000
--- a/common/src/main/java/com/android/prefs/AndroidLocation.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.prefs;
-
-import com.android.annotations.NonNull;
-
-import java.io.File;
-
-/**
- * Manages the location of the android files (including emulator files, ddms config, debug keystore)
- */
-public final class AndroidLocation {
-
- /**
- * The name of the .android folder returned by {@link #getFolder()}.
- */
- public static final String FOLDER_DOT_ANDROID = ".android";
-
- /**
- * Virtual Device folder inside the path returned by {@link #getFolder()}
- */
- public static final String FOLDER_AVD = "avd";
-
- /**
- * Throw when the location of the android folder couldn't be found.
- */
- public static final class AndroidLocationException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public AndroidLocationException(String string) {
- super(string);
- }
- }
-
- private static String sPrefsLocation = null;
-
- /**
- * Returns the folder used to store android related files.
- * @return an OS specific path, terminated by a separator.
- * @throws AndroidLocationException
- */
- @NonNull public final static String getFolder() throws AndroidLocationException {
- if (sPrefsLocation == null) {
- String home = findValidPath("ANDROID_SDK_HOME", "user.home", "HOME");
-
- // if the above failed, we throw an exception.
- if (home == null) {
- throw new AndroidLocationException(
- "Unable to get the Android SDK home directory.\n" +
- "Make sure the environment variable ANDROID_SDK_HOME is set up.");
- } else {
- sPrefsLocation = home;
- if (!sPrefsLocation.endsWith(File.separator)) {
- sPrefsLocation += File.separator;
- }
- sPrefsLocation += FOLDER_DOT_ANDROID + File.separator;
- }
- }
-
- // make sure the folder exists!
- File f = new File(sPrefsLocation);
- if (f.exists() == false) {
- try {
- f.mkdir();
- } catch (SecurityException e) {
- AndroidLocationException e2 = new AndroidLocationException(String.format(
- "Unable to create folder '%1$s'. " +
- "This is the path of preference folder expected by the Android tools.",
- sPrefsLocation));
- e2.initCause(e);
- throw e2;
- }
- } else if (f.isFile()) {
- throw new AndroidLocationException(sPrefsLocation +
- " is not a directory! " +
- "This is the path of preference folder expected by the Android tools.");
- }
-
- return sPrefsLocation;
- }
-
- /**
- * Resets the folder used to store android related files. For testing.
- */
- public final static void resetFolder() {
- sPrefsLocation = null;
- }
-
- /**
- * Checks a list of system properties and/or system environment variables for validity, and
- * existing director, and returns the first one.
- * @param names
- * @return the content of the first property/variable.
- */
- private static String findValidPath(String... names) {
- for (String name : names) {
- String path;
- if (name.indexOf('.') != -1) {
- path = System.getProperty(name);
- } else {
- path = System.getenv(name);
- }
-
- if (path != null) {
- File f = new File(path);
- if (f.isDirectory()) {
- return path;
- }
- }
- }
-
- return null;
- }
-}
diff --git a/common/src/main/java/com/android/utils/ILogger.java b/common/src/main/java/com/android/utils/ILogger.java
deleted file mode 100644
index 7df5d10..0000000
--- a/common/src/main/java/com/android/utils/ILogger.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.annotations.NonNull;
-
-import java.util.Formatter;
-
-/**
- * Interface used to display warnings/errors while parsing the SDK content.
- * <p/>
- * There are a few default implementations available:
- * <ul>
- * <li> {@link NullLogger} is an implementation that does <em>nothing</em> with the log.
- * Useful for limited cases where you need to call a class that requires a non-null logging
- * yet the calling code does not have any mean of reporting logs itself. It can be
- * acceptable for use as a temporary implementation but most of the time that means the caller
- * code needs to be reworked to take a logger object from its own caller.
- * </li>
- * <li> {@link StdLogger} is an implementation that dumps the log to {@link System#out} or
- * {@link System#err}. This is useful for unit tests or code that does not have any GUI.
- * GUI based apps based should not use it and should provide a better way to report to the user.
- * </li>
- * </ul>
- */
-public interface ILogger {
-
- /**
- * Prints an error message.
- *
- * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, its
- * message will be printed out.
- * @param msgFormat is an optional error format. If non-null, it will be printed
- * using a {@link Formatter} with the provided arguments.
- * @param args provides the arguments for errorFormat.
- */
- void error(Throwable t, String msgFormat, Object... args);
-
- /**
- * Prints a warning message.
- *
- * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for warningFormat.
- */
- void warning(@NonNull String msgFormat, Object... args);
-
- /**
- * Prints an information message.
- *
- * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for msgFormat.
- */
- void info(@NonNull String msgFormat, Object... args);
-
- /**
- * Prints a verbose message.
- *
- * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for msgFormat.
- */
- void verbose(@NonNull String msgFormat, Object... args);
-
-}
diff --git a/common/src/main/java/com/android/utils/NullLogger.java b/common/src/main/java/com/android/utils/NullLogger.java
deleted file mode 100644
index 8b1a3d9..0000000
--- a/common/src/main/java/com/android/utils/NullLogger.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.annotations.NonNull;
-
-/**
- * Dummy implementation of an {@link ILogger}.
- * <p/>
- * Use {@link #getLogger()} to get a default instance of this {@link NullLogger}.
- */
-public class NullLogger implements ILogger {
-
- private static final ILogger sThis = new NullLogger();
-
- public static ILogger getLogger() {
- return sThis;
- }
-
- @Override
- public void error(Throwable t, String errorFormat, Object... args) {
- // ignore
- }
-
- @Override
- public void warning(@NonNull String warningFormat, Object... args) {
- // ignore
- }
-
- @Override
- public void info(@NonNull String msgFormat, Object... args) {
- // ignore
- }
-
- @Override
- public void verbose(@NonNull String msgFormat, Object... args) {
- // ignore
- }
-
-}
diff --git a/common/src/main/java/com/android/utils/Pair.java b/common/src/main/java/com/android/utils/Pair.java
deleted file mode 100644
index 63694de..0000000
--- a/common/src/main/java/com/android/utils/Pair.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-/**
- * A Pair class is simply a 2-tuple for use in this package. We might want to
- * think about adding something like this to a more central utility place, or
- * replace it by a common tuple class if one exists, or even rewrite the layout
- * classes using this Pair by a more dedicated data structure (so we don't have
- * to pass around generic signatures as is currently done, though at least the
- * construction is helped a bit by the {@link #of} factory method.
- *
- * @param <S> The type of the first value
- * @param <T> The type of the second value
- */
-public class Pair<S,T> {
- private final S mFirst;
- private final T mSecond;
-
- // Use {@link Pair#of} factory instead since it infers generic types
- private Pair(S first, T second) {
- this.mFirst = first;
- this.mSecond = second;
- }
-
- /**
- * Return the first item in the pair
- *
- * @return the first item in the pair
- */
- public S getFirst() {
- return mFirst;
- }
-
- /**
- * Return the second item in the pair
- *
- * @return the second item in the pair
- */
- public T getSecond() {
- return mSecond;
- }
-
- /**
- * Constructs a new pair of the given two objects, inferring generic types.
- *
- * @param first the first item to store in the pair
- * @param second the second item to store in the pair
- * @param <S> the type of the first item
- * @param <T> the type of the second item
- * @return a new pair wrapping the two items
- */
- public static <S,T> Pair<S,T> of(S first, T second) {
- return new Pair<S,T>(first,second);
- }
-
- @Override
- public String toString() {
- return "Pair [first=" + mFirst + ", second=" + mSecond + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode());
- result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode());
- return result;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Pair other = (Pair) obj;
- if (mFirst == null) {
- if (other.mFirst != null)
- return false;
- } else if (!mFirst.equals(other.mFirst))
- return false;
- if (mSecond == null) {
- if (other.mSecond != null)
- return false;
- } else if (!mSecond.equals(other.mSecond))
- return false;
- return true;
- }
-}
diff --git a/common/src/main/java/com/android/utils/PositionXmlParser.java b/common/src/main/java/com/android/utils/PositionXmlParser.java
deleted file mode 100644
index 73574d5..0000000
--- a/common/src/main/java/com/android/utils/PositionXmlParser.java
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.Text;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * A simple DOM XML parser which can retrieve exact beginning and end offsets
- * (and line and column numbers) for element nodes as well as attribute nodes.
- */
-public class PositionXmlParser {
- private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
- private static final String UTF_16 = "UTF_16"; //$NON-NLS-1$
- private static final String UTF_16LE = "UTF_16LE"; //$NON-NLS-1$
- private static final String CONTENT_KEY = "contents"; //$NON-NLS-1$
- private final static String POS_KEY = "offsets"; //$NON-NLS-1$
- private static final String NAMESPACE_PREFIX_FEATURE =
- "http://xml.org/sax/features/namespace-prefixes"; //$NON-NLS-1$
- private static final String NAMESPACE_FEATURE =
- "http://xml.org/sax/features/namespaces"; //$NON-NLS-1$
- /** See http://www.w3.org/TR/REC-xml/#NT-EncodingDecl */
- private static final Pattern ENCODING_PATTERN =
- Pattern.compile("encoding=['\"](\\S*)['\"]");//$NON-NLS-1$
-
- /**
- * Parses the XML content from the given input stream.
- *
- * @param input the input stream containing the XML to be parsed
- * @return the corresponding document
- * @throws ParserConfigurationException if a SAX parser is not available
- * @throws SAXException if the document contains a parsing error
- * @throws IOException if something is seriously wrong. This should not
- * happen since the input source is known to be constructed from
- * a string.
- */
- @Nullable
- public Document parse(@NonNull InputStream input)
- throws ParserConfigurationException, SAXException, IOException {
- // Read in all the data
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buf = new byte[1024];
- while (true) {
- int r = input.read(buf);
- if (r == -1) {
- break;
- }
- out.write(buf, 0, r);
- }
- input.close();
- return parse(out.toByteArray());
- }
-
- /**
- * Parses the XML content from the given byte array
- *
- * @param data the raw XML data (with unknown encoding)
- * @return the corresponding document
- * @throws ParserConfigurationException if a SAX parser is not available
- * @throws SAXException if the document contains a parsing error
- * @throws IOException if something is seriously wrong. This should not
- * happen since the input source is known to be constructed from
- * a string.
- */
- @Nullable
- public Document parse(@NonNull byte[] data)
- throws ParserConfigurationException, SAXException, IOException {
- String xml = getXmlString(data);
- return parse(xml, new InputSource(new StringReader(xml)), true);
- }
-
- /**
- * Parses the given XML content.
- *
- * @param xml the XML string to be parsed. This must be in the correct
- * encoding already.
- * @return the corresponding document
- * @throws ParserConfigurationException if a SAX parser is not available
- * @throws SAXException if the document contains a parsing error
- * @throws IOException if something is seriously wrong. This should not
- * happen since the input source is known to be constructed from
- * a string.
- */
- @Nullable
- public Document parse(@NonNull String xml)
- throws ParserConfigurationException, SAXException, IOException {
- return parse(xml, new InputSource(new StringReader(xml)), true);
- }
-
- @NonNull
- private Document parse(@NonNull String xml, @NonNull InputSource input, boolean checkBom)
- throws ParserConfigurationException, SAXException, IOException {
- try {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setFeature(NAMESPACE_FEATURE, true);
- factory.setFeature(NAMESPACE_PREFIX_FEATURE, true);
- SAXParser parser = factory.newSAXParser();
- DomBuilder handler = new DomBuilder(xml);
- parser.parse(input, handler);
- return handler.getDocument();
- } catch (SAXException e) {
- if (checkBom && e.getMessage().contains("Content is not allowed in prolog")) {
- // Byte order mark in the string? Skip it. There are many markers
- // (see http://en.wikipedia.org/wiki/Byte_order_mark) so here we'll
- // just skip those up to the XML prolog beginning character, <
- xml = xml.replaceFirst("^([\\W]+)<","<"); //$NON-NLS-1$ //$NON-NLS-2$
- return parse(xml, new InputSource(new StringReader(xml)), false);
- }
- throw e;
- }
- }
-
- /**
- * Returns the String corresponding to the given byte array of XML data
- * (with unknown encoding). This method attempts to guess the encoding based
- * on the XML prologue.
- * @param data the XML data to be decoded into a string
- * @return a string corresponding to the XML data
- */
- public static String getXmlString(byte[] data) {
- int offset = 0;
-
- String defaultCharset = UTF_8;
- String charset = null;
- // Look for the byte order mark, to see if we need to remove bytes from
- // the input stream (and to determine whether files are big endian or little endian) etc
- // for files which do not specify the encoding.
- // See http://unicode.org/faq/utf_bom.html#BOM for more.
- if (data.length > 4) {
- if (data[0] == (byte)0xef && data[1] == (byte)0xbb && data[2] == (byte)0xbf) {
- // UTF-8
- defaultCharset = charset = UTF_8;
- offset += 3;
- } else if (data[0] == (byte)0xfe && data[1] == (byte)0xff) {
- // UTF-16, big-endian
- defaultCharset = charset = UTF_16;
- offset += 2;
- } else if (data[0] == (byte)0x0 && data[1] == (byte)0x0
- && data[2] == (byte)0xfe && data[3] == (byte)0xff) {
- // UTF-32, big-endian
- defaultCharset = charset = "UTF_32"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe
- && data[2] == (byte)0x0 && data[3] == (byte)0x0) {
- // UTF-32, little-endian. We must check for this *before* looking for
- // UTF_16LE since UTF_32LE has the same prefix!
- defaultCharset = charset = "UTF_32LE"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe) {
- // UTF-16, little-endian
- defaultCharset = charset = UTF_16LE;
- offset += 2;
- }
- }
- int length = data.length - offset;
-
- // Guess encoding by searching for an encoding= entry in the first line.
- // The prologue, and the encoding names, will always be in ASCII - which means
- // we don't need to worry about strange character encodings for the prologue characters.
- // However, one wrinkle is that the whole file may be encoded in something like UTF-16
- // where there are two bytes per character, so we can't just look for
- // ['e','n','c','o','d','i','n','g'] etc in the byte array since there could be
- // multiple bytes for each character. However, since again the prologue is in ASCII,
- // we can just drop the zeroes.
- boolean seenOddZero = false;
- boolean seenEvenZero = false;
- int prologueStart = -1;
- for (int lineEnd = offset; lineEnd < data.length; lineEnd++) {
- if (data[lineEnd] == 0) {
- if ((lineEnd - offset) % 2 == 0) {
- seenEvenZero = true;
- } else {
- seenOddZero = true;
- }
- } else if (data[lineEnd] == '\n' || data[lineEnd] == '\r') {
- break;
- } else if (data[lineEnd] == '<') {
- prologueStart = lineEnd;
- } else if (data[lineEnd] == '>') {
- // End of prologue. Quick check to see if this is a utf-8 file since that's
- // common
- for (int i = lineEnd - 4; i >= 0; i--) {
- if ((data[i] == 'u' || data[i] == 'U')
- && (data[i + 1] == 't' || data[i + 1] == 'T')
- && (data[i + 2] == 'f' || data[i + 2] == 'F')
- && (data[i + 3] == '-' || data[i + 3] == '_')
- && (data[i + 4] == '8')
- ) {
- charset = UTF_8;
- break;
- }
- }
-
- if (charset == null) {
- StringBuilder sb = new StringBuilder();
- for (int i = prologueStart; i <= lineEnd; i++) {
- if (data[i] != 0) {
- sb.append((char) data[i]);
- }
- }
- String prologue = sb.toString();
- int encodingIndex = prologue.indexOf("encoding"); //$NON-NLS-1$
- if (encodingIndex != -1) {
- Matcher matcher = ENCODING_PATTERN.matcher(prologue);
- if (matcher.find(encodingIndex)) {
- charset = matcher.group(1);
- }
- }
- }
-
- break;
- }
- }
-
- // No prologue on the first line, and no byte order mark: Assume UTF-8/16
- if (charset == null) {
- charset = seenOddZero ? UTF_16LE : seenEvenZero ? UTF_16 : UTF_8;
- }
-
- String xml = null;
- try {
- xml = new String(data, offset, length, charset);
- } catch (UnsupportedEncodingException e) {
- try {
- if (charset != defaultCharset) {
- xml = new String(data, offset, length, defaultCharset);
- }
- } catch (UnsupportedEncodingException u) {
- // Just use the default encoding below
- }
- }
- if (xml == null) {
- xml = new String(data, offset, length);
- }
- return xml;
- }
-
- /**
- * Returns the position for the given node. This is the start position. The
- * end position can be obtained via {@link Position#getEnd()}.
- *
- * @param node the node to look up position for
- * @return the position, or null if the node type is not supported for
- * position info
- */
- @Nullable
- public Position getPosition(@NonNull Node node) {
- return getPosition(node, -1, -1);
- }
-
- /**
- * Returns the position for the given node. This is the start position. The
- * end position can be obtained via {@link Position#getEnd()}. A specific
- * range within the node can be specified with the {@code start} and
- * {@code end} parameters.
- *
- * @param node the node to look up position for
- * @param start the relative offset within the node range to use as the
- * starting position, inclusive, or -1 to not limit the range
- * @param end the relative offset within the node range to use as the ending
- * position, or -1 to not limit the range
- * @return the position, or null if the node type is not supported for
- * position info
- */
- @Nullable
- public Position getPosition(@NonNull Node node, int start, int end) {
- // Look up the position information stored while parsing for the given node.
- // Note however that we only store position information for elements (because
- // there is no SAX callback for individual attributes).
- // Therefore, this method special cases this:
- // -- First, it looks at the owner element and uses its position
- // information as a first approximation.
- // -- Second, it uses that, as well as the original XML text, to search
- // within the node range for an exact text match on the attribute name
- // and if found uses that as the exact node offsets instead.
- if (node instanceof Attr) {
- Attr attr = (Attr) node;
- Position pos = (Position) attr.getOwnerElement().getUserData(POS_KEY);
- if (pos != null) {
- int startOffset = pos.getOffset();
- int endOffset = pos.getEnd().getOffset();
- if (start != -1) {
- startOffset += start;
- if (end != -1) {
- endOffset = start + end;
- }
- }
-
- // Find attribute in the text
- String contents = (String) node.getOwnerDocument().getUserData(CONTENT_KEY);
- if (contents == null) {
- return null;
- }
-
- // Locate the name=value attribute in the source text
- // Fast string check first for the common occurrence
- String name = attr.getName();
- Pattern pattern = Pattern.compile(
- String.format("%1$s\\s*=\\s*[\"'].*[\"']", name)); //$NON-NLS-1$
- Matcher matcher = pattern.matcher(contents);
- if (matcher.find(startOffset) && matcher.start() <= endOffset) {
- int index = matcher.start();
- // Adjust the line and column to this new offset
- int line = pos.getLine();
- int column = pos.getColumn();
- for (int offset = pos.getOffset(); offset < index; offset++) {
- char t = contents.charAt(offset);
- if (t == '\n') {
- line++;
- column = 0;
- } else {
- column++;
- }
- }
-
- Position attributePosition = createPosition(line, column, index);
- // Also set end range for retrieval in getLocation
- attributePosition.setEnd(createPosition(line, column + matcher.end() - index,
- matcher.end()));
- return attributePosition;
- } else {
- // No regexp match either: just fall back to element position
- return pos;
- }
- }
- } else if (node instanceof Text) {
- // Position of parent element, if any
- Position pos = null;
- if (node.getPreviousSibling() != null) {
- pos = (Position) node.getPreviousSibling().getUserData(POS_KEY);
- }
- if (pos == null) {
- pos = (Position) node.getParentNode().getUserData(POS_KEY);
- }
- if (pos != null) {
- // Attempt to point forward to the actual text node
- int startOffset = pos.getOffset();
- int endOffset = pos.getEnd().getOffset();
- int line = pos.getLine();
- int column = pos.getColumn();
-
- // Find attribute in the text
- String contents = (String) node.getOwnerDocument().getUserData(CONTENT_KEY);
- if (contents == null || contents.length() < endOffset) {
- return null;
- }
-
- boolean inAttribute = false;
- for (int offset = startOffset; offset <= endOffset; offset++) {
- char c = contents.charAt(offset);
- if (c == '>' && !inAttribute) {
- // Found the end of the element open tag: this is where the
- // text begins.
-
- // Skip >
- offset++;
- column++;
-
- String text = node.getNodeValue();
- int textIndex = 0;
- int textLength = text.length();
- int newLine = line;
- int newColumn = column;
- if (start != -1) {
- textLength = Math.min(textLength, start);
- for (; textIndex < textLength; textIndex++) {
- char t = text.charAt(textIndex);
- if (t == '\n') {
- newLine++;
- newColumn = 0;
- } else {
- newColumn++;
- }
- }
- } else {
- // Skip text whitespace prefix, if the text node contains
- // non-whitespace characters
- for (; textIndex < textLength; textIndex++) {
- char t = text.charAt(textIndex);
- if (t == '\n') {
- newLine++;
- newColumn = 0;
- } else if (!Character.isWhitespace(t)) {
- break;
- } else {
- newColumn++;
- }
- }
- }
- if (textIndex == text.length()) {
- textIndex = 0; // Whitespace node
- } else {
- line = newLine;
- column = newColumn;
- }
-
- Position attributePosition = createPosition(line, column,
- offset + textIndex);
- // Also set end range for retrieval in getLocation
- if (end != -1) {
- attributePosition.setEnd(createPosition(line, column,
- offset + end));
- } else {
- attributePosition.setEnd(createPosition(line, column,
- offset + textLength));
- }
- return attributePosition;
- } else if (c == '"') {
- inAttribute = !inAttribute;
- } else if (c == '\n') {
- line++;
- column = -1; // pre-subtract column added below
- }
- column++;
- }
-
- return pos;
- }
- }
-
- return (Position) node.getUserData(POS_KEY);
- }
-
- /**
- * SAX parser handler which incrementally builds up a DOM document as we go
- * along, and updates position information along the way. Position
- * information is attached to the DOM nodes by setting user data with the
- * {@link POS_KEY} key.
- */
- private final class DomBuilder extends DefaultHandler {
- private final String mXml;
- private final Document mDocument;
- private Locator mLocator;
- private int mCurrentLine = 0;
- private int mCurrentOffset;
- private int mCurrentColumn;
- private final List<Element> mStack = new ArrayList<Element>();
- private final StringBuilder mPendingText = new StringBuilder();
-
- private DomBuilder(String xml) throws ParserConfigurationException {
- mXml = xml;
-
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setValidating(false);
- DocumentBuilder docBuilder = factory.newDocumentBuilder();
- mDocument = docBuilder.newDocument();
- mDocument.setUserData(CONTENT_KEY, xml, null);
- }
-
- /** Returns the document parsed by the handler */
- Document getDocument() {
- return mDocument;
- }
-
- @Override
- public void setDocumentLocator(Locator locator) {
- this.mLocator = locator;
- }
-
- @Override
- public void startElement(String uri, String localName, String qName,
- Attributes attributes) throws SAXException {
- try {
- flushText();
- Element element = mDocument.createElement(qName);
- for (int i = 0; i < attributes.getLength(); i++) {
- if (attributes.getURI(i) != null && attributes.getURI(i).length() > 0) {
- Attr attr = mDocument.createAttributeNS(attributes.getURI(i),
- attributes.getQName(i));
- attr.setValue(attributes.getValue(i));
- element.setAttributeNodeNS(attr);
- assert attr.getOwnerElement() == element;
- } else {
- Attr attr = mDocument.createAttribute(attributes.getQName(i));
- attr.setValue(attributes.getValue(i));
- element.setAttributeNode(attr);
- assert attr.getOwnerElement() == element;
- }
- }
-
- Position pos = getCurrentPosition();
-
- // The starting position reported to us by SAX is really the END of the
- // open tag in an element, when all the attributes have been processed.
- // We have to scan backwards to find the real beginning. We'll do that
- // by scanning backwards.
- // -1: Make sure that when we have <foo></foo> we don't consider </foo>
- // the beginning since pos.offset will typically point to the first character
- // AFTER the element open tag, which could be a closing tag or a child open
- // tag
-
- for (int offset = pos.getOffset() - 1; offset >= 0; offset--) {
- char c = mXml.charAt(offset);
- // < cannot appear in attribute values or anywhere else within
- // an element open tag, so we know the first occurrence is the real
- // element start
- if (c == '<') {
- // Adjust line position
- int line = pos.getLine();
- for (int i = offset, n = pos.getOffset(); i < n; i++) {
- if (mXml.charAt(i) == '\n') {
- line--;
- }
- }
-
- // Compute new column position
- int column = 0;
- for (int i = offset - 1; i >= 0; i--, column++) {
- if (mXml.charAt(i) == '\n') {
- break;
- }
- }
-
- pos = createPosition(line, column, offset);
- break;
- }
- }
-
- element.setUserData(POS_KEY, pos, null);
- mStack.add(element);
- } catch (Exception t) {
- throw new SAXException(t);
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) {
- flushText();
- Element element = mStack.remove(mStack.size() - 1);
-
- Position pos = (Position) element.getUserData(POS_KEY);
- assert pos != null;
- pos.setEnd(getCurrentPosition());
-
- if (mStack.isEmpty()) {
- mDocument.appendChild(element);
- } else {
- Element parent = mStack.get(mStack.size() - 1);
- parent.appendChild(element);
- }
- }
-
- /**
- * Returns a position holder for the current position. The most
- * important part of this function is to incrementally compute the
- * offset as well, by counting forwards until it reaches the new line
- * number and column position of the XML parser, counting characters as
- * it goes along.
- */
- private Position getCurrentPosition() {
- int line = mLocator.getLineNumber() - 1;
- int column = mLocator.getColumnNumber() - 1;
-
- // Compute offset incrementally now that we have the new line and column
- // numbers
- int xmlLength = mXml.length();
- while (mCurrentLine < line && mCurrentOffset < xmlLength) {
- char c = mXml.charAt(mCurrentOffset);
- if (c == '\r' && mCurrentOffset < xmlLength - 1) {
- if (mXml.charAt(mCurrentOffset + 1) != '\n') {
- mCurrentLine++;
- mCurrentColumn = 0;
- }
- } else if (c == '\n') {
- mCurrentLine++;
- mCurrentColumn = 0;
- } else {
- mCurrentColumn++;
- }
- mCurrentOffset++;
- }
-
- mCurrentOffset += column - mCurrentColumn;
- if (mCurrentOffset >= xmlLength) {
- // The parser sometimes passes wrong column numbers at the
- // end of the file: Ensure that the offset remains valid.
- mCurrentOffset = xmlLength;
- }
- mCurrentColumn = column;
-
- return createPosition(mCurrentLine, mCurrentColumn, mCurrentOffset);
- }
-
- @Override
- public void characters(char c[], int start, int length) throws SAXException {
- mPendingText.append(c, start, length);
- }
-
- private void flushText() {
- if (mPendingText.length() > 0 && !mStack.isEmpty()) {
- Element element = mStack.get(mStack.size() - 1);
- Node textNode = mDocument.createTextNode(mPendingText.toString());
- element.appendChild(textNode);
- mPendingText.setLength(0);
- }
- }
- }
-
- /**
- * Creates a position while constructing the DOM document. This method
- * allows a subclass to create a custom implementation of the position
- * class.
- *
- * @param line the line number for the position
- * @param column the column number for the position
- * @param offset the character offset
- * @return a new position
- */
- @NonNull
- protected Position createPosition(int line, int column, int offset) {
- return new DefaultPosition(line, column, offset);
- }
-
- protected interface Position {
- /**
- * Linked position: for a begin position this will point to the
- * corresponding end position. For an end position this will be null.
- *
- * @return the end position, or null
- */
- @Nullable
- public Position getEnd();
-
- /**
- * Linked position: for a begin position this will point to the
- * corresponding end position. For an end position this will be null.
- *
- * @param end the end position
- */
- public void setEnd(@NonNull Position end);
-
- /** @return the line number, 0-based */
- public int getLine();
-
- /** @return the offset number, 0-based */
- public int getOffset();
-
- /** @return the column number, 0-based, and -1 if the column number if not known */
- public int getColumn();
- }
-
- protected static class DefaultPosition implements Position {
- /** The line number (0-based where the first line is line 0) */
- private final int mLine;
- private final int mColumn;
- private final int mOffset;
- private Position mEnd;
-
- /**
- * Creates a new {@link Position}
- *
- * @param line the 0-based line number, or -1 if unknown
- * @param column the 0-based column number, or -1 if unknown
- * @param offset the offset, or -1 if unknown
- */
- public DefaultPosition(int line, int column, int offset) {
- this.mLine = line;
- this.mColumn = column;
- this.mOffset = offset;
- }
-
- @Override
- public int getLine() {
- return mLine;
- }
-
- @Override
- public int getOffset() {
- return mOffset;
- }
-
- @Override
- public int getColumn() {
- return mColumn;
- }
-
- @Override
- public Position getEnd() {
- return mEnd;
- }
-
- @Override
- public void setEnd(@NonNull Position end) {
- mEnd = end;
- }
- }
-}
diff --git a/common/src/main/java/com/android/utils/SdkUtils.java b/common/src/main/java/com/android/utils/SdkUtils.java
deleted file mode 100644
index 160f95d..0000000
--- a/common/src/main/java/com/android/utils/SdkUtils.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-
-/** Miscellaneous utilities used by the Android SDK tools */
-public class SdkUtils {
- /**
- * Returns true if the given string ends with the given suffix, using a
- * case-insensitive comparison.
- *
- * @param string the full string to be checked
- * @param suffix the suffix to be checked for
- * @return true if the string case-insensitively ends with the given suffix
- */
- public static boolean endsWithIgnoreCase(String string, String suffix) {
- return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
- suffix, 0, suffix.length());
- }
-
- /**
- * Returns true if the given sequence ends with the given suffix (case
- * sensitive).
- *
- * @param sequence the character sequence to be checked
- * @param suffix the suffix to look for
- * @return true if the given sequence ends with the given suffix
- */
- public static boolean endsWith(CharSequence sequence, CharSequence suffix) {
- return endsWith(sequence, sequence.length(), suffix);
- }
-
- /**
- * Returns true if the given sequence ends at the given offset with the given suffix (case
- * sensitive)
- *
- * @param sequence the character sequence to be checked
- * @param endOffset the offset at which the sequence is considered to end
- * @param suffix the suffix to look for
- * @return true if the given sequence ends with the given suffix
- */
- public static boolean endsWith(CharSequence sequence, int endOffset, CharSequence suffix) {
- if (endOffset < suffix.length()) {
- return false;
- }
-
- for (int i = endOffset - 1, j = suffix.length() - 1; j >= 0; i--, j--) {
- if (sequence.charAt(i) != suffix.charAt(j)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns true if the given string starts with the given prefix, using a
- * case-insensitive comparison.
- *
- * @param string the full string to be checked
- * @param prefix the prefix to be checked for
- * @return true if the string case-insensitively starts with the given prefix
- */
- public static boolean startsWithIgnoreCase(String string, String prefix) {
- return string.regionMatches(true /* ignoreCase */, 0, prefix, 0, prefix.length());
- }
-
- /**
- * Returns true if the given string starts at the given offset with the
- * given prefix, case insensitively.
- *
- * @param string the full string to be checked
- * @param offset the offset in the string to start looking
- * @param prefix the prefix to be checked for
- * @return true if the string case-insensitively starts at the given offset
- * with the given prefix
- */
- public static boolean startsWith(String string, int offset, String prefix) {
- return string.regionMatches(true /* ignoreCase */, offset, prefix, 0, prefix.length());
- }
-
- /**
- * Strips the whitespace from the given string
- *
- * @param string the string to be cleaned up
- * @return the string, without whitespace
- */
- public static String stripWhitespace(String string) {
- StringBuilder sb = new StringBuilder(string.length());
- for (int i = 0, n = string.length(); i < n; i++) {
- char c = string.charAt(i);
- if (!Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Returns true if the given string has an upper case character.
- *
- * @param s the string to check
- * @return true if it contains uppercase characters
- */
- public static boolean hasUpperCaseCharacter(String s) {
- for (int i = 0; i < s.length(); i++) {
- if (Character.isUpperCase(s.charAt(i))) {
- return true;
- }
- }
-
- return false;
- }
-
- /** For use by {@link #getLineSeparator()} */
- private static String sLineSeparator;
-
- /**
- * Returns the default line separator to use.
- * <p>
- * NOTE: If you have an associated IDocument (Eclipse), it is better to call
- * TextUtilities#getDefaultLineDelimiter(IDocument) since that will
- * allow (for example) editing a \r\n-delimited document on a \n-delimited
- * platform and keep a consistent usage of delimiters in the file.
- *
- * @return the delimiter string to use
- */
- @NonNull
- public static String getLineSeparator() {
- if (sLineSeparator == null) {
- // This is guaranteed to exist:
- sLineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
- }
-
- return sLineSeparator;
- }
-
- /**
- * Wraps the given text at the given line width, with an optional hanging
- * indent.
- *
- * @param text the text to be wrapped
- * @param lineWidth the number of characters to wrap the text to
- * @param hangingIndent the hanging indent (to be used for the second and
- * subsequent lines in each paragraph, or null if not known
- * @return the string, wrapped
- */
- @NonNull
- public static String wrap(
- @NonNull String text,
- int lineWidth,
- @Nullable String hangingIndent) {
- if (hangingIndent == null) {
- hangingIndent = "";
- }
- int explanationLength = text.length();
- StringBuilder sb = new StringBuilder(explanationLength * 2);
- int index = 0;
-
- while (index < explanationLength) {
- int lineEnd = text.indexOf('\n', index);
- int next;
-
- if (lineEnd != -1 && (lineEnd - index) < lineWidth) {
- next = lineEnd + 1;
- } else {
- // Line is longer than available width; grab as much as we can
- lineEnd = Math.min(index + lineWidth, explanationLength);
- if (lineEnd - index < lineWidth) {
- next = explanationLength;
- } else {
- // then back up to the last space
- int lastSpace = text.lastIndexOf(' ', lineEnd);
- if (lastSpace > index) {
- lineEnd = lastSpace;
- next = lastSpace + 1;
- } else {
- // No space anywhere on the line: it contains something wider than
- // can fit (like a long URL) so just hard break it
- next = lineEnd + 1;
- }
- }
- }
-
- if (sb.length() > 0) {
- sb.append(hangingIndent);
- } else {
- lineWidth -= hangingIndent.length();
- }
-
- sb.append(text.substring(index, lineEnd));
- sb.append('\n');
- index = next;
- }
-
- return sb.toString();
- }
-
-}
diff --git a/common/src/main/java/com/android/utils/StdLogger.java b/common/src/main/java/com/android/utils/StdLogger.java
deleted file mode 100644
index 05eb456..0000000
--- a/common/src/main/java/com/android/utils/StdLogger.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-
-import java.io.PrintStream;
-import java.util.Formatter;
-
-
-/**
- * An implementation of {@link ILogger} that prints to {@link System#out} and {@link System#err}.
- * <p/>
- *
- */
-public class StdLogger implements ILogger {
-
- private final Level mLevel;
-
- public enum Level {
- VERBOSE(0),
- INFO(1),
- WARNING(2),
- ERROR(3);
-
- private final int mLevel;
-
- Level(int level) {
- mLevel = level;
- }
- }
-
- /**
- * Creates the {@link StdLogger} with a given log {@link Level}.
- * @param level the log Level.
- */
- public StdLogger(@NonNull Level level) {
- if (level == null) {
- throw new IllegalArgumentException("level cannot be null");
- }
-
- mLevel = level;
- }
-
- /**
- * Returns the logger's log {@link Level}.
- * @return the log level.
- */
- public Level getLevel() {
- return mLevel;
- }
-
- /**
- * Prints an error message.
- * <p/>
- * The message will be tagged with "Error" on the output so the caller does not
- * need to put such a prefix in the format string.
- * <p/>
- * The output is done on {@link System#err}.
- * <p/>
- * This is always displayed, independent of the logging {@link Level}.
- *
- * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's
- * message will be printed out.
- * @param errorFormat is an optional error format. If non-null, it will be printed
- * using a {@link Formatter} with the provided arguments.
- * @param args provides the arguments for errorFormat.
- */
- @Override
- public void error(Throwable t, String errorFormat, Object... args) {
- if (errorFormat != null) {
- String msg = String.format("Error: " + errorFormat, args);
-
- printMessage(msg, System.err);
- }
- if (t != null) {
- System.err.println(String.format("Error: %1$s", t.getMessage()));
- }
- }
-
- /**
- * Prints a warning message.
- * <p/>
- * The message will be tagged with "Warning" on the output so the caller does not
- * need to put such a prefix in the format string.
- * <p/>
- * The output is done on {@link System#out}.
- * <p/>
- * This is displayed only if the logging {@link Level} is {@link Level#WARNING} or higher.
- *
- * @param warningFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for warningFormat.
- */
- @Override
- public void warning(@NonNull String warningFormat, Object... args) {
- if (mLevel.mLevel > Level.WARNING.mLevel) {
- return;
- }
-
- String msg = String.format("Warning: " + warningFormat, args);
-
- printMessage(msg, System.out);
- }
-
- /**
- * Prints an info message.
- * <p/>
- * The output is done on {@link System#out}.
- * <p/>
- * This is displayed only if the logging {@link Level} is {@link Level#INFO} or higher.
- *
- * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for msgFormat.
- */
- @Override
- public void info(@NonNull String msgFormat, Object... args) {
- if (mLevel.mLevel > Level.INFO.mLevel) {
- return;
- }
-
- String msg = String.format(msgFormat, args);
-
- printMessage(msg, System.out);
- }
-
- /**
- * Prints a verbose message.
- * <p/>
- * The output is done on {@link System#out}.
- * <p/>
- * This is displayed only if the logging {@link Level} is {@link Level#VERBOSE} or higher.
- *
- * @param msgFormat is a string format to be used with a {@link Formatter}. Cannot be null.
- * @param args provides the arguments for msgFormat.
- */
- @Override
- public void verbose(@NonNull String msgFormat, Object... args) {
- if (mLevel.mLevel > Level.VERBOSE.mLevel) {
- return;
- }
-
- String msg = String.format(msgFormat, args);
-
- printMessage(msg, System.out);
- }
-
- private void printMessage(String msg, PrintStream stream) {
- if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS &&
- !msg.endsWith("\r\n") &&
- msg.endsWith("\n")) {
- // remove last \n so that println can use \r\n as needed.
- msg = msg.substring(0, msg.length() - 1);
- }
-
- stream.print(msg);
-
- if (!msg.endsWith("\n")) {
- stream.println();
- }
- }
-
-}
diff --git a/common/src/main/java/com/android/utils/XmlUtils.java b/common/src/main/java/com/android/utils/XmlUtils.java
deleted file mode 100644
index c77baee..0000000
--- a/common/src/main/java/com/android/utils/XmlUtils.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import static com.android.SdkConstants.AMP_ENTITY;
-import static com.android.SdkConstants.ANDROID_NS_NAME;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.APOS_ENTITY;
-import static com.android.SdkConstants.APP_PREFIX;
-import static com.android.SdkConstants.LT_ENTITY;
-import static com.android.SdkConstants.QUOT_ENTITY;
-import static com.android.SdkConstants.XMLNS;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-import static com.android.SdkConstants.XMLNS_URI;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.base.Splitter;
-
-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;
-import org.w3c.dom.NodeList;
-
-import java.util.HashSet;
-
-/** XML Utilities */
-public class XmlUtils {
- /**
- * Returns the namespace prefix matching the requested namespace URI.
- * If no such declaration is found, returns the default "android" prefix for
- * the Android URI, and "app" for other URI's. By default the app namespace
- * will be created. If this is not desirable, call
- * {@link #lookupNamespacePrefix(Node, String, boolean)} instead.
- *
- * @param node The current node. Must not be null.
- * @param nsUri The namespace URI of which the prefix is to be found,
- * e.g. {@link SdkConstants#ANDROID_URI}
- * @return The first prefix declared or the default "android" prefix
- * (or "app" for non-Android URIs)
- */
- @NonNull
- public static String lookupNamespacePrefix(@NonNull Node node, @NonNull String nsUri) {
- String defaultPrefix = ANDROID_URI.equals(nsUri) ? ANDROID_NS_NAME : APP_PREFIX;
- return lookupNamespacePrefix(node, nsUri, defaultPrefix, true /*create*/);
- }
-
- /**
- * Returns the namespace prefix matching the requested namespace URI. If no
- * such declaration is found, returns the default "android" prefix for the
- * Android URI, and "app" for other URI's.
- *
- * @param node The current node. Must not be null.
- * @param nsUri The namespace URI of which the prefix is to be found, e.g.
- * {@link SdkConstants#ANDROID_URI}
- * @param create whether the namespace declaration should be created, if
- * necessary
- * @return The first prefix declared or the default "android" prefix (or
- * "app" for non-Android URIs)
- */
- @NonNull
- public static String lookupNamespacePrefix(@NonNull Node node, @NonNull String nsUri,
- boolean create) {
- String defaultPrefix = ANDROID_URI.equals(nsUri) ? ANDROID_NS_NAME : APP_PREFIX;
- return lookupNamespacePrefix(node, nsUri, defaultPrefix, create);
- }
-
- /**
- * Returns the namespace prefix matching the requested namespace URI. If no
- * such declaration is found, returns the default "android" prefix.
- *
- * @param node The current node. Must not be null.
- * @param nsUri The namespace URI of which the prefix is to be found, e.g.
- * {@link SdkConstants#ANDROID_URI}
- * @param defaultPrefix The default prefix (root) to use if the namespace is
- * not found. If null, do not create a new namespace if this URI
- * is not defined for the document.
- * @param create whether the namespace declaration should be created, if
- * necessary
- * @return The first prefix declared or the provided prefix (possibly with a
- * number appended to avoid conflicts with existing prefixes.
- */
- public static String lookupNamespacePrefix(
- @Nullable Node node, @Nullable String nsUri, @Nullable String defaultPrefix,
- boolean create) {
- // Note: Node.lookupPrefix is not implemented in wst/xml/core NodeImpl.java
- // The following code emulates this simple call:
- // String prefix = node.lookupPrefix(NS_RESOURCES);
-
- // if the requested URI is null, it denotes an attribute with no namespace.
- if (nsUri == null) {
- return null;
- }
-
- // per XML specification, the "xmlns" URI is reserved
- if (XMLNS_URI.equals(nsUri)) {
- return XMLNS;
- }
-
- HashSet<String> visited = new HashSet<String>();
- Document doc = node == null ? null : node.getOwnerDocument();
-
- // Ask the document about it. This method may not be implemented by the Document.
- String nsPrefix = null;
- try {
- nsPrefix = doc != null ? doc.lookupPrefix(nsUri) : null;
- if (nsPrefix != null) {
- return nsPrefix;
- }
- } catch (Throwable t) {
- // ignore
- }
-
- // If that failed, try to look it up manually.
- // This also gathers prefixed in use in the case we want to generate a new one below.
- for (; node != null && node.getNodeType() == Node.ELEMENT_NODE;
- node = node.getParentNode()) {
- NamedNodeMap attrs = node.getAttributes();
- for (int n = attrs.getLength() - 1; n >= 0; --n) {
- Node attr = attrs.item(n);
- if (XMLNS.equals(attr.getPrefix())) {
- String uri = attr.getNodeValue();
- nsPrefix = attr.getLocalName();
- // Is this the URI we are looking for? If yes, we found its prefix.
- if (nsUri.equals(uri)) {
- return nsPrefix;
- }
- visited.add(nsPrefix);
- }
- }
- }
-
- // Failed the find a prefix. Generate a new sensible default prefix, unless
- // defaultPrefix was null in which case the caller does not want the document
- // modified.
- if (defaultPrefix == null) {
- return null;
- }
-
- //
- // We need to make sure the prefix is not one that was declared in the scope
- // visited above. Pick a unique prefix from the provided default prefix.
- String prefix = defaultPrefix;
- String base = prefix;
- for (int i = 1; visited.contains(prefix); i++) {
- prefix = base + Integer.toString(i);
- }
- // Also create & define this prefix/URI in the XML document as an attribute in the
- // first element of the document.
- if (doc != null) {
- node = doc.getFirstChild();
- while (node != null && node.getNodeType() != Node.ELEMENT_NODE) {
- node = node.getNextSibling();
- }
- if (node != null && create) {
- // This doesn't work:
- //Attr attr = doc.createAttributeNS(XMLNS_URI, prefix);
- //attr.setPrefix(XMLNS);
- //
- // Xerces throws
- //org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or
- // change an object in a way which is incorrect with regard to namespaces.
- //
- // Instead pass in the concatenated prefix. (This is covered by
- // the UiElementNodeTest#testCreateNameSpace() test.)
- Attr attr = doc.createAttributeNS(XMLNS_URI, XMLNS_PREFIX + prefix);
- attr.setValue(nsUri);
- node.getAttributes().setNamedItemNS(attr);
- }
- }
-
- return prefix;
- }
-
- /**
- * Converts the given attribute value to an XML-attribute-safe value, meaning that
- * single and double quotes are replaced with their corresponding XML entities.
- *
- * @param attrValue the value to be escaped
- * @return the escaped value
- */
- @NonNull
- public static String toXmlAttributeValue(@NonNull String attrValue) {
- for (int i = 0, n = attrValue.length(); i < n; i++) {
- char c = attrValue.charAt(i);
- if (c == '"' || c == '\'' || c == '<' || c == '&') {
- StringBuilder sb = new StringBuilder(2 * attrValue.length());
- appendXmlAttributeValue(sb, attrValue);
- return sb.toString();
- }
- }
-
- return attrValue;
- }
-
- /**
- * Converts the given attribute value to an XML-text-safe value, meaning that
- * less than and ampersand characters are escaped.
- *
- * @param textValue the text value to be escaped
- * @return the escaped value
- */
- @NonNull
- public static String toXmlTextValue(@NonNull String textValue) {
- for (int i = 0, n = textValue.length(); i < n; i++) {
- char c = textValue.charAt(i);
- if (c == '<' || c == '&') {
- StringBuilder sb = new StringBuilder(2 * textValue.length());
- appendXmlTextValue(sb, textValue);
- return sb.toString();
- }
- }
-
- return textValue;
- }
-
- /**
- * Appends text to the given {@link StringBuilder} and escapes it as required for a
- * DOM attribute node.
- *
- * @param sb the string builder
- * @param attrValue the attribute value to be appended and escaped
- */
- public static void appendXmlAttributeValue(@NonNull StringBuilder sb,
- @NonNull String attrValue) {
- int n = attrValue.length();
- // &, ", ' and < are illegal in attributes; see http://www.w3.org/TR/REC-xml/#NT-AttValue
- // (' legal in a " string and " is legal in a ' string but here we'll stay on the safe
- // side)
- for (int i = 0; i < n; i++) {
- char c = attrValue.charAt(i);
- if (c == '"') {
- sb.append(QUOT_ENTITY);
- } else if (c == '<') {
- sb.append(LT_ENTITY);
- } else if (c == '\'') {
- sb.append(APOS_ENTITY);
- } else if (c == '&') {
- sb.append(AMP_ENTITY);
- } else {
- sb.append(c);
- }
- }
- }
-
- /**
- * Appends text to the given {@link StringBuilder} and escapes it as required for a
- * DOM text node.
- *
- * @param sb the string builder
- * @param textValue the text value to be appended and escaped
- */
- public static void appendXmlTextValue(@NonNull StringBuilder sb, @NonNull String textValue) {
- for (int i = 0, n = textValue.length(); i < n; i++) {
- char c = textValue.charAt(i);
- if (c == '<') {
- sb.append(LT_ENTITY);
- } else if (c == '&') {
- sb.append(AMP_ENTITY);
- } else {
- sb.append(c);
- }
- }
- }
-
- /**
- * Dump an XML tree to string. This isn't going to do a beautiful job pretty
- * printing the XML; it's intended mostly for non-user editable files and
- * for debugging. If true, preserve whitespace exactly as in the DOM
- * document (typically used for a DOM which is already formatted), otherwise
- * this method will insert some newlines here and there (for example, one
- * per element and one per attribute.)
- *
- * @param node the node (which can be a document, an element, a text node,
- * etc.
- * @param preserveWhitespace whether to preserve the whitespace (text nodes)
- * in the DOM
- * @return a string version of the file
- */
- public static String toXml(Node node, boolean preserveWhitespace) {
- StringBuilder sb = new StringBuilder(1000);
-
- append(sb, node, 0, preserveWhitespace);
-
- return sb.toString();
- }
-
- private static void indent(StringBuilder sb, int indent) {
- for (int i = 0; i < indent; i++) {
- sb.append(" ");
- }
- }
-
- private static void append(
- @NonNull StringBuilder sb,
- @NonNull Node node,
- int indent,
- boolean preserveWhitespace) {
- short nodeType = node.getNodeType();
- switch (nodeType) {
- case Node.DOCUMENT_NODE:
- case Node.DOCUMENT_FRAGMENT_NODE: {
- sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
- NodeList children = node.getChildNodes();
- for (int i = 0, n = children.getLength(); i < n; i++) {
- append(sb, children.item(i), indent, preserveWhitespace);
- }
- break;
- }
- case Node.COMMENT_NODE:
- case Node.TEXT_NODE: {
- if (nodeType == Node.COMMENT_NODE) {
- if (!preserveWhitespace) {
- indent(sb, indent);
- }
- sb.append("<!--"); //$NON-NLS-1$
- if (!preserveWhitespace) {
- sb.append('\n');
- }
- }
- String text = node.getNodeValue();
- if (!preserveWhitespace) {
- text = text.trim();
- for (String line : Splitter.on('\n').split(text)) {
- indent(sb, indent + 1);
- sb.append(toXmlTextValue(line));
- sb.append('\n');
- }
- } else {
- sb.append(toXmlTextValue(text));
- }
- if (nodeType == Node.COMMENT_NODE) {
- if (!preserveWhitespace) {
- indent(sb, indent);
- }
- sb.append("-->"); //$NON-NLS-1$
- if (!preserveWhitespace) {
- sb.append('\n');
- }
- }
- break;
- }
- case Node.ELEMENT_NODE: {
- if (!preserveWhitespace) {
- indent(sb, indent);
- }
- sb.append('<');
- Element element = (Element) node;
- sb.append(element.getTagName());
-
- NamedNodeMap attributes = element.getAttributes();
- NodeList children = element.getChildNodes();
- int childCount = children.getLength();
- int attributeCount = attributes.getLength();
-
- if (attributeCount > 0) {
- for (int i = 0; i < attributeCount; i++) {
- Node attribute = attributes.item(i);
- sb.append(' ');
- sb.append(attribute.getNodeName());
- sb.append('=').append('"');
- sb.append(toXmlAttributeValue(attribute.getNodeValue()));
- sb.append('"');
- }
- }
-
- if (childCount == 0) {
- sb.append('/');
- }
- sb.append('>');
- if (!preserveWhitespace) {
- sb.append('\n');
- }
- if (childCount > 0) {
- for (int i = 0; i < childCount; i++) {
- Node child = children.item(i);
- append(sb, child, indent + 1, preserveWhitespace);
- }
- if (!preserveWhitespace) {
- if (sb.charAt(sb.length() - 1) != '\n') {
- sb.append('\n');
- }
- indent(sb, indent);
- }
- sb.append('<').append('/');
- sb.append(element.getTagName());
- sb.append('>');
- if (!preserveWhitespace) {
- sb.append('\n');
- }
- }
- break;
- }
-
- default:
- throw new UnsupportedOperationException(
- "Unsupported node type " + nodeType + ": not yet implemented");
- }
- }
-} \ No newline at end of file
diff --git a/common/src/main/java/com/android/xml/AndroidManifest.java b/common/src/main/java/com/android/xml/AndroidManifest.java
deleted file mode 100644
index 306471e..0000000
--- a/common/src/main/java/com/android/xml/AndroidManifest.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.SdkConstants;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.io.StreamException;
-
-import org.w3c.dom.Node;
-import org.xml.sax.InputSource;
-
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-
-/**
- * Helper and Constants for the AndroidManifest.xml file.
- *
- */
-public final class AndroidManifest {
-
- public static final String NODE_MANIFEST = "manifest";
- public static final String NODE_APPLICATION = "application";
- public static final String NODE_ACTIVITY = "activity";
- public static final String NODE_ACTIVITY_ALIAS = "activity-alias";
- public static final String NODE_SERVICE = "service";
- public static final String NODE_RECEIVER = "receiver";
- public static final String NODE_PROVIDER = "provider";
- public static final String NODE_INTENT = "intent-filter";
- public static final String NODE_ACTION = "action";
- public static final String NODE_CATEGORY = "category";
- public static final String NODE_USES_SDK = "uses-sdk";
- public static final String NODE_INSTRUMENTATION = "instrumentation";
- public static final String NODE_USES_LIBRARY = "uses-library";
- public static final String NODE_SUPPORTS_SCREENS = "supports-screens";
- public static final String NODE_USES_CONFIGURATION = "uses-configuration";
- public static final String NODE_USES_FEATURE = "uses-feature";
-
- public static final String ATTRIBUTE_PACKAGE = "package";
- public static final String ATTRIBUTE_VERSIONCODE = "versionCode";
- public static final String ATTRIBUTE_NAME = "name";
- public static final String ATTRIBUTE_REQUIRED = "required";
- public static final String ATTRIBUTE_GLESVERSION = "glEsVersion";
- public static final String ATTRIBUTE_PROCESS = "process";
- public static final String ATTRIBUTE_DEBUGGABLE = "debuggable";
- public static final String ATTRIBUTE_LABEL = "label";
- public static final String ATTRIBUTE_ICON = "icon";
- public static final String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion";
- public static final String ATTRIBUTE_TARGET_SDK_VERSION = "targetSdkVersion";
- public static final String ATTRIBUTE_TARGET_PACKAGE = "targetPackage";
- public static final String ATTRIBUTE_TARGET_ACTIVITY = "targetActivity";
- public static final String ATTRIBUTE_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity";
- public static final String ATTRIBUTE_EXPORTED = "exported";
- public static final String ATTRIBUTE_RESIZEABLE = "resizeable";
- public static final String ATTRIBUTE_ANYDENSITY = "anyDensity";
- public static final String ATTRIBUTE_SMALLSCREENS = "smallScreens";
- public static final String ATTRIBUTE_NORMALSCREENS = "normalScreens";
- public static final String ATTRIBUTE_LARGESCREENS = "largeScreens";
- public static final String ATTRIBUTE_REQ_5WAYNAV = "reqFiveWayNav";
- public static final String ATTRIBUTE_REQ_NAVIGATION = "reqNavigation";
- public static final String ATTRIBUTE_REQ_HARDKEYBOARD = "reqHardKeyboard";
- public static final String ATTRIBUTE_REQ_KEYBOARDTYPE = "reqKeyboardType";
- public static final String ATTRIBUTE_REQ_TOUCHSCREEN = "reqTouchScreen";
- public static final String ATTRIBUTE_THEME = "theme";
- public static final String ATTRIBUTE_BACKUP_AGENT = "backupAgent";
- public static final String ATTRIBUTE_PARENT_ACTIVITY_NAME = "parentActivityName";
-
- /**
- * Returns an {@link IAbstractFile} object representing the manifest for the given project.
- *
- * @param projectFolder The project containing the manifest file.
- * @return An IAbstractFile object pointing to the manifest or null if the manifest
- * is missing.
- */
- public static IAbstractFile getManifest(IAbstractFolder projectFolder) {
- IAbstractFile file = projectFolder.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML);
- if (file.exists()) {
- return file;
- }
-
- return null;
- }
-
- /**
- * Returns the package for a given project.
- * @param projectFolder the folder of the project.
- * @return the package info or null (or empty) if not found.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static String getPackage(IAbstractFolder projectFolder)
- throws XPathExpressionException, StreamException {
- IAbstractFile file = getManifest(projectFolder);
- if (file != null) {
- return getPackage(file);
- }
-
- return null;
- }
-
- /**
- * Returns the package for a given manifest.
- * @param manifestFile the manifest to parse.
- * @return the package info or null (or empty) if not found.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static String getPackage(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- return xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/@" + ATTRIBUTE_PACKAGE,
- new InputSource(manifestFile.getContents()));
- }
-
- /**
- * Returns whether the manifest is set to make the application debuggable.
- *
- * If the give manifest does not contain the debuggable attribute then the application
- * is considered to not be debuggable.
- *
- * @param manifestFile the manifest to parse.
- * @return true if the application is debuggable.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static boolean getDebuggable(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- String value = xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/" + NODE_APPLICATION +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_DEBUGGABLE,
- new InputSource(manifestFile.getContents()));
-
- // default is not debuggable, which is the same behavior as parseBoolean
- return Boolean.parseBoolean(value);
- }
-
- /**
- * Returns the value of the versionCode attribute or -1 if the value is not set.
- * @param manifestFile the manifest file to read the attribute from.
- * @return the integer value or -1 if not set.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static int getVersionCode(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- String result = xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_VERSIONCODE,
- new InputSource(manifestFile.getContents()));
-
- try {
- return Integer.parseInt(result);
- } catch (NumberFormatException e) {
- return -1;
- }
- }
-
- /**
- * Returns whether the version Code attribute is set in a given manifest.
- * @param manifestFile the manifest to check
- * @return true if the versionCode attribute is present and its value is not empty.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static boolean hasVersionCode(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- Object result = xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_VERSIONCODE,
- new InputSource(manifestFile.getContents()),
- XPathConstants.NODE);
-
- if (result != null) {
- Node node = (Node)result;
- if (node.getNodeValue().length() > 0) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns the value of the minSdkVersion attribute.
- * <p/>
- * If the attribute is set with an int value, the method returns an Integer object.
- * <p/>
- * If the attribute is set with a codename, it returns the codename as a String object.
- * <p/>
- * If the attribute is not set, it returns null.
- *
- * @param manifestFile the manifest file to read the attribute from.
- * @return the attribute value.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static Object getMinSdkVersion(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- String result = xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/" + NODE_USES_SDK +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_MIN_SDK_VERSION,
- new InputSource(manifestFile.getContents()));
-
- try {
- return Integer.valueOf(result);
- } catch (NumberFormatException e) {
- return result.length() > 0 ? result : null;
- }
- }
-
- /**
- * Returns the value of the targetSdkVersion attribute (defaults to 1 if the attribute is
- * not set), or -1 if the value is a codename.
- * @param manifestFile the manifest file to read the attribute from.
- * @return the integer value or -1 if not set.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static Integer getTargetSdkVersion(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- String result = xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/" + NODE_USES_SDK +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_TARGET_SDK_VERSION,
- new InputSource(manifestFile.getContents()));
-
- try {
- return Integer.valueOf(result);
- } catch (NumberFormatException e) {
- return result.length() > 0 ? -1 : null;
- }
- }
-
- /**
- * Returns the application icon for a given manifest.
- * @param manifestFile the manifest to parse.
- * @return the icon or null (or empty) if not found.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static String getApplicationIcon(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- return xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/" + NODE_APPLICATION +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_ICON,
- new InputSource(manifestFile.getContents()));
- }
-
- /**
- * Returns the application label for a given manifest.
- * @param manifestFile the manifest to parse.
- * @return the label or null (or empty) if not found.
- * @throws XPathExpressionException
- * @throws StreamException If any error happens when reading the manifest.
- */
- public static String getApplicationLabel(IAbstractFile manifestFile)
- throws XPathExpressionException, StreamException {
- XPath xPath = AndroidXPathFactory.newXPath();
-
- return xPath.evaluate(
- "/" + NODE_MANIFEST +
- "/" + NODE_APPLICATION +
- "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
- ":" + ATTRIBUTE_LABEL,
- new InputSource(manifestFile.getContents()));
- }
-
- /**
- * Combines a java package, with a class value from the manifest to make a fully qualified
- * class name
- * @param javaPackage the java package from the manifest.
- * @param className the class name from the manifest.
- * @return the fully qualified class name.
- */
- public static String combinePackageAndClassName(String javaPackage, String className) {
- if (className == null || className.length() == 0) {
- return javaPackage;
- }
- if (javaPackage == null || javaPackage.length() == 0) {
- return className;
- }
-
- // the class name can be a subpackage (starts with a '.'
- // char), a simple class name (no dot), or a full java package
- boolean startWithDot = (className.charAt(0) == '.');
- boolean hasDot = (className.indexOf('.') != -1);
- if (startWithDot || hasDot == false) {
-
- // add the concatenation of the package and class name
- if (startWithDot) {
- return javaPackage + className;
- } else {
- return javaPackage + '.' + className;
- }
- } else {
- // just add the class as it should be a fully qualified java name.
- return className;
- }
- }
-
- /**
- * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
- * package base name (e.g. com.foo), returns the relative activity name that would be used
- * the "name" attribute of an "activity" element.
- *
- * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
- * @param packageName The project base package name, e.g. "com.foo"
- * @return The relative activity name if it can be computed or the original fullActivityName.
- */
- public static String extractActivityName(String fullActivityName, String packageName) {
- if (packageName != null && fullActivityName != null) {
- if (packageName.length() > 0 && fullActivityName.startsWith(packageName)) {
- String name = fullActivityName.substring(packageName.length());
- if (name.length() > 0 && name.charAt(0) == '.') {
- return name;
- }
- }
- }
-
- return fullActivityName;
- }
-}
diff --git a/common/src/main/java/com/android/xml/AndroidXPathFactory.java b/common/src/main/java/com/android/xml/AndroidXPathFactory.java
deleted file mode 100644
index ee5b87b..0000000
--- a/common/src/main/java/com/android/xml/AndroidXPathFactory.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.SdkConstants;
-
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.xml.XMLConstants;
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathFactory;
-
-/**
- * XPath factory with automatic support for the android name space.
- */
-public class AndroidXPathFactory {
- /** Default prefix for android name space: 'android' */
- public final static String DEFAULT_NS_PREFIX = "android"; //$NON-NLS-1$
-
- private final static XPathFactory sFactory = XPathFactory.newInstance();
-
- /** Name space context for Android resource XML files. */
- private static class AndroidNamespaceContext implements NamespaceContext {
- private final static AndroidNamespaceContext sThis = new AndroidNamespaceContext(
- DEFAULT_NS_PREFIX);
-
- private final String mAndroidPrefix;
- private final List<String> mAndroidPrefixes;
-
- /**
- * Returns the default {@link AndroidNamespaceContext}.
- */
- private static AndroidNamespaceContext getDefault() {
- return sThis;
- }
-
- /**
- * Construct the context with the prefix associated with the android namespace.
- * @param androidPrefix the Prefix
- */
- public AndroidNamespaceContext(String androidPrefix) {
- mAndroidPrefix = androidPrefix;
- mAndroidPrefixes = Collections.singletonList(mAndroidPrefix);
- }
-
- @Override
- public String getNamespaceURI(String prefix) {
- if (prefix != null) {
- if (prefix.equals(mAndroidPrefix)) {
- return SdkConstants.NS_RESOURCES;
- }
- }
-
- return XMLConstants.NULL_NS_URI;
- }
-
- @Override
- public String getPrefix(String namespaceURI) {
- if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
- return mAndroidPrefix;
- }
-
- return null;
- }
-
- @Override
- public Iterator<?> getPrefixes(String namespaceURI) {
- if (SdkConstants.NS_RESOURCES.equals(namespaceURI)) {
- return mAndroidPrefixes.iterator();
- }
-
- return null;
- }
- }
-
- /**
- * Creates a new XPath object, specifying which prefix in the query is used for the
- * android namespace.
- * @param androidPrefix The namespace prefix.
- */
- public static XPath newXPath(String androidPrefix) {
- XPath xpath = sFactory.newXPath();
- xpath.setNamespaceContext(new AndroidNamespaceContext(androidPrefix));
- return xpath;
- }
-
- /**
- * Creates a new XPath object using the default prefix for the android namespace.
- * @see #DEFAULT_NS_PREFIX
- */
- public static XPath newXPath() {
- XPath xpath = sFactory.newXPath();
- xpath.setNamespaceContext(AndroidNamespaceContext.getDefault());
- return xpath;
- }
-}
diff --git a/common/src/test/.classpath b/common/src/test/.classpath
deleted file mode 100644
index 7564f2f..0000000
--- a/common/src/test/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="java"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry combineaccessrules="false" kind="src" path="/common"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/common/src/test/.project b/common/src/test/.project
deleted file mode 100644
index 9f550a3..0000000
--- a/common/src/test/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>common-tests</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/common/src/test/.settings/org.moreunit.prefs b/common/src/test/.settings/org.moreunit.prefs
deleted file mode 100644
index 5c0456e..0000000
--- a/common/src/test/.settings/org.moreunit.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-eclipse.preferences.version=1
-org.moreunit.prefixes=
-org.moreunit.unitsourcefolder=common-tests\:java\:common\:src/main/java
-org.moreunit.useprojectsettings=true
diff --git a/common/src/test/java/com/android/utils/PositionXmlParserTest.java b/common/src/test/java/com/android/utils/PositionXmlParserTest.java
deleted file mode 100644
index 18eda43..0000000
--- a/common/src/test/java/com/android/utils/PositionXmlParserTest.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import com.android.utils.PositionXmlParser.Position;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.Text;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("javadoc")
-public class PositionXmlParserTest extends TestCase {
- public void test() throws Exception {
- String xml =
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
- "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
- " android:layout_width=\"match_parent\"\n" +
- " android:layout_height=\"wrap_content\"\n" +
- " android:orientation=\"vertical\" >\n" +
- "\n" +
- " <Button\n" +
- " android:id=\"@+id/button1\"\n" +
- " android:layout_width=\"wrap_content\"\n" +
- " android:layout_height=\"wrap_content\"\n" +
- " android:text=\"Button\" />\n" +
- "\n" +
- " <Button\n" +
- " android:id=\"@+id/button2\"\n" +
- " android:layout_width=\"wrap_content\"\n" +
- " android:layout_height=\"wrap_content\"\n" +
- " android:text=\"Button\" />\n" +
- "\n" +
- "</LinearLayout>\n";
- PositionXmlParser parser = new PositionXmlParser();
- File file = File.createTempFile("parsertest", ".xml");
- Writer fw = new BufferedWriter(new FileWriter(file));
- fw.write(xml);
- fw.close();
- Document document = parser.parse(new FileInputStream(file));
- assertNotNull(document);
-
- // Basic parsing heart beat tests
- Element linearLayout = (Element) document.getElementsByTagName("LinearLayout").item(0);
- assertNotNull(linearLayout);
- NodeList buttons = document.getElementsByTagName("Button");
- assertEquals(2, buttons.getLength());
- final String ANDROID_URI = "http://schemas.android.com/apk/res/android";
- assertEquals("wrap_content",
- linearLayout.getAttributeNS(ANDROID_URI, "layout_height"));
-
- // Check attribute positions
- Attr attr = linearLayout.getAttributeNodeNS(ANDROID_URI, "layout_width");
- assertNotNull(attr);
- Position start = parser.getPosition(attr);
- Position end = start.getEnd();
- assertEquals(2, start.getLine());
- assertEquals(4, start.getColumn());
- assertEquals(xml.indexOf("android:layout_width"), start.getOffset());
- assertEquals(2, end.getLine());
- String target = "android:layout_width=\"match_parent\"";
- assertEquals(xml.indexOf(target) + target.length(), end.getOffset());
-
- // Check element positions
- Element button = (Element) buttons.item(0);
- start = parser.getPosition(button);
- end = start.getEnd();
- assertNull(end.getEnd());
- assertEquals(6, start.getLine());
- assertEquals(4, start.getColumn());
- assertEquals(xml.indexOf("<Button"), start.getOffset());
- assertEquals(xml.indexOf("/>") + 2, end.getOffset());
- assertEquals(10, end.getLine());
- int button1End = end.getOffset();
-
- Element button2 = (Element) buttons.item(1);
- start = parser.getPosition(button2);
- end = start.getEnd();
- assertEquals(12, start.getLine());
- assertEquals(4, start.getColumn());
- assertEquals(xml.indexOf("<Button", button1End), start.getOffset());
- assertEquals(xml.indexOf("/>", start.getOffset()) + 2, end.getOffset());
- assertEquals(16, end.getLine());
-
- file.delete();
- }
-
- public void testText() throws Exception {
- String xml =
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
- "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
- " android:layout_width=\"match_parent\"\n" +
- " android:layout_height=\"wrap_content\"\n" +
- " android:orientation=\"vertical\" >\n" +
- "\n" +
- " <Button\n" +
- " android:id=\"@+id/button1\"\n" +
- " android:layout_width=\"wrap_content\"\n" +
- " android:layout_height=\"wrap_content\"\n" +
- " android:text=\"Button\" />\n" +
- " some text\n" +
- "\n" +
- "</LinearLayout>\n";
- PositionXmlParser parser = new PositionXmlParser();
- File file = File.createTempFile("parsertest", ".xml");
- file.deleteOnExit();
- Writer fw = new BufferedWriter(new FileWriter(file));
- fw.write(xml);
- fw.close();
- Document document = parser.parse(new FileInputStream(file));
- assertNotNull(document);
-
- // Basic parsing heart beat tests
- Element linearLayout = (Element) document.getElementsByTagName("LinearLayout").item(0);
- assertNotNull(linearLayout);
- NodeList buttons = document.getElementsByTagName("Button");
- assertEquals(1, buttons.getLength());
- final String ANDROID_URI = "http://schemas.android.com/apk/res/android";
- assertEquals("wrap_content",
- linearLayout.getAttributeNS(ANDROID_URI, "layout_height"));
-
- // Check text positions
- Element button = (Element) buttons.item(0);
- Text text = (Text) button.getNextSibling();
- assertNotNull(text);
-
- // Check attribute positions
- Position start = parser.getPosition(text);
- assertEquals(11, start.getLine());
- assertEquals(10, start.getColumn());
- assertEquals(xml.indexOf("some text"), start.getOffset());
-
- // Check attribute positions with text node offsets
- start = parser.getPosition(text, 13, 15);
- assertEquals(11, start.getLine());
- assertEquals(12, start.getColumn());
- assertEquals(xml.indexOf("me"), start.getOffset());
- }
-
- public void testLineEndings() throws Exception {
- // Test for http://code.google.com/p/android/issues/detail?id=22925
- String xml =
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
- "<LinearLayout>\r\n" +
- "\r" +
- "<LinearLayout></LinearLayout>\r\n" +
- "</LinearLayout>\r\n";
- PositionXmlParser parser = new PositionXmlParser();
- File file = File.createTempFile("parsertest2", ".xml");
- Writer fw = new BufferedWriter(new FileWriter(file));
- fw.write(xml);
- fw.close();
- Document document = parser.parse(new FileInputStream(file));
- assertNotNull(document);
-
- file.delete();
- }
-
- private static void checkEncoding(String encoding, boolean writeBom, boolean writeEncoding,
- String lineEnding)
- throws Exception {
- // Norwegian extra vowel characters such as "latin small letter a with ring above"
- String value = "\u00e6\u00d8\u00e5";
- StringBuilder sb = new StringBuilder();
-
- sb.append("<?xml version=\"1.0\"");
- if (writeEncoding) {
- sb.append(" encoding=\"");
- sb.append(encoding);
- sb.append("\"");
- }
- sb.append("?>");
- sb.append(lineEnding);
- sb.append(
- "<!-- This is a " + lineEnding +
- " multiline comment" + lineEnding +
- "-->" + lineEnding +
- "<foo ");
- int startAttrOffset = sb.length();
- sb.append("attr=\"");
- sb.append(value);
- sb.append("\"");
- sb.append(">" + lineEnding +
- lineEnding +
- "<bar></bar>" + lineEnding +
- "</foo>" + lineEnding);
- PositionXmlParser parser = new PositionXmlParser();
- File file = File.createTempFile("parsertest" + encoding + writeBom + writeEncoding,
- ".xml");
- BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
- OutputStreamWriter writer = new OutputStreamWriter(stream, encoding);
-
- if (writeBom) {
- String normalized = encoding.toLowerCase().replace("-", "_");
- if (normalized.equals("utf_8")) {
- stream.write(0xef);
- stream.write(0xbb);
- stream.write(0xbf);
- } else if (normalized.equals("utf_16")) {
- stream.write(0xfe);
- stream.write(0xff);
- } else if (normalized.equals("utf_16le")) {
- stream.write(0xff);
- stream.write(0xfe);
- } else if (normalized.equals("utf_32")) {
- stream.write(0x0);
- stream.write(0x0);
- stream.write(0xfe);
- stream.write(0xff);
- } else if (normalized.equals("utf_32le")) {
- stream.write(0xff);
- stream.write(0xfe);
- stream.write(0x0);
- stream.write(0x0);
- } else {
- fail("Can't write BOM for encoding " + encoding);
- }
- }
-
- writer.write(sb.toString());
- writer.close();
-
- Document document = parser.parse(new FileInputStream(file));
- assertNotNull(document);
- Element root = document.getDocumentElement();
- assertEquals(file.getPath(), value, root.getAttribute("attr"));
- assertEquals(4, parser.getPosition(root).getLine());
-
- Attr attribute = root.getAttributeNode("attr");
- assertNotNull(attribute);
- Position position = parser.getPosition(attribute);
- assertNotNull(position);
- assertEquals(4, position.getLine());
- assertEquals(startAttrOffset, position.getOffset());
-
- file.delete();
- }
-
- public void testEncoding() throws Exception {
- checkEncoding("utf-8", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF-8", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_16", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF-16", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_16LE", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_32", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_32LE", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("windows-1252", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("MacRoman", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("ISO-8859-1", false /*bom*/, true /*encoding*/, "\n");
- checkEncoding("iso-8859-1", false /*bom*/, true /*encoding*/, "\n");
-
- // Try BOM's (with no encoding specified)
- checkEncoding("utf-8", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF-8", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_16", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF-16", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_16LE", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_32", true /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_32LE", true /*bom*/, false /*encoding*/, "\n");
-
- // Try default encodings (only defined for utf-8 and utf-16)
- checkEncoding("utf-8", false /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF-8", false /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_16", false /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF-16", false /*bom*/, false /*encoding*/, "\n");
- checkEncoding("UTF_16LE", false /*bom*/, false /*encoding*/, "\n");
-
- // Try BOM's (with explicit encoding specified)
- checkEncoding("utf-8", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF-8", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_16", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF-16", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_16LE", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_32", true /*bom*/, true /*encoding*/, "\n");
- checkEncoding("UTF_32LE", true /*bom*/, true /*encoding*/, "\n");
-
- // Make sure this works for \r and \r\n as well
- checkEncoding("UTF-16", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("UTF_16LE", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("UTF_32", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("UTF_32LE", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("windows-1252", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("MacRoman", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("ISO-8859-1", false /*bom*/, true /*encoding*/, "\r");
- checkEncoding("iso-8859-1", false /*bom*/, true /*encoding*/, "\r");
-
- checkEncoding("UTF-16", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("UTF_16LE", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("UTF_32", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("UTF_32LE", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("windows-1252", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("MacRoman", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("ISO-8859-1", false /*bom*/, true /*encoding*/, "\r\n");
- checkEncoding("iso-8859-1", false /*bom*/, true /*encoding*/, "\r\n");
- }
-}
diff --git a/common/src/test/java/com/android/utils/SdkUtilsTest.java b/common/src/test/java/com/android/utils/SdkUtilsTest.java
deleted file mode 100644
index 030e1b7..0000000
--- a/common/src/test/java/com/android/utils/SdkUtilsTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("javadoc")
-public class SdkUtilsTest extends TestCase {
- public void testEndsWithIgnoreCase() {
- assertTrue(SdkUtils.endsWithIgnoreCase("foo", "foo"));
- assertTrue(SdkUtils.endsWithIgnoreCase("foo", "Foo"));
- assertTrue(SdkUtils.endsWithIgnoreCase("foo", "foo"));
- assertTrue(SdkUtils.endsWithIgnoreCase("Barfoo", "foo"));
- assertTrue(SdkUtils.endsWithIgnoreCase("BarFoo", "foo"));
- assertTrue(SdkUtils.endsWithIgnoreCase("BarFoo", "foO"));
-
- assertFalse(SdkUtils.endsWithIgnoreCase("foob", "foo"));
- assertFalse(SdkUtils.endsWithIgnoreCase("foo", "fo"));
- }
-
- public void testStartsWithIgnoreCase() {
- assertTrue(SdkUtils.startsWithIgnoreCase("foo", "foo"));
- assertTrue(SdkUtils.startsWithIgnoreCase("foo", "Foo"));
- assertTrue(SdkUtils.startsWithIgnoreCase("foo", "foo"));
- assertTrue(SdkUtils.startsWithIgnoreCase("barfoo", "bar"));
- assertTrue(SdkUtils.startsWithIgnoreCase("BarFoo", "bar"));
- assertTrue(SdkUtils.startsWithIgnoreCase("BarFoo", "bAr"));
-
- assertFalse(SdkUtils.startsWithIgnoreCase("bfoo", "foo"));
- assertFalse(SdkUtils.startsWithIgnoreCase("fo", "foo"));
- }
-
- public void testStartsWith() {
- assertTrue(SdkUtils.startsWith("foo", 0, "foo"));
- assertTrue(SdkUtils.startsWith("foo", 0, "Foo"));
- assertTrue(SdkUtils.startsWith("Foo", 0, "foo"));
- assertTrue(SdkUtils.startsWith("aFoo", 1, "foo"));
-
- assertFalse(SdkUtils.startsWith("aFoo", 0, "foo"));
- assertFalse(SdkUtils.startsWith("aFoo", 2, "foo"));
- }
-
- public void testEndsWith() {
- assertTrue(SdkUtils.endsWith("foo", "foo"));
- assertTrue(SdkUtils.endsWith("foobar", "obar"));
- assertTrue(SdkUtils.endsWith("foobar", "bar"));
- assertTrue(SdkUtils.endsWith("foobar", "ar"));
- assertTrue(SdkUtils.endsWith("foobar", "r"));
- assertTrue(SdkUtils.endsWith("foobar", ""));
-
- assertTrue(SdkUtils.endsWith(new StringBuilder("foobar"), "bar"));
- assertTrue(SdkUtils.endsWith(new StringBuilder("foobar"), new StringBuffer("obar")));
- assertTrue(SdkUtils.endsWith("foobar", new StringBuffer("obar")));
-
- assertFalse(SdkUtils.endsWith("foo", "fo"));
- assertFalse(SdkUtils.endsWith("foobar", "Bar"));
- assertFalse(SdkUtils.endsWith("foobar", "longfoobar"));
- }
-
- public void testEndsWith2() {
- assertTrue(SdkUtils.endsWith("foo", "foo".length(), "foo"));
- assertTrue(SdkUtils.endsWith("foo", "fo".length(), "fo"));
- assertTrue(SdkUtils.endsWith("foo", "f".length(), "f"));
- }
-
- public void testStripWhitespace() {
- assertEquals("foo", SdkUtils.stripWhitespace("foo"));
- assertEquals("foobar", SdkUtils.stripWhitespace("foo bar"));
- assertEquals("foobar", SdkUtils.stripWhitespace(" foo bar \n\t"));
- }
-
- public void testWrap() {
- String s =
- "Hardcoding text attributes directly in layout files is bad for several reasons:\n" +
- "\n" +
- "* When creating configuration variations (for example for landscape or portrait)" +
- "you have to repeat the actual text (and keep it up to date when making changes)\n" +
- "\n" +
- "* The application cannot be translated to other languages by just adding new " +
- "translations for existing string resources.";
- String wrapped = SdkUtils.wrap(s, 70, "");
- assertEquals(
- "Hardcoding text attributes directly in layout files is bad for several\n" +
- "reasons:\n" +
- "\n" +
- "* When creating configuration variations (for example for landscape or\n" +
- "portrait)you have to repeat the actual text (and keep it up to date\n" +
- "when making changes)\n" +
- "\n" +
- "* The application cannot be translated to other languages by just\n" +
- "adding new translations for existing string resources.\n",
- wrapped);
- }
-
- public void testWrapPrefix() {
- String s =
- "Hardcoding text attributes directly in layout files is bad for several reasons:\n" +
- "\n" +
- "* When creating configuration variations (for example for landscape or portrait)" +
- "you have to repeat the actual text (and keep it up to date when making changes)\n" +
- "\n" +
- "* The application cannot be translated to other languages by just adding new " +
- "translations for existing string resources.";
- String wrapped = SdkUtils.wrap(s, 70, " ");
- assertEquals(
- "Hardcoding text attributes directly in layout files is bad for several\n" +
- " reasons:\n" +
- " \n" +
- " * When creating configuration variations (for example for\n" +
- " landscape or portrait)you have to repeat the actual text (and keep\n" +
- " it up to date when making changes)\n" +
- " \n" +
- " * The application cannot be translated to other languages by just\n" +
- " adding new translations for existing string resources.\n",
- wrapped);
- }
-
-
-}
diff --git a/common/src/test/java/com/android/utils/XmlUtilsTest.java b/common/src/test/java/com/android/utils/XmlUtilsTest.java
deleted file mode 100644
index edf0235..0000000
--- a/common/src/test/java/com/android/utils/XmlUtilsTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.utils;
-
-import static com.android.SdkConstants.XMLNS;
-
-import com.android.SdkConstants;
-import com.android.annotations.Nullable;
-
-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;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("javadoc")
-public class XmlUtilsTest extends TestCase {
- public void testlookupNamespacePrefix() throws Exception {
- // Setup
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setValidating(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.newDocument();
- Element rootElement = document.createElement("root");
- Attr attr = document.createAttributeNS(SdkConstants.XMLNS_URI,
- "xmlns:customPrefix");
- attr.setValue(SdkConstants.ANDROID_URI);
- rootElement.getAttributes().setNamedItemNS(attr);
- document.appendChild(rootElement);
- Element root = document.getDocumentElement();
- root.appendChild(document.createTextNode(" "));
- Element foo = document.createElement("foo");
- root.appendChild(foo);
- root.appendChild(document.createTextNode(" "));
- Element bar = document.createElement("bar");
- root.appendChild(bar);
- Element baz = document.createElement("baz");
- root.appendChild(baz);
-
- String prefix = XmlUtils.lookupNamespacePrefix(baz, SdkConstants.ANDROID_URI);
- assertEquals("customPrefix", prefix);
-
- prefix = XmlUtils.lookupNamespacePrefix(baz,
- "http://schemas.android.com/tools", "tools", false);
- assertEquals("tools", prefix);
-
- prefix = XmlUtils.lookupNamespacePrefix(baz,
- "http://schemas.android.com/apk/res/my/pkg", "app", false);
- assertEquals("app", prefix);
- assertFalse(declaresNamespace(document, "http://schemas.android.com/apk/res/my/pkg"));
-
- prefix = XmlUtils.lookupNamespacePrefix(baz,
- "http://schemas.android.com/apk/res/my/pkg", "app", true /*create*/);
- assertEquals("app", prefix);
- assertTrue(declaresNamespace(document, "http://schemas.android.com/apk/res/my/pkg"));
- }
-
- private static boolean declaresNamespace(Document document, String uri) {
- NamedNodeMap attributes = document.getDocumentElement().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) && uri.equals(attribute.getValue())) {
- return true;
- }
- }
-
- return false;
- }
-
- public void testToXmlAttributeValue() throws Exception {
- assertEquals("", XmlUtils.toXmlAttributeValue(""));
- assertEquals("foo", XmlUtils.toXmlAttributeValue("foo"));
- assertEquals("foo&lt;bar", XmlUtils.toXmlAttributeValue("foo<bar"));
- assertEquals("foo>bar", XmlUtils.toXmlAttributeValue("foo>bar"));
-
- assertEquals("&quot;", XmlUtils.toXmlAttributeValue("\""));
- assertEquals("&apos;", XmlUtils.toXmlAttributeValue("'"));
- assertEquals("foo&quot;b&apos;&apos;ar",
- XmlUtils.toXmlAttributeValue("foo\"b''ar"));
- assertEquals("&lt;&quot;&apos;>&amp;", XmlUtils.toXmlAttributeValue("<\"'>&"));
- }
-
- public void testAppendXmlAttributeValue() throws Exception {
- StringBuilder sb = new StringBuilder();
- XmlUtils.appendXmlAttributeValue(sb, "<\"'>&");
- assertEquals("&lt;&quot;&apos;>&amp;", sb.toString());
- }
-
- public void testToXmlTextValue() throws Exception {
- assertEquals("&lt;\"'>&amp;", XmlUtils.toXmlTextValue("<\"'>&"));
- }
-
- public void testAppendXmlTextValue() throws Exception {
- StringBuilder sb = new StringBuilder();
- XmlUtils.appendXmlTextValue(sb, "<\"'>&");
- assertEquals("&lt;\"'>&amp;", sb.toString());
- }
-
- public void testNew() throws Exception {
- Document doc = createEmptyPlainDocument();
- Element root = doc.createElement("myroot");
- doc.appendChild(root);
- root.setAttribute("foo", "bar");
- root.setAttribute("baz", "baz");
- Element child = doc.createElement("mychild");
- root.appendChild(child);
- Element child2 = doc.createElement("hasComment");
- root.appendChild(child2);
- Node comment = doc.createComment("This is my comment");
- child2.appendChild(comment);
- Element child3 = doc.createElement("hasText");
- root.appendChild(child3);
- Node text = doc.createTextNode(" This is my text ");
- child3.appendChild(text);
-
- String xml = XmlUtils.toXml(doc, false);
- assertEquals(
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
- "<myroot baz=\"baz\" foo=\"bar\">\n" +
- " <mychild/>\n" +
- " <hasComment>\n" +
- " <!--\n" +
- " This is my comment\n" +
- " -->\n" +
- " </hasComment>\n" +
- " <hasText>\n" +
- " This is my text\n" +
- " </hasText>\n" +
- "</myroot>\n",
- xml);
-
- xml = XmlUtils.toXml(doc, true);
- assertEquals(
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
- "<myroot baz=\"baz\" foo=\"bar\"><mychild/><hasComment><!--This is my comment--></hasComment><hasText> This is my text </hasText></myroot>",
- xml);
-
- }
-
- @Nullable
- private static Document createEmptyPlainDocument() throws Exception {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setValidating(false);
- factory.setIgnoringComments(true);
- DocumentBuilder builder;
- builder = factory.newDocumentBuilder();
- return builder.newDocument();
- }
-}
diff --git a/ddms/app/etc/manifest.txt b/ddms/app/etc/manifest.txt
index 88249c4..f3d4fdd 100644
--- a/ddms/app/etc/manifest.txt
+++ b/ddms/app/etc/manifest.txt
@@ -1,3 +1,3 @@
Main-Class: com.android.ddms.Main
-Class-Path: common.jar sdkstats.jar ddmlib.jar ddmuilib.jar swtmenubar.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.equinox.common_3.6.0.v20100503.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar jcommon-1.0.12.jar jfreechart-1.0.9.jar jfreechart-1.0.9-swt.jar osgi.jar
+Class-Path: common.jar sdkstats.jar ddmlib.jar ddmuilib.jar swtmenubar.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.equinox.common_3.6.0.v20100503.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar jcommon-1.0.12.jar jfreechart-1.0.9.jar jfreechart-1.0.9-swt.jar osgi.jar guava-tools.jar
diff --git a/ddms/libs/ddmlib/Android.mk b/ddms/libs/ddmlib/Android.mk
index c479e79..c5ad99e 100644
--- a/ddms/libs/ddmlib/Android.mk
+++ b/ddms/libs/ddmlib/Android.mk
@@ -26,7 +26,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := kxml2-2.3.0
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java
index 1a547c7..2804629 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatBufferChangeListener.java
@@ -16,6 +16,8 @@
package com.android.ddmuilib.logcat;
+import com.android.ddmlib.logcat.LogCatMessage;
+
import java.util.List;
/**
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java
index 6e814b0..728b518 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/ILogCatMessageSelectionListener.java
@@ -15,6 +15,8 @@
*/
package com.android.ddmuilib.logcat;
+import com.android.ddmlib.logcat.LogCatMessage;
+
/**
* Classes interested in listening to user selection of logcat
* messages should implement this interface.
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilter.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilter.java
deleted file mode 100644
index 7bdd98a..0000000
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilter.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-/**
- * A Filter for logcat messages. A filter can be constructed to match
- * different fields of a logcat message. It can then be queried to see if
- * a message matches the filter's settings.
- */
-public final class LogCatFilter {
- private static final String PID_KEYWORD = "pid:"; //$NON-NLS-1$
- private static final String APP_KEYWORD = "app:"; //$NON-NLS-1$
- private static final String TAG_KEYWORD = "tag:"; //$NON-NLS-1$
- private static final String TEXT_KEYWORD = "text:"; //$NON-NLS-1$
-
- private final String mName;
- private final String mTag;
- private final String mText;
- private final String mPid;
- private final String mAppName;
- private final LogLevel mLogLevel;
-
- /** Indicates the number of messages that match this filter, but have not
- * yet been read by the user. This is really metadata about this filter
- * necessary for the UI. If we ever end up needing to store more metadata,
- * then it is probably better to move it out into a separate class. */
- private int mUnreadCount;
-
- /** Indicates that this filter is transient, and should not be persisted
- * across Eclipse sessions. */
- private boolean mTransient;
-
- private boolean mCheckPid;
- private boolean mCheckAppName;
- private boolean mCheckTag;
- private boolean mCheckText;
-
- private Pattern mAppNamePattern;
- private Pattern mTagPattern;
- private Pattern mTextPattern;
-
- /**
- * Construct a filter with the provided restrictions for the logcat message. All the text
- * fields accept Java regexes as input, but ignore invalid regexes. Filters are saved and
- * restored across Eclipse sessions unless explicitly marked transient using
- * {@link LogCatFilter#setTransient}.
- * @param name name for the filter
- * @param tag value for the logcat message's tag field.
- * @param text value for the logcat message's text field.
- * @param pid value for the logcat message's pid field.
- * @param appName value for the logcat message's app name field.
- * @param logLevel value for the logcat message's log level. Only messages of
- * higher priority will be accepted by the filter.
- */
- public LogCatFilter(String name, String tag, String text, String pid, String appName,
- LogLevel logLevel) {
- mName = name.trim();
- mTag = tag.trim();
- mText = text.trim();
- mPid = pid.trim();
- mAppName = appName.trim();
- mLogLevel = logLevel;
-
- mUnreadCount = 0;
-
- // By default, all filters are persistent. Transient filters should explicitly
- // mark it so by calling setTransient.
- mTransient = false;
-
- mCheckPid = mPid.length() != 0;
-
- if (mAppName.length() != 0) {
- try {
- mAppNamePattern = Pattern.compile(mAppName, getPatternCompileFlags(mAppName));
- mCheckAppName = true;
- } catch (PatternSyntaxException e) {
- mCheckAppName = false;
- }
- }
-
- if (mTag.length() != 0) {
- try {
- mTagPattern = Pattern.compile(mTag, getPatternCompileFlags(mTag));
- mCheckTag = true;
- } catch (PatternSyntaxException e) {
- mCheckTag = false;
- }
- }
-
- if (mText.length() != 0) {
- try {
- mTextPattern = Pattern.compile(mText, getPatternCompileFlags(mText));
- mCheckText = true;
- } catch (PatternSyntaxException e) {
- mCheckText = false;
- }
- }
- }
-
- /**
- * Obtain the flags to pass to {@link Pattern#compile(String, int)}. This method
- * tries to figure out whether case sensitive matching should be used. It is based on
- * the following heuristic: if the regex has an upper case character, then the match
- * will be case sensitive. Otherwise it will be case insensitive.
- */
- private int getPatternCompileFlags(String regex) {
- for (char c : regex.toCharArray()) {
- if (Character.isUpperCase(c)) {
- return 0;
- }
- }
-
- return Pattern.CASE_INSENSITIVE;
- }
-
- /**
- * Construct a list of {@link LogCatFilter} objects by decoding the query.
- * @param query encoded search string. The query is simply a list of words (can be regexes)
- * a user would type in a search bar. These words are searched for in the text field of
- * each collected logcat message. To search in a different field, the word could be prefixed
- * with a keyword corresponding to the field name. Currently, the following keywords are
- * supported: "pid:", "tag:" and "text:". Invalid regexes are ignored.
- * @param minLevel minimum log level to match
- * @return list of filter settings that fully match the given query
- */
- public static List<LogCatFilter> fromString(String query, LogLevel minLevel) {
- List<LogCatFilter> filterSettings = new ArrayList<LogCatFilter>();
-
- for (String s : query.trim().split(" ")) {
- String tag = "";
- String text = "";
- String pid = "";
- String app = "";
-
- if (s.startsWith(PID_KEYWORD)) {
- pid = s.substring(PID_KEYWORD.length());
- } else if (s.startsWith(APP_KEYWORD)) {
- app = s.substring(APP_KEYWORD.length());
- } else if (s.startsWith(TAG_KEYWORD)) {
- tag = s.substring(TAG_KEYWORD.length());
- } else {
- if (s.startsWith(TEXT_KEYWORD)) {
- text = s.substring(TEXT_KEYWORD.length());
- } else {
- text = s;
- }
- }
- filterSettings.add(new LogCatFilter("livefilter-" + s,
- tag, text, pid, app, minLevel));
- }
-
- return filterSettings;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getTag() {
- return mTag;
- }
-
- public String getText() {
- return mText;
- }
-
- public String getPid() {
- return mPid;
- }
-
- public String getAppName() {
- return mAppName;
- }
-
- public LogLevel getLogLevel() {
- return mLogLevel;
- }
-
- /**
- * Check whether a given message will make it through this filter.
- * @param m message to check
- * @return true if the message matches the filter's conditions.
- */
- public boolean matches(LogCatMessage m) {
- /* filter out messages of a lower priority */
- if (m.getLogLevel().getPriority() < mLogLevel.getPriority()) {
- return false;
- }
-
- /* if pid filter is enabled, filter out messages whose pid does not match
- * the filter's pid */
- if (mCheckPid && !m.getPid().equals(mPid)) {
- return false;
- }
-
- /* if app name filter is enabled, filter out messages not matching the app name */
- if (mCheckAppName) {
- Matcher matcher = mAppNamePattern.matcher(m.getAppName());
- if (!matcher.find()) {
- return false;
- }
- }
-
- /* if tag filter is enabled, filter out messages not matching the tag */
- if (mCheckTag) {
- Matcher matcher = mTagPattern.matcher(m.getTag());
- if (!matcher.find()) {
- return false;
- }
- }
-
- if (mCheckText) {
- Matcher matcher = mTextPattern.matcher(m.getMessage());
- if (!matcher.find()) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Update the unread count based on new messages received. The unread count
- * is incremented by the count of messages in the received list that will be
- * accepted by this filter.
- * @param newMessages list of new messages.
- */
- public void updateUnreadCount(List<LogCatMessage> newMessages) {
- for (LogCatMessage m : newMessages) {
- if (matches(m)) {
- mUnreadCount++;
- }
- }
- }
-
- /**
- * Reset count of unread messages.
- */
- public void resetUnreadCount() {
- mUnreadCount = 0;
- }
-
- /**
- * Get current value for the unread message counter.
- */
- public int getUnreadCount() {
- return mUnreadCount;
- }
-
- /** Make this filter transient: It will not be persisted across sessions. */
- public void setTransient() {
- mTransient = true;
- }
-
- public boolean isTransient() {
- return mTransient;
- }
-}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java
index 68c08d4..629b0e0 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterContentProvider.java
@@ -15,6 +15,8 @@
*/
package com.android.ddmuilib.logcat;
+import com.android.ddmlib.logcat.LogCatFilter;
+
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java
new file mode 100644
index 0000000..dbc34d8
--- /dev/null
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterData.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.ddmuilib.logcat;
+
+import com.android.ddmlib.logcat.LogCatFilter;
+import com.android.ddmlib.logcat.LogCatMessage;
+
+import java.util.List;
+
+public class LogCatFilterData {
+ private final LogCatFilter mFilter;
+
+ /** Indicates the number of messages that match this filter, but have not
+ * yet been read by the user. This is really metadata about this filter
+ * necessary for the UI. If we ever end up needing to store more metadata,
+ * then it is probably better to move it out into a separate class. */
+ private int mUnreadCount;
+
+ /** Indicates that this filter is transient, and should not be persisted
+ * across Eclipse sessions. */
+ private boolean mTransient;
+
+ public LogCatFilterData(LogCatFilter f) {
+ mFilter = f;
+
+ // By default, all filters are persistent. Transient filters should explicitly
+ // mark it so by calling setTransient.
+ mTransient = false;
+ }
+
+ /**
+ * Update the unread count based on new messages received. The unread count
+ * is incremented by the count of messages in the received list that will be
+ * accepted by this filter.
+ * @param newMessages list of new messages.
+ */
+ public void updateUnreadCount(List<LogCatMessage> newMessages) {
+ for (LogCatMessage m : newMessages) {
+ if (mFilter.matches(m)) {
+ mUnreadCount++;
+ }
+ }
+ }
+
+ /**
+ * Reset count of unread messages.
+ */
+ public void resetUnreadCount() {
+ mUnreadCount = 0;
+ }
+
+ /**
+ * Get current value for the unread message counter.
+ */
+ public int getUnreadCount() {
+ return mUnreadCount;
+ }
+
+ /** Make this filter transient: It will not be persisted across sessions. */
+ public void setTransient() {
+ mTransient = true;
+ }
+
+ public boolean isTransient() {
+ return mTransient;
+ }
+}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java
index 59e236c..fe24ddd 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterLabelProvider.java
@@ -15,15 +15,25 @@
*/
package com.android.ddmuilib.logcat;
+import com.android.ddmlib.logcat.LogCatFilter;
+
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;
+import java.util.Map;
+
/**
* A JFace label provider for the LogCat filters. It expects elements of type
* {@link LogCatFilter}.
*/
public final class LogCatFilterLabelProvider extends LabelProvider implements ITableLabelProvider {
+ private Map<LogCatFilter, LogCatFilterData> mFilterData;
+
+ public LogCatFilterLabelProvider(Map<LogCatFilter, LogCatFilterData> filterData) {
+ mFilterData = filterData;
+ }
+
@Override
public Image getColumnImage(Object arg0, int arg1) {
return null;
@@ -42,11 +52,12 @@ public final class LogCatFilterLabelProvider extends LabelProvider implements IT
}
LogCatFilter f = (LogCatFilter) element;
+ LogCatFilterData fd = mFilterData.get(f);
- if (f.getUnreadCount() == 0) {
- return f.getName();
+ if (fd != null && fd.getUnreadCount() > 0) {
+ return String.format("%s (%d)", f.getName(), fd.getUnreadCount());
} else {
- return String.format("%s (%d)", f.getName(), f.getUnreadCount());
+ return f.getName();
}
}
}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java
index 12fbdfa..de35162 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializer.java
@@ -16,9 +16,11 @@
package com.android.ddmuilib.logcat;
import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.logcat.LogCatFilter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Class to help save/restore user created filters.
@@ -49,14 +51,17 @@ public final class LogCatFilterSettingsSerializer {
* {@link LogCatFilterSettingsSerializer#decodeFromPreferenceString(String)} for the
* reverse operation.
* @param filters list of filters to save.
+ * @param filterData mapping from filter to per filter UI data
* @return an encoded string that can be saved in Eclipse preference store. The encoded string
* is of a list of key:'value' pairs.
*/
- public String encodeToPreferenceString(List<LogCatFilter> filters) {
+ public String encodeToPreferenceString(List<LogCatFilter> filters,
+ Map<LogCatFilter, LogCatFilterData> filterData) {
StringBuffer sb = new StringBuffer();
for (LogCatFilter f : filters) {
- if (f.isTransient()) {
+ LogCatFilterData fd = filterData.get(f);
+ if (fd != null && fd.isTransient()) {
// do not persist transient filters
continue;
}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessage.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessage.java
deleted file mode 100644
index aea4ead..0000000
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessage.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.Log.LogLevel;
-
-/**
- * Model a single log message output from {@code logcat -v long}.
- * A logcat message has a {@link LogLevel}, the pid (process id) of the process
- * generating the message, the time at which the message was generated, and
- * the tag and message itself.
- */
-public final class LogCatMessage {
- private final LogLevel mLogLevel;
- private final String mPid;
- private final String mTid;
- private final String mAppName;
- private final String mTag;
- private final String mTime;
- private final String mMessage;
-
- /**
- * Construct an immutable log message object.
- */
- public LogCatMessage(LogLevel logLevel, String pid, String tid, String appName,
- String tag, String time, String msg) {
- mLogLevel = logLevel;
- mPid = pid;
- mAppName = appName;
- mTag = tag;
- mTime = time;
- mMessage = msg;
-
- long tidValue;
- try {
- // Thread id's may be in hex on some platforms.
- // Decode and store them in radix 10.
- tidValue = Long.decode(tid.trim());
- } catch (NumberFormatException e) {
- tidValue = -1;
- }
-
- mTid = Long.toString(tidValue);
- }
-
- public LogLevel getLogLevel() {
- return mLogLevel;
- }
-
- public String getPid() {
- return mPid;
- }
-
- public String getTid() {
- return mTid;
- }
-
- public String getAppName() {
- return mAppName;
- }
-
- public String getTag() {
- return mTag;
- }
-
- public String getTime() {
- return mTime;
- }
-
- public String getMessage() {
- return mMessage;
- }
-
- @Override
- public String toString() {
- return mTime + ": "
- + mLogLevel.getPriorityLetter() + "/"
- + mTag + "("
- + mPid + "): "
- + mMessage;
- }
-}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java
index 080dbc1..c5cd548 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageList.java
@@ -16,6 +16,8 @@
package com.android.ddmuilib.logcat;
+import com.android.ddmlib.logcat.LogCatMessage;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageParser.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageParser.java
deleted file mode 100644
index b69a433..0000000
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatMessageParser.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Class to parse raw output of {@code adb logcat -v long} to {@link LogCatMessage} objects.
- */
-public final class LogCatMessageParser {
- private LogLevel mCurLogLevel = LogLevel.WARN;
- private String mCurPid = "?";
- private String mCurTid = "?";
- private String mCurTag = "?";
- private String mCurTime = "?:??";
-
- /**
- * This pattern is meant to parse the first line of a log message with the option
- * 'logcat -v long'. The first line represents the date, tag, severity, etc.. while the
- * following lines are the message (can be several lines).<br>
- * This first line looks something like:<br>
- * {@code "[ 00-00 00:00:00.000 <pid>:0x<???> <severity>/<tag>]"}
- * <br>
- * Note: severity is one of V, D, I, W, E, A? or F. However, there doesn't seem to be
- * a way to actually generate an A (assert) message. Log.wtf is supposed to generate
- * a message with severity A, however it generates the undocumented F level. In
- * such a case, the parser will change the level from F to A.<br>
- * Note: the fraction of second value can have any number of digit.<br>
- * Note: the tag should be trimmed as it may have spaces at the end.
- */
- private static Pattern sLogHeaderPattern = Pattern.compile(
- "^\\[\\s(\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d+)"
- + "\\s+(\\d*):\\s*(\\S+)\\s([VDIWEAF])/(.*)\\]$");
-
- /**
- * Parse a list of strings into {@link LogCatMessage} objects. This method
- * maintains state from previous calls regarding the last seen header of
- * logcat messages.
- * @param lines list of raw strings obtained from logcat -v long
- * @param pidToNameMapper mapper to obtain the app name given a pid
- * @return list of LogMessage objects parsed from the input
- */
- public List<LogCatMessage> processLogLines(String[] lines,
- LogCatPidToNameMapper pidToNameMapper) {
- List<LogCatMessage> messages = new ArrayList<LogCatMessage>(lines.length);
-
- for (String line : lines) {
- if (line.length() == 0) {
- continue;
- }
-
- Matcher matcher = sLogHeaderPattern.matcher(line);
- if (matcher.matches()) {
- mCurTime = matcher.group(1);
- mCurPid = matcher.group(2);
- mCurTid = matcher.group(3);
- mCurLogLevel = LogLevel.getByLetterString(matcher.group(4));
- mCurTag = matcher.group(5).trim();
-
- /* LogLevel doesn't support messages with severity "F". Log.wtf() is supposed
- * to generate "A", but generates "F". */
- if (mCurLogLevel == null && matcher.group(4).equals("F")) {
- mCurLogLevel = LogLevel.ASSERT;
- }
- } else {
- LogCatMessage m = new LogCatMessage(mCurLogLevel, mCurPid, mCurTid,
- pidToNameMapper.getName(mCurPid),
- mCurTag, mCurTime, line);
- messages.add(m);
- }
- }
-
- return messages;
- }
-}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java
index 4f27f02..bda742c 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPanel.java
@@ -19,6 +19,8 @@ package com.android.ddmuilib.logcat;
import com.android.ddmlib.DdmConstants;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.logcat.LogCatFilter;
+import com.android.ddmlib.logcat.LogCatMessage;
import com.android.ddmuilib.AbstractBufferFindTarget;
import com.android.ddmuilib.FindDialog;
import com.android.ddmuilib.ITableFocusListener;
@@ -85,6 +87,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -160,6 +164,7 @@ public final class LogCatPanel extends SelectionDependentPanel
private IPreferenceStore mPrefStore;
private List<LogCatFilter> mLogCatFilters;
+ private Map<LogCatFilter, LogCatFilterData> mLogCatFilterData;
private int mCurrentSelectedFilterIndex;
private ToolItem mNewFilterToolItem;
@@ -236,18 +241,25 @@ public final class LogCatPanel extends SelectionDependentPanel
private void initializeFilters() {
mLogCatFilters = new ArrayList<LogCatFilter>();
+ mLogCatFilterData = new ConcurrentHashMap<LogCatFilter, LogCatFilterData>();
/* add default filter matching all messages */
String tag = "";
String text = "";
String pid = "";
String app = "";
- mLogCatFilters.add(new LogCatFilter("All messages (no filters)",
- tag, text, pid, app, LogLevel.VERBOSE));
+ LogCatFilter defaultFilter = new LogCatFilter("All messages (no filters)",
+ tag, text, pid, app, LogLevel.VERBOSE);
+
+ mLogCatFilters.add(defaultFilter);
+ mLogCatFilterData.put(defaultFilter, new LogCatFilterData(defaultFilter));
/* restore saved filters from prefStore */
List<LogCatFilter> savedFilters = getSavedFilters();
- mLogCatFilters.addAll(savedFilters);
+ for (LogCatFilter f: savedFilters) {
+ mLogCatFilters.add(f);
+ mLogCatFilterData.put(f, new LogCatFilterData(f));
+ }
}
private void setupDefaultPreferences() {
@@ -323,7 +335,7 @@ public final class LogCatPanel extends SelectionDependentPanel
/* save all filter settings except the first one which is the default */
String e = serializer.encodeToPreferenceString(
- mLogCatFilters.subList(1, mLogCatFilters.size()));
+ mLogCatFilters.subList(1, mLogCatFilters.size()), mLogCatFilterData);
mPrefStore.setValue(LOGCAT_FILTERS_LIST, e);
}
@@ -348,7 +360,8 @@ public final class LogCatPanel extends SelectionDependentPanel
// When switching between devices, existing filter match count should be reset.
for (LogCatFilter f : mLogCatFilters) {
- f.resetUnreadCount();
+ LogCatFilterData fd = mLogCatFilterData.get(f);
+ fd.resetUnreadCount();
}
}
@@ -478,6 +491,7 @@ public final class LogCatPanel extends SelectionDependentPanel
LogLevel.getByString(d.getLogLevel()));
mLogCatFilters.add(f);
+ mLogCatFilterData.put(f, new LogCatFilterData(f));
mFiltersTableViewer.refresh();
/* select the newly added entry */
@@ -489,8 +503,7 @@ public final class LogCatPanel extends SelectionDependentPanel
}
private void addNewFilter() {
- addNewFilter("", "", "",
- "", LogLevel.VERBOSE);
+ addNewFilter("", "", "", "", LogLevel.VERBOSE);
}
private void deleteSelectedFilter() {
@@ -500,7 +513,10 @@ public final class LogCatPanel extends SelectionDependentPanel
return;
}
+ LogCatFilter f = mLogCatFilters.get(selectedIndex);
mLogCatFilters.remove(selectedIndex);
+ mLogCatFilterData.remove(f);
+
mFiltersTableViewer.refresh();
mFiltersTableViewer.getTable().setSelection(selectedIndex - 1);
@@ -551,6 +567,10 @@ public final class LogCatPanel extends SelectionDependentPanel
if (f == null) {
f = createTransientAppFilter(appName);
mLogCatFilters.add(f);
+
+ LogCatFilterData fd = new LogCatFilterData(f);
+ fd.setTransient();
+ mLogCatFilterData.put(f, fd);
}
selectFilterAt(mLogCatFilters.indexOf(f));
@@ -558,7 +578,8 @@ public final class LogCatPanel extends SelectionDependentPanel
private LogCatFilter findTransientAppFilter(String appName) {
for (LogCatFilter f : mLogCatFilters) {
- if (f.isTransient() && f.getAppName().equals(appName)) {
+ LogCatFilterData fd = mLogCatFilterData.get(f);
+ if (fd != null && fd.isTransient() && f.getAppName().equals(appName)) {
return f;
}
}
@@ -572,7 +593,6 @@ public final class LogCatPanel extends SelectionDependentPanel
"",
appName,
LogLevel.VERBOSE);
- f.setTransient();
return f;
}
@@ -594,7 +614,7 @@ public final class LogCatPanel extends SelectionDependentPanel
mFiltersTableViewer = new TableViewer(table);
mFiltersTableViewer.setContentProvider(new LogCatFilterContentProvider());
- mFiltersTableViewer.setLabelProvider(new LogCatFilterLabelProvider());
+ mFiltersTableViewer.setLabelProvider(new LogCatFilterLabelProvider(mLogCatFilterData));
mFiltersTableViewer.setInput(mLogCatFilters);
mFiltersTableViewer.getTable().addSelectionListener(new SelectionAdapter() {
@@ -671,6 +691,7 @@ public final class LogCatPanel extends SelectionDependentPanel
if (mReceiver != null) {
mReceiver.clearMessages();
refreshLogCatTable();
+ resetUnreadCountForAllFilters();
// the filters view is not cleared unless the filters are re-applied.
updateAppliedFilters();
@@ -1091,13 +1112,15 @@ public final class LogCatPanel extends SelectionDependentPanel
mCurrentSelectedFilterIndex = idx;
- resetUnreadCountForSelectedFilter();
+ resetUnreadCountForAllFilters();
updateFiltersToolBar();
updateAppliedFilters();
}
- private void resetUnreadCountForSelectedFilter() {
- mLogCatFilters.get(mCurrentSelectedFilterIndex).resetUnreadCount();
+ private void resetUnreadCountForAllFilters() {
+ for (LogCatFilterData fd: mLogCatFilterData.values()) {
+ fd.resetUnreadCount();
+ }
refreshFiltersTable();
}
@@ -1142,6 +1165,8 @@ public final class LogCatPanel extends SelectionDependentPanel
@Override
public void bufferChanged(List<LogCatMessage> addedMessages,
List<LogCatMessage> deletedMessages) {
+ updateUnreadCount(addedMessages);
+ refreshFiltersTable();
synchronized (mLogBuffer) {
addedMessages = applyCurrentFilters(addedMessages);
@@ -1152,8 +1177,6 @@ public final class LogCatPanel extends SelectionDependentPanel
}
refreshLogCatTable();
- updateUnreadCount(addedMessages);
- refreshFiltersTable();
}
private void reloadLogBuffer() {
@@ -1184,7 +1207,9 @@ public final class LogCatPanel extends SelectionDependentPanel
/* no need to update unread count for currently selected filter */
continue;
}
- mLogCatFilters.get(i).updateUnreadCount(receivedMessages);
+ LogCatFilter f = mLogCatFilters.get(i);
+ LogCatFilterData fd = mLogCatFilterData.get(f);
+ fd.updateUnreadCount(receivedMessages);
}
}
@@ -1328,7 +1353,9 @@ public final class LogCatPanel extends SelectionDependentPanel
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
- startScrollBarMonitor(mTable.getVerticalBar());
+ if (!mTable.isDisposed()) {
+ startScrollBarMonitor(mTable.getVerticalBar());
+ }
}
});
}
@@ -1372,7 +1399,9 @@ public final class LogCatPanel extends SelectionDependentPanel
/** Scroll to the last line. */
private void scrollToLatestLog() {
- mTable.setTopIndex(mTable.getItemCount() - 1);
+ if (!mTable.isDisposed()) {
+ mTable.setTopIndex(mTable.getItemCount() - 1);
+ }
}
/**
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPidToNameMapper.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPidToNameMapper.java
deleted file mode 100644
index a4455d0..0000000
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatPidToNameMapper.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.AndroidDebugBridge;
-import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
-import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
-import com.android.ddmlib.Client;
-import com.android.ddmlib.ClientData;
-import com.android.ddmlib.IDevice;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This class maintains a mapping between the PID and the application name for all
- * running apps on a device. It does this by implementing callbacks to two events:
- * {@link AndroidDebugBridge.IDeviceChangeListener} and
- * {@link AndroidDebugBridge.IClientChangeListener}.
- */
-public class LogCatPidToNameMapper {
- /** Default name used when the actual name cannot be determined. */
- public static final String UNKNOWN_APP = "";
-
- private IClientChangeListener mClientChangeListener;
- private IDeviceChangeListener mDeviceChangeListener;
- private IDevice mDevice;
- private Map<String, String> mPidToName;
-
- public LogCatPidToNameMapper(IDevice device) {
- mDevice = device;
- mClientChangeListener = constructClientChangeListener();
- AndroidDebugBridge.addClientChangeListener(mClientChangeListener);
-
- mDeviceChangeListener = constructDeviceChangeListener();
- AndroidDebugBridge.addDeviceChangeListener(mDeviceChangeListener);
-
- mPidToName = new HashMap<String, String>();
-
- updateClientList(device);
- }
-
- private IClientChangeListener constructClientChangeListener() {
- return new IClientChangeListener() {
- @Override
- public void clientChanged(Client client, int changeMask) {
- if ((changeMask & Client.CHANGE_NAME) == Client.CHANGE_NAME) {
- ClientData cd = client.getClientData();
- updateClientName(cd);
- }
- }
- };
- }
-
- private void updateClientName(ClientData cd) {
- String name = cd.getClientDescription();
- if (name != null) {
- int pid = cd.getPid();
- if (mPidToName != null) {
- mPidToName.put(Integer.toString(pid), name);
- }
- }
- }
-
- private IDeviceChangeListener constructDeviceChangeListener() {
- return new IDeviceChangeListener() {
- @Override
- public void deviceDisconnected(IDevice device) {
- }
-
- @Override
- public void deviceConnected(IDevice device) {
- }
-
- @Override
- public void deviceChanged(IDevice device, int changeMask) {
- if (changeMask == IDevice.CHANGE_CLIENT_LIST) {
- updateClientList(device);
- }
- }
- };
- }
-
- private void updateClientList(IDevice device) {
- if (mDevice == null) {
- return;
- }
-
- if (!mDevice.equals(device)) {
- return;
- }
-
- mPidToName = new HashMap<String, String>();
- for (Client c : device.getClients()) {
- ClientData cd = c.getClientData();
- String name = cd.getClientDescription();
- int pid = cd.getPid();
-
- /* The name will be null for apps that have just been created.
- * In such a case, we fill in the default name, and wait for the
- * clientChangeListener to do the update with the correct name.
- */
- if (name == null) {
- name = UNKNOWN_APP;
- }
-
- mPidToName.put(Integer.toString(pid), name);
- }
- }
-
- /**
- * Get the application name corresponding to given pid.
- * @param pid application's pid
- * @return application name if available, else {@link LogCatPidToNameMapper#UNKNOWN_APP}.
- */
- public String getName(String pid) {
- String name = mPidToName.get(pid);
- return name != null ? name : UNKNOWN_APP;
- }
-}
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java
index da3e86f..a85cd03 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogCatReceiver.java
@@ -17,10 +17,10 @@
package com.android.ddmuilib.logcat;
import com.android.ddmlib.IDevice;
-import com.android.ddmlib.IShellOutputReceiver;
-import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
-import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.logcat.LogCatListener;
+import com.android.ddmlib.logcat.LogCatMessage;
+import com.android.ddmlib.logcat.LogCatReceiverTask;
import org.eclipse.jface.preference.IPreferenceStore;
@@ -33,19 +33,15 @@ import java.util.Set;
* A class to monitor a device for logcat messages. It stores the received
* log messages in a circular buffer.
*/
-public final class LogCatReceiver {
- private static final String LOGCAT_COMMAND = "logcat -v long";
- private static final int DEVICE_POLL_INTERVAL_MSEC = 1000;
+public final class LogCatReceiver implements LogCatListener {
private static LogCatMessage DEVICE_DISCONNECTED_MESSAGE =
new LogCatMessage(LogLevel.ERROR, "", "", "",
"", "", "Device disconnected");
private LogCatMessageList mLogMessages;
private IDevice mCurrentDevice;
- private LogCatOutputReceiver mCurrentLogCatOutputReceiver;
+ private LogCatReceiverTask mLogCatReceiverTask;
private Set<ILogCatBufferChangeListener> mLogCatMessageListeners;
- private LogCatMessageParser mLogCatMessageParser;
- private LogCatPidToNameMapper mPidToNameMapper;
private IPreferenceStore mPrefStore;
/**
@@ -61,9 +57,6 @@ public final class LogCatReceiver {
mPrefStore = prefStore;
mLogCatMessageListeners = new HashSet<ILogCatBufferChangeListener>();
- mLogCatMessageParser = new LogCatMessageParser();
- mPidToNameMapper = new LogCatPidToNameMapper(mCurrentDevice);
-
mLogMessages = new LogCatMessageList(getFifoSize());
startReceiverThread();
@@ -73,13 +66,14 @@ public final class LogCatReceiver {
* Stop receiving messages from currently active device.
*/
public void stop() {
- if (mCurrentLogCatOutputReceiver != null) {
+ if (mLogCatReceiverTask != null) {
/* stop the current logcat command */
- mCurrentLogCatOutputReceiver.mIsCancelled = true;
- mCurrentLogCatOutputReceiver = null;
+ mLogCatReceiverTask.removeLogCatListener(this);
+ mLogCatReceiverTask.stop();
+ mLogCatReceiverTask = null;
// add a message to the log indicating that the device has been disconnected.
- processLogMessages(Collections.singletonList(DEVICE_DISCONNECTED_MESSAGE));
+ log(Collections.singletonList(DEVICE_DISCONNECTED_MESSAGE));
}
mCurrentDevice = null;
@@ -91,85 +85,26 @@ public final class LogCatReceiver {
}
private void startReceiverThread() {
- mCurrentLogCatOutputReceiver = new LogCatOutputReceiver();
-
- Thread t = new Thread(new Runnable() {
- @Override
- public void run() {
- /* wait while the device comes online */
- while (mCurrentDevice != null && !mCurrentDevice.isOnline()) {
- try {
- Thread.sleep(DEVICE_POLL_INTERVAL_MSEC);
- } catch (InterruptedException e) {
- return;
- }
- }
-
- try {
- if (mCurrentDevice != null) {
- mCurrentDevice.executeShellCommand(LOGCAT_COMMAND,
- mCurrentLogCatOutputReceiver, 0);
- }
- } catch (Exception e) {
- /* There are 4 possible exceptions: TimeoutException,
- * AdbCommandRejectedException, ShellCommandUnresponsiveException and
- * IOException. In case of any of them, the only recourse is to just
- * log this unexpected situation and move on.
- */
- Log.e("Unexpected error while launching logcat. Try reselecting the device.",
- e);
- }
- }
- });
- t.setName("LogCat output receiver for " + mCurrentDevice.getSerialNumber());
- t.start();
- }
-
- /**
- * LogCatOutputReceiver implements {@link MultiLineReceiver#processNewLines(String[])},
- * which is called whenever there is output from logcat. It simply redirects this output
- * to {@link LogCatReceiver#processLogLines(String[])}. This class is expected to be
- * used from a different thread, and the only way to stop that thread is by using the
- * {@link LogCatOutputReceiver#mIsCancelled} variable.
- * See {@link IDevice#executeShellCommand(String, IShellOutputReceiver, int)} for more
- * details.
- */
- private class LogCatOutputReceiver extends MultiLineReceiver {
- private boolean mIsCancelled;
-
- public LogCatOutputReceiver() {
- setTrimLine(false);
+ if (mCurrentDevice == null) {
+ return;
}
- /** Implements {@link IShellOutputReceiver#isCancelled() }. */
- @Override
- public boolean isCancelled() {
- return mIsCancelled;
- }
+ mLogCatReceiverTask = new LogCatReceiverTask(mCurrentDevice);
+ mLogCatReceiverTask.addLogCatListener(this);
- @Override
- public void processNewLines(String[] lines) {
- if (!mIsCancelled) {
- processLogLines(lines);
- }
- }
- }
-
- private void processLogLines(String[] lines) {
- List<LogCatMessage> newMessages = mLogCatMessageParser.processLogLines(lines,
- mPidToNameMapper);
- processLogMessages(newMessages);
+ Thread t = new Thread(mLogCatReceiverTask);
+ t.setName("LogCat output receiver for " + mCurrentDevice.getSerialNumber());
+ t.start();
}
- private void processLogMessages(List<LogCatMessage> newMessages) {
- if (newMessages.size() > 0) {
- List<LogCatMessage> deletedMessages;
- synchronized (mLogMessages) {
- deletedMessages = mLogMessages.ensureSpace(newMessages.size());
- mLogMessages.appendMessages(newMessages);
- }
- sendLogChangedEvent(newMessages, deletedMessages);
+ @Override
+ public void log(List<LogCatMessage> newMessages) {
+ List<LogCatMessage> deletedMessages;
+ synchronized (mLogMessages) {
+ deletedMessages = mLogMessages.ensureSpace(newMessages.size());
+ mLogMessages.appendMessages(newMessages);
}
+ sendLogChangedEvent(newMessages, deletedMessages);
}
/**
diff --git a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializerTest.java b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializerTest.java
index 0fc0c76..e6c0e76 100644
--- a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializerTest.java
+++ b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterSettingsSerializerTest.java
@@ -16,8 +16,10 @@
package com.android.ddmuilib.logcat;
import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.logcat.LogCatFilter;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import junit.framework.TestCase;
@@ -34,7 +36,8 @@ public class LogCatFilterSettingsSerializerTest extends TestCase {
LogLevel.ERROR);
LogCatFilterSettingsSerializer serializer = new LogCatFilterSettingsSerializer();
- String s = serializer.encodeToPreferenceString(Arrays.asList(fs));
+ String s = serializer.encodeToPreferenceString(Arrays.asList(fs),
+ new HashMap<LogCatFilter, LogCatFilterData>());
List<LogCatFilter> decodedFiltersList = serializer.decodeFromPreferenceString(s);
assertEquals(1, decodedFiltersList.size());
@@ -57,10 +60,14 @@ public class LogCatFilterSettingsSerializerTest extends TestCase {
"123", //$NON-NLS-1$
"TestAppName.*", //$NON-NLS-1$
LogLevel.ERROR);
- fs.setTransient();
+ LogCatFilterData fd = new LogCatFilterData(fs);
+ fd.setTransient();
+ HashMap<LogCatFilter, LogCatFilterData> fdMap =
+ new HashMap<LogCatFilter, LogCatFilterData>();
+ fdMap.put(fs, fd);
LogCatFilterSettingsSerializer serializer = new LogCatFilterSettingsSerializer();
- String s = serializer.encodeToPreferenceString(Arrays.asList(fs));
+ String s = serializer.encodeToPreferenceString(Arrays.asList(fs), fdMap);
List<LogCatFilter> decodedFiltersList = serializer.decodeFromPreferenceString(s);
assertEquals(0, decodedFiltersList.size());
diff --git a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterTest.java b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterTest.java
deleted file mode 100644
index 7fedb08..0000000
--- a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatFilterTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.util.List;
-
-import junit.framework.TestCase;
-
-public class LogCatFilterTest extends TestCase {
- public void testFilterByLogLevel() {
- LogCatFilter filter = new LogCatFilter("",
- "", "", "", "", LogLevel.DEBUG);
-
- /* filter message below filter's log level */
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "", "", "");
- assertEquals(false, filter.matches(msg));
-
- /* do not filter message above filter's log level */
- msg = new LogCatMessage(LogLevel.ERROR,
- "", "", "", "", "", "");
- assertEquals(true, filter.matches(msg));
- }
-
- public void testFilterByPid() {
- LogCatFilter filter = new LogCatFilter("",
- "", "", "123", "", LogLevel.VERBOSE);
-
- /* show message with pid matching filter */
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "123", "", "", "", "", "");
- assertEquals(true, filter.matches(msg));
-
- /* don't show message with pid not matching filter */
- msg = new LogCatMessage(LogLevel.VERBOSE,
- "12", "", "", "", "", "");
- assertEquals(false, filter.matches(msg));
- }
-
- public void testFilterByAppNameRegex() {
- LogCatFilter filter = new LogCatFilter("",
- "", "", "", "dalvik.*", LogLevel.VERBOSE);
-
- /* show message with pid matching filter */
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "dalvikvm1", "", "", "");
- assertEquals(true, filter.matches(msg));
-
- /* don't show message with pid not matching filter */
- msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "system", "", "", "");
- assertEquals(false, filter.matches(msg));
- }
-
- public void testFilterByTagRegex() {
- LogCatFilter filter = new LogCatFilter("",
- "tag.*", "", "", "", LogLevel.VERBOSE);
-
- /* show message with tag matching filter */
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "tag123", "", "");
- assertEquals(true, filter.matches(msg));
-
- msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "ta123", "", "");
- assertEquals(false, filter.matches(msg));
- }
-
- public void testFilterByTextRegex() {
- LogCatFilter filter = new LogCatFilter("",
- "", "text.*", "", "", LogLevel.VERBOSE);
-
- /* show message with text matching filter */
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "", "", "text123");
- assertEquals(true, filter.matches(msg));
-
- msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "", "", "te123");
- assertEquals(false, filter.matches(msg));
- }
-
- public void testMatchingText() {
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- "message with word1 and word2"); //$NON-NLS-1$
- assertEquals(true, search("word1 with", msg)); //$NON-NLS-1$
- assertEquals(true, search("text:w.* ", msg)); //$NON-NLS-1$
- assertEquals(false, search("absent", msg)); //$NON-NLS-1$
- }
-
- public void testTagKeyword() {
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "tag", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- "sample message"); //$NON-NLS-1$
- assertEquals(false, search("t.*", msg)); //$NON-NLS-1$
- assertEquals(true, search("tag:t.*", msg)); //$NON-NLS-1$
- }
-
- public void testPidKeyword() {
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "123", "", "", "", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- "sample message"); //$NON-NLS-1$
- assertEquals(false, search("123", msg)); //$NON-NLS-1$
- assertEquals(true, search("pid:123", msg)); //$NON-NLS-1$
- }
-
- public void testAppNameKeyword() {
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "dalvik", "", "", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- "sample message"); //$NON-NLS-1$
- assertEquals(false, search("dalv.*", msg)); //$NON-NLS-1$
- assertEquals(true, search("app:dal.*k", msg)); //$NON-NLS-1$
- }
-
- public void testCaseSensitivity() {
- LogCatMessage msg = new LogCatMessage(LogLevel.VERBOSE,
- "", "", "", "", "",
- "Sample message");
-
- // if regex has an upper case character, it should be
- // treated as a case sensitive search
- assertEquals(false, search("Message", msg));
-
- // if regex is all lower case, then it should be a
- // case insensitive search
- assertEquals(true, search("sample", msg));
- }
-
- /**
- * Helper method: search if the query string matches the message.
- * @param query words to search for
- * @param message text to search in
- * @return true if the encoded query is present in message
- */
- private boolean search(String query, LogCatMessage message) {
- List<LogCatFilter> filters = LogCatFilter.fromString(query,
- LogLevel.VERBOSE);
-
- /* all filters have to match for the query to match */
- for (LogCatFilter f : filters) {
- if (!f.matches(message)) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatMessageParserTest.java b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatMessageParserTest.java
deleted file mode 100644
index dfde250..0000000
--- a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/logcat/LogCatMessageParserTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.ddmuilib.logcat;
-
-import com.android.ddmlib.Log.LogLevel;
-
-import java.util.List;
-
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link LogCatMessageParser}.
- */
-public final class LogCatMessageParserTest extends TestCase {
- private List<LogCatMessage> mParsedMessages;
-
- /** A list of messages generated with the following code:
- * <pre>
- * {@code
- * Log.d("dtag", "debug message");
- * Log.e("etag", "error message");
- * Log.i("itag", "info message");
- * Log.v("vtag", "verbose message");
- * Log.w("wtag", "warning message");
- * Log.wtf("wtftag", "wtf message");
- * Log.d("dtag", "debug message");
- * }
- * </pre>
- * Note: On Android 2.3, Log.wtf doesn't really generate the message.
- * It only produces the message header, but swallows the message tag.
- * This string has been modified to include the message.
- */
- private static final String[] MESSAGES = new String[] {
- "[ 08-11 19:11:07.132 495:0x1ef D/dtag ]", //$NON-NLS-1$
- "debug message", //$NON-NLS-1$
- "[ 08-11 19:11:07.132 495: 234 E/etag ]", //$NON-NLS-1$
- "error message", //$NON-NLS-1$
- "[ 08-11 19:11:07.132 495:0x1ef I/itag ]", //$NON-NLS-1$
- "info message", //$NON-NLS-1$
- "[ 08-11 19:11:07.132 495:0x1ef V/vtag ]", //$NON-NLS-1$
- "verbose message", //$NON-NLS-1$
- "[ 08-11 19:11:07.132 495:0x1ef W/wtag ]", //$NON-NLS-1$
- "warning message", //$NON-NLS-1$
- "[ 08-11 19:11:07.132 495:0x1ef F/wtftag ]", //$NON-NLS-1$
- "wtf message", //$NON-NLS-1$
- "[ 08-11 21:15:35.7524 540:0x21c D/dtag ]", //$NON-NLS-1$
- "debug message", //$NON-NLS-1$
- };
-
- @Override
- protected void setUp() throws Exception {
- LogCatMessageParser parser = new LogCatMessageParser();
- mParsedMessages = parser.processLogLines(MESSAGES, new LogCatPidToNameMapper(null));
- }
-
- /** Check that the correct number of messages are received. */
- public void testMessageCount() {
- assertEquals(7, mParsedMessages.size());
- }
-
- /** Check the log level in a few of the parsed messages. */
- public void testLogLevel() {
- assertEquals(mParsedMessages.get(0).getLogLevel(), LogLevel.DEBUG);
- assertEquals(mParsedMessages.get(5).getLogLevel(), LogLevel.ASSERT);
- }
-
- /** Check the parsed tag. */
- public void testTag() {
- assertEquals(mParsedMessages.get(1).getTag(), "etag"); //$NON-NLS-1$
- }
-
- /** Check the time field. */
- public void testTime() {
- assertEquals(mParsedMessages.get(6).getTime(), "08-11 21:15:35.7524"); //$NON-NLS-1$
- }
-
- /** Check the message field. */
- public void testMessage() {
- assertEquals(mParsedMessages.get(2).getMessage(), MESSAGES[5]);
- }
-
- public void testTid() {
- assertEquals(mParsedMessages.get(0).getTid(), Integer.toString(0x1ef));
- assertEquals(mParsedMessages.get(1).getTid(), "234");
- }
-}
diff --git a/device_validator/dvlib/Android.mk b/device_validator/dvlib/Android.mk
index 8db8260..8d07043 100644
--- a/device_validator/dvlib/Android.mk
+++ b/device_validator/dvlib/Android.mk
@@ -15,27 +15,20 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+# The dvlib code has moved to tools/base/dvlib.
+# The rule below uses the prebuilt dvlib.jar.
+#
+# If you want to run the tests, cd to tools/base/dvlib
+# and run ./gradlew :dvlib:test
+
LOCAL_JAVA_RESOURCE_DIRS := src/main/resources
LOCAL_MODULE := dvlib
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-
-# Build tests
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
-LOCAL_JAVA_RESOURCE_DIRS := src/test/resources
-
-LOCAL_MODULE := dvlib-tests
-LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_PREBUILT)
-LOCAL_JAVA_LIBRARIES := \
- dvlib \
- junit
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/device_validator/dvlib/src/main/java/com/android/dvlib/DeviceSchema.java b/device_validator/dvlib/src/main/java/com/android/dvlib/DeviceSchema.java
deleted file mode 100644
index b02471b..0000000
--- a/device_validator/dvlib/src/main/java/com/android/dvlib/DeviceSchema.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * 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.dvlib;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import javax.xml.XMLConstants;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import javax.xml.validation.Validator;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-public class DeviceSchema {
-
- public static final String NS_DEVICES_XSD = "http://schemas.android.com/sdk/devices/1";
-
- /**
- * The "devices" element is the root element of this schema.
- *
- * It must contain one or more "device" elements that each define the
- * hardware, software, and states for a given device.
- */
- public static final String NODE_DEVICES = "devices";
-
- /**
- * A "device" element contains a "hardware" element, a "software" element
- * for each API version it supports, and a "state" element for each possible
- * state the device could be in.
- */
- public static final String NODE_DEVICE = "device";
-
- /**
- * The "hardware" element contains all of the hardware information for a
- * given device.
- */
- public static final String NODE_HARDWARE = "hardware";
-
- /**
- * The "software" element contains all of the software information for an
- * API version of the given device.
- */
- public static final String NODE_SOFTWARE = "software";
-
- /**
- * The "state" element contains all of the parameters for a given state of
- * the device. It's also capable of redefining hardware configurations if
- * they change based on state.
- */
- public static final String NODE_STATE = "state";
-
- public static final String NODE_KEYBOARD = "keyboard";
-
- public static final String NODE_TOUCH = "touch";
-
- public static final String NODE_GL_EXTENSIONS = "gl-extensions";
-
- public static final String NODE_GL_VERSION = "gl-version";
-
- public static final String NODE_NETWORKING = "networking";
-
- public static final String NODE_REMOVABLE_STORAGE = "removable-storage";
-
- public static final String NODE_FLASH = "flash";
-
- public static final String NODE_LIVE_WALLPAPER_SUPPORT = "live-wallpaper-support";
-
- public static final String NODE_STATUS_BAR = "status-bar";
-
- public static final String NODE_BUTTONS = "buttons";
-
- public static final String NODE_CAMERA = "camera";
-
- public static final String NODE_LOCATION = "location";
-
- public static final String NODE_GPU = "gpu";
-
- public static final String NODE_DOCK = "dock";
-
- public static final String NODE_YDPI = "ydpi";
-
- public static final String NODE_POWER_TYPE= "power-type";
-
- public static final String NODE_Y_DIMENSION = "y-dimension";
-
- public static final String NODE_SCREEN_RATIO = "screen-ratio";
-
- public static final String NODE_NAV_STATE = "nav-state";
-
- public static final String NODE_MIC = "mic";
-
- public static final String NODE_RAM = "ram";
-
- public static final String NODE_XDPI = "xdpi";
-
- public static final String NODE_DIMENSIONS = "dimensions";
-
- public static final String NODE_ABI = "abi";
-
- public static final String NODE_MECHANISM = "mechanism";
-
- public static final String NODE_MULTITOUCH = "multitouch";
-
- public static final String NODE_NAV = "nav";
-
- public static final String NODE_PIXEL_DENSITY = "pixel-density";
-
- public static final String NODE_SCREEN_ORIENTATION = "screen-orientation";
-
- public static final String NODE_AUTOFOCUS = "autofocus";
-
- public static final String NODE_SCREEN_SIZE = "screen-size";
-
- public static final String NODE_DESCRIPTION = "description";
-
- public static final String NODE_BLUETOOTH_PROFILES = "bluetooth-profiles";
-
- public static final String NODE_SCREEN = "screen";
-
- public static final String NODE_SENSORS = "sensors";
-
- public static final String NODE_DIAGONAL_LENGTH = "diagonal-length";
-
- public static final String NODE_SCREEN_TYPE = "screen-type";
-
- public static final String NODE_KEYBOARD_STATE = "keyboard-state";
-
- public static final String NODE_X_DIMENSION = "x-dimension";
-
- public static final String NODE_CPU = "cpu";
-
- public static final String NODE_INTERNAL_STORAGE = "internal-storage";
-
- public static final String NODE_META = "meta";
-
- public static final String NODE_ICONS = "icons";
-
- public static final String NODE_SIXTY_FOUR = "sixty-four";
-
- public static final String NODE_SIXTEEN = "sixteen";
-
- public static final String NODE_FRAME = "frame";
-
- public static final String NODE_PATH = "path";
-
- public static final String NODE_PORTRAIT_X_OFFSET = "portrait-x-offset";
-
- public static final String NODE_PORTRAIT_Y_OFFSET = "portrait-y-offset";
-
- public static final String NODE_LANDSCAPE_X_OFFSET = "landscape-x-offset";
-
- public static final String NODE_LANDSCAPE_Y_OFFSET = "landscape-y-offset";
-
- public static final String NODE_NAME = "name";
-
- public static final String NODE_API_LEVEL = "api-level";
-
- public static final String NODE_MANUFACTURER = "manufacturer";
-
- public static final String ATTR_DEFAULT = "default";
-
- public static final String ATTR_UNIT = "unit";
-
- public static final String ATTR_NAME = "name";
-
- /**
- * Validates the input stream.
- *
- * @param deviceXml
- * The XML InputStream to validate.
- * @param out
- * The OutputStream for error messages.
- * @param parent
- * The parent directory of the input stream.
- * @return Whether the given input constitutes a valid devices file.
- */
- public static boolean validate(InputStream deviceXml, OutputStream out, File parent) {
- Schema s;
- SAXParserFactory factory = SAXParserFactory.newInstance();
- PrintWriter writer = new PrintWriter(out);
- try {
- s = DeviceSchema.getSchema();
- factory.setValidating(false);
- factory.setNamespaceAware(true);
- factory.setSchema(s);
- ValidationHandler validator = new ValidationHandler(parent, writer);
- SAXParser parser = factory.newSAXParser();
- parser.parse(deviceXml, validator);
- return validator.isValidDevicesFile();
- } catch (SAXException e) {
- writer.println(e.getMessage());
- return false;
- } catch (ParserConfigurationException e) {
- writer.println("Error creating SAX parser:");
- writer.println(e.getMessage());
- return false;
- } catch (IOException e) {
- writer.println("Error reading file stream:");
- writer.println(e.getMessage());
- return false;
- } finally {
- writer.flush();
- }
- }
-
- /**
- * Helper to get an input stream of the device config XML schema.
- */
- public static InputStream getXsdStream() {
- return DeviceSchema.class.getResourceAsStream("devices.xsd"); //$NON-NLS-1$
- }
-
- /** Helper method that returns a {@link Validator} for our XSD */
- public static Schema getSchema() throws SAXException {
- InputStream xsdStream = getXsdStream();
- SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- Schema schema = factory.newSchema(new StreamSource(xsdStream));
- return schema;
- }
-
- /**
- * A DefaultHandler that parses only to validate the XML is actually a valid
- * devices config, since validation can't be entirely encoded in the devices
- * schema.
- */
- private static class ValidationHandler extends DefaultHandler {
- private boolean mValidDevicesFile = true;
- private boolean mDefaultSeen = false;
- private String mDeviceName;
- private final File mDirectory;
- private final PrintWriter mWriter;
- private final StringBuilder mStringAccumulator = new StringBuilder();
-
- public ValidationHandler(File directory, PrintWriter writer) {
- mDirectory = directory; // Possibly null
- mWriter = writer;
- }
-
- @Override
- public void startElement(String uri, String localName, String name, Attributes attributes)
- throws SAXException {
- if (NODE_DEVICE.equals(localName)) {
- // Reset for a new device
- mDefaultSeen = false;
- } else if (NODE_STATE.equals(localName)) {
- // Check if the state is set to be a default state
- String val = attributes.getValue(ATTR_DEFAULT);
- if (val != null && ("1".equals(val) || Boolean.parseBoolean(val))) {
- /*
- * If it is and we already have a default state for this
- * device, then the device configuration is invalid.
- * Otherwise, set that we've seen a default state for this
- * device and continue
- */
-
- if (mDefaultSeen) {
- validationError("More than one default state for device " + mDeviceName);
- } else {
- mDefaultSeen = true;
- }
- }
- }
- mStringAccumulator.setLength(0);
- }
-
- @Override
- public void characters(char[] ch, int start, int length) {
- mStringAccumulator.append(ch, start, length);
- }
-
- @Override
- public void endElement(String uri, String localName, String name) throws SAXException {
- // If this is the end of a device node, make sure we have at least
- // one default state
- if (NODE_DEVICE.equals(localName) && !mDefaultSeen) {
- validationError("No default state for device " + mDeviceName);
- } else if (NODE_NAME.equals(localName)) {
- mDeviceName = mStringAccumulator.toString().trim();
- } else if (NODE_PATH.equals(localName) || NODE_SIXTY_FOUR.equals(localName)
- || NODE_SIXTEEN.equals(localName)) {
- if (mDirectory == null) {
- // There is no given parent directory, so this is not a
- // valid devices file
- validationError("No parent directory given, but relative paths exist.");
- return;
- }
- // This is going to break on any files that end with a space,
- // but that should be an incredibly rare corner case.
- String relativePath = mStringAccumulator.toString().trim();
- File f = new File(mDirectory, relativePath);
- if (f == null || !f.isFile()) {
- validationError(relativePath + " is not a valid path.");
- return;
- }
- String fileName = f.getName();
- int extensionStart = fileName.lastIndexOf(".");
- if (extensionStart == -1 || !fileName.substring(extensionStart + 1).equals("png")) {
- validationError(relativePath + " is not a valid file type.");
- }
- }
- }
-
- @Override
- public void error(SAXParseException e) {
- validationError(e.getMessage());
- }
-
- @Override
- public void fatalError(SAXParseException e) {
- validationError(e.getMessage());
- }
-
- public boolean isValidDevicesFile() {
- return mValidDevicesFile;
- }
-
- private void validationError(String reason) {
- mWriter.println("Error: " + reason);
- mValidDevicesFile = false;
- }
-
- }
-}
diff --git a/device_validator/dvlib/src/main/resources/com/android/dvlib/devices.xsd b/device_validator/dvlib/src/main/resources/com/android/dvlib/devices.xsd
deleted file mode 100644
index bfa915f..0000000
--- a/device_validator/dvlib/src/main/resources/com/android/dvlib/devices.xsd
+++ /dev/null
@@ -1,892 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * 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.
--->
-
-<xsd:schema
- targetNamespace="http://schemas.android.com/sdk/devices/1"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:c="http://schemas.android.com/sdk/devices/1"
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- version="1">
-
- <xsd:element name="devices" type="c:devicesType" />
-
- <xsd:complexType name="devicesType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The "devices" element is the root element of this schema.
-
- It must contain one or more "device" elements that each define the configurations
- and states available for a given device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="device" minOccurs="1" maxOccurs="unbounded">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- A device element contains one hardware profile for a device, along with
- 1 or more software profiles and 1 or more states. Each software profile
- defines the supported software for a given API release, and each state
- profile defines a different possible state of the device (screen in
- portrait orientation, screen in landscape orientation with the keyboard
- out, etc.)
- </xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="name" type= "xsd:token" />
- <xsd:element name="manufacturer" type= "xsd:token" />
- <xsd:element name="meta" type= "c:metaType" minOccurs="0" />
- <xsd:element name="hardware" type= "c:hardwareType" />
- <xsd:element name="software" type= "c:softwareType"
- maxOccurs="unbounded" />
- <xsd:element name="state" type= "c:stateType"
- maxOccurs="unbounded" />
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:complexType name="hardwareType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The hardwareType contains all of the hardware information for
- a given device. This includes things like the GPU type, screen
- size, mic presence, etc.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="screen" type= "c:screenType" />
- <xsd:element name="networking" type= "c:networkingType" />
- <xsd:element name="sensors" type= "c:sensorsType" />
- <xsd:element name="mic" type= "c:micType" />
- <xsd:element name="camera" type= "c:cameraType"
- minOccurs="0" maxOccurs="unbounded" />
- <xsd:element name="keyboard" type= "c:keyboardType" />
- <xsd:element name="nav" type= "c:navType" />
- <xsd:element name="ram" type= "c:ramType" />
- <xsd:element name="buttons" type= "c:buttonsType" />
- <xsd:element name="internal-storage" type= "c:internalStorageType" />
- <xsd:element name="removable-storage" type= "c:removableStorageType" />
- <xsd:element name="cpu" type= "c:cpuType" />
- <xsd:element name="gpu" type= "c:gpuType" />
- <xsd:element name="abi" type= "c:abiType" />
- <xsd:element name="dock" type= "c:dockType" />
- <xsd:element name="power-type" type= "c:powerType" />
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:complexType name="softwareType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The softwareType contains all of the device's software
- information for a given API version. This includes things like
- live wallpaper support, OpenGL version, etc.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="api-level">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies which API version(s) this this element is
- defining. This can in the form of a single number
- or a range of low to high, separated with a dash and
- with either limit missing. The default lower limit is
- one, and the default upper limit is unbounded.
- The following are valid:
- 10
- 7-10
- -10
- 7-
- -
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:pattern value="[\d]*-[\d]*|[\d]+" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="live-wallpaper-support" type="xsd:boolean">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the device supports live wallpapers.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
-
- <xsd:element name="bluetooth-profiles">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies all of the available Bluetooth profiles.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:NMTOKEN">
- <xsd:enumeration value="A2DP" />
- <xsd:enumeration value="ATT" />
- <xsd:enumeration value="AVRCP" />
- <xsd:enumeration value="AVDTP" />
- <xsd:enumeration value="BIP" />
- <xsd:enumeration value="BPP" />
- <xsd:enumeration value="CIP" />
- <xsd:enumeration value="CTP" />
- <xsd:enumeration value="DIP" />
- <xsd:enumeration value="DUN" />
- <xsd:enumeration value="FAX" />
- <xsd:enumeration value="FTP" />
- <xsd:enumeration value="GAVDP" />
- <xsd:enumeration value="GAP" />
- <xsd:enumeration value="GATT" />
- <xsd:enumeration value="GOEP" />
- <xsd:enumeration value="HCRP" />
- <xsd:enumeration value="HDP" />
- <xsd:enumeration value="HFP" />
- <xsd:enumeration value="HID" />
- <xsd:enumeration value="HSP" />
- <xsd:enumeration value="ICP" />
- <xsd:enumeration value="LAP" />
- <xsd:enumeration value="MAP" />
- <xsd:enumeration value="OPP" />
- <xsd:enumeration value="PAN" />
- <xsd:enumeration value="PBA" />
- <xsd:enumeration value="PBAP" />
- <xsd:enumeration value="SPP" />
- <xsd:enumeration value="SDAP" />
- <xsd:enumeration value="SAP" />
- <xsd:enumeration value="SIM" />
- <xsd:enumeration value="rSAP" />
- <xsd:enumeration value="SYNCH" />
- <xsd:enumeration value="VDP" />
- <xsd:enumeration value="WAPB" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="gl-version">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the OpenGL version supported for this release.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:decimal">
- <xsd:pattern value="[0-9]\.[0-9]" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="gl-extensions">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies all of the supported OpenGL extensions for
- this release.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:list itemType="xsd:NMTOKEN" />
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="status-bar" type="xsd:boolean">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the device has a status bar in this
- software configuration.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:complexType name="stateType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The stateType contains the information for a given state of
- of the device. States include things like portrait mode,
- landscape with the keyboard exposed, etc. States can also
- modify the hardware attributes of a device. For instance, if
- sliding out the keyboard increased the available screen
- real estate, you can define a new screenType to override the
- default one defined in the device's hardwareType.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="description" type="xsd:token">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- A description of the defined state.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
-
- <xsd:element name="screen-orientation">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Defines the orientation of the screen. Use square if
- the device's screen has equal height and width,
- otherwise use landscape or portrait.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="port" />
- <xsd:enumeration value="land" />
- <xsd:enumeration value="square" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="keyboard-state">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Defines the state of the keyboard. If the device has no
- keyboard use keysoft, otherwise use keysexposed or keyshidden.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="keyssoft" />
- <xsd:enumeration value="keyshidden" />
- <xsd:enumeration value="keysexposed" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="nav-state">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Defines the state of the primary non-touchscreen
- navigation hardware on the devices. If the device
- doesn't have non-touchscreen navigation hardware use
- nonav, otherwise use navexposed or navhidden.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="nonav" />
- <xsd:enumeration value="navhidden" />
- <xsd:enumeration value="navexposed" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="screen" type="c:screenType" minOccurs="0" />
- <xsd:element name="networking" type="c:networkingType"
- minOccurs="0" />
- <xsd:element name="sensors" type="c:sensorsType" minOccurs="0" />
- <xsd:element name="mic" type="c:micType" minOccurs="0" />
- <xsd:element name="camera" type="c:cameraType"
- minOccurs="0" maxOccurs="unbounded" />
- <xsd:element name="keyboard" type="c:keyboardType" minOccurs="0" />
- <xsd:element name="nav" type="c:navType" minOccurs="0" />
- <xsd:element name="ram" type="c:ramType" minOccurs="0" />
- <xsd:element name="buttons" type="c:buttonsType" minOccurs="0" />
- <xsd:element name="internal-storage" type="c:internalStorageType"
- minOccurs="0" />
- <xsd:element name="removable-storage" type="c:removableStorageType"
- minOccurs="0" />
- <xsd:element name="cpu" type="c:cpuType" minOccurs="0" />
- <xsd:element name="gpu" type="c:gpuType" minOccurs="0" />
- <xsd:element name="abi" type="c:abiType" minOccurs="0" />
- <xsd:element name="dock" type="c:dockType" minOccurs="0" />
- <xsd:element name="power-type" type="c:powerType"
- minOccurs="0" />
- </xsd:sequence>
- <xsd:attribute name="name" use="required" type="xsd:token" />
- <xsd:attribute name="default" use="optional" type="xsd:boolean" />
- </xsd:complexType>
-
- <xsd:complexType name="metaType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Details where more device information can be found, such as
- icons and frame images.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="icons" minOccurs="0">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Contains the relative paths to the icon files for this
- device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="sixty-four" type="xsd:normalizedString">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Relative path for the 64x64 icon.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="sixteen" type="xsd:normalizedString"
- minOccurs="0">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Relative path for the 16x16 icon.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="frame" minOccurs="0">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Contains information about the frame for the device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="path"
- type="xsd:normalizedString">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The relative path to the emulator frame for
- the device.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="portrait-x-offset"
- type="xsd:nonNegativeInteger">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The offset for the frame in the x direction,
- in portrait mode.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="portrait-y-offset"
- type="xsd:nonNegativeInteger">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The offset for the frame in the y direction,
- in portrait mode.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="landscape-x-offset"
- type="xsd:nonNegativeInteger">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The offset for the frame in the x direction,
- in landscape mode.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- <xsd:element name="landscape-y-offset"
- type="xsd:nonNegativeInteger">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- The offset for the frame in the y direction,
- in landscape mode.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:complexType name="screenType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Contains the specifications for the device's screen.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="screen-size">
- <xsd:simpleType>
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the class of the screen.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="small" />
- <xsd:enumeration value="normal" />
- <xsd:enumeration value="large" />
- <xsd:enumeration value="xlarge" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="diagonal-length">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the diagonal length of the screen in inches.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:decimal">
- <!-- Negative lengths are not valid -->
- <xsd:minInclusive value="0" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="pixel-density">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the screen density of the device. The
- medium density of traditional HVGA screens (mdpi)
- is defined to be approximately 160dpi; low density
- (ldpi) is 120, and high density (hdpi) is 240. There
- is thus a 4:3 scaling factor between each density,
- so a 9x9 bitmap in ldpi would be 12x12 in mdpi and
- 16x16 in hdpi.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="ldpi" />
- <xsd:enumeration value="mdpi" />
- <xsd:enumeration value="tvdpi" />
- <xsd:enumeration value="hdpi" />
- <xsd:enumeration value="xhdpi" />
- <xsd:enumeration value="xxhdpi" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="screen-ratio">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the configuration is for a taller or
- wider than traditional screen. This is based purely on
- the aspect ratio of the screen: QVGA, HVGA, and VGA are
- notlong; WQVGA, WVGA, FWVGA are long. Note that long may
- mean either wide or tall, depending on the current
- orientation.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="notlong" />
- <xsd:enumeration value="long" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="dimensions">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the device screen resolution in pixels.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="x-dimension">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the x-dimension's resolution in
- pixels.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:positiveInteger" />
- </xsd:simpleType>
- </xsd:element>
- <xsd:element name="y-dimension">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the y-dimension's resolution in
- pixels.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:positiveInteger" />
- </xsd:simpleType>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
-
- <xsd:element name="xdpi">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the actual density in X of the device screen.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:decimal">
- <!-- Negative DPIs are not valid -->
- <xsd:minInclusive value="0" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="ydpi">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the actual density in Y of the device screen.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:decimal">
- <!-- Negative DPIs are not valid -->
- <xsd:minInclusive value="0" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="touch">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the touch properties of the device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="multitouch">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the multitouch capabilities of the
- device. This can be none if multitouch is
- not supported, basic if the device can track
- only basic two finger gestures, distinct if
- the device can track two or more fingers
- simultaneously, or jazz-hands if the device
- can track 5 or more fingers simultaneously.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="none" />
- <xsd:enumeration value="basic" />
- <xsd:enumeration value="distinct" />
- <xsd:enumeration value="jazz-hands" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="mechanism">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the mechanism the device was
- created for.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="notouch" />
- <xsd:enumeration value="stylus" />
- <xsd:enumeration value="finger" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="screen-type">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the type of touch screen on the
- device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="notouch" />
- <xsd:enumeration value="capacitive" />
- <xsd:enumeration value="resistive" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
- </xsd:element>
-
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:simpleType name="networkingType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the available networking hardware.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="NFC" />
- <xsd:enumeration value="Bluetooth" />
- <xsd:enumeration value="Wifi" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
-
- <xsd:simpleType name="sensorsType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the available sensors.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="Accelerometer" />
- <xsd:enumeration value="Barometer" />
- <xsd:enumeration value="Compass" />
- <xsd:enumeration value="GPS" />
- <xsd:enumeration value="Gyroscope" />
- <xsd:enumeration value="LightSensor" />
- <xsd:enumeration value="ProximitySensor" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
-
- <xsd:simpleType name="micType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the device has a mic or not.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:boolean" />
- </xsd:simpleType>
-
- <xsd:complexType name="cameraType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the attributes of the camera.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:sequence>
- <xsd:element name="location">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the location of the camera.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="front" />
- <xsd:enumeration value="back" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:element>
-
- <xsd:element name="autofocus" type="xsd:boolean">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the camera can autofocus
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
-
- <xsd:element name="flash" type="xsd:boolean">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the camera has flash.
- </xsd:documentation>
- </xsd:annotation>
- </xsd:element>
- </xsd:sequence>
- </xsd:complexType>
-
- <xsd:simpleType name="keyboardType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the type of keyboard on the device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="qwerty" />
- <xsd:enumeration value="12key" />
- <xsd:enumeration value="nokeys" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:simpleType name="navType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the primary non-touchscreen navigation
- hardware on the device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="dpad" />
- <xsd:enumeration value="trackball" />
- <xsd:enumeration value="wheel" />
- <xsd:enumeration value="nonav" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:complexType name="ramType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the amount of RAM on the device in the unit provided.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleContent>
- <xsd:extension base="xsd:positiveInteger">
- <xsd:attribute name="unit" type="c:storageUnitType" use="required" />
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
-
- <xsd:simpleType name="buttonsType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the device has physical (hard) buttons
- (Home, Search, etc.), or uses soft buttons.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="hard" />
- <xsd:enumeration value="soft" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:complexType name="internalStorageType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- A list specifying the sizes of internal storage in
- the device, in the storage size unit provided.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleContent>
- <xsd:extension base="c:storageListType">
- <xsd:attribute name="unit" type="c:storageUnitType"
- use="required" />
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
-
- <xsd:complexType name="removableStorageType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the range of available removable storage sizes
- in the unit provided. A positive value indicates the device is
- available with that storage size included while a zero value
- indicates an empty storage slot.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:simpleContent>
- <xsd:extension base="c:storageListType">
- <xsd:attribute name="unit" type="c:storageUnitType"
- use="required" />
- </xsd:extension>
- </xsd:simpleContent>
- </xsd:complexType>
-
- <xsd:simpleType name="storageListType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Defines a list for storage configurations such as internal or
- removable storage. A positive value indicates the the device
- has a storage unit of that size, while a zero value indicates
- there is an empty location for a storage unit (such as an empty
- SD card slot).
- </xsd:documentation>
- </xsd:annotation>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:nonNegativeInteger" />
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
- <xsd:simpleType name="gpuType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the device's GPU.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:minLength value="1" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:simpleType name="cpuType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the device's CPU.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:minLength value="1" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:simpleType name="abiType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies which ABIs the device conforms to.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="armeabi" />
- <xsd:enumeration value="armeabi-v7a" />
- <xsd:enumeration value="x86" />
- <xsd:enumeration value="mips" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
-
- <xsd:simpleType name="dockType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the official docks available for the device.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:list>
- <xsd:simpleType>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="desk" />
- <xsd:enumeration value="television" />
- <xsd:enumeration value="car" />
- </xsd:restriction>
- </xsd:simpleType>
- </xsd:list>
- </xsd:simpleType>
-
- <xsd:simpleType name="powerType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies whether the device is plugged in.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="plugged-in" />
- <xsd:enumeration value="battery" />
- </xsd:restriction>
- </xsd:simpleType>
-
- <xsd:simpleType name="storageUnitType">
- <xsd:annotation>
- <xsd:documentation xml:lang="en">
- Specifies the unit of storage. This can be MiB, GiB, etc.
- </xsd:documentation>
- </xsd:annotation>
- <xsd:restriction base="xsd:token">
- <xsd:enumeration value="B" />
- <xsd:enumeration value="KiB" />
- <xsd:enumeration value="MiB" />
- <xsd:enumeration value="GiB" />
- <xsd:enumeration value="TiB" />
- </xsd:restriction>
- </xsd:simpleType>
-
-</xsd:schema>
diff --git a/device_validator/dvlib/src/test/java/com/android/dvlib/DeviceSchemaTest.java b/device_validator/dvlib/src/test/java/com/android/dvlib/DeviceSchemaTest.java
deleted file mode 100644
index de70ef3..0000000
--- a/device_validator/dvlib/src/test/java/com/android/dvlib/DeviceSchemaTest.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.dvlib;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Stack;
-
-import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import junit.framework.TestCase;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-public class DeviceSchemaTest extends TestCase {
-
- private void checkFailure(Map<String, String> replacements, String regex) throws Exception {
- // Generate XML stream with replacements
- InputStream xmlStream = getReplacedStream(replacements);
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- assertFalse(
- "Validation Assertion Failed, XML failed to validate when it was expected to pass\n",
- DeviceSchema.validate(xmlStream, baos, null));
- assertTrue(String.format("Regex Assertion Failed:\nExpected: %s\nActual: %s\n", regex, baos
- .toString().trim()), baos.toString().trim().matches(regex));
- }
-
- private void checkFailure(String resource, String regex) throws Exception {
- InputStream xml = DeviceSchemaTest.class.getResourceAsStream(resource);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- assertFalse("Validation Assertion Failed, XML validated when it was expected to fail\n",
- DeviceSchema.validate(xml, baos, null));
- assertTrue(String.format("Regex Assertion Failed:\nExpected: %s\nActual: %s\n", regex, baos
- .toString().trim()), baos.toString().trim().matches(regex));
- }
-
- private void checkSuccess(Map<String, String> replacements) throws Exception {
- InputStream xmlStream = getReplacedStream(replacements);
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- assertTrue(DeviceSchema.validate(xmlStream, baos, null));
- assertTrue(baos.toString().trim().matches(""));
- }
-
- public static InputStream getReplacedStream(Map<String, String> replacements) throws Exception {
- InputStream xml = DeviceSchema.class.getResourceAsStream("devices_minimal.xml");
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- SAXParser parser = factory.newSAXParser();
- ReplacementHandler replacer = new ReplacementHandler(replacements);
- parser.parse(xml, replacer);
- Document doc = replacer.getGeneratedDocument();
- Transformer tf = TransformerFactory.newInstance().newTransformer();
- // Add indents so we're closer to user generated output
- tf.setOutputProperty(OutputKeys.INDENT, "yes");
- DOMSource source = new DOMSource(doc);
- StringWriter out = new StringWriter();
- StreamResult result = new StreamResult(out);
- tf.transform(source, result);
- return new ByteArrayInputStream(out.toString().getBytes("UTF-8"));
- }
-
- public void testValidXml() throws Exception {
- InputStream xml = DeviceSchemaTest.class.getResourceAsStream("devices.xml");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- boolean result = DeviceSchema.validate(xml, baos, null);
- String output = baos.toString().trim();
- assertTrue(
- String.format(
- "Validation Assertion Failed, XML failed to validate when it was expected to pass\n%s\n",output), result);
- assertTrue(String.format("Regex Assertion Failed\nExpected No Output\nActual: %s\n", baos
- .toString().trim()), baos.toString().trim().matches(""));
- }
-
- public void testNoHardware() throws Exception {
- String regex = "Error: cvc-complex-type.2.4.a: Invalid content was found starting with "
- + "element 'd:software'.*";
- checkFailure("devices_no_hardware.xml", regex);
- }
-
- public void testNoSoftware() throws Exception {
- String regex = "Error: cvc-complex-type.2.4.a: Invalid content was found starting with "
- + "element 'd:state'.*";
- checkFailure("devices_no_software.xml", regex);
- }
-
- public void testNoDefault() throws Exception {
- String regex = "Error: No default state for device Galaxy Nexus.*";
- checkFailure("devices_no_default.xml", regex);
- }
-
- public void testTooManyDefaults() throws Exception {
- String regex = "Error: More than one default state for device Galaxy Nexus.*";
- checkFailure("devices_too_many_defaults.xml", regex);
- }
-
- public void testNoStates() throws Exception {
- String regex = "Error: cvc-complex-type.2.4.b: The content of element 'd:device' is not "
- + "complete.*\nError: No default state for device Galaxy Nexus.*";
- checkFailure("devices_no_states.xml", regex);
- }
-
- public void testBadMechanism() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_MECHANISM, "fanger");
- checkFailure(replacements, "Error: cvc-enumeration-valid: Value 'fanger' is not "
- + "facet-valid.*\nError: cvc-type.3.1.3: The value 'fanger' of element "
- + "'d:mechanism' is not valid.*");
- }
-
- public void testNegativeXdpi() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_XDPI, "-1.0");
- checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1.0'.*\n"
- + "Error: cvc-type.3.1.3: The value '-1.0' of element 'd:xdpi' is not valid.*");
- }
-
- public void testNegativeYdpi() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_YDPI, "-1");
- checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1'.*\n"
- + "Error: cvc-type.3.1.3: The value '-1' of element 'd:ydpi' is not valid.*");
-
- }
-
- public void testNegativeDiagonalLength() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_DIAGONAL_LENGTH, "-1.0");
-
- checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1.0'.*\n"
- + "Error: cvc-type.3.1.3: The value '-1.0' of element 'd:diagonal-length'.*");
-
- }
-
- public void testInvalidOpenGLVersion() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_GL_VERSION, "2");
- checkFailure(replacements, "Error: cvc-pattern-valid: Value '2' is not facet-valid.*\n"
- + "Error: cvc-type.3.1.3: The value '2' of element 'd:gl-version' is not valid.*");
- }
-
- public void testEmptyOpenGLExtensions() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_GL_EXTENSIONS, "");
- checkSuccess(replacements);
- }
-
- public void testEmptySensors() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_SENSORS, "");
- checkSuccess(replacements);
- }
-
- public void testEmptyNetworking() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_NETWORKING, "");
- checkSuccess(replacements);
- }
-
- public void testEmptyCpu() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_CPU, "");
- checkFailure(replacements, "Error: cvc-minLength-valid: Value '' with length = '0'.*\n"
- + "Error: cvc-type.3.1.3: The value '' of element 'd:cpu' is not valid.*");
- }
-
- public void testEmptyGpu() throws Exception {
- Map<String, String> replacements = new HashMap<String, String>();
- replacements.put(DeviceSchema.NODE_GPU, "");
- checkFailure(replacements, "Error: cvc-minLength-valid: Value '' with length = '0'.*\n"
- + "Error: cvc-type.3.1.3: The value '' of element 'd:gpu' is not valid.*");
- }
-
- /**
- * Reads in a valid devices XML file and if an element tag is in the
- * replacements map, it replaces its text content with the corresponding
- * value. Note this has no concept of namespaces or hierarchy, so it will
- * replace the contents any and all elements with the specified tag name.
- */
- private static class ReplacementHandler extends DefaultHandler {
- private Element mCurrElement = null;
- private Document mDocument;
- private final Stack<Element> mElementStack = new Stack<Element>();
- private final Map<String, String> mPrefixes = new HashMap<String, String>();
- private final Map<String, String> mReplacements;
- private final StringBuilder mStringAccumulator = new StringBuilder();
-
- public ReplacementHandler(Map<String, String> replacements) {
- mReplacements = replacements;
- }
-
- @Override
- public void startDocument() {
- try {
- mDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
- } catch (ParserConfigurationException e) {
- fail(e.getMessage());
- }
- }
-
- @Override
- public void startElement(String uri, String localName, String name, Attributes attributes) {
- Element element = mDocument.createElement(name);
- for (int i = 0; i < attributes.getLength(); i++) {
- element.setAttribute(attributes.getQName(i), attributes.getValue(i));
- }
- for (String key : mPrefixes.keySet()) {
- element.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + key, mPrefixes.get(key));
- }
- mPrefixes.clear();
- if (mCurrElement != null) {
- mElementStack.push(mCurrElement);
- }
- mCurrElement = element;
- }
-
- @Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- mPrefixes.put(prefix, uri);
- }
-
- @Override
- public void characters(char[] ch, int start, int length) {
- mStringAccumulator.append(ch, start, length);
- }
-
- @Override
- public void endElement(String uri, String localName, String name) throws SAXException {
- if (mReplacements.containsKey(localName)) {
- mCurrElement.appendChild(mDocument.createTextNode(mReplacements.get(localName)));
- } else {
- String content = mStringAccumulator.toString().trim();
- if (!content.isEmpty()) {
- mCurrElement.appendChild(mDocument.createTextNode(content));
- }
- }
-
- if (mElementStack.empty()) {
- mDocument.appendChild(mCurrElement);
- mCurrElement = null;
- } else {
- Element parent = mElementStack.pop();
- parent.appendChild(mCurrElement);
- mCurrElement = parent;
- }
- mStringAccumulator.setLength(0);
- }
-
- @Override
- public void error(SAXParseException e) {
- fail(e.getMessage());
- }
-
- @Override
- public void fatalError(SAXParseException e) {
- fail(e.getMessage());
- }
-
- public Document getGeneratedDocument() {
- return mDocument;
- }
-
- }
-}
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices.xml
deleted file mode 100644
index 6662099..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices.xml
+++ /dev/null
@@ -1,273 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock>
- </d:dock>
- <!-- plugged in (never, charge, always) -->
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>14-</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- <d:state name="Landscape">
- <d:description>The phone in landscape view</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
- <d:device>
- <d:name>Droid</d:name>
- <d:manufacturer>Motorola</d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>3.7</d:diagonal-length>
- <d:pixel-density>hdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>480</d:x-dimension>
- <d:y-dimension>854</d:y-dimension>
- </d:dimensions>
- <d:xdpi>265</d:xdpi>
- <d:ydpi>265</d:ydpi>
- <d:touch>
- <d:multitouch>distinct</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Compass
- GPS
- ProximitySensor
- LightSensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>qwerty</d:keyboard>
- <d:nav>dpad</d:nav>
- <d:ram unit="MiB">256</d:ram>
- <d:buttons>hard</d:buttons>
- <d:internal-storage unit="MiB">512</d:internal-storage>
- <d:removable-storage unit="GiB">16</d:removable-storage>
- <d:cpu>OMAP 3430</d:cpu>
- <d:gpu>PowerVR SGX 53</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <d:dock>
- car
- desk
- </d:dock>
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>5-8</d:api-level>
- <d:live-wallpaper-support>false</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- GAP
- SPP
- HSP
- HFP
- A2DP
- AVRCP
- SDAP
- </d:bluetooth-profiles>
- <d:gl-version>1.1</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_OES_byte_coordinates
- GL_OES_fixed_point
- GL_OES_single_precision
- GL_OES_matrix_get
- GL_OES_read_format
- GL_OES_compressed_paletted_texture
- GL_OES_point_sprite
- GL_OES_point_size_array
- GL_OES_matrix_palette
- GL_OES_draw_texture
- GL_OES_query_matrix
- GL_OES_texture_env_crossbar
- GL_OES_texture_mirrored_repeat
- GL_OES_texture_cube_map
- GL_OES_blend_subtract
- GL_OES_blend_func_separate
- GL_OES_blend_equation_separate
- GL_OES_stencil_wrap
- GL_OES_extended_matrix_palette
- GL_OES_framebuffer_object
- GL_OES_rgb8_rgba8
- GL_OES_depth24
- GL_OES_stencil8
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_mapbuffer
- GL_OES_EGL_image
- GL_EXT_multi_draw_arrays
- GL_OES_required_internalformat
- GL_IMG_read_format
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_EXT_texture_format_BGRA8888
- GL_IMG_texture_stream
- GL_IMG_vertex_program
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyshidden</d:keyboard-state>
- <d:nav-state>navhidden</d:nav-state>
- </d:state>
- <d:state name="Landscape, closed">
- <d:description>The phone in landscape view with the keyboard closed</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keyshidden</d:keyboard-state>
- <d:nav-state>navhidden</d:nav-state>
- </d:state>
- <d:state name="Landscape, open">
- <d:description>The phone in landscape view with the keyboard open</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keysexposed</d:keyboard-state>
- <d:nav-state>navexposed</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_minimal.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_minimal.xml
deleted file mode 100644
index e063fd1..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_minimal.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock></d:dock>
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>15</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- <d:state name="Landscape">
- <d:description>The phone in landscape view</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_default.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_default.xml
deleted file mode 100644
index 605a6c1..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_default.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock>
- </d:dock>
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>14</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_hardware.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_hardware.xml
deleted file mode 100644
index fb133ad..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_hardware.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:software>
- <d:api-level>14</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- <d:state name="Landscape">
- <d:description>The phone in landscape view</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_software.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_software.xml
deleted file mode 100644
index ae709bb..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_software.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock>
- </d:dock>
- <!-- plugged in (never, charge, always) -->
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_states.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_states.xml
deleted file mode 100644
index 8685e3b..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_no_states.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock>
- </d:dock>
- <!-- plugged in (never, charge, always) -->
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>14</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_too_many_defaults.xml b/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_too_many_defaults.xml
deleted file mode 100644
index c720a7a..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/devices_too_many_defaults.xml
+++ /dev/null
@@ -1,141 +0,0 @@
-<?xml version="1.0"?>
-<d:devices
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:d="http://schemas.android.com/sdk/devices/1">
-
- <d:device>
- <d:name>
- Galaxy Nexus
- </d:name>
- <d:manufacturer>
- Samsung
- </d:manufacturer>
- <d:hardware>
- <d:screen>
- <d:screen-size>normal</d:screen-size>
- <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
- <d:pixel-density>xhdpi</d:pixel-density>
- <d:screen-ratio>long</d:screen-ratio>
- <d:dimensions>
- <d:x-dimension>720</d:x-dimension>
- <d:y-dimension>1280</d:y-dimension>
- </d:dimensions>
- <d:xdpi>316</d:xdpi>
- <d:ydpi>316</d:ydpi>
- <d:touch>
- <d:multitouch>jazz-hands</d:multitouch>
- <d:mechanism>finger</d:mechanism>
- <d:screen-type>capacitive</d:screen-type>
- </d:touch>
- </d:screen>
- <d:networking>
- Bluetooth
- Wifi
- NFC
- </d:networking>
- <d:sensors>
- Accelerometer
- Barometer
- Gyroscope
- Compass
- GPS
- ProximitySensor
- </d:sensors>
- <d:mic>true</d:mic>
- <d:camera>
- <d:location>front</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>false</d:flash>
- </d:camera>
- <d:camera>
- <d:location>back</d:location>
- <d:autofocus>true</d:autofocus>
- <d:flash>true</d:flash>
- </d:camera>
- <d:keyboard>nokeys</d:keyboard>
- <d:nav>nonav</d:nav>
- <d:ram unit="GiB">1</d:ram>
- <d:buttons>soft</d:buttons>
- <d:internal-storage unit="GiB">16</d:internal-storage>
- <d:removable-storage unit="KiB"></d:removable-storage>
- <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
- <d:gpu>PowerVR SGX540</d:gpu>
- <d:abi>
- armeabi
- armeabi-v7a
- </d:abi>
- <!--dock (car, desk, tv, none)-->
- <d:dock>
- </d:dock>
- <!-- plugged in (never, charge, always) -->
- <d:power-type>battery</d:power-type>
- </d:hardware>
- <d:software>
- <d:api-level>14</d:api-level>
- <d:live-wallpaper-support>true</d:live-wallpaper-support>
- <d:bluetooth-profiles>
- HSP
- HFP
- SPP
- A2DP
- AVRCP
- OPP
- PBAP
- GAVDP
- AVDTP
- HID
- HDP
- PAN
- </d:bluetooth-profiles>
- <d:gl-version>2.0</d:gl-version>
- <!--
- These can be gotten via
- javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
- -->
- <d:gl-extensions>
- GL_EXT_discard_framebuffer
- GL_EXT_multi_draw_arrays
- GL_EXT_shader_texture_lod
- GL_EXT_texture_format_BGRA8888
- GL_IMG_multisampled_render_to_texture
- GL_IMG_program_binary
- GL_IMG_read_format
- GL_IMG_shader_binary
- GL_IMG_texture_compression_pvrtc
- GL_IMG_texture_format_BGRA8888
- GL_IMG_texture_npot
- GL_OES_compressed_ETC1_RGB8_texture
- GL_OES_depth_texture
- GL_OES_depth24
- GL_OES_EGL_image
- GL_OES_EGL_image_external
- GL_OES_egl_sync
- GL_OES_element_index_uint
- GL_OES_fragment_precision_high
- GL_OES_get_program_binary
- GL_OES_mapbuffer
- GL_OES_packed_depth_stencil
- GL_OES_required_internalformat
- GL_OES_rgb8_rgba8
- GL_OES_standard_derivatives
- GL_OES_texture_float
- GL_OES_texture_half_float
- GL_OES_vertex_array_object
- GL_OES_vertex_half_float
- </d:gl-extensions>
- <d:status-bar>true</d:status-bar>
- </d:software>
- <d:state name="Portrait" default="true">
- <d:description>The phone in portrait view</d:description>
- <d:screen-orientation>port</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- <d:state name="Landscape" default="true">
- <d:description>The phone in landscape view</d:description>
- <d:screen-orientation>land</d:screen-orientation>
- <d:keyboard-state>keyssoft</d:keyboard-state>
- <d:nav-state>nonav</d:nav-state>
- </d:state>
- </d:device>
-</d:devices>
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.jpeg b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.jpeg
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.jpeg
+++ /dev/null
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.png b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.png
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/frame.png
+++ /dev/null
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.jpeg b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.jpeg
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.jpeg
+++ /dev/null
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.png b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.png
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixteen.png
+++ /dev/null
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.jpeg b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.jpeg
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.jpeg
+++ /dev/null
diff --git a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.png b/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.png
deleted file mode 100644
index e69de29..0000000
--- a/device_validator/dvlib/src/test/resources/com/android/dvlib/extras/sixtyfour.png
+++ /dev/null
diff --git a/draw9patch/Android.mk b/draw9patch/Android.mk
index ef2184d..ddb8707 100644
--- a/draw9patch/Android.mk
+++ b/draw9patch/Android.mk
@@ -20,9 +20,6 @@ LOCAL_JAVA_RESOURCE_DIRS := src
LOCAL_JAR_MANIFEST := etc/manifest.txt
-LOCAL_JAVA_LIBRARIES := \
- swing-worker-1.1
-
LOCAL_MODULE := draw9patch
LOCAL_MODULE_TAGS := debug
diff --git a/draw9patch/etc/manifest.txt b/draw9patch/etc/manifest.txt
index b2e3528..2616706 100644
--- a/draw9patch/etc/manifest.txt
+++ b/draw9patch/etc/manifest.txt
@@ -1,2 +1 @@
Main-Class: com.android.draw9patch.Application
-Class-Path: swing-worker-1.1.jar
diff --git a/draw9patch/src/com/android/draw9patch/ui/ImageEditorPanel.java b/draw9patch/src/com/android/draw9patch/ui/ImageEditorPanel.java
index bf3754b..845ee54 100644
--- a/draw9patch/src/com/android/draw9patch/ui/ImageEditorPanel.java
+++ b/draw9patch/src/com/android/draw9patch/ui/ImageEditorPanel.java
@@ -685,6 +685,12 @@ class ImageEditorPanel extends JPanel {
private boolean showBadPatches;
private JPanel helpPanel;
+ private boolean drawingLine;
+ private int lineFromX;
+ private int lineFromY;
+ private int lineToX;
+ private int lineToY;
+ private boolean showDrawingLine;
ImageViewer() {
setLayout(new GridBagLayout());
@@ -735,7 +741,12 @@ class ImageEditorPanel extends JPanel {
// changed state).
currentButton = event.isShiftDown() ? MouseEvent.BUTTON3 : event.getButton();
currentButton = event.isControlDown() ? MouseEvent.BUTTON2 : currentButton;
- paint(event.getX(), event.getY(), currentButton);
+ startDrawingLine(event.getX(), event.getY(), currentButton);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent event) {
+ endDrawingLine();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@@ -743,7 +754,8 @@ class ImageEditorPanel extends JPanel {
public void mouseDragged(MouseEvent event) {
if (!checkLockedRegion(event.getX(), event.getY())) {
// use the stored button, see note above
- paint(event.getX(), event.getY(), currentButton);
+
+ moveLine(event.getX(), event.getY());
}
}
@@ -754,7 +766,7 @@ class ImageEditorPanel extends JPanel {
});
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(AWTEvent event) {
- enableEraseMode((KeyEvent) event);
+ enableEraseMode((KeyEvent) event);
}
}, AWTEvent.KEY_EVENT_MASK);
@@ -857,21 +869,34 @@ class ImageEditorPanel extends JPanel {
}
}
- private void paint(int x, int y, int button) {
- int color;
- switch (button) {
- case MouseEvent.BUTTON1:
- color = BLACK_TICK;
- break;
- case MouseEvent.BUTTON2:
- color = RED_TICK;
- break;
- case MouseEvent.BUTTON3:
- color = 0;
- break;
- default:
- return;
+ private void startDrawingLine(int x, int y, int button) {
+ int left = (getWidth() - size.width) / 2;
+ int top = helpPanel.getHeight() + (getHeight() - size.height) / 2;
+
+ x = (x - left) / zoom;
+ y = (y - top) / zoom;
+
+ int width = image.getWidth();
+ int height = image.getHeight();
+ if (((x == 0 || x == width - 1) && (y > 0 && y < height - 1))
+ || ((x > 0 && x < width - 1) && (y == 0 || y == height - 1))) {
+ drawingLine = true;
+ lineFromX = x;
+ lineFromY = y;
+ lineToX = x;
+ lineToY = y;
+
+ showDrawingLine = true;
+
+ showCursor = false;
+
+ repaint();
}
+ }
+
+ private void moveLine(int x, int y) {
+ if (drawingLine == false)
+ return;
int left = (getWidth() - size.width) / 2;
int top = helpPanel.getHeight() + (getHeight() - size.height) / 2;
@@ -881,16 +906,74 @@ class ImageEditorPanel extends JPanel {
int width = image.getWidth();
int height = image.getHeight();
- if (((x == 0 || x == width - 1) && (y > 0 && y < height - 1)) ||
- ((x > 0 && x < width - 1) && (y == 0 || y == height - 1))) {
- image.setRGB(x, y, color);
- findPatches();
- stretchesViewer.computePatches();
- if (showBadPatches) {
- findBadPatches();
+
+ showDrawingLine = false;
+
+ if (((x == lineFromX) && (y > 0 && y < height - 1))
+ || ((x > 0 && x < width - 1) && (y == lineFromY))) {
+ if (x == lineFromX || y == lineFromY) {
+ lineToX = x;
+ lineToY = y;
+
+ showDrawingLine = true;
}
- repaint();
}
+
+ repaint();
+ }
+
+ private void endDrawingLine() {
+ if (drawingLine == false)
+ return;
+
+ drawingLine = false;
+
+ if (showDrawingLine == false)
+ return;
+
+ int color;
+ switch (currentButton) {
+ case MouseEvent.BUTTON1:
+ color = BLACK_TICK;
+ break;
+ case MouseEvent.BUTTON2:
+ color = RED_TICK;
+ break;
+ case MouseEvent.BUTTON3:
+ color = 0;
+ break;
+ default:
+ return;
+ }
+
+ int x = lineFromX;
+ int y = lineFromY;
+
+ int dx = 0;
+ int dy = 0;
+
+ if (lineToX != lineFromX)
+ dx = lineToX > lineFromX ? 1 : -1;
+ else if (lineToY != lineFromY)
+ dy = lineToY > lineFromY ? 1 : -1;
+
+ do {
+ image.setRGB(x, y, color);
+
+ if (x == lineToX && y == lineToY)
+ break;
+
+ x += dx;
+ y += dy;
+ } while (true);
+
+ findPatches();
+ stretchesViewer.computePatches();
+ if (showBadPatches) {
+ findBadPatches();
+ }
+
+ repaint();
}
private boolean checkLockedRegion(int x, int y) {
@@ -915,8 +998,10 @@ class ImageEditorPanel extends JPanel {
locked = x > 0 && x < width - 1 && y > 0 && y < height - 1;
boolean previousCursor = showCursor;
- showCursor = ((x == 0 || x == width - 1) && (y > 0 && y < height - 1)) ||
- ((x > 0 && x < width - 1) && (y == 0 || y == height - 1));
+ showCursor =
+ !drawingLine &&
+ ( ((x == 0 || x == width - 1) && (y > 0 && y < height - 1)) ||
+ ((x > 0 && x < width - 1) && (y == 0 || y == height - 1)) );
if (locked != previousLock) {
repaint();
@@ -989,6 +1074,32 @@ class ImageEditorPanel extends JPanel {
g2.dispose();
+ if (drawingLine && showDrawingLine) {
+ Graphics cursor = g.create();
+ cursor.setXORMode(Color.WHITE);
+ cursor.setColor(Color.BLACK);
+
+ x = Math.min(lineFromX, lineToX);
+ y = Math.min(lineFromY, lineToY);
+ int w = Math.abs(lineFromX - lineToX) + 1;
+ int h = Math.abs(lineFromY - lineToY) + 1;
+
+ x = x * zoom;
+ y = y * zoom;
+ w = w * zoom;
+ h = h * zoom;
+
+ int left = (getWidth() - size.width) / 2;
+ int top = helpPanel.getHeight() + (getHeight() - size.height)
+ / 2;
+
+ x += left;
+ y += top;
+
+ cursor.drawRect(x, y, w, h);
+ cursor.dispose();
+ }
+
if (showCursor) {
Graphics cursor = g.create();
cursor.setXORMode(Color.WHITE);
diff --git a/draw9patch/src/com/android/draw9patch/ui/MainFrame.java b/draw9patch/src/com/android/draw9patch/ui/MainFrame.java
index a272a28..ff749f4 100644
--- a/draw9patch/src/com/android/draw9patch/ui/MainFrame.java
+++ b/draw9patch/src/com/android/draw9patch/ui/MainFrame.java
@@ -16,24 +16,24 @@
package com.android.draw9patch.ui;
+import com.android.draw9patch.graphics.GraphicsUtilities;
import com.android.draw9patch.ui.action.ExitAction;
import com.android.draw9patch.ui.action.OpenAction;
import com.android.draw9patch.ui.action.SaveAction;
-import com.android.draw9patch.graphics.GraphicsUtilities;
-import javax.swing.JFrame;
-import javax.swing.JMenuBar;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.ActionMap;
-import javax.swing.JFileChooser;
-import javax.imageio.ImageIO;
import java.awt.HeadlessException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.ExecutionException;
-import org.jdesktop.swingworker.SwingWorker;
+import javax.imageio.ImageIO;
+import javax.swing.ActionMap;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.SwingWorker;
public class MainFrame extends JFrame {
private ActionMap actionsMap;
diff --git a/draw9patch/src/com/android/draw9patch/ui/action/BackgroundAction.java b/draw9patch/src/com/android/draw9patch/ui/action/BackgroundAction.java
index 85d9d4f..11bf261 100644
--- a/draw9patch/src/com/android/draw9patch/ui/action/BackgroundAction.java
+++ b/draw9patch/src/com/android/draw9patch/ui/action/BackgroundAction.java
@@ -16,9 +16,8 @@
package com.android.draw9patch.ui.action;
-import org.jdesktop.swingworker.SwingWorker;
-
import javax.swing.AbstractAction;
+import javax.swing.SwingWorker;
public abstract class BackgroundAction extends AbstractAction {
protected void executeBackgroundTask(SwingWorker<?, ?> worker) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index 262da58..7cdb400 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -58,7 +58,6 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
com.android.ide.common.layout;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.common.layout.grid;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.common.layout.relative;x-friends:="com.android.ide.eclipse.tests",
- com.android.ide.common.rendering.api;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.common.resources.platform;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal;x-friends:="com.android.ide.eclipse.tests",
@@ -112,6 +111,7 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
com.android.ide.eclipse.adt.internal.sdk;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.sourcelookup;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.ui;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.utils;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.welcome;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.actions;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.export;x-friends:="com.android.ide.eclipse.tests",
@@ -119,11 +119,8 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
com.android.ide.eclipse.adt.internal.wizards.newxmlfile;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.wizards.templates;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.io;x-friends:="com.android.ide.eclipse.tests",
- com.android.layoutlib.api;x-friends:="com.android.ide.eclipse.tests",
com.android.manifmerger;x-friends:="com.android.ide.eclipse.tests",
- com.android.menubar;x-friends:="com.android.ide.eclipse.tests",
com.android.ninepatch;x-friends:="com.android.ide.eclipse.tests",
- com.android.resources;x-friends:="com.android.ide.eclipse.tests",
com.android.sdkuilib.internal.repository;x-friends:="com.android.ide.eclipse.tests",
com.android.sdkuilib.internal.repository.core;x-friends:="com.android.ide.eclipse.tests",
com.android.sdkuilib.internal.repository.icons;x-friends:="com.android.ide.eclipse.tests",
@@ -135,7 +132,6 @@ Export-Package: com.android.assetstudiolib;x-friends:="com.android.ide.eclipse.t
com.android.tools.lint.checks;x-friends:="com.android.ide.eclipse.tests",
com.android.tools.lint.client.api;x-friends:="com.android.ide.eclipse.tests",
com.android.tools.lint.detector.api;x-friends:="com.android.ide.eclipse.tests",
- com.android.util;x-friends:="com.android.ide.eclipse.tests",
freemarker.cache;x-friends:="com.android.ide.eclipse.tests",
freemarker.template;x-friends:="com.android.ide.eclipse.tests",
org.kxml2.io;x-friends:="com.android.ide.eclipse.tests",
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 752bbc6..88e9c15 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -1884,7 +1884,7 @@ public class AdtPlugin extends AbstractUIPlugin implements ILogger {
// --------- ILogger methods -----------
@Override
- public void error(Throwable t, String format, Object... args) {
+ public void error(@Nullable Throwable t, @Nullable String format, Object... args) {
if (t != null) {
log(t, format, args);
} else {
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 223e5e5..697a0bc 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
@@ -23,6 +23,7 @@ import static org.eclipse.ui.IWorkbenchPage.MATCH_INPUT;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.common.sdk.SdkVersionInfo;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
@@ -989,7 +990,7 @@ public class AdtUtils {
* @return the highest known API number
*/
public static int getHighestKnownApiLevel() {
- return SdkConstants.HIGHEST_KNOWN_API;
+ return SdkVersionInfo.HIGHEST_KNOWN_API;
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java
index 9c42967..df204b8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java
@@ -21,7 +21,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler;
import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler.Solution;
import com.android.ide.eclipse.adt.Messages;
-import com.android.sdklib.internal.repository.packages.FullRevision;
+import com.android.sdklib.repository.FullRevision;
import com.android.sdklib.repository.PkgProps;
import org.osgi.framework.Constants;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java
index 4155989..71c8263 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java
@@ -28,7 +28,7 @@ import com.android.sdklib.io.FileOp;
import com.android.sdklib.util.GrabProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.Wait;
-import com.android.sdkuilib.repository.ISdkChangeListener;
+import com.android.sdklib.repository.ISdkChangeListener;
import com.android.sdkuilib.repository.SdkUpdaterWindow;
import com.android.sdkuilib.repository.SdkUpdaterWindow.SdkInvocationContext;
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 ba23c95..0f0cbcc 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
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.build.builders;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.common.xml.ManifestData;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
@@ -55,9 +56,9 @@ import com.android.sdklib.io.FileOp;
import com.android.utils.ILogger;
import com.android.utils.Pair;
import com.android.xml.AndroidManifest;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Multimap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
@@ -78,9 +79,9 @@ import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
@@ -94,6 +95,7 @@ import javax.xml.parsers.ParserConfigurationException;
* </ul>
*
*/
+@SuppressWarnings("deprecation")
public class PreCompilerBuilder extends BaseBuilder {
/** This ID is used in plugin.xml and in each project's .project file.
@@ -806,6 +808,7 @@ public class PreCompilerBuilder extends BaseBuilder {
}
}
+ @SuppressWarnings("deprecation")
private void handleBuildConfig(@SuppressWarnings("rawtypes") Map args)
throws IOException, CoreException {
boolean debugMode = !args.containsKey(RELEASE_REQUESTED);
@@ -895,7 +898,8 @@ public class PreCompilerBuilder extends BaseBuilder {
}
@Override
- public void error(Throwable t, String errorFormat, Object... args) {
+ public void error(@Nullable Throwable t, @Nullable String errorFormat,
+ Object... args) {
errors.add(String.format(errorFormat, args));
}
}),
@@ -1034,6 +1038,7 @@ public class PreCompilerBuilder extends BaseBuilder {
* @param proguardFile an optional path to store proguard information
* @throws AbortBuildException
*/
+ @SuppressWarnings("deprecation")
private void execAapt(IProject project, IAndroidTarget projectTarget, String osOutputPath,
String osResPath, String osManifestPath, IFolder packageFolder,
ArrayList<IFolder> libResFolders, List<Pair<File, String>> libRFiles,
@@ -1049,7 +1054,6 @@ public class PreCompilerBuilder extends BaseBuilder {
// launch aapt: create the command line
ArrayList<String> array = new ArrayList<String>();
- @SuppressWarnings("deprecation")
String aaptPath = projectTarget.getPath(IAndroidTarget.AAPT);
array.add(aaptPath);
@@ -1160,71 +1164,40 @@ public class PreCompilerBuilder extends BaseBuilder {
// if the project has no resources, the file could not exist.
if (rFile.isFile()) {
// 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());
+ SymbolLoader fullSymbolValues = new SymbolLoader(rFile);
+ fullSymbolValues.load();
+
+ Multimap<String, SymbolLoader> libMap = ArrayListMultimap.create();
+
+ // First pass processing the libraries, collecting them by packageName,
+ // and ignoring the ones that have the same package name as the application
+ // (since that R class was already created).
+
+ for (Pair<File, String> lib : libRFiles) {
+ String libPackage = lib.getSecond();
+ File rText = lib.getFirst();
+
+ if (rText.isFile()) {
+ // load the lib symbols
+ SymbolLoader libSymbols = new SymbolLoader(rText);
+ libSymbols.load();
+
+ // store these symbols by associating them with the package name.
+ libMap.put(libPackage, libSymbols);
}
+ }
- // 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);
- }
+ // now loop on all the package names, merge all the symbols to write,
+ // and write them
+ for (String packageName : libMap.keySet()) {
+ Collection<SymbolLoader> symbols = libMap.get(packageName);
+
+ SymbolWriter writer = new SymbolWriter(osOutputPath, packageName,
+ fullSymbolValues);
+ for (SymbolLoader symbolLoader : symbols) {
+ writer.addSymbolsToWrite(symbolLoader);
}
+ writer.write();
}
}
}
@@ -1283,19 +1256,6 @@ 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/launch/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java
index 31d4d0f..4281f19 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java
@@ -377,6 +377,9 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AvdInfo preferredAvd = null;
if (config.mAvdName != null) {
preferredAvd = avdManager.getAvd(config.mAvdName, true /*validAvdOnly*/);
+ }
+
+ if (preferredAvd != null) {
IAndroidTarget preferredAvdTarget = preferredAvd.getTarget();
if (preferredAvdTarget != null
&& !preferredAvdTarget.getVersion().canRun(minApiVersion)) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAnnotation.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAnnotation.java
index d7a0758..b047b1b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAnnotation.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAnnotation.java
@@ -25,13 +25,13 @@ import static org.eclipse.jdt.core.dom.SingleMemberAnnotation.VALUE_PROPERTY;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.common.sdk.SdkVersionInfo;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.tools.lint.checks.AnnotationDetector;
import com.android.tools.lint.checks.ApiDetector;
import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
import com.android.tools.lint.detector.api.Scope;
import org.eclipse.core.resources.IMarker;
@@ -345,7 +345,8 @@ class AddSuppressAnnotation implements IMarkerResolution2 {
}
Issue issue = EclipseLintClient.getRegistry().getIssue(id);
- boolean isClassDetector = issue != null && issue.getScope().contains(Scope.CLASS_FILE);
+ boolean isClassDetector = issue != null && issue.getImplementation().getScope().contains(
+ Scope.CLASS_FILE);
// Don't offer to suppress (with an annotation) the annotation checks
if (issue == AnnotationDetector.ISSUE) {
@@ -409,7 +410,7 @@ class AddSuppressAnnotation implements IMarkerResolution2 {
// @TargetApi is only valid on methods and classes, not fields etc
&& (body instanceof MethodDeclaration
|| body instanceof TypeDeclaration)) {
- String apiString = LintUtils.getBuildCode(api);
+ String apiString = SdkVersionInfo.getBuildCode(api);
if (apiString == null) {
apiString = Integer.toString(api);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
index 0d751cb..b77b475 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
@@ -22,13 +22,13 @@ import static com.android.SdkConstants.DOT_XML;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.common.sdk.SdkVersionInfo;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
import com.android.tools.lint.checks.ApiDetector;
-import com.android.tools.lint.detector.api.LintUtils;
import com.google.common.collect.Lists;
import org.eclipse.core.resources.IMarker;
@@ -186,7 +186,7 @@ class AddSuppressAttribute implements ICompletionProposal {
if (matcher.find()) {
api = Integer.parseInt(matcher.group(1));
String targetApi;
- String buildCode = LintUtils.getBuildCode(api);
+ String buildCode = SdkVersionInfo.getBuildCode(api);
if (buildCode != null) {
targetApi = buildCode.toLowerCase(Locale.US);
fixes.add(new AddSuppressAttribute(editor, id, marker, element,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
index f6b18e0..45ae2c5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java
@@ -105,6 +105,7 @@ import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
+import lombok.ast.TypeReference;
import lombok.ast.ecj.EcjTreeConverter;
import lombok.ast.grammar.ParseProblem;
import lombok.ast.grammar.Source;
@@ -614,8 +615,8 @@ public class EclipseLintClient extends LintClient implements IDomParser {
return "";
}
- String summary = issue.getDescription();
- String explanation = issue.getExplanationAsSimpleText();
+ String summary = issue.getDescription(Issue.OutputFormat.TEXT);
+ String explanation = issue.getExplanation(Issue.OutputFormat.TEXT);
StringBuilder sb = new StringBuilder(summary.length() + explanation.length() + 20);
try {
@@ -1213,6 +1214,19 @@ public class EclipseLintClient extends LintClient implements IDomParser {
@NonNull lombok.ast.Node compilationUnit) {
}
+ @Override
+ @Nullable
+ public lombok.ast.Node resolve(@NonNull JavaContext context,
+ @NonNull lombok.ast.Node node) {
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public TypeReference getType(@NonNull JavaContext context, @NonNull lombok.ast.Node node) {
+ return null;
+ }
+
/* Handle for creating positions cheaply and returning full fledged locations later */
private class LocationHandle implements Handle {
private File mFile;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFix.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFix.java
index feb6bb5..401703e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFix.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFix.java
@@ -37,6 +37,7 @@ import com.android.tools.lint.checks.TypographyDetector;
import com.android.tools.lint.checks.UseCompoundDrawableDetector;
import com.android.tools.lint.checks.UselessViewDetector;
import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Issue.OutputFormat;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
@@ -109,7 +110,7 @@ abstract class LintFix implements ICompletionProposal {
public String getAdditionalProposalInfo() {
Issue issue = EclipseLintClient.getRegistry().getIssue(mId);
if (issue != null) {
- return issue.getExplanationAsHtml();
+ return issue.getExplanation(OutputFormat.HTML);
}
return null;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java
index 22fe23b..ce5fd55 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java
@@ -27,6 +27,7 @@ import com.android.tools.lint.client.api.Configuration;
import com.android.tools.lint.client.api.DefaultConfiguration;
import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Issue.OutputFormat;
import com.android.tools.lint.detector.api.Project;
import com.android.tools.lint.detector.api.Severity;
import com.android.utils.SdkUtils;
@@ -488,11 +489,12 @@ public class LintFixGenerator implements IMarkerResolutionGenerator2, IQuickAssi
sb.append('\n').append('\n');
sb.append("Issue Explanation:");
sb.append('\n');
- if (issue.getExplanation() != null) {
+ String explanation = issue.getExplanation(Issue.OutputFormat.TEXT);
+ if (explanation != null && !explanation.isEmpty()) {
sb.append('\n');
- sb.append(issue.getExplanationAsSimpleText());
+ sb.append(explanation);
} else {
- sb.append(issue.getDescription());
+ sb.append(issue.getDescription(Issue.OutputFormat.TEXT));
}
if (issue.getMoreInfo() != null) {
@@ -543,7 +545,8 @@ public class LintFixGenerator implements IMarkerResolutionGenerator2, IQuickAssi
public String getAdditionalProposalInfo() {
return "Provides more information about this issue."
+ "<br><br>" //$NON-NLS-1$
- + EclipseLintClient.getRegistry().getIssue(mId).getExplanationAsHtml();
+ + EclipseLintClient.getRegistry().getIssue(mId).getExplanation(
+ OutputFormat.HTML);
}
@Override
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintJob.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintJob.java
index 95e9f18..bd1eb72 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintJob.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintJob.java
@@ -140,7 +140,7 @@ final class LintJob extends Job {
if (issue == null) {
continue;
}
- if (issue.isAdequate(scope)) {
+ if (issue.getImplementation().isAdequate(scope)) {
marker.delete();
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
index 6e18837..02af2fd 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java
@@ -15,6 +15,9 @@
*/
package com.android.ide.eclipse.adt.internal.preferences;
+import static com.android.tools.lint.detector.api.Issue.OutputFormat.RAW;
+import static com.android.tools.lint.detector.api.Issue.OutputFormat.TEXT;
+
import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
@@ -448,8 +451,8 @@ public class LintPreferencePage extends PropertyPage implements IWorkbenchPrefer
Object data = item != null ? item.getData() : null;
if (data instanceof Issue) {
Issue issue = (Issue) data;
- String summary = issue.getDescription();
- String explanation = issue.getExplanation();
+ String summary = issue.getDescription(Issue.OutputFormat.TEXT);
+ String explanation = issue.getExplanation(Issue.OutputFormat.TEXT);
StringBuilder sb = new StringBuilder(summary.length() + explanation.length() + 20);
sb.append(summary);
@@ -568,7 +571,7 @@ public class LintPreferencePage extends PropertyPage implements IWorkbenchPrefer
|| issue.getCategory().getName().toLowerCase(Locale.US).startsWith(filter)
|| issue.getCategory().getFullName().toLowerCase(Locale.US).startsWith(filter)
|| issue.getId().toLowerCase(Locale.US).contains(filter)
- || issue.getDescription().toLowerCase(Locale.US).contains(filter);
+ || issue.getDescription(RAW).toLowerCase(Locale.US).contains(filter);
}
private class ContentProvider extends TreeNodeContentProvider {
@@ -712,7 +715,7 @@ public class LintPreferencePage extends PropertyPage implements IWorkbenchPrefer
case 0:
return issue.getId();
case 1:
- return issue.getDescription();
+ return issue.getDescription(TEXT);
}
return null;
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 f6fa6ee..406cebc 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
@@ -146,7 +146,7 @@ class ApplicationPackageNameRefactoring extends Refactoring {
TextEdit rewrittenImports = importVisitor.getTextEdit();
// If the import of R was potentially implicit, insert an import statement
- if (cu.getPackage().getName().getFullyQualifiedName()
+ if (rewrittenImports != null && cu.getPackage().getName().getFullyQualifiedName()
.equals(mOldPackageName.getFullyQualifiedName())) {
UsageVisitor usageVisitor = new UsageVisitor();
@@ -438,10 +438,10 @@ class ApplicationPackageNameRefactoring extends Refactoring {
mParser.setSource(icu);
CompilationUnit cu = (CompilationUnit) mParser.createAST(null);
- TextEdit text_edit = updateJavaFileImports(cu);
- if (text_edit.hasChildren()) {
+ TextEdit textEdit = updateJavaFileImports(cu);
+ if (textEdit != null && textEdit.hasChildren()) {
MultiTextEdit edit = new MultiTextEdit();
- edit.addChild(text_edit);
+ edit.addChild(textEdit);
TextFileChange text_file_change = new TextFileChange(file.getName(), file);
text_file_change.setTextType(SdkConstants.EXT_JAVA);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java
index 26afebd..2396a4c 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AdtConsoleSdkLog.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.internal.sdk;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.utils.ILogger;
@@ -28,7 +29,7 @@ public class AdtConsoleSdkLog implements ILogger {
private static final String TAG = "SDK Manager"; //$NON-NLS-1$
@Override
- public void error(Throwable t, String errorFormat, Object... args) {
+ public void error(@Nullable Throwable t, @Nullable String errorFormat, Object... args) {
if (t != null) {
AdtPlugin.logAndPrintError(t, TAG, "Error: " + errorFormat, args);
} else {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
index 5d9c0ef..f187a3f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
@@ -235,7 +235,8 @@ public final class Sdk {
final ArrayList<String> logMessages = new ArrayList<String>();
ILogger log = new ILogger() {
@Override
- public void error(Throwable throwable, String errorFormat, Object... arg) {
+ public void error(@Nullable Throwable throwable, @Nullable String errorFormat,
+ Object... arg) {
if (errorFormat != null) {
logMessages.add(String.format("Error: " + errorFormat, arg));
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
index 65ddbd4..e99a637 100644
--- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/LogCatMonitor.java
@@ -19,8 +19,8 @@ import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.logcat.LogCatMessage;
import com.android.ddmuilib.logcat.ILogCatBufferChangeListener;
-import com.android.ddmuilib.logcat.LogCatMessage;
import com.android.ddmuilib.logcat.LogCatReceiver;
import com.android.ddmuilib.logcat.LogCatReceiverFactory;
import com.android.ide.eclipse.ddms.views.LogCatView;
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java
index 3514db0..9f78c4a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java
+++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/LogCatView.java
@@ -15,8 +15,8 @@
*/
package com.android.ide.eclipse.ddms.views;
+import com.android.ddmlib.logcat.LogCatMessage;
import com.android.ddmuilib.logcat.ILogCatMessageSelectionListener;
-import com.android.ddmuilib.logcat.LogCatMessage;
import com.android.ddmuilib.logcat.LogCatPanel;
import com.android.ddmuilib.logcat.LogCatStackTraceParser;
import com.android.ide.eclipse.ddms.DdmsPlugin;
diff --git a/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/META-INF/MANIFEST.MF
index 3554b41..d4e8b7d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/META-INF/MANIFEST.MF
@@ -10,7 +10,8 @@ Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.console,
- com.android.ide.eclipse.ddms
+ com.android.ide.eclipse.ddms,
+ com.android.ide.eclipse.base
Bundle-ClassPath: .,
libs/hierarchyviewerlib.jar
Export-Package: com.android.ide.eclipse.hierarchyviewer
diff --git a/eclipse/plugins/com.android.ide.eclipse.ndk/.classpath b/eclipse/plugins/com.android.ide.eclipse.ndk/.classpath
index d37aeb2..58a22d6 100644
--- a/eclipse/plugins/com.android.ide.eclipse.ndk/.classpath
+++ b/eclipse/plugins/com.android.ide.eclipse.ndk/.classpath
@@ -5,6 +5,6 @@
<classpathentry kind="src" path="src"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmuilib"/>
- <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/sdklib"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
index ae0cb35..ab36b62 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
@@ -7,8 +7,6 @@
<classpathentry kind="lib" path="kxml2-2.3.0.jar"/>
<classpathentry kind="lib" path="easymock.jar"/>
<classpathentry kind="lib" path="sdktestutils.jar"/>
- <classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
- <classpathentry combineaccessrules="false" kind="src" path="/ddmuilib"/>
<classpathentry kind="lib" path="/plugin-adt/libs/ninepatch.jar" sourcepath="/ninepatch"/>
<classpathentry kind="lib" path="/plugin-base/libs/sdklib.jar" sourcepath="/SdkLib"/>
<classpathentry kind="lib" path="/plugin-adt/libs/sdkuilib.jar" sourcepath="/SdkUiLib"/>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandlerTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandlerTest.java
index 4fc2fbe..48681d0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandlerTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandlerTest.java
@@ -17,7 +17,6 @@ package com.android.ide.eclipse.adt.internal.wizards.templates;
import static com.android.SdkConstants.CURRENT_PLATFORM;
import static com.android.SdkConstants.FD_TOOLS;
-import static com.android.SdkConstants.HIGHEST_KNOWN_API;
import static com.android.SdkConstants.PLATFORM_WINDOWS;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API;
import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_BUILD_API;
@@ -25,6 +24,7 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHan
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
+import com.android.ide.common.sdk.SdkVersionInfo;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient;
@@ -329,14 +329,16 @@ public class TemplateHandlerTest extends SdkLoadingTestCase {
}
for (int minSdk = 1;
- minSdk <= HIGHEST_KNOWN_API;
- minSdk++) {
+ minSdk <= SdkVersionInfo.HIGHEST_KNOWN_API;
+ minSdk++) {
// Don't bother checking *every* single minSdk, just pick some interesting ones
if (!isInterestingApiLevel(minSdk)) {
continue;
}
- for (int targetSdk = minSdk; targetSdk <= HIGHEST_KNOWN_API; targetSdk++) {
+ for (int targetSdk = minSdk;
+ targetSdk <= SdkVersionInfo.HIGHEST_KNOWN_API;
+ targetSdk++) {
if (!isInterestingApiLevel(targetSdk)) {
continue;
}
@@ -440,14 +442,16 @@ public class TemplateHandlerTest extends SdkLoadingTestCase {
}
for (int minSdk = 1;
- minSdk <= HIGHEST_KNOWN_API;
- minSdk++) {
+ minSdk <= SdkVersionInfo.HIGHEST_KNOWN_API;
+ minSdk++) {
// Don't bother checking *every* single minSdk, just pick some interesting ones
if (!isInterestingApiLevel(minSdk)) {
continue;
}
- for (int targetSdk = minSdk; targetSdk <= HIGHEST_KNOWN_API; targetSdk++) {
+ for (int targetSdk = minSdk;
+ targetSdk <= SdkVersionInfo.HIGHEST_KNOWN_API;
+ targetSdk++) {
if (!isInterestingApiLevel(targetSdk)) {
continue;
}
diff --git a/eclipse/scripts/build.xml b/eclipse/scripts/build.xml
new file mode 100644
index 0000000..67861bc
--- /dev/null
+++ b/eclipse/scripts/build.xml
@@ -0,0 +1,133 @@
+<!--
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+
+*Sample* build.xml for ADT plugin build. Do not use for actual releases.
+
+Note: this uses the target platform from eclipse-build-deps.
+All these are newer than Eclipse 3.6.2 which is our current baseline.
+
+Note: for actual releases, use build_server.sh instead of this.
+
+To build:
+$ cd sdk/eclipse/scripts
+$ ant
+This should create the plugins in $OUT/host/eclipse/adtplugins/build/v<timestamp>-aosp
+
+-->
+<project name="com.android.eclipse.rcp.build" default="build">
+ <!-- The timestamp for the context qualifier. -->
+ <tstamp>
+ <format property="adt.timestamp"
+ pattern="yyyyMMddHHmmss" />
+ </tstamp>
+
+ <!-- Root of Android Source Tree -->
+ <property name="ANDROID_SRC" location="../../../" />
+
+ <!-- Host Eclipse used for building the RCP -->
+ <property name="basebuilder" value="${ANDROID_SRC}/external/eclipse-basebuilder/basebuilder-3.6.2/org.eclipse.releng.basebuilder/" />
+
+ <!-- Source for target prebuilts -->
+ <property name="targetSrcDir1" value="${ANDROID_SRC}/prebuilts/eclipse/" />
+ <property name="targetSrcDir2" value="${ANDROID_SRC}/prebuilts/eclipse-build-deps/" />
+
+ <!-- Location where build happens and resulting binaries are generated -->
+ <property name="outDir" value="${ANDROID_SRC}/out/host/eclipse/adtplugins/" />
+
+ <!-- Location where the target platform is created -->
+ <property name="targetDir" value="${outDir}/target" />
+
+ <!-- Location where the target platform is created -->
+ <property name="buildDir" value="${outDir}/build" />
+
+ <!-- Location of the sources -->
+ <property name="srcDir" value="${ANDROID_SRC}/sdk/eclipse/" />
+
+ <!-- locate launcher plugin inside eclipse -->
+ <path id="equinox.launcher.path">
+ <fileset dir="${basebuilder}/plugins">
+ <include name="org.eclipse.equinox.launcher_*.jar" />
+ </fileset>
+ </path>
+ <property name="equinox.launcher" refid="equinox.launcher.path" />
+
+ <!-- locate pde build plugin inside eclipse -->
+ <path id="pde.build.dir.path">
+ <dirset dir="${basebuilder}/plugins">
+ <include name="org.eclipse.pde.build_*" />
+ </dirset>
+ </path>
+ <property name="pde.build.dir" refid="pde.build.dir.path" />
+
+ <!-- create the build directory, copy plugins and features into it -->
+ <target name="copy_srcs">
+ <mkdir dir="${buildDir}" />
+ <copy todir="${buildDir}" preservelastmodified="true">
+ <fileset dir="${srcDir}/">
+ <include name="plugins/**" />
+ <include name="features/**" />
+ <exclude name="plugins/*/bin/**" />
+ </fileset>
+ </copy>
+ </target>
+
+ <!-- create target platform -->
+ <target name="create-target">
+ <mkdir dir="${targetDir}" />
+ <mkdir dir="${targetDir}/deltapack" />
+ <mkdir dir="${targetDir}/repos" />
+
+ <unzip src="${targetSrcDir1}/deltapack/eclipse-3.7.2-delta-pack.zip" dest="${targetDir}/deltapack" overwrite="false" />
+ <unzip src="${targetSrcDir1}/platform/org.eclipse.platform-3.7.2.zip" dest="${targetDir}/repos/platform" overwrite="false" />
+ <unzip src="${targetSrcDir2}/cdt/cdt-master-8.0.2.zip" dest="${targetDir}/repos/cdt" overwrite="false" />
+ <unzip src="${targetSrcDir2}/emf/emf-xsd-SDK-M201201231045.zip" dest="${targetDir}/repos/emf" overwrite="false" />
+ <unzip src="${targetSrcDir2}/jdt/org.eclipse.jdt.source-3.7.2.zip" dest="${targetDir}/repos/jdt" overwrite="false" />
+ <unzip src="${targetSrcDir2}/wtp/wtp-repo-R-3.3.2-20120210195245.zip" dest="${targetDir}/repos/wtp" overwrite="false" />
+ <unzip src="${targetSrcDir2}/gef/GEF-SDK-3.7.2.zip" dest="${targetDir}/repos/gef" overwrite="false" />
+ </target>
+
+ <!-- Launch pde build -->
+ <target name="pde-build" depends="copy_srcs, create-target">
+ <java classname="org.eclipse.equinox.launcher.Main" fork="true" failonerror="true">
+ <arg value="-application" />
+ <arg value="org.eclipse.ant.core.antRunner" />
+ <arg value="-buildfile" />
+ <arg value="${pde.build.dir}/scripts/build.xml" />
+ <arg value="-data" />
+ <arg value="${buildDir}/workspace" />
+ <arg value="-configuration" />
+ <arg value="${buildDir}/configuration" />
+ <arg value="-Dbuilder=${srcDir}/buildConfig" />
+ <arg value="-Dtimestamp=${timestamp}" />
+ <arg value="-DeclipseLocation=${baseBuilder}" />
+ <arg value="-DbuildDirectory=${buildDir}" />
+ <arg value="-DbaseLocation=${targetDir}/deltapack/eclipse" />
+ <arg value="-DrepoBaseLocation=${targetDir}/repos/" />
+ <arg value="-DtransformedRepoLocation=${targetDir}/transformedRepos/" />
+ <arg value="-DupdateSiteSource=${srcDir}/sites/external" />
+ <arg value="-DforceContextQualifier=v${adt.timestamp}-aosp" />
+ <classpath>
+ <pathelement location="${equinox.launcher}" />
+ </classpath>
+ </java>
+ </target>
+
+ <target name="clean">
+ <delete dir="${outDir}" />
+ <delete dir="${targetDir}" />
+ </target>
+
+ <target name="build" depends="pde-build" />
+</project>
diff --git a/eclipse/scripts/create_all_symlinks.sh b/eclipse/scripts/create_all_symlinks.sh
index 3130cf1..8f48fb7 100755
--- a/eclipse/scripts/create_all_symlinks.sh
+++ b/eclipse/scripts/create_all_symlinks.sh
@@ -211,7 +211,7 @@ LIBS="$LIBS $SDKMAN_LIBS"
if [[ $PLATFORM != "windows-x86" ]]; then
# liblzf doesn't build under cygwin. If necessary, this should be fixed first.
-
+
GLD_DEST="sdk/eclipse/plugins/com.android.ide.eclipse.gldebugger/libs"
GLD_LIBS="host-libprotobuf-java-2.3.0-lite liblzf"
@@ -219,6 +219,22 @@ if [[ $PLATFORM != "windows-x86" ]]; then
CP_FILES="$CP_FILES @:$GLD_DEST $GLD_LIBS"
fi
+# If some of the libs are available in prebuilts/devtools, use link to them directly
+# instead of trying to rebuild them so remove them from the libs to build. Note that
+# they are already listed in CP_FILES so we'll adjust the source to copy later.
+
+LIBS2=""
+for LIB in $LIBS; do
+ J="prebuilts/devtools/$LIB.jar"
+ if [[ -f $J ]]; then
+ warn "## Using existing $J"
+ else
+ LIBS2="$LIBS2 $LIB"
+ fi
+done
+LIBS="$LIBS2"
+unset LIBS2
+
# In the mode to only echo dependencies, output them and we're done
if [[ -n $ONLY_SHOW_DEPS ]]; then
echo $LIBS
@@ -254,7 +270,11 @@ for SRC in $CP_FILES; do
fi
if [[ ! -f "$SRC" ]]; then
ORIG_SRC="$SRC"
- SRC="out/host/$PLATFORM/framework/$SRC.jar"
+ # Take a prebuilts/devtools instead of a framework one if possible.
+ SRC="prebuilts/devtools/$SRC.jar"
+ if [[ ! -f "$SRC" ]]; then
+ SRC="out/host/$PLATFORM/framework/$ORIG_SRC.jar"
+ fi
fi
if [[ -f "$SRC" ]]; then
if [[ ! -d "$DEST" ]]; then
diff --git a/hierarchyviewer/etc/manifest.txt b/hierarchyviewer/etc/manifest.txt
index f7ddfa9..06efd79 100644
--- a/hierarchyviewer/etc/manifest.txt
+++ b/hierarchyviewer/etc/manifest.txt
@@ -1,2 +1,2 @@
Main-Class: com.android.hierarchyviewer.HierarchyViewer
-Class-Path: ddmlib.jar swing-worker-1.1.jar org-openide-util.jar org-netbeans-api-visual.jar
+Class-Path: ddmlib.jar org-openide-util.jar org-netbeans-api-visual.jar
diff --git a/hierarchyviewer/src/Android.mk b/hierarchyviewer/src/Android.mk
index a578218..e84c8f8 100644
--- a/hierarchyviewer/src/Android.mk
+++ b/hierarchyviewer/src/Android.mk
@@ -21,7 +21,6 @@ LOCAL_JAVA_RESOURCE_DIRS := resources
LOCAL_JAR_MANIFEST := ../etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
ddmlib \
- swing-worker-1.1 \
org-openide-util \
org-netbeans-api-visual
LOCAL_MODULE := hierarchyviewer
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/ui/ScreenViewer.java b/hierarchyviewer/src/com/android/hierarchyviewer/ui/ScreenViewer.java
index 3b0662f..bae1270 100644
--- a/hierarchyviewer/src/com/android/hierarchyviewer/ui/ScreenViewer.java
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/ui/ScreenViewer.java
@@ -2,54 +2,53 @@ package com.android.hierarchyviewer.ui;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.RawImage;
-import com.android.hierarchyviewer.util.WorkerThread;
import com.android.hierarchyviewer.scene.ViewNode;
-import com.android.hierarchyviewer.ui.util.PngFileFilter;
import com.android.hierarchyviewer.ui.util.IconLoader;
+import com.android.hierarchyviewer.ui.util.PngFileFilter;
+import com.android.hierarchyviewer.util.WorkerThread;
-import javax.swing.JComponent;
-import javax.swing.JScrollPane;
-import javax.swing.Timer;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-import javax.swing.BorderFactory;
-import javax.swing.JLabel;
-import javax.swing.JSlider;
-import javax.swing.Box;
-import javax.swing.JCheckBox;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.ChangeEvent;
-import javax.imageio.ImageIO;
-
-import org.jdesktop.swingworker.SwingWorker;
-
-import java.io.IOException;
-import java.io.File;
-import java.awt.image.BufferedImage;
-import java.awt.Graphics;
-import java.awt.Dimension;
+import java.awt.AlphaComposite;
import java.awt.BorderLayout;
-import java.awt.Graphics2D;
import java.awt.Color;
-import java.awt.Rectangle;
-import java.awt.Point;
-import java.awt.GridBagLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
import java.awt.Insets;
-import java.awt.FlowLayout;
-import java.awt.AlphaComposite;
+import java.awt.Point;
+import java.awt.Rectangle;
import java.awt.RenderingHints;
-import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
import java.util.concurrent.ExecutionException;
+import javax.imageio.ImageIO;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSlider;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
+import javax.swing.Timer;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
class ScreenViewer extends JPanel implements ActionListener {
private final Workspace workspace;
private final IDevice device;
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java b/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
index 82375e0..bfa15b3 100644
--- a/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
@@ -22,43 +22,70 @@ import com.android.hierarchyviewer.device.DeviceBridge;
import com.android.hierarchyviewer.device.Window;
import com.android.hierarchyviewer.laf.UnifiedContentBorder;
import com.android.hierarchyviewer.scene.CaptureLoader;
+import com.android.hierarchyviewer.scene.ProfilesLoader;
import com.android.hierarchyviewer.scene.VersionLoader;
import com.android.hierarchyviewer.scene.ViewHierarchyLoader;
import com.android.hierarchyviewer.scene.ViewHierarchyScene;
import com.android.hierarchyviewer.scene.ViewManager;
import com.android.hierarchyviewer.scene.ViewNode;
import com.android.hierarchyviewer.scene.WindowsLoader;
-import com.android.hierarchyviewer.scene.ProfilesLoader;
-import com.android.hierarchyviewer.ui.action.DumpDisplayListAction;
-import com.android.hierarchyviewer.ui.util.PsdFileFilter;
-import com.android.hierarchyviewer.util.OS;
-import com.android.hierarchyviewer.util.WorkerThread;
-import com.android.hierarchyviewer.ui.action.ShowDevicesAction;
-import com.android.hierarchyviewer.ui.action.RequestLayoutAction;
-import com.android.hierarchyviewer.ui.action.InvalidateAction;
-import com.android.hierarchyviewer.ui.action.CaptureNodeAction;
import com.android.hierarchyviewer.ui.action.CaptureLayersAction;
-import com.android.hierarchyviewer.ui.action.RefreshWindowsAction;
-import com.android.hierarchyviewer.ui.action.StopServerAction;
-import com.android.hierarchyviewer.ui.action.StartServerAction;
+import com.android.hierarchyviewer.ui.action.CaptureNodeAction;
+import com.android.hierarchyviewer.ui.action.DumpDisplayListAction;
import com.android.hierarchyviewer.ui.action.ExitAction;
+import com.android.hierarchyviewer.ui.action.InvalidateAction;
import com.android.hierarchyviewer.ui.action.LoadGraphAction;
+import com.android.hierarchyviewer.ui.action.RefreshWindowsAction;
+import com.android.hierarchyviewer.ui.action.RequestLayoutAction;
import com.android.hierarchyviewer.ui.action.SaveSceneAction;
-import com.android.hierarchyviewer.ui.util.PngFileFilter;
-import com.android.hierarchyviewer.ui.util.IconLoader;
+import com.android.hierarchyviewer.ui.action.ShowDevicesAction;
+import com.android.hierarchyviewer.ui.action.StartServerAction;
+import com.android.hierarchyviewer.ui.action.StopServerAction;
+import com.android.hierarchyviewer.ui.model.ProfilesTableModel;
import com.android.hierarchyviewer.ui.model.PropertiesTableModel;
import com.android.hierarchyviewer.ui.model.ViewsTreeModel;
-import com.android.hierarchyviewer.ui.model.ProfilesTableModel;
-import org.jdesktop.swingworker.SwingWorker;
+import com.android.hierarchyviewer.ui.util.IconLoader;
+import com.android.hierarchyviewer.ui.util.PngFileFilter;
+import com.android.hierarchyviewer.ui.util.PsdFileFilter;
+import com.android.hierarchyviewer.util.OS;
+import com.android.hierarchyviewer.util.WorkerThread;
+
import org.netbeans.api.visual.graph.layout.TreeGraphLayout;
import org.netbeans.api.visual.model.ObjectSceneEvent;
import org.netbeans.api.visual.model.ObjectSceneEventType;
import org.netbeans.api.visual.model.ObjectSceneListener;
import org.netbeans.api.visual.model.ObjectState;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
import javax.imageio.ImageIO;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
+import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
@@ -72,56 +99,31 @@ import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
-import javax.swing.JScrollPane;
import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTable;
+import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
+import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
-import javax.swing.JTree;
-import javax.swing.Box;
-import javax.swing.JTextField;
-import javax.swing.text.Document;
-import javax.swing.text.BadLocationException;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.DocumentEvent;
+import javax.swing.event.TreeSelectionListener;
import javax.swing.table.DefaultTableModel;
-import java.awt.image.BufferedImage;
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.GridBagLayout;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import java.awt.FlowLayout;
-import java.awt.Color;
-import java.awt.Image;
-import java.awt.Graphics2D;
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
-import java.awt.event.MouseWheelListener;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.concurrent.ExecutionException;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreePath;
public class Workspace extends JFrame {
private JLabel viewCountLabel;
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/ui/action/BackgroundAction.java b/hierarchyviewer/src/com/android/hierarchyviewer/ui/action/BackgroundAction.java
index 051e3f3..b2046fd 100644
--- a/hierarchyviewer/src/com/android/hierarchyviewer/ui/action/BackgroundAction.java
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/ui/action/BackgroundAction.java
@@ -16,9 +16,8 @@
package com.android.hierarchyviewer.ui.action;
-import org.jdesktop.swingworker.SwingWorker;
-
import javax.swing.AbstractAction;
+import javax.swing.SwingWorker;
public abstract class BackgroundAction extends AbstractAction {
protected void executeBackgroundTask(SwingWorker<?, ?> worker) {
diff --git a/hierarchyviewer2/app/etc/manifest.txt b/hierarchyviewer2/app/etc/manifest.txt
index 0caa3c2..68222bd 100644
--- a/hierarchyviewer2/app/etc/manifest.txt
+++ b/hierarchyviewer2/app/etc/manifest.txt
@@ -1,2 +1,2 @@
Main-Class: com.android.hierarchyviewer.HierarchyViewerApplication
-Class-Path: ddmlib.jar ddmuilib.jar hierarchyviewerlib.jar sdklib.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar org.eclipse.equinox.common_3.6.0.v20100503.jar
+Class-Path: ddmlib.jar ddmuilib.jar hierarchyviewerlib.jar sdklib.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar org.eclipse.equinox.common_3.6.0.v20100503.jar guava-tools.jar
diff --git a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
index 38f10bc..8983f67 100644
--- a/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
+++ b/hierarchyviewer2/app/src/com/android/hierarchyviewer/HierarchyViewerApplication.java
@@ -47,6 +47,7 @@ import com.android.hierarchyviewerlib.models.PixelPerfectModel.IImageChangeListe
import com.android.hierarchyviewerlib.models.TreeViewModel;
import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener;
import com.android.hierarchyviewerlib.ui.DeviceSelector;
+import com.android.hierarchyviewerlib.ui.InvokeMethodPrompt;
import com.android.hierarchyviewerlib.ui.LayoutViewer;
import com.android.hierarchyviewerlib.ui.PixelPerfect;
import com.android.hierarchyviewerlib.ui.PixelPerfectControls;
@@ -127,9 +128,9 @@ public class HierarchyViewerApplication extends ApplicationWindow {
private LayoutViewer mLayoutViewer;
private PixelPerfectLoupe mPixelPerfectLoupe;
private Composite mTreeViewControls;
+ private InvokeMethodPrompt mInvokeMethodPrompt;
private ActionButton dumpDisplayList;
- private ActionButton mProfileNodes;
private HierarchyViewerDirector mDirector;
@@ -428,8 +429,13 @@ public class HierarchyViewerApplication extends ApplicationWindow {
new TreeViewOverview(treeViewOverviewContainer);
Composite propertyViewerContainer = new Composite(sideSash, SWT.BORDER);
- propertyViewerContainer.setLayout(new FillLayout());
- new PropertyViewer(propertyViewerContainer);
+ propertyViewerContainer.setLayout(new GridLayout());
+
+ PropertyViewer pv = new PropertyViewer(propertyViewerContainer);
+ pv.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ mInvokeMethodPrompt = new InvokeMethodPrompt(propertyViewerContainer);
+ mInvokeMethodPrompt.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Composite layoutViewerContainer = new Composite(sideSash, SWT.NONE);
GridLayout layoutViewerLayout = new GridLayout();
@@ -695,6 +701,8 @@ public class HierarchyViewerApplication extends ApplicationWindow {
mTreeViewButton.setSelection(true);
mTreeViewButton.setImage(mTreeViewSelectedImage);
+ mInvokeMethodPrompt.setEnabled(hvDevice.isViewUpdateEnabled());
+
mPixelPerfectButton.setSelection(false);
mPixelPerfectButton.setImage(mPixelPerfectImage);
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/.classpath b/hierarchyviewer2/libs/hierarchyviewerlib/.classpath
index 105d22e..779f384 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/.classpath
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/.classpath
@@ -4,6 +4,8 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmuilib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/common"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/linux-x86/swt/swt.jar"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/eclipse/org.eclipse.core.commands_3.6.0.I20100512-1500.jar"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/eclipse/org.eclipse.equinox.common_3.6.0.v20100503.jar"/>
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/manifest.txt b/hierarchyviewer2/libs/hierarchyviewerlib/manifest.txt
index 3805b59..984261a 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/manifest.txt
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/manifest.txt
@@ -1 +1 @@
-Class-Path: ddmlib.jar ddmuilib.jar hierarchyviewerlib.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar org.eclipse.equinox.common_3.6.0.v20100503.jar
+Class-Path: ddmlib.jar ddmuilib.jar hierarchyviewerlib.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar org.eclipse.equinox.common_3.6.0.v20100503.jar guava-13.0.1.jar common.jar
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk b/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
index 1afbc92..59753e1 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/Android.mk
@@ -20,8 +20,10 @@ LOCAL_JAVA_RESOURCE_DIRS := ../src
LOCAL_JAR_MANIFEST := ../manifest.txt
-LOCAL_JAVA_LIBRARIES := ddmlib \
+LOCAL_JAVA_LIBRARIES := common \
+ ddmlib \
ddmuilib \
+ guava-tools \
swt \
org.eclipse.jface_3.6.2.M20110210-1200 \
org.eclipse.core.commands_3.6.0.I20100512-1500
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
index 0f0cf65..cba35f2 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/HierarchyViewerDirector.java
@@ -48,6 +48,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -615,6 +616,20 @@ public abstract class HierarchyViewerDirector implements IDeviceChangeListener,
}
}
+ public void invokeMethodOnSelectedView(final String method, final List<Object> args) {
+ final DrawableViewNode selectedNode = TreeViewModel.getModel().getSelection();
+ if (selectedNode != null) {
+ executeInBackground("Invoke View Method", new Runnable() {
+ @Override
+ public void run() {
+ IHvDevice hvDevice = getHvDevice(selectedNode.viewNode.window.getDevice());
+ hvDevice.invokeViewMethod(selectedNode.viewNode.window, selectedNode.viewNode,
+ method, args);
+ }
+ });
+ }
+ }
+
public void loadAllViews() {
executeInBackground("Loading all views", new Runnable() {
@Override
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
index 0a6e938..0172995 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/DdmViewDebugDevice.java
@@ -144,7 +144,7 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
try {
HandleViewDebug.listViewRoots(c, handler);
} catch (IOException e) {
- Log.e(TAG, e);
+ Log.i(TAG, "No connection to client: " + cd.getClientDescription());
continue;
}
@@ -215,7 +215,11 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
return null;
}
- byte[] data = handler.getData(10, TimeUnit.SECONDS);
+ byte[] data = handler.getData(20, TimeUnit.SECONDS);
+ if (data == null) {
+ return null;
+ }
+
String viewHierarchy = new String(data, Charset.forName("UTF-8"));
return DeviceBridge.parseViewHierarchy(new BufferedReader(new StringReader(viewHierarchy)),
window);
@@ -370,4 +374,44 @@ public class DdmViewDebugDevice extends AbstractHvDevice implements IDeviceChang
reloadWindows();
}
}
+
+ @Override
+ public boolean isViewUpdateEnabled() {
+ return true;
+ }
+
+ @Override
+ public void invokeViewMethod(Window window, ViewNode viewNode, String method,
+ List<?> args) {
+ Client c = window.getClient();
+ if (c == null) {
+ return;
+ }
+
+ String viewRoot = window.getTitle();
+ try {
+ HandleViewDebug.invokeMethod(c, viewRoot, viewNode.toString(), method, args.toArray());
+ } catch (IOException e) {
+ Log.e(TAG, e);
+ }
+ }
+
+ @Override
+ public boolean setLayoutParameter(Window window, ViewNode viewNode, String property,
+ int value) {
+ Client c = window.getClient();
+ if (c == null) {
+ return false;
+ }
+
+ String viewRoot = window.getTitle();
+ try {
+ HandleViewDebug.setLayoutParameter(c, viewRoot, viewNode.toString(), property, value);
+ } catch (IOException e) {
+ Log.e(TAG, e);
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
index c38a9cc..24a5a4f 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/HvDeviceFactory.java
@@ -21,13 +21,26 @@ import com.android.ddmlib.ClientData;
import com.android.ddmlib.IDevice;
public class HvDeviceFactory {
- private static final boolean ALWAYS_USE_VIEWSERVER = false; // for debugging
+ private static final String sHvProtoEnvVar =
+ System.getenv("ANDROID_HVPROTO"); //$NON-NLS-1$
public static IHvDevice create(IDevice device) {
- if (ALWAYS_USE_VIEWSERVER) {
+ // default to old mechanism until the new one is fully tested
+ if (sHvProtoEnvVar == null ||
+ !"ddm".equalsIgnoreCase(sHvProtoEnvVar)) { //$NON-NLS-1$
return new ViewServerDevice(device);
}
+ // Wait for a few seconds after the device has been connected to
+ // allow all the clients to be initialized. Specifically, we need to wait
+ // until the client data is filled with the list of features supported
+ // by the client.
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
boolean ddmViewHierarchy = false;
// see if any of the clients on the device support view hierarchy via DDMS
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
index fe8d1ba..6f1fd37 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/IHvDevice.java
@@ -24,6 +24,8 @@ import com.android.hierarchyviewerlib.ui.util.PsdFile;
import org.eclipse.swt.graphics.Image;
+import java.util.List;
+
/** Represents a device that can perform view debug operations. */
public interface IHvDevice {
/**
@@ -51,6 +53,10 @@ public interface IHvDevice {
void requestLayout(ViewNode viewNode);
void outputDisplayList(ViewNode viewNode);
+ boolean isViewUpdateEnabled();
+ void invokeViewMethod(Window window, ViewNode viewNode, String method, List<?> args);
+ boolean setLayoutParameter(Window window, ViewNode viewNode, String property, int value);
+
void addWindowChangeListener(IWindowChangeListener l);
void removeWindowChangeListener(IWindowChangeListener l);
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
index 0febcef..4445e9a 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/device/ViewServerDevice.java
@@ -26,6 +26,8 @@ import com.android.hierarchyviewerlib.ui.util.PsdFile;
import org.eclipse.swt.graphics.Image;
+import java.util.List;
+
public class ViewServerDevice extends AbstractHvDevice {
static final String TAG = "ViewServerDevice";
@@ -146,4 +148,22 @@ public class ViewServerDevice extends AbstractHvDevice {
WindowUpdater.stopListenForWindowChanges(l, mDevice);
}
}
+
+ @Override
+ public boolean isViewUpdateEnabled() {
+ return false;
+ }
+
+ @Override
+ public void invokeViewMethod(Window window, ViewNode viewNode, String method,
+ List<?> args) {
+ // not supported
+ }
+
+ @Override
+ public boolean setLayoutParameter(Window window, ViewNode viewNode, String property,
+ int value) {
+ // not supported
+ return false;
+ }
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java
new file mode 100644
index 0000000..1bbc97f
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/DevicePropertyEditingSupport.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.hierarchyviewerlib.ui;
+
+import com.android.SdkConstants;
+import com.android.hierarchyviewerlib.device.IHvDevice;
+import com.android.hierarchyviewerlib.models.ViewNode;
+import com.android.hierarchyviewerlib.models.ViewNode.Property;
+import com.android.utils.SdkUtils;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+public class DevicePropertyEditingSupport {
+ public enum PropertyType {
+ INTEGER,
+ INTEGER_OR_CONSTANT,
+ ENUM,
+ };
+
+ private static final List<IDevicePropertyEditor> sDevicePropertyEditors = Arrays.asList(
+ new LayoutPropertyEditor(),
+ new PaddingPropertyEditor()
+ );
+
+ public boolean canEdit(Property p) {
+ return getPropertyEditorFor(p) != null;
+ }
+
+ private IDevicePropertyEditor getPropertyEditorFor(Property p) {
+ for (IDevicePropertyEditor pe: sDevicePropertyEditors) {
+ if (pe.canEdit(p)) {
+ return pe;
+ }
+ }
+
+ return null;
+ }
+
+ public PropertyType getPropertyType(Property p) {
+ return getPropertyEditorFor(p).getType(p);
+ }
+
+ public String[] getPropertyRange(Property p) {
+ return getPropertyEditorFor(p).getPropertyRange(p);
+ }
+
+ public boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ return getPropertyEditorFor(p).setValue(properties, p, newValue, viewNode, device);
+ }
+
+ private static String stripCategoryPrefix(String name) {
+ return name.substring(name.indexOf(':') + 1);
+ }
+
+ private interface IDevicePropertyEditor {
+ boolean canEdit(Property p);
+ PropertyType getType(Property p);
+ String[] getPropertyRange(Property p);
+ boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device);
+ }
+
+ private static class LayoutPropertyEditor implements IDevicePropertyEditor {
+ private static final Set<String> sLayoutPropertiesWithStringValues =
+ ImmutableSet.of(SdkConstants.ATTR_LAYOUT_WIDTH,
+ SdkConstants.ATTR_LAYOUT_HEIGHT,
+ SdkConstants.ATTR_LAYOUT_GRAVITY);
+
+ private static final int MATCH_PARENT = -1;
+ private static final int FILL_PARENT = -1;
+ private static final int WRAP_CONTENT = -2;
+
+ private enum LayoutGravity {
+ top(0x30),
+ bottom(0x50),
+ left(0x03),
+ right(0x05),
+ center_vertical(0x10),
+ fill_vertical(0x70),
+ center_horizontal(0x01),
+ fill_horizontal(0x07),
+ center(0x11),
+ fill(0x77),
+ clip_vertical(0x80),
+ clip_horizontal(0x08),
+ start(0x00800003),
+ end(0x00800005);
+
+ private final int mValue;
+
+ private LayoutGravity(int v) {
+ mValue = v;
+ }
+ }
+
+ /**
+ * Returns true if this is a layout property with either a known string value, or an
+ * integer value.
+ */
+ @Override
+ public boolean canEdit(Property p) {
+ String name = stripCategoryPrefix(p.name);
+ if (!name.startsWith(SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX)) {
+ return false;
+ }
+
+ if (sLayoutPropertiesWithStringValues.contains(name)) {
+ return true;
+ }
+
+ try {
+ SdkUtils.parseLocalizedInt(p.value);
+ return true;
+ } catch (ParseException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public PropertyType getType(Property p) {
+ String name = stripCategoryPrefix(p.name);
+ if (sLayoutPropertiesWithStringValues.contains(name)) {
+ return PropertyType.INTEGER_OR_CONSTANT;
+ } else {
+ return PropertyType.INTEGER;
+ }
+ }
+
+ @Override
+ public String[] getPropertyRange(Property p) {
+ return new String[0];
+ }
+
+ @Override
+ public boolean setValue(Collection<Property> properties, Property p, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ String name = stripCategoryPrefix(p.name);
+
+ // nothing to do if same as current value
+ if (p.value.equals(newValue)) {
+ return false;
+ }
+
+ int value = -1;
+ String textValue = null;
+
+ if (SdkConstants.ATTR_LAYOUT_GRAVITY.equals(name)) {
+ value = 0;
+ StringBuilder sb = new StringBuilder(20);
+ for (String attr: Splitter.on('|').split((String) newValue)) {
+ LayoutGravity g;
+ try {
+ g = LayoutGravity.valueOf(attr);
+ } catch (IllegalArgumentException e) {
+ // ignore this gravity attribute
+ continue;
+ }
+
+ value |= g.mValue;
+
+ if (sb.length() > 0) {
+ sb.append('|');
+ }
+ sb.append(g.name());
+ }
+ textValue = sb.toString();
+ } else if (SdkConstants.ATTR_LAYOUT_HEIGHT.equals(name)
+ || SdkConstants.ATTR_LAYOUT_WIDTH.equals(name)) {
+ // newValue is of type string, but its contents may be a named constant or a integer
+ String s = (String) newValue;
+ if (s.equalsIgnoreCase(SdkConstants.VALUE_MATCH_PARENT)) {
+ textValue = SdkConstants.VALUE_MATCH_PARENT;
+ value = MATCH_PARENT;
+ } else if (s.equalsIgnoreCase(SdkConstants.VALUE_FILL_PARENT)) {
+ textValue = SdkConstants.VALUE_FILL_PARENT;
+ value = FILL_PARENT;
+ } else if (s.equalsIgnoreCase(SdkConstants.VALUE_WRAP_CONTENT)) {
+ textValue = SdkConstants.VALUE_WRAP_CONTENT;
+ value = WRAP_CONTENT;
+ }
+ }
+
+ if (textValue == null) {
+ try {
+ value = Integer.parseInt((String) newValue);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ // attempt to set the value on the device
+ name = name.substring(SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX.length());
+ if (device.setLayoutParameter(viewNode.window, viewNode, name, value)) {
+ p.value = textValue != null ? textValue : (String) newValue;
+ }
+
+ return true;
+ }
+ }
+
+ private static class PaddingPropertyEditor implements IDevicePropertyEditor {
+ // These names should match the field names used for padding in the Framework's View class
+ private static final String PADDING_LEFT = "mPaddingLeft"; //$NON-NLS-1$
+ private static final String PADDING_RIGHT = "mPaddingRight"; //$NON-NLS-1$
+ private static final String PADDING_TOP = "mPaddingTop"; //$NON-NLS-1$
+ private static final String PADDING_BOTTOM = "mPaddingBottom"; //$NON-NLS-1$
+
+ private static final Set<String> sPaddingProperties = ImmutableSet.of(
+ PADDING_LEFT, PADDING_RIGHT, PADDING_TOP, PADDING_BOTTOM);
+
+ @Override
+ public boolean canEdit(Property p) {
+ return sPaddingProperties.contains(stripCategoryPrefix(p.name));
+ }
+
+ @Override
+ public PropertyType getType(Property p) {
+ return PropertyType.INTEGER;
+ }
+
+ @Override
+ public String[] getPropertyRange(Property p) {
+ return new String[0];
+ }
+
+ /**
+ * Set padding: Since the only view method is setPadding(l, t, r, b), we need access
+ * to all 4 padding's to update any particular one.
+ */
+ @Override
+ public boolean setValue(Collection<Property> properties, Property prop, Object newValue,
+ ViewNode viewNode, IHvDevice device) {
+ int v;
+ try {
+ v = Integer.parseInt((String) newValue);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+
+ int pLeft = 0;
+ int pRight = 0;
+ int pTop = 0;
+ int pBottom = 0;
+
+ String propName = stripCategoryPrefix(prop.name);
+ for (Property p: properties) {
+ String name = stripCategoryPrefix(p.name);
+ if (!sPaddingProperties.contains(name)) {
+ continue;
+ }
+
+ if (name.equals(PADDING_LEFT)) {
+ pLeft = propName.equals(PADDING_LEFT) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_RIGHT)) {
+ pRight = propName.equals(PADDING_RIGHT) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_TOP)) {
+ pTop = propName.equals(PADDING_TOP) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ } else if (name.equals(PADDING_BOTTOM)) {
+ pBottom = propName.equals(PADDING_BOTTOM) ?
+ v : SdkUtils.parseLocalizedInt(p.value, 0);
+ }
+ }
+
+ // invoke setPadding() on the device
+ device.invokeViewMethod(viewNode.window, viewNode, "setPadding", Arrays.asList(
+ Integer.valueOf(pLeft),
+ Integer.valueOf(pTop),
+ Integer.valueOf(pRight),
+ Integer.valueOf(pBottom)
+ ));
+
+ // update the value set in the property (to avoid reading all properties back from
+ // the device)
+ prop.value = Integer.toString(v);
+ return true;
+ }
+ }
+}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java
new file mode 100644
index 0000000..944a57a
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/InvokeMethodPrompt.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.hierarchyviewerlib.ui;
+
+import com.android.ddmlib.Log;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+import com.android.hierarchyviewerlib.device.IHvDevice;
+import com.android.hierarchyviewerlib.models.TreeViewModel;
+import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener;
+import com.android.hierarchyviewerlib.models.ViewNode;
+import com.android.hierarchyviewerlib.ui.util.DrawableViewNode;
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Text;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class InvokeMethodPrompt extends Composite implements ITreeChangeListener {
+ private TreeViewModel mModel;
+ private DrawableViewNode mSelectedNode;
+ private Text mText;
+ private static final Splitter CMD_SPLITTER = Splitter.on(CharMatcher.anyOf(", "))
+ .trimResults().omitEmptyStrings();
+
+ public InvokeMethodPrompt(Composite parent) {
+ super(parent, SWT.NONE);
+ setLayout(new FillLayout());
+
+ mText = new Text(this, SWT.BORDER);
+ mText.addKeyListener(new KeyListener() {
+ @Override
+ public void keyReleased(KeyEvent ke) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent ke) {
+ onKeyPress(ke);
+ }
+ });
+
+ mModel = TreeViewModel.getModel();
+ mModel.addTreeChangeListener(this);
+ }
+
+ private void onKeyPress(KeyEvent ke) {
+ if (ke.keyCode == SWT.CR) {
+ String cmd = mText.getText().trim();
+ if (!cmd.isEmpty()) {
+ invokeViewMethod(cmd);
+ }
+ mText.setText("");
+ }
+ }
+
+ private void invokeViewMethod(String cmd) {
+ Iterator<String> segmentIterator = CMD_SPLITTER.split(cmd).iterator();
+
+ String method = null;
+ if (segmentIterator.hasNext()) {
+ method = segmentIterator.next();
+ } else {
+ return;
+ }
+
+ List<Object> args = new ArrayList<Object>(10);
+ while (segmentIterator.hasNext()) {
+ String arg = segmentIterator.next();
+
+ // check for boolean
+ if (arg.equalsIgnoreCase("true")) {
+ args.add(Boolean.TRUE);
+ continue;
+ } else if (arg.equalsIgnoreCase("false")) {
+ args.add(Boolean.FALSE);
+ continue;
+ }
+
+ // see if last character gives a clue regarding the argument type
+ char typeSpecifier = Character.toUpperCase(arg.charAt(arg.length() - 1));
+ try {
+ switch (typeSpecifier) {
+ case 'L':
+ args.add(Long.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'D':
+ args.add(Double.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'F':
+ args.add(Float.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'S':
+ args.add(Short.valueOf(arg.substring(0, arg.length())));
+ break;
+ case 'B':
+ args.add(Byte.valueOf(arg.substring(0, arg.length())));
+ break;
+ default: // default to integer
+ args.add(Integer.valueOf(arg));
+ break;
+ }
+ } catch (NumberFormatException e) {
+ Log.e("hv", "Unable to parse method argument: " + arg);
+ return;
+ }
+ }
+
+ HierarchyViewerDirector.getDirector().invokeMethodOnSelectedView(method, args);
+ }
+
+ @Override
+ public void selectionChanged() {
+ mSelectedNode = mModel.getSelection();
+ refresh();
+ }
+
+ private boolean isViewUpdateEnabled(ViewNode viewNode) {
+ IHvDevice device = viewNode.window.getHvDevice();
+ return device != null && device.isViewUpdateEnabled();
+ }
+
+ private void refresh() {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ mText.setEnabled(mSelectedNode != null
+ && isViewUpdateEnabled(mSelectedNode.viewNode));
+ }
+ });
+ }
+
+ @Override
+ public void treeChanged() {
+ selectionChanged();
+ }
+
+ @Override
+ public void viewportChanged() {
+ }
+
+ @Override
+ public void zoomChanged() {
+ }
+}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
index 90d2405..9456a0a 100644
--- a/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/com/android/hierarchyviewerlib/ui/PropertyViewer.java
@@ -16,17 +16,27 @@
package com.android.hierarchyviewerlib.ui;
+import com.android.ddmuilib.ImageLoader;
+import com.android.hierarchyviewerlib.HierarchyViewerDirector;
+import com.android.hierarchyviewerlib.device.IHvDevice;
import com.android.hierarchyviewerlib.models.TreeViewModel;
-import com.android.hierarchyviewerlib.models.ViewNode;
import com.android.hierarchyviewerlib.models.TreeViewModel.ITreeChangeListener;
+import com.android.hierarchyviewerlib.models.ViewNode;
import com.android.hierarchyviewerlib.models.ViewNode.Property;
+import com.android.hierarchyviewerlib.ui.DevicePropertyEditingSupport.PropertyType;
import com.android.hierarchyviewerlib.ui.util.DrawableViewNode;
import com.android.hierarchyviewerlib.ui.util.TreeColumnResizer;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
@@ -42,13 +52,17 @@ import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import java.util.ArrayList;
+import java.util.Collection;
public class PropertyViewer extends Composite implements ITreeChangeListener {
private TreeViewModel mModel;
private TreeViewer mTreeViewer;
-
private Tree mTree;
+ private TreeViewerColumn mValueColumn;
+ private PropertyValueEditingSupport mPropertyValueEditingSupport;
+
+ private Image mImage;
private DrawableViewNode mSelectedNode;
@@ -144,6 +158,13 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
@Override
public Image getColumnImage(Object element, int column) {
+ if (mSelectedNode == null) {
+ return null;
+ }
+ if (column == 1 && mPropertyValueEditingSupport.canEdit(element)) {
+ return mImage;
+ }
+
return null;
}
@@ -188,6 +209,79 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
}
}
+ private class PropertyValueEditingSupport extends EditingSupport {
+ private DevicePropertyEditingSupport mDevicePropertyEditingSupport =
+ new DevicePropertyEditingSupport();
+
+ public PropertyValueEditingSupport(ColumnViewer viewer) {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ if (mSelectedNode == null) {
+ return false;
+ }
+
+ return element instanceof Property
+ && mSelectedNode.viewNode.window.getHvDevice().isViewUpdateEnabled()
+ && mDevicePropertyEditingSupport.canEdit((Property) element);
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ Property p = (Property) element;
+ PropertyType type = mDevicePropertyEditingSupport.getPropertyType(p);
+ Composite parent = (Composite) getViewer().getControl();
+
+ switch (type) {
+ case INTEGER:
+ case INTEGER_OR_CONSTANT:
+ return new TextCellEditor(parent);
+ case ENUM:
+ String[] items = mDevicePropertyEditingSupport.getPropertyRange(p);
+ return new ComboBoxCellEditor(parent, items, SWT.READ_ONLY);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ Property p = (Property) element;
+ PropertyType type = mDevicePropertyEditingSupport.getPropertyType(p);
+
+ if (type == PropertyType.ENUM) {
+ // for enums, return the index of the current value in the list of possible values
+ String[] items = mDevicePropertyEditingSupport.getPropertyRange(p);
+ return Integer.valueOf(indexOf(p.value, items));
+ }
+
+ return ((Property) element).value;
+ }
+
+ private int indexOf(String item, String[] items) {
+ for (int i = 0; i < items.length; i++) {
+ if (items[i].equals(item)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Override
+ protected void setValue(Object element, Object newValue) {
+ Property p = (Property) element;
+ IHvDevice device = mSelectedNode.viewNode.window.getHvDevice();
+ Collection<Property> properties = mSelectedNode.viewNode.namedProperties.values();
+ if (mDevicePropertyEditingSupport.setValue(properties, p, newValue,
+ mSelectedNode.viewNode, device)) {
+ doRefresh();
+ }
+ }
+ }
+
public PropertyViewer(Composite parent) {
super(parent, SWT.NONE);
setLayout(new FillLayout());
@@ -202,6 +296,10 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
TreeColumn valueColumn = new TreeColumn(mTree, SWT.NONE);
valueColumn.setText("Value");
+ mValueColumn = new TreeViewerColumn(mTreeViewer, valueColumn);
+ mPropertyValueEditingSupport = new PropertyValueEditingSupport(mTreeViewer);
+ mValueColumn.setEditingSupport(mPropertyValueEditingSupport);
+
mModel = TreeViewModel.getModel();
ContentProvider contentProvider = new ContentProvider();
mTreeViewer.setContentProvider(contentProvider);
@@ -211,10 +309,14 @@ public class PropertyViewer extends Composite implements ITreeChangeListener {
addDisposeListener(mDisposeListener);
- new TreeColumnResizer(this, propertyColumn, valueColumn);
+ @SuppressWarnings("unused")
+ TreeColumnResizer resizer = new TreeColumnResizer(this, propertyColumn, valueColumn);
addControlListener(mControlListener);
+ ImageLoader imageLoader = ImageLoader.getLoader(HierarchyViewerDirector.class);
+ mImage = imageLoader.loadImage("picker.png", Display.getDefault()); //$NON-NLS-1$
+
treeChanged();
}
diff --git a/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png b/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png
new file mode 100644
index 0000000..8ea2bed
--- /dev/null
+++ b/hierarchyviewer2/libs/hierarchyviewerlib/src/images/picker.png
Binary files differ
diff --git a/jobb/Android.mk b/jobb/Android.mk
index 9865f30..1a58732 100644
--- a/jobb/Android.mk
+++ b/jobb/Android.mk
@@ -23,7 +23,7 @@ LOCAL_MODULE_TAGS := debug
LOCAL_JAVA_LIBRARIES := fat32lib
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/layoutlib_api/Android.mk b/layoutlib_api/Android.mk
index 32ee53f..169cf37 100644
--- a/layoutlib_api/Android.mk
+++ b/layoutlib_api/Android.mk
@@ -16,7 +16,11 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
+# The layoutlib_api code has moved to tools/base/layoutlib_api.
+# The rule below uses the prebuilt layoutlib_api.jar.
+#
+# If you want to run the tests, cd to tools/base/layoutlib_api
+# and run ./gradlew :layoutlib_api:test
LOCAL_JAVA_LIBRARIES := \
common \
@@ -24,17 +28,8 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_MODULE := layoutlib_api
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-# build tests
-include $(CLEAR_VARS)
-
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
-
-LOCAL_MODULE := layoutlib_api-tests
-LOCAL_MODULE_TAGS := optional
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-LOCAL_JAVA_LIBRARIES := layoutlib_api junit
+include $(BUILD_HOST_PREBUILT)
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AdapterBinding.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AdapterBinding.java
deleted file mode 100644
index ddcdbd5..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AdapterBinding.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Describe the content of the dynamic android.widget.Adapter used to fill
- * android.widget.AdapterView
- */
-public class AdapterBinding implements Iterable<DataBindingItem> {
-
- private final int mRepeatCount;
- private final List<ResourceReference> mHeaders = new ArrayList<ResourceReference>();
- private final List<DataBindingItem> mItems = new ArrayList<DataBindingItem>();
- private final List<ResourceReference> mFooters = new ArrayList<ResourceReference>();
-
- public AdapterBinding(int repeatCount) {
- mRepeatCount = repeatCount;
- }
-
- public int getRepeatCount() {
- return mRepeatCount;
- }
-
- public void addHeader(ResourceReference layoutInfo) {
- mHeaders.add(layoutInfo);
- }
-
- public int getHeaderCount() {
- return mHeaders.size();
- }
-
- public ResourceReference getHeaderAt(int index) {
- return mHeaders.get(index);
- }
-
- public void addItem(DataBindingItem item) {
- mItems.add(item);
- }
-
- public int getItemCount() {
- return mItems.size();
- }
-
- public DataBindingItem getItemAt(int index) {
- return mItems.get(index);
- }
-
- public void addFooter(ResourceReference layoutInfo) {
- mFooters.add(layoutInfo);
- }
-
- public int getFooterCount() {
- return mFooters.size();
- }
-
- public ResourceReference getFooterAt(int index) {
- return mFooters.get(index);
- }
-
- @Override
- public Iterator<DataBindingItem> iterator() {
- return mItems.iterator();
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AttrResourceValue.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AttrResourceValue.java
deleted file mode 100644
index 530e3d5..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/AttrResourceValue.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.ResourceType;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A Resource value representing an attr resource.
- *
- * {@link #getValue()} will return null, instead use {@link #getAttributeValues()} to
- * get the enum/flag value associated with an attribute defined in the declare-styleable.
- *
- */
-public class AttrResourceValue extends ResourceValue {
-
- private Map<String, Integer> mValueMap;
-
-
- public AttrResourceValue(ResourceType type, String name, boolean isFramework) {
- super(type, name, isFramework);
- }
-
- /**
- * Return the enum/flag integer values.
- *
- * @return the map of (name, integer) values. Can be null.
- */
- public Map<String, Integer> getAttributeValues() {
- return mValueMap;
- }
-
- public void addValue(String name, Integer value) {
- if (mValueMap == null) {
- mValueMap = new HashMap<String, Integer>();
- }
-
- mValueMap.put(name, value);
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Bridge.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Bridge.java
deleted file mode 100644
index a19b8d5..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Bridge.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-
-import static com.android.ide.common.rendering.api.Result.Status.NOT_IMPLEMENTED;
-
-import com.android.ide.common.rendering.api.Result.Status;
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.util.EnumSet;
-import java.util.Map;
-
-/**
- * Entry point of the Layout Library. Extensions of this class provide a method to compute
- * and render a layout.
- */
-public abstract class Bridge {
-
- public final static int API_CURRENT = 9;
-
- /**
- * Returns the API level of the layout library.
- * <p/>
- * While no methods will ever be removed, some may become deprecated, and some new ones
- * will appear.
- * <p/>All Layout libraries based on {@link Bridge} return at minimum an API level of 5.
- */
- public abstract int getApiLevel();
-
- /**
- * Returns the revision of the library inside a given (layoutlib) API level.
- * The true revision number of the library is {@link #getApiLevel()}.{@link #getRevision()}
- */
- public int getRevision() {
- return 0;
- }
-
- /**
- * Returns an {@link EnumSet} of the supported {@link Capability}.
- * @return an {@link EnumSet} with the supported capabilities.
- *
- */
- public EnumSet<Capability> getCapabilities() {
- return EnumSet.noneOf(Capability.class);
- }
-
- /**
- * Initializes the Bridge object.
- *
- * @param platformProperties The build properties for the platform.
- * @param fontLocation the location of the fonts.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }. This is typically
- * read from attrs.xml in the SDK target.
- * @param log a {@link LayoutLog} object. Can be null.
- * @return true if success.
- */
- public boolean init(Map<String, String> platformProperties,
- File fontLocation,
- Map<String, Map<String, Integer>> enumValueMap,
- LayoutLog log) {
- return false;
- }
-
- /**
- * Prepares the layoutlib to unloaded.
- */
- public boolean dispose() {
- return false;
- }
-
- /**
- * Starts a layout session by inflating and rendering it. The method returns a
- * {@link RenderSession} on which further actions can be taken.
- *
- * @return a new {@link RenderSession} object that contains the result of the scene creation and
- * first rendering.
- */
- public RenderSession createSession(SessionParams params) {
- return null;
- }
-
- /**
- * Renders a Drawable. If the rendering is successful, the result image is accessible through
- * {@link Result#getData()}. It is of type {@link BufferedImage}
- * @param params the rendering parameters.
- * @return the result of the action.
- */
- public Result renderDrawable(DrawableParams params) {
- return Status.NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Clears the resource cache for a specific project.
- * <p/>This cache contains bitmaps and nine patches that are loaded from the disk and reused
- * until this method is called.
- * <p/>The cache is not configuration dependent and should only be cleared when a
- * resource changes (at this time only bitmaps and 9 patches go into the cache).
- * <p/>
- * The project key provided must be similar to the one passed in {@link RenderParams}.
- *
- * @param projectKey the key for the project.
- */
- public void clearCaches(Object projectKey) {
-
- }
-
- /**
- * Utility method returning the parent of a given view object.
- *
- * @param viewObject the object for which to return the parent.
- *
- * @return a {@link Result} indicating the status of the action, and if success, the parent
- * object in {@link Result#getData()}
- */
- public Result getViewParent(Object viewObject) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Utility method returning the index of a given view in its parent.
- * @param viewObject the object for which to return the index.
- *
- * @return a {@link Result} indicating the status of the action, and if success, the index in
- * the parent in {@link Result#getData()}
- */
- public Result getViewIndex(Object viewObject) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Utility method returning the baseline value for a given view object. This basically returns
- * View.getBaseline().
- *
- * @param viewObject the object for which to return the index.
- *
- * @return the baseline value or -1 if not applicable to the view object or if this layout
- * library does not implement this method.
- *
- * @deprecated use the extended ViewInfo.
- */
- @Deprecated
- public Result getViewBaseline(Object viewObject) {
- return NOT_IMPLEMENTED.createResult();
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Capability.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Capability.java
deleted file mode 100644
index 5ad438d..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Capability.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-/**
- * Enum describing the layout bridge capabilities.
- *
- */
-public enum Capability {
- /** Ability to render at full size, as required by the layout, and unbound by the screen */
- UNBOUND_RENDERING,
- /** Ability to override the background of the rendering with transparency using
- * {@link SessionParams#setOverrideBgColor(int)} */
- CUSTOM_BACKGROUND_COLOR,
- /** Ability to call {@link RenderSession#render()} and {@link RenderSession#render(long)}. */
- RENDER,
- /** Ability to ask for a layout only with no rendering through
- * {@link SessionParams#setLayoutOnly()}
- */
- LAYOUT_ONLY,
- /**
- * Ability to control embedded layout parsers through {@link ILayoutPullParser#getParser(String)}
- */
- EMBEDDED_LAYOUT,
- /** Ability to call<br>
- * {@link RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)}<br>
- * {@link RenderSession#moveChild(Object, Object, int, java.util.Map, IAnimationListener)}<br>
- * {@link RenderSession#setProperty(Object, String, String)}<br>
- * The method that receives an animation listener can only use it if the
- * ANIMATED_VIEW_MANIPULATION, or FULL_ANIMATED_VIEW_MANIPULATION is also supported.
- */
- VIEW_MANIPULATION,
- /** Ability to play animations with<br>
- * {@link RenderSession#animate(Object, String, boolean, IAnimationListener)}
- */
- PLAY_ANIMATION,
- /**
- * Ability to manipulate views with animation, as long as the view does not change parent.
- * {@link RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)}<br>
- * {@link RenderSession#moveChild(Object, Object, int, java.util.Map, IAnimationListener)}<br>
- * {@link RenderSession#removeChild(Object, IAnimationListener)}<br>
- */
- ANIMATED_VIEW_MANIPULATION,
- /**
- * Ability to move views (even into a different ViewGroup) with animation.
- * see {@link RenderSession#moveChild(Object, Object, int, java.util.Map, IAnimationListener)}
- */
- FULL_ANIMATED_VIEW_MANIPULATION,
- ADAPTER_BINDING,
- EXTENDED_VIEWINFO,
- /**
- * Ability to properly resize nine-patch assets.
- */
- FIXED_SCALABLE_NINE_PATCH;
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DataBindingItem.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DataBindingItem.java
deleted file mode 100644
index 2a93f15..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DataBindingItem.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.ResourceType;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A data binding item. It contain a {@link ResourceReference} to the view used to represent it.
- * It also contains how many items of this type the AdapterView should display.
- *
- * It can also contain an optional list of children in case the AdapterView is an
- * ExpandableListView. In this case, the count value is used as a repeat count for the children,
- * similar to {@link AdapterBinding#getRepeatCount()}.
- *
- */
-public class DataBindingItem implements Iterable<DataBindingItem> {
- private final ResourceReference mReference;
- private final int mCount;
- private List<DataBindingItem> mChildren;
-
- public DataBindingItem(ResourceReference reference, int count) {
- mReference = reference;
- mCount = count;
- }
-
- public DataBindingItem(String name, boolean platformLayout, int count) {
- this(new ResourceReference(name, platformLayout), count);
- }
-
- public DataBindingItem(String name, boolean platformLayout) {
- this(name, platformLayout, 1);
- }
-
- public DataBindingItem(String name, int count) {
- this(name, false /*platformLayout*/, count);
- }
-
- public DataBindingItem(String name) {
- this(name, false /*platformLayout*/, 1);
- }
-
- /**
- * Returns the {@link ResourceReference} for the view. The {@link ResourceType} for the
- * referenced resource is implied to be {@link ResourceType#LAYOUT}.
- */
- public ResourceReference getViewReference() {
- return mReference;
- }
-
- /**
- * The repeat count for this object or the repeat count for the children if there are any.
- */
- public int getCount() {
- return mCount;
- }
-
- public void addChild(DataBindingItem child) {
- if (mChildren == null) {
- mChildren = new ArrayList<DataBindingItem>();
- }
-
- mChildren.add(child);
- }
-
- public List<DataBindingItem> getChildren() {
- if (mChildren != null) {
- return mChildren;
- }
-
- return Collections.emptyList();
- }
-
- @Override
- public Iterator<DataBindingItem> iterator() {
- List<DataBindingItem> list = getChildren();
- return list.iterator();
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java
deleted file mode 100644
index a8f269f..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.ResourceType;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A Resource value representing a declare-styleable resource.
- *
- * {@link #getValue()} will return null, instead use {@link #getAttributeValues(String)} to
- * get the enum/flag value associated with an attribute defined in the declare-styleable.
- *
- * @deprecated This class is broken as it does not handle the namespace for each attribute.
- * Thankfully, newer versions of layoutlib don't actually use it, so we just keep it as is for
- * backward compatibility on older layoutlibs.
- *
- */
-@Deprecated
-public class DeclareStyleableResourceValue extends ResourceValue {
-
- private Map<String, AttrResourceValue> mAttrMap;
-
- public DeclareStyleableResourceValue(ResourceType type, String name, boolean isFramework) {
- super(type, name, isFramework);
- }
-
- /**
- * Return the enum/flag integer value for a given attribute.
- * @param name the name of the attribute
- * @return the map of (name, integer) values.
- */
- public Map<String, Integer> getAttributeValues(String name) {
- if (mAttrMap != null) {
- AttrResourceValue attr = mAttrMap.get(name);
- if (attr != null) {
- return attr.getAttributeValues();
- }
- }
-
- return null;
- }
-
- public Map<String, AttrResourceValue> getAllAttributes() {
- return mAttrMap;
- }
-
- public void addValue(AttrResourceValue attr) {
- if (mAttrMap == null) {
- mAttrMap = new HashMap<String, AttrResourceValue>();
- }
-
- mAttrMap.put(attr.getName(), attr);
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DensityBasedResourceValue.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DensityBasedResourceValue.java
deleted file mode 100644
index 5add715..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DensityBasedResourceValue.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.layoutlib.api.IDensityBasedResourceValue;
-import com.android.resources.ResourceType;
-
-@SuppressWarnings("deprecation")
-public class DensityBasedResourceValue extends ResourceValue implements IDensityBasedResourceValue {
-
- private com.android.resources.Density mDensity;
-
- public DensityBasedResourceValue(ResourceType type, String name, String value,
- com.android.resources.Density density, boolean isFramework) {
- super(type, name, value, isFramework);
- mDensity = density;
- }
-
- /**
- * Returns the density for which this resource is configured.
- * @return the density.
- */
- public com.android.resources.Density getResourceDensity() {
- return mDensity;
- }
-
- /** Legacy method, do not call
- * @deprecated use {@link #getResourceDensity()} instead.
- */
- @Override
- @Deprecated
- public Density getDensity() {
- return Density.getEnum(mDensity.getDpiValue());
- }
-
- @Override
- public String toString() {
- return "DensityBasedResourceValue ["
- + getResourceType() + "/" + getName() + " = " + getValue()
- + " (density:" + mDensity +", framework:" + isFramework() + ")]";
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + ((mDensity == null) ? 0 : mDensity.hashCode());
- return result;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!super.equals(obj))
- return false;
- if (getClass() != obj.getClass())
- return false;
- DensityBasedResourceValue other = (DensityBasedResourceValue) obj;
- if (mDensity == null) {
- if (other.mDensity != null)
- return false;
- } else if (!mDensity.equals(other.mDensity))
- return false;
- return true;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DrawableParams.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DrawableParams.java
deleted file mode 100644
index b566ad3..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/DrawableParams.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-
-/**
- * Rendering parameters for {@link Bridge#renderDrawable(DrawableParams)}
- *
- */
-public class DrawableParams extends RenderParams {
-
- private final ResourceValue mDrawable;
-
- /**
- * Builds a param object with all the necessary parameters to render a drawable with
- * {@link Bridge#renderDrawable(DrawableParams)}
- *
- * @param drawable the {@link ResourceValue} identifying the drawable.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param hardwareConfig the {@link HardwareConfig}.
- * @param renderResources a {@link RenderResources} object providing access to the resources.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param minSdkVersion the minSdkVersion of the project
- * @param targetSdkVersion the targetSdkVersion of the project
- * @param log the object responsible for displaying warning/errors to the user.
- */
- public DrawableParams(
- ResourceValue drawable,
- Object projectKey,
- HardwareConfig hardwareConfig,
- RenderResources renderResources,
- IProjectCallback projectCallback,
- int minSdkVersion, int targetSdkVersion,
- LayoutLog log) {
- super(projectKey, hardwareConfig,
- renderResources, projectCallback, minSdkVersion, targetSdkVersion, log);
- mDrawable = drawable;
- }
-
- public DrawableParams(DrawableParams params) {
- super(params);
- mDrawable = params.mDrawable;
- }
-
- public ResourceValue getDrawable() {
- return mDrawable;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/HardwareConfig.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/HardwareConfig.java
deleted file mode 100644
index 89f1424..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/HardwareConfig.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.Density;
-import com.android.resources.ScreenOrientation;
-import com.android.resources.ScreenSize;
-
-/**
- * Hardware configuration for the rendering.
- * This is immutable.
- *
- * @since 9
- */
-public class HardwareConfig {
-
- private final int mScreenWidth;
- private final int mScreenHeight;
- private final Density mDensity;
- private final float mXdpi;
- private final float mYdpi;
- private final ScreenOrientation mOrientation;
- private final ScreenSize mScreenSize;
-
- private final boolean mSoftwareButtons;
-
- public HardwareConfig(
- int screenWidth,
- int screenHeight,
- Density density,
- float xdpi,
- float ydpi,
- ScreenSize screenSize,
- ScreenOrientation orientation,
- boolean softwareButtons) {
- mScreenWidth = screenWidth;
- mScreenHeight = screenHeight;
- mDensity = density;
- mXdpi = xdpi;
- mYdpi = ydpi;
- mScreenSize = screenSize;
- mOrientation = orientation;
- mSoftwareButtons = softwareButtons;
- }
-
- public int getScreenWidth() {
- return mScreenWidth;
- }
-
- public int getScreenHeight() {
- return mScreenHeight;
- }
-
- public Density getDensity() {
- return mDensity;
- }
-
- public float getXdpi() {
- return mXdpi;
- }
-
- public float getYdpi() {
- return mYdpi;
- }
-
- public ScreenSize getScreenSize() {
- return mScreenSize;
- }
-
- public ScreenOrientation getOrientation() {
- return mOrientation;
- }
-
- public boolean hasSoftwareButtons() {
- return mSoftwareButtons;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IAnimationListener.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IAnimationListener.java
deleted file mode 100644
index 81a2320..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IAnimationListener.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-
-import java.awt.image.BufferedImage;
-
-public interface IAnimationListener {
- /**
- * Called when a new animation frame is available for display.
- *
- * <p>The {@link RenderSession} object is provided as a convenience. It should be queried
- * for the image through {@link RenderSession#getImage()}.
- *
- * <p>If no {@link IImageFactory} is used, then each new animation frame will be rendered
- * in its own new {@link BufferedImage} object. However if an image factory is used, and it
- * always re-use the same object, then the image is only guaranteed to be valid during
- * this method call. As soon as this method return the image content will be overridden
- * with new drawing.
- *
- */
- void onNewFrame(RenderSession scene);
-
- /**
- * Called when the animation is done playing.
- */
- void done(Result result);
-
- /**
- * Return true to cancel the animation.
- */
- boolean isCanceled();
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IImageFactory.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IImageFactory.java
deleted file mode 100644
index 7681243..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IImageFactory.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-
-import java.awt.image.BufferedImage;
-
-/**
- * Image Factory Interface.
- *
- * An Image factory's task is to create the {@link BufferedImage} into which the scene will be
- * rendered. The goal is to let the layoutlib caller create an image that's optimized for its use
- * case.
- *
- * If no factory is passed in {@link RenderParams#setImageFactory(IImageFactory)}, then a default
- * {@link BufferedImage} of type {@link BufferedImage#TYPE_INT_ARGB} is created.
- *
- */
-public interface IImageFactory {
-
- /**
- * Creates a buffered image with the given size
- * @param width the width of the image
- * @param height the height of the image
- * @return a new (or reused) BufferedImage of the given size.
- */
- BufferedImage getImage(int width, int height);
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ILayoutPullParser.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ILayoutPullParser.java
deleted file mode 100644
index 9c0e97b..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ILayoutPullParser.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * Extended version of {@link XmlPullParser} to use with
- * {@link Bridge#createSession(SessionParams)}
- */
-public interface ILayoutPullParser extends XmlPullParser {
-
- /**
- * Returns a cookie for the current XML node.
- * <p/>This cookie will be passed back in the {@link ViewInfo} objects, allowing association
- * of a particular XML node with its result from the layout computation.
- *
- * @see ViewInfo#getCookie()
- */
- Object getViewCookie();
-
- /**
- * Returns a custom parser for the layout of the given name.
- * @param layoutName the name of the layout.
- * @return returns a custom parser or null if no custom parsers are needed.
- *
- * @deprecated use {@link IProjectCallback#getParser(String)} instead
- */
- @Deprecated
- ILayoutPullParser getParser(String layoutName);
-}
-
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IProjectCallback.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IProjectCallback.java
deleted file mode 100644
index a88b0d3..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/IProjectCallback.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.ResourceType;
-import com.android.util.Pair;
-
-import java.net.URL;
-
-/**
- * Callback for project information needed by the Layout Library.
- * Classes implementing this interface provide methods giving access to some project data, like
- * resource resolution, namespace information, and instantiation of custom view.
- */
-public interface IProjectCallback {
-
- public enum ViewAttribute {
- TEXT(String.class),
- IS_CHECKED(Boolean.class),
- SRC(URL.class),
- COLOR(Integer.class);
-
- private final Class<?> mClass;
-
- private ViewAttribute(Class<?> theClass) {
- mClass = theClass;
- }
-
- public Class<?> getAttributeClass() {
- return mClass;
- }
- }
-
- /**
- * Loads a custom view with the given constructor signature and arguments.
- * @param name The fully qualified name of the class.
- * @param constructorSignature The signature of the class to use
- * @param constructorArgs The arguments to use on the constructor
- * @return A newly instantiated android.view.View object.
- * @throws ClassNotFoundException
- * @throws Exception
- */
- @SuppressWarnings("unchecked")
- Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
- throws ClassNotFoundException, Exception;
-
- /**
- * Returns the namespace of the application.
- * <p/>This lets the Layout Lib load custom attributes for custom views.
- */
- String getNamespace();
-
- /**
- * Resolves the id of a resource Id.
- * <p/>The resource id is the value of a <code>R.&lt;type&gt;.&lt;name&gt;</code>, and
- * this method will return both the type and name of the resource.
- * @param id the Id to resolve.
- * @return a Pair of {@link ResourceType} and resource name, or null if the id
- * does not match any resource.
- */
- @SuppressWarnings("deprecation")
- Pair<ResourceType, String> resolveResourceId(int id);
-
- /**
- * Resolves the id of a resource Id of type int[]
- * <p/>The resource id is the value of a R.styleable.&lt;name&gt;, and this method will
- * return the name of the resource.
- * @param id the Id to resolve.
- * @return the name of the resource or <code>null</code> if not found.
- */
- String resolveResourceId(int[] id);
-
- /**
- * Returns the id of a resource.
- * <p/>The provided type and name must match an existing constant defined as
- * <code>R.&lt;type&gt;.&lt;name&gt;</code>.
- * @param type the type of the resource
- * @param name the name of the resource
- * @return an Integer containing the resource Id, or <code>null</code> if not found.
- */
- Integer getResourceId(ResourceType type, String name);
-
- /**
- * Returns a custom parser for the layout of the given name.
- * @param layoutName the name of the layout.
- * @return returns a custom parser or null if no custom parsers are needed.
- * @deprecated This is replaced by {@link #getParser(ResourceValue)} but older version
- * of the layoutlib (before API7) will still call this method.
- */
- @Deprecated
- ILayoutPullParser getParser(String layoutName);
-
- /**
- * Returns a custom parser for a given layout.
- * @param layoutResource The layout.
- * @return returns a custom parser or null if no custom parsers are needed.
- */
- ILayoutPullParser getParser(ResourceValue layoutResource);
-
- /**
- * Returns the value of an item used by an adapter.
- * @param adapterView The {@link ResourceReference} for the adapter view info.
- * @param adapterCookie the view cookie for this particular view.
- * @param itemRef the {@link ResourceReference} for the layout used by the adapter item.
- * @param fullPosition the position of the item in the full list.
- * @param positionPerType the position of the item if only items of the same type are
- * considered. If there is only one type of items, this is the same as
- * <var>fullPosition</var>.
- * @param fullParentPosition the full position of the item's parent. This is only
- * valid if the adapter view is an ExpandableListView.
- * @param parentPositionPerType the position of the parent's item, only considering items
- * of the same type. This is only valid if the adapter view is an ExpandableListView.
- * If there is only one type of items, this is the same as <var>fullParentPosition</var>.
- * @param viewRef The {@link ResourceReference} for the view we're trying to fill.
- * @param viewAttribute the attribute being queried.
- * @param defaultValue the default value for this attribute. The object class matches the
- * class associated with the {@link ViewAttribute}.
- * @return the item value or null if there's no value.
- *
- * @see ViewAttribute#getAttributeClass()
- */
- Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie,
- ResourceReference itemRef,
- int fullPosition, int positionPerType,
- int fullParentPosition, int parentPositionPerType,
- ResourceReference viewRef, ViewAttribute viewAttribute, Object defaultValue);
-
- /**
- * Returns an adapter binding for a given adapter view.
- * This is only called if {@link SessionParams} does not have an {@link AdapterBinding} for
- * the given {@link ResourceReference} already.
- *
- * @param adapterViewRef the reference of adapter view to return the adapter binding for.
- * @param adapterCookie the view cookie for this particular view.
- * @param viewObject the view object for the adapter.
- * @return an adapter binding for the given view or null if there's no data.
- */
- AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie,
- Object viewObject);
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/LayoutLog.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/LayoutLog.java
deleted file mode 100644
index df29537..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/LayoutLog.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-/**
- * Log class for actions executed through {@link Bridge} and {@link RenderSession}.
- */
-public class LayoutLog {
- /**
- * Prefix for resource warnings/errors. This is not meant to be used as-is by the Layout
- * Library, but is there to help test against a wider type of warning/error.
- * <p/>
- * {@code tag.startsWith(LayoutLog.TAG_RESOURCE_PREFIX} will test if the tag is any type
- * of resource warning/error
- */
- public final static String TAG_RESOURCES_PREFIX = "resources.";
-
- /**
- * Prefix for matrix warnings/errors. This is not meant to be used as-is by the Layout
- * Library, but is there to help test against a wider type of warning/error.
- * <p/>
- * {@code tag.startsWith(LayoutLog.TAG_MATRIX_PREFIX} will test if the tag is any type
- * of matrix warning/error
- */
- public final static String TAG_MATRIX_PREFIX = "matrix.";
-
- /**
- * Tag for unsupported feature that can have a big impact on the rendering. For instance, aild
- * access.
- */
- public final static String TAG_UNSUPPORTED = "unsupported";
-
- /**
- * Tag for error when something really unexpected happens.
- */
- public final static String TAG_BROKEN = "broken";
-
- /**
- * Tag for resource resolution failure.
- * In this case the warning/error data object will be a ResourceValue containing the type
- * and name of the resource that failed to resolve
- */
- public final static String TAG_RESOURCES_RESOLVE = TAG_RESOURCES_PREFIX + "resolve";
-
- /**
- * Tag for resource resolution failure, specifically for theme attributes.
- * In this case the warning/error data object will be a ResourceValue containing the type
- * and name of the resource that failed to resolve
- */
- public final static String TAG_RESOURCES_RESOLVE_THEME_ATTR = TAG_RESOURCES_RESOLVE + ".theme";
-
- /**
- * Tag for failure when reading the content of a resource file.
- */
- public final static String TAG_RESOURCES_READ = TAG_RESOURCES_PREFIX + "read";
-
- /**
- * Tag for wrong format in a resource value.
- */
- public final static String TAG_RESOURCES_FORMAT = TAG_RESOURCES_PREFIX + "format";
-
- /**
- * Fidelity Tag used when a non affine transformation matrix is used in a Java API.
- */
- public final static String TAG_MATRIX_AFFINE = TAG_MATRIX_PREFIX + "affine";
-
- /**
- * Tag used when a matrix cannot be inverted.
- */
- public final static String TAG_MATRIX_INVERSE = TAG_MATRIX_PREFIX + "inverse";
-
- /**
- * Fidelity Tag used when a mask filter type is used but is not supported.
- */
- public final static String TAG_MASKFILTER = "maskfilter";
-
- /**
- * Fidelity Tag used when a draw filter type is used but is not supported.
- */
- public final static String TAG_DRAWFILTER = "drawfilter";
-
- /**
- * Fidelity Tag used when a path effect type is used but is not supported.
- */
- public final static String TAG_PATHEFFECT = "patheffect";
-
- /**
- * Fidelity Tag used when a color filter type is used but is not supported.
- */
- public final static String TAG_COLORFILTER = "colorfilter";
-
- /**
- * Fidelity Tag used when a rasterize type is used but is not supported.
- */
- public final static String TAG_RASTERIZER = "rasterizer";
-
- /**
- * Fidelity Tag used when a shader type is used but is not supported.
- */
- public final static String TAG_SHADER = "shader";
-
- /**
- * Fidelity Tag used when a xfermode type is used but is not supported.
- */
- public final static String TAG_XFERMODE = "xfermode";
-
- /**
- * Logs a warning.
- * @param tag a tag describing the type of the warning
- * @param message the message of the warning
- * @param data an optional data bundle that the client can use to improve the warning display.
- */
- public void warning(String tag, String message, Object data) {
- }
-
- /**
- * Logs a fidelity warning.
- *
- * This type of warning indicates that the render will not be
- * the same as the rendering on a device due to limitation of the Java rendering API.
- *
- * @param tag a tag describing the type of the warning
- * @param message the message of the warning
- * @param throwable an optional Throwable that triggered the warning
- * @param data an optional data bundle that the client can use to improve the warning display.
- */
- public void fidelityWarning(String tag, String message, Throwable throwable, Object data) {
- }
-
- /**
- * Logs an error.
- *
- * @param tag a tag describing the type of the error
- * @param message the message of the error
- * @param data an optional data bundle that the client can use to improve the error display.
- */
- public void error(String tag, String message, Object data) {
- }
-
- /**
- * Logs an error, and the {@link Throwable} that triggered it.
- *
- * @param tag a tag describing the type of the error
- * @param message the message of the error
- * @param throwable the Throwable that triggered the error
- * @param data an optional data bundle that the client can use to improve the error display.
- */
- public void error(String tag, String message, Throwable throwable, Object data) {
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/MergeCookie.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/MergeCookie.java
deleted file mode 100644
index ce5d21d..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/MergeCookie.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-/**
- * Special wrapper class used in special case for {@link ILayoutPullParser#getViewCookie()}.
- * <p/>
- * When an {@code include} tag points to a layout with a {@code merge} top level item, there is no
- * top level item that can use the {@code include} item as cookie.
- * <p/>
- * This class is used as a cookie for all items under the {@code merge} (while referencing the
- * original {@code include} cookie) to make it easy on the client to group all merged items
- * into a single outline item.
- *
- */
-public final class MergeCookie {
-
- private final Object mCookie;
-
- public MergeCookie(Object cookie) {
- mCookie = cookie;
-
- }
-
- public Object getCookie() {
- return mCookie;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderParams.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderParams.java
deleted file mode 100644
index 2e53f14..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderParams.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.Density;
-import com.android.resources.ScreenSize;
-
-/**
- * Base class for rendering parameters. This include the generic parameters but not what needs
- * to be rendered or additional parameters.
- *
- */
-public abstract class RenderParams {
-
- public final static long DEFAULT_TIMEOUT = 250; //ms
-
- private final Object mProjectKey;
- private final HardwareConfig mHardwareConfig;
- private final RenderResources mRenderResources;
- private final IProjectCallback mProjectCallback;
- private final int mMinSdkVersion;
- private final int mTargetSdkVersion;
- private final LayoutLog mLog;
-
- private boolean mCustomBackgroundEnabled;
- private int mCustomBackgroundColor;
- private long mTimeout;
-
- private IImageFactory mImageFactory = null;
-
- private String mAppIcon = null;
- private String mAppLabel = null;
- private String mLocale = null;
- private boolean mForceNoDecor;
-
- /**
- *
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param hardwareConfig the {@link HardwareConfig}.
- * @param renderResources a {@link RenderResources} object providing access to the resources.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param minSdkVersion the minSdkVersion of the project
- * @param targetSdkVersion the targetSdkVersion of the project
- * @param log the object responsible for displaying warning/errors to the user.
- */
- public RenderParams(
- Object projectKey,
- HardwareConfig hardwareConfig,
- RenderResources renderResources,
- IProjectCallback projectCallback,
- int minSdkVersion, int targetSdkVersion,
- LayoutLog log) {
- mProjectKey = projectKey;
- mHardwareConfig = hardwareConfig;
- mRenderResources = renderResources;
- mProjectCallback = projectCallback;
- mMinSdkVersion = minSdkVersion;
- mTargetSdkVersion = targetSdkVersion;
- mLog = log;
- mCustomBackgroundEnabled = false;
- mTimeout = DEFAULT_TIMEOUT;
- }
-
- /**
- * Copy constructor.
- */
- public RenderParams(RenderParams params) {
- mProjectKey = params.mProjectKey;
- mHardwareConfig = params.mHardwareConfig;
- mRenderResources = params.mRenderResources;
- mProjectCallback = params.mProjectCallback;
- mMinSdkVersion = params.mMinSdkVersion;
- mTargetSdkVersion = params.mTargetSdkVersion;
- mLog = params.mLog;
- mCustomBackgroundEnabled = params.mCustomBackgroundEnabled;
- mCustomBackgroundColor = params.mCustomBackgroundColor;
- mTimeout = params.mTimeout;
- mImageFactory = params.mImageFactory;
- mAppIcon = params.mAppIcon;
- mAppLabel = params.mAppLabel;
- mLocale = params.mLocale;
- mForceNoDecor = params.mForceNoDecor;
- }
-
- public void setOverrideBgColor(int color) {
- mCustomBackgroundEnabled = true;
- mCustomBackgroundColor = color;
- }
-
- public void setTimeout(long timeout) {
- mTimeout = timeout;
- }
-
- public void setImageFactory(IImageFactory imageFactory) {
- mImageFactory = imageFactory;
- }
-
- public void setAppIcon(String appIcon) {
- mAppIcon = appIcon;
- }
-
- public void setAppLabel(String appLabel) {
- mAppLabel = appLabel;
- }
-
- public void setLocale(String locale) {
- mLocale = locale;
- }
-
- public void setForceNoDecor() {
- mForceNoDecor = true;
- }
-
- public Object getProjectKey() {
- return mProjectKey;
- }
-
- public HardwareConfig getHardwareConfig() {
- return mHardwareConfig;
- }
-
- public int getMinSdkVersion() {
- return mMinSdkVersion;
- }
-
- public int getTargetSdkVersion() {
- return mTargetSdkVersion;
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public int getScreenWidth() {
- return mHardwareConfig.getScreenWidth();
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public int getScreenHeight() {
- return mHardwareConfig.getScreenHeight();
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public Density getDensity() {
- return mHardwareConfig.getDensity();
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public float getXdpi() {
- return mHardwareConfig.getXdpi();
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public float getYdpi() {
- return mHardwareConfig.getYdpi();
- }
-
- public RenderResources getResources() {
- return mRenderResources;
- }
-
- public IProjectCallback getProjectCallback() {
- return mProjectCallback;
- }
-
- public LayoutLog getLog() {
- return mLog;
- }
-
- public boolean isBgColorOverridden() {
- return mCustomBackgroundEnabled;
- }
-
- public int getOverrideBgColor() {
- return mCustomBackgroundColor;
- }
-
- public long getTimeout() {
- return mTimeout;
- }
-
- public IImageFactory getImageFactory() {
- return mImageFactory;
- }
-
- /**
- * @deprecated Use {@link #getHardwareConfig()}
- */
- @Deprecated
- public ScreenSize getConfigScreenSize() {
- return mHardwareConfig.getScreenSize();
- }
-
- public String getAppIcon() {
- return mAppIcon;
- }
-
- public String getAppLabel() {
- return mAppLabel;
- }
-
- public String getLocale() {
- return mLocale;
- }
-
- public boolean isForceNoDecor() {
- return mForceNoDecor;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderResources.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderResources.java
deleted file mode 100644
index c362224..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderResources.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.resources.ResourceType;
-
-/**
- * A class containing all the resources needed to do a rendering.
- * <p/>
- * This contains both the project specific resources and the framework resources, and provide
- * convenience methods to resolve resource and theme references.
- */
-public class RenderResources {
-
- public final static String REFERENCE_NULL = "@null";
-
- public static class FrameworkResourceIdProvider {
- public Integer getId(ResourceType resType, String resName) {
- return null;
- }
- }
-
- public void setFrameworkResourceIdProvider(FrameworkResourceIdProvider provider) {
- }
-
- public void setLogger(LayoutLog logger) {
- }
-
- /**
- * Returns the {@link StyleResourceValue} representing the current theme.
- * @return the theme or null if there is no current theme.
- */
- public StyleResourceValue getCurrentTheme() {
- return null;
- }
-
- /**
- * Returns a theme by its name.
- *
- * @param name the name of the theme
- * @param frameworkTheme whether the theme is a framework theme.
- * @return the theme or null if there's no match
- */
- public StyleResourceValue getTheme(String name, boolean frameworkTheme) {
- return null;
- }
-
- /**
- * Returns whether a theme is a parent of a given theme.
- * @param parentTheme the parent theme
- * @param childTheme the child theme.
- * @return true if the parent theme is indeed a parent theme of the child theme.
- */
- public boolean themeIsParentOf(StyleResourceValue parentTheme, StyleResourceValue childTheme) {
- return false;
- }
-
- /**
- * Returns a framework resource by type and name. The returned resource is resolved.
- * @param resourceType the type of the resource
- * @param resourceName the name of the resource
- */
- public ResourceValue getFrameworkResource(ResourceType resourceType, String resourceName) {
- return null;
- }
-
- /**
- * Returns a project resource by type and name. The returned resource is resolved.
- * @param resourceType the type of the resource
- * @param resourceName the name of the resource
- */
- public ResourceValue getProjectResource(ResourceType resourceType, String resourceName) {
- return null;
- }
-
- /**
- * Returns the {@link ResourceValue} matching a given name in the current theme. If the
- * item is not directly available in the theme, the method looks in its parent theme.
- *
- * @param itemName the name of the item to search for.
- * @return the {@link ResourceValue} object or <code>null</code>
- *
- * @deprecated Use {@link #findItemInTheme(String, boolean)}
- */
- @Deprecated
- public ResourceValue findItemInTheme(String itemName) {
- StyleResourceValue currentTheme = getCurrentTheme();
- if (currentTheme != null) {
- return findItemInStyle(currentTheme, itemName);
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ResourceValue} matching a given attribute in the current theme. If the
- * item is not directly available in the theme, the method looks in its parent theme.
- *
- * @param attrName the name of the attribute to search for.
- * @param isFrameworkAttr whether the attribute is a framework attribute
- * @return the {@link ResourceValue} object or <code>null</code>
- */
- public ResourceValue findItemInTheme(String attrName, boolean isFrameworkAttr) {
- StyleResourceValue currentTheme = getCurrentTheme();
- if (currentTheme != null) {
- return findItemInStyle(currentTheme, attrName, isFrameworkAttr);
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ResourceValue} matching a given name in a given style. If the
- * item is not directly available in the style, the method looks in its parent style.
- *
- * This version of doesn't support providing the namespace of the attribute so it'll search
- * in both the project's namespace and then in the android namespace.
- *
- * @param style the style to search in
- * @param attrName the name of the attribute to search for.
- * @return the {@link ResourceValue} object or <code>null</code>
- *
- * @deprecated Use {@link #findItemInStyle(StyleResourceValue, String, boolean)} since this
- * method doesn't know the item namespace.
- */
- @Deprecated
- public ResourceValue findItemInStyle(StyleResourceValue style, String attrName) {
- return null;
- }
-
- /**
- * Returns the {@link ResourceValue} matching a given attribute in a given style. If the
- * item is not directly available in the style, the method looks in its parent style.
- *
- * @param style the style to search in
- * @param attrName the name of the attribute to search for.
- * @param isFrameworkAttr whether the attribute is a framework attribute
- * @return the {@link ResourceValue} object or <code>null</code>
- */
- public ResourceValue findItemInStyle(StyleResourceValue style, String attrName,
- boolean isFrameworkAttr) {
- return null;
- }
-
- /**
- * Searches for, and returns a {@link ResourceValue} by its reference.
- * <p/>
- * The reference format can be:
- * <pre>@resType/resName</pre>
- * <pre>@android:resType/resName</pre>
- * <pre>@resType/android:resName</pre>
- * <pre>?resType/resName</pre>
- * <pre>?android:resType/resName</pre>
- * <pre>?resType/android:resName</pre>
- * Any other string format will return <code>null</code>.
- * <p/>
- * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
- * only support the android namespace.
- *
- * @param reference the resource reference to search for.
- * @param forceFrameworkOnly if true all references are considered to be toward framework
- * resource even if the reference does not include the android: prefix.
- * @return a {@link ResourceValue} or <code>null</code>.
- */
- public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
- return null;
- }
-
- /**
- * Resolves the value of a resource, if the value references a theme or resource value.
- * <p/>
- * This method ensures that it returns a {@link ResourceValue} object that does not
- * reference another resource.
- * If the resource cannot be resolved, it returns <code>null</code>.
- * <p/>
- * If a value that does not need to be resolved is given, the method will return a new
- * instance of {@link ResourceValue} that contains the input value.
- *
- * @param type the type of the resource
- * @param name the name of the attribute containing this value.
- * @param value the resource value, or reference to resolve
- * @param isFrameworkValue whether the value is a framework value.
- *
- * @return the resolved resource value or <code>null</code> if it failed to resolve it.
- */
- public ResourceValue resolveValue(ResourceType type, String name, String value,
- boolean isFrameworkValue) {
- return null;
- }
-
- /**
- * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
- * <p/>
- * This method ensures that it returns a {@link ResourceValue} object that does not
- * reference another resource.
- * If the resource cannot be resolved, it returns <code>null</code>.
- * <p/>
- * If a value that does not need to be resolved is given, the method will return the input
- * value.
- *
- * @param value the value containing the reference to resolve.
- * @return a {@link ResourceValue} object or <code>null</code>
- */
- public ResourceValue resolveResValue(ResourceValue value) {
- return null;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderSession.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderSession.java
deleted file mode 100644
index 96caa6a..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/RenderSession.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import static com.android.ide.common.rendering.api.Result.Status.NOT_IMPLEMENTED;
-
-import com.android.ide.common.rendering.api.Result.Status;
-
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An object allowing interaction with an Android layout.
- *
- * This is returned by {@link Bridge#createSession(SessionParams)}.
- * and can then be used for subsequent actions on the layout.
- *
- * @since 5
- *
- */
-public class RenderSession {
-
- /**
- * Returns the last operation result.
- */
- public Result getResult() {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Returns the {@link ViewInfo} objects for the top level views.
- * <p/>
- * In most case the list will only contain one item. If the top level node is {@code merge}
- * though then it will contain all the items under the {@code merge} tag.
- * <p/>
- * This is reset to a new instance every time {@link #render()} is called and can be
- * <code>null</code> if the call failed (and the method returned a {@link Result} with
- * {@link Status#ERROR_UNKNOWN} or {@link Status#NOT_IMPLEMENTED}.
- * <p/>
- * This can be safely modified by the caller.
- *
- * @return the list of {@link ViewInfo} or null if there aren't any.
- */
- public List<ViewInfo> getRootViews() {
- return null;
- }
-
- /**
- * Returns the rendering of the full layout.
- * <p>
- * This is reset to a new instance every time {@link #render()} is called and can be
- * <code>null</code> if the call failed (and the method returned a {@link Result} with
- * {@link Status#ERROR_UNKNOWN} or {@link Status#NOT_IMPLEMENTED}.
- * <p/>
- * This can be safely modified by the caller.
- */
- public BufferedImage getImage() {
- return null;
- }
-
- /**
- * Returns true if the current image alpha channel is relevant.
- *
- * @return whether the image alpha channel is relevant.
- */
- public boolean isAlphaChannelImage() {
- return true;
- }
-
- /**
- * Returns a map of (XML attribute name, attribute value) containing only default attribute
- * values, for the given view Object.
- * @param viewObject the view object.
- * @return a map of the default property values or null.
- */
- public Map<String, String> getDefaultProperties(Object viewObject) {
- return null;
- }
-
- /**
- * Re-renders the layout as-is.
- * In case of success, this should be followed by calls to {@link #getRootViews()} and
- * {@link #getImage()} to access the result of the rendering.
- *
- * This is equivalent to calling <code>render(SceneParams.DEFAULT_TIMEOUT)</code>
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result render() {
- return render(RenderParams.DEFAULT_TIMEOUT);
- }
-
- /**
- * Re-renders the layout as-is, with a given timeout in case other renderings are being done.
- * In case of success, this should be followed by calls to {@link #getRootViews()} and
- * {@link #getImage()} to access the result of the rendering.
- *
- * The {@link Bridge} is only able to inflate or render one layout at a time. There
- * is an internal lock object whenever such an action occurs. The timeout parameter is used
- * when attempting to acquire the lock. If the timeout expires, the method will return
- * {@link Status#ERROR_TIMEOUT}.
- *
- * @param timeout timeout for the rendering, in milliseconds.
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result render(long timeout) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Sets the value of a given property on a given object.
- * <p/>
- * This does nothing more than change the property. To render the scene in its new state, a
- * call to {@link #render()} is required.
- * <p/>
- * Any amount of actions can be taken on the scene before {@link #render()} is called.
- *
- * @param objectView
- * @param propertyName
- * @param propertyValue
- *
- * @return a {@link Result} indicating the status of the action.
- *
- * @throws IllegalArgumentException if the view object is not an android.view.View
- */
- public Result setProperty(Object objectView, String propertyName, String propertyValue) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * returns the value of a given property on a given object.
- * <p/>
- * This returns a {@link Result} object. If the operation of querying the object for its
- * property was successful (check {@link Result#isSuccess()}), then the property value
- * is set in the result and can be accessed through {@link Result#getData()}.
- *
- * @param objectView
- * @param propertyName
- *
- * @return a {@link Result} indicating the status of the action.
- *
- * @throws IllegalArgumentException if the view object is not an android.view.View
- */
- public Result getProperty(Object objectView, String propertyName) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Inserts a new child in a ViewGroup object, and renders the result.
- * <p/>
- * The child is first inflated and then added to its new parent, at the given <var>index<var>
- * position. If the <var>index</var> is -1 then the child is added at the end of the parent.
- * <p/>
- * If an animation listener is passed then the rendering is done asynchronously and the
- * result is sent to the listener.
- * If the listener is null, then the rendering is done synchronously.
- * <p/>
- * The child stays in the view hierarchy after the rendering is done. To remove it call
- * {@link #removeChild(Object, IAnimationListener)}
- * <p/>
- * The returned {@link Result} object will contain the android.view.View object for
- * the newly inflated child. It is accessible through {@link Result#getData()}.
- *
- * @param parentView the parent View object to receive the new child.
- * @param childXml an {@link ILayoutPullParser} containing the content of the new child,
- * including ViewGroup.LayoutParams attributes.
- * @param index the index at which position to add the new child into the parent. -1 means at
- * the end.
- * @param listener an optional {@link IAnimationListener}.
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result insertChild(Object parentView, ILayoutPullParser childXml, int index,
- IAnimationListener listener) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Move a new child to a different ViewGroup object.
- * <p/>
- * The child is first removed from its current parent, and then added to its new parent, at the
- * given <var>index<var> position. In case the <var>parentView</var> is the current parent of
- * <var>childView</var> then the index must be the value with the <var>childView</var> removed
- * from its parent. If the <var>index</var> is -1 then the child is added at the end of
- * the parent.
- * <p/>
- * If an animation listener is passed then the rendering is done asynchronously and the
- * result is sent to the listener.
- * If the listener is null, then the rendering is done synchronously.
- * <p/>
- * The child stays in the view hierarchy after the rendering is done. To remove it call
- * {@link #removeChild(Object, IAnimationListener)}
- * <p/>
- * The returned {@link Result} object will contain the android.view.ViewGroup.LayoutParams
- * object created from the <var>layoutParams</var> map if it was non <code>null</code>.
- *
- * @param parentView the parent View object to receive the child. Can be the current parent
- * already.
- * @param childView the view to move.
- * @param index the index at which position to add the new child into the parent. -1 means at
- * the end.
- * @param layoutParams an optional map of new ViewGroup.LayoutParams attribute. If non null,
- * then the current layout params of the view will be removed and a new one will
- * be inflated and set with the content of the map.
- * @param listener an optional {@link IAnimationListener}.
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result moveChild(Object parentView, Object childView, int index,
- Map<String, String> layoutParams, IAnimationListener listener) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Removes a child from a ViewGroup object.
- * <p/>
- * This does nothing more than change the layout. To render the scene in its new state, a
- * call to {@link #render()} is required.
- * <p/>
- * Any amount of actions can be taken on the scene before {@link #render()} is called.
- *
- * @param childView the view object to remove from its parent
- * @param listener an optional {@link IAnimationListener}.
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result removeChild(Object childView, IAnimationListener listener) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Starts playing an given animation on a given object.
- * <p/>
- * The animation playback is asynchronous and the rendered frame is sent vi the
- * <var>listener</var>.
- *
- * @param targetObject the view object to animate
- * @param animationName the name of the animation (res/anim) to play.
- * @param listener the listener callback.
- *
- * @return a {@link Result} indicating the status of the action.
- */
- public Result animate(Object targetObject, String animationName,
- boolean isFrameworkAnimation, IAnimationListener listener) {
- return NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Discards the layout. No more actions can be called on this object.
- */
- public void dispose() {
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceReference.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceReference.java
deleted file mode 100644
index f22f51e..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceReference.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-/**
- * A resource reference. This contains the String ID of the resource and whether this is a framework
- * reference.
- * This is an immutable class.
- *
- */
-public class ResourceReference {
- private final String mName;
- private final boolean mIsFramework;
-
- /**
- * Builds a resource reference.
- * @param name the name of the resource
- * @param isFramework whether the reference is to a framework resource.
- */
- public ResourceReference(String name, boolean isFramework) {
- mName = name;
- mIsFramework = isFramework;
- }
-
- /**
- * Builds a non-framework resource reference.
- * @param name the name of the resource
- */
- public ResourceReference(String name) {
- this(name, false /*platformLayout*/);
- }
-
- /**
- * Returns the name of the resource, as defined in the XML.
- */
- public final String getName() {
- return mName;
- }
-
- /**
- * Returns whether the resource is a framework resource (<code>true</code>) or a project
- * resource (<code>false</false>).
- */
- public final boolean isFramework() {
- return mIsFramework;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (mIsFramework ? 1231 : 1237);
- result = prime * result + ((mName == null) ? 0 : mName.hashCode());
- return result;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ResourceReference other = (ResourceReference) obj;
- if (mIsFramework != other.mIsFramework)
- return false;
- if (mName == null) {
- if (other.mName != null)
- return false;
- } else if (!mName.equals(other.mName))
- return false;
- return true;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return "ResourceReference [" + mName + " (framework:" + mIsFramework+ ")]";
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceValue.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceValue.java
deleted file mode 100644
index dceb7c5..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ResourceValue.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.layoutlib.api.IResourceValue;
-import com.android.resources.ResourceType;
-
-/**
- * Represents an android resource with a name and a string value.
- */
-@SuppressWarnings("deprecation")
-public class ResourceValue extends ResourceReference implements IResourceValue {
- private final ResourceType mType;
- private String mValue = null;
-
- public ResourceValue(ResourceType type, String name, boolean isFramework) {
- super(name, isFramework);
- mType = type;
- }
-
- public ResourceValue(ResourceType type, String name, String value, boolean isFramework) {
- super(name, isFramework);
- mType = type;
- mValue = value;
- }
-
- public ResourceType getResourceType() {
- return mType;
- }
-
- /**
- * Returns the type of the resource. For instance "drawable", "color", etc...
- * @deprecated use {@link #getResourceType()} instead.
- */
- @Override
- @Deprecated
- public String getType() {
- return mType.getName();
- }
-
- /**
- * Returns the value of the resource, as defined in the XML. This can be <code>null</code>
- */
- @Override
- public final String getValue() {
- return mValue;
- }
-
- /**
- * Sets the value of the resource.
- * @param value the new value
- */
- public void setValue(String value) {
- mValue = value;
- }
-
- /**
- * Sets the value from another resource.
- * @param value the resource value
- */
- public void replaceWith(ResourceValue value) {
- mValue = value.mValue;
- }
-
- @Override
- public String toString() {
- return "ResourceValue [" + mType + "/" + getName() + " = " + mValue //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- + " (framework:" + isFramework() + ")]"; //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + ((mType == null) ? 0 : mType.hashCode());
- result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
- return result;
- }
-
- /* (non-Javadoc)
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!super.equals(obj))
- return false;
- if (getClass() != obj.getClass())
- return false;
- ResourceValue other = (ResourceValue) obj;
- if (mType == null) {
- if (other.mType != null)
- return false;
- } else if (!mType.equals(other.mType))
- return false;
- if (mValue == null) {
- if (other.mValue != null)
- return false;
- } else if (!mValue.equals(other.mValue))
- return false;
- return true;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Result.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Result.java
deleted file mode 100644
index a739e79..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/Result.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-/**
- * Scene result class. This is an immutable class.
- * <p/>
- * This cannot be allocated directly, instead use
- * {@link Status#createResult()},
- * {@link Status#createResult(String, Throwable)},
- * {@link Status#createResult(String)}
- * {@link Status#createResult(Object)}
- */
-public class Result {
-
- private final Status mStatus;
- private final String mErrorMessage;
- private final Throwable mThrowable;
- private Object mData;
-
- /**
- * Scene Status enum.
- * <p/>This indicates the status of all scene actions.
- */
- public enum Status {
- SUCCESS,
- NOT_IMPLEMENTED,
- ERROR_TIMEOUT,
- ERROR_LOCK_INTERRUPTED,
- ERROR_INFLATION,
- ERROR_VIEWGROUP_NO_CHILDREN,
- ERROR_NOT_INFLATED,
- ERROR_RENDER,
- ERROR_ANIM_NOT_FOUND,
- ERROR_NOT_A_DRAWABLE,
- ERROR_REFLECTION,
- ERROR_UNKNOWN;
-
- private Result mResult;
-
- /**
- * Returns a {@link Result} object with this status.
- * @return an instance of SceneResult;
- */
- public Result createResult() {
- // don't want to get generic error that way.
- assert this != ERROR_UNKNOWN;
-
- if (mResult == null) {
- mResult = new Result(this);
- }
-
- return mResult;
- }
-
- /**
- * Returns a {@link Result} object with this status, and the given data.
- * @return an instance of SceneResult;
- *
- * @see Result#getData()
- */
- public Result createResult(Object data) {
- Result res = createResult();
-
- if (data != null) {
- res = res.getCopyWithData(data);
- }
-
- return res;
- }
-
- /**
- * Returns a {@link #ERROR_UNKNOWN} result with the given message and throwable
- * @param errorMessage the error message
- * @param throwable the throwable
- * @return an instance of SceneResult.
- */
- public Result createResult(String errorMessage, Throwable throwable) {
- return new Result(this, errorMessage, throwable);
- }
-
- /**
- * Returns a {@link #ERROR_UNKNOWN} result with the given message
- * @param errorMessage the error message
- * @return an instance of SceneResult.
- */
- public Result createResult(String errorMessage) {
- return new Result(this, errorMessage, null /*throwable*/);
- }
- }
-
- /**
- * Creates a {@link Result} object with the given SceneStatus.
- *
- * @param status the status. Must not be null.
- */
- private Result(Status status) {
- this(status, null, null);
- }
-
- /**
- * Creates a {@link Result} object with the given SceneStatus, and the given message
- * and {@link Throwable}
- *
- * @param status the status. Must not be null.
- * @param errorMessage an optional error message.
- * @param t an optional exception.
- */
- private Result(Status status, String errorMessage, Throwable t) {
- assert status != null;
- mStatus = status;
- mErrorMessage = errorMessage;
- mThrowable = t;
- }
-
- private Result(Result result) {
- mStatus = result.mStatus;
- mErrorMessage = result.mErrorMessage;
- mThrowable = result.mThrowable;
- }
-
- /**
- * Returns a copy of the current result with the added (or replaced) given data
- * @param data the data bundle
- *
- * @return returns a new SceneResult instance.
- */
- public Result getCopyWithData(Object data) {
- Result r = new Result(this);
- r.mData = data;
- return r;
- }
-
-
- /**
- * Returns whether the status is successful.
- * <p>
- * This is the same as calling <code>getStatus() == SceneStatus.SUCCESS</code>
- * @return <code>true</code> if the status is successful.
- */
- public boolean isSuccess() {
- return mStatus == Status.SUCCESS;
- }
-
- /**
- * Returns the status. This is never null.
- */
- public Status getStatus() {
- return mStatus;
- }
-
- /**
- * Returns the error message. This is only non-null when {@link #getStatus()} returns
- * {@link Status#ERROR_UNKNOWN}
- */
- public String getErrorMessage() {
- return mErrorMessage;
- }
-
- /**
- * Returns the exception. This is only non-null when {@link #getStatus()} returns
- * {@link Status#ERROR_UNKNOWN}
- */
- public Throwable getException() {
- return mThrowable;
- }
-
- /**
- * Returns the optional data bundle stored in the result object.
- * @return the data bundle or <code>null</code> if none have been set.
- */
- public Object getData() {
- return mData;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/SessionParams.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/SessionParams.java
deleted file mode 100644
index 709207e..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/SessionParams.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Rendering parameters for a {@link RenderSession}.
- */
-public class SessionParams extends RenderParams {
-
- public static enum RenderingMode {
- NORMAL(false, false),
- V_SCROLL(false, true),
- H_SCROLL(true, false),
- FULL_EXPAND(true, true);
-
- private final boolean mHorizExpand;
- private final boolean mVertExpand;
-
- private RenderingMode(boolean horizExpand, boolean vertExpand) {
- mHorizExpand = horizExpand;
- mVertExpand = vertExpand;
- }
-
- public boolean isHorizExpand() {
- return mHorizExpand;
- }
-
- public boolean isVertExpand() {
- return mVertExpand;
- }
- }
-
- private final ILayoutPullParser mLayoutDescription;
- private final RenderingMode mRenderingMode;
- private boolean mLayoutOnly = false;
- private Map<ResourceReference, AdapterBinding> mAdapterBindingMap;
- private boolean mExtendedViewInfoMode = false;
-
- /**
- *
- * @param layoutDescription the {@link ILayoutPullParser} letting the LayoutLib Bridge visit the
- * layout file.
- * @param renderingMode The rendering mode.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param hardwareConfig the {@link HardwareConfig}.
- * @param renderResources a {@link RenderResources} object providing access to the resources.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param minSdkVersion the minSdkVersion of the project
- * @param targetSdkVersion the targetSdkVersion of the project
- * @param log the object responsible for displaying warning/errors to the user.
- */
- public SessionParams(
- ILayoutPullParser layoutDescription,
- RenderingMode renderingMode,
- Object projectKey,
- HardwareConfig hardwareConfig,
- RenderResources renderResources,
- IProjectCallback projectCallback,
- int minSdkVersion, int targetSdkVersion,
- LayoutLog log) {
- super(projectKey, hardwareConfig,
- renderResources, projectCallback, minSdkVersion, targetSdkVersion, log);
-
- mLayoutDescription = layoutDescription;
- mRenderingMode = renderingMode;
- }
-
- public SessionParams(SessionParams params) {
- super(params);
- mLayoutDescription = params.mLayoutDescription;
- mRenderingMode = params.mRenderingMode;
- if (params.mAdapterBindingMap != null) {
- mAdapterBindingMap = new HashMap<ResourceReference, AdapterBinding>(
- params.mAdapterBindingMap);
- }
- mExtendedViewInfoMode = params.mExtendedViewInfoMode;
- }
-
- public ILayoutPullParser getLayoutDescription() {
- return mLayoutDescription;
- }
-
- public RenderingMode getRenderingMode() {
- return mRenderingMode;
- }
-
- public void setLayoutOnly() {
- mLayoutOnly = true;
- }
-
- public boolean isLayoutOnly() {
- return mLayoutOnly;
- }
-
- public void addAdapterBinding(ResourceReference reference, AdapterBinding data) {
- if (mAdapterBindingMap == null) {
- mAdapterBindingMap = new HashMap<ResourceReference, AdapterBinding>();
- }
-
- mAdapterBindingMap.put(reference, data);
- }
-
- public Map<ResourceReference, AdapterBinding> getAdapterBindings() {
- if (mAdapterBindingMap == null) {
- return Collections.emptyMap();
- }
-
- return Collections.unmodifiableMap(mAdapterBindingMap);
- }
-
- public void setExtendedViewInfoMode(boolean mode) {
- mExtendedViewInfoMode = mode;
- }
-
- public boolean getExtendedViewInfoMode() {
- return mExtendedViewInfoMode;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/StyleResourceValue.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/StyleResourceValue.java
deleted file mode 100644
index 7fdfd6a..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/StyleResourceValue.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-import com.android.resources.ResourceType;
-import com.android.util.Pair;
-
-import java.util.HashMap;
-
-/**
- * Represents an android style resources with a name and a list of children {@link ResourceValue}.
- */
-@SuppressWarnings("deprecation")
-public final class StyleResourceValue extends ResourceValue implements IStyleResourceValue {
-
- private String mParentStyle = null;
- private HashMap<Pair<String, Boolean>, ResourceValue> mItems = new HashMap<Pair<String, Boolean>, ResourceValue>();
-
- public StyleResourceValue(ResourceType type, String name, boolean isFramework) {
- super(type, name, isFramework);
- }
-
- public StyleResourceValue(ResourceType type, String name, String parentStyle,
- boolean isFramework) {
- super(type, name, isFramework);
- mParentStyle = parentStyle;
- }
-
- /**
- * Returns the parent style name or <code>null</code> if unknown.
- */
- @Override
- public String getParentStyle() {
- return mParentStyle;
- }
-
- /**
- * Finds a value in the list by name
- * @param name the name of the resource
- *
- * @deprecated use {@link #findValue(String, boolean)}
- */
- @Deprecated
- public ResourceValue findValue(String name) {
- return mItems.get(Pair.of(name, isFramework()));
- }
-
- /**
- * Finds a value in the list by name
- * @param name the name of the resource
- */
- public ResourceValue findValue(String name, boolean isFrameworkAttr) {
- return mItems.get(Pair.of(name, isFrameworkAttr));
- }
-
- public void addValue(ResourceValue value, boolean isFrameworkAttr) {
- mItems.put(Pair.of(value.getName(), isFrameworkAttr), value);
- }
-
- @Override
- public void replaceWith(ResourceValue value) {
- assert value instanceof StyleResourceValue;
- super.replaceWith(value);
-
- if (value instanceof StyleResourceValue) {
- mItems.clear();
- mItems.putAll(((StyleResourceValue)value).mItems);
- }
- }
-
- /**
- * Legacy method.
- * @deprecated use {@link #getValue()}
- */
- @Override
- @Deprecated
- public IResourceValue findItem(String name) {
- return mItems.get(name);
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ViewInfo.java b/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ViewInfo.java
deleted file mode 100644
index d859e95..0000000
--- a/layoutlib_api/src/main/java/com/android/ide/common/rendering/api/ViewInfo.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.api;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Layout information for a specific view object
- */
-public class ViewInfo {
-
- private final Object mCookie;
- private final String mName;
- private final int mLeft;
- private final int mRight;
- private final int mTop;
- private final int mBottom;
- private List<ViewInfo> mChildren = Collections.emptyList();
- private final Object mViewObject;
- private final Object mLayoutParamsObject;
-
- // optional info
- private int mBaseLine = Integer.MIN_VALUE;
- private int mLeftMargin = Integer.MIN_VALUE;
- private int mTopMargin = Integer.MIN_VALUE;
- private int mRightMargin = Integer.MIN_VALUE;
- private int mBottomMargin = Integer.MIN_VALUE;
-
- public ViewInfo(String name, Object cookie, int left, int top, int right, int bottom) {
- this(name, cookie, left, top, right, bottom, null /*viewObject*/,
- null /*layoutParamsObject*/);
- }
-
- public ViewInfo(String name, Object cookie, int left, int top, int right, int bottom,
- Object viewObject, Object layoutParamsObject) {
- mName = name;
- mCookie = cookie;
- mLeft = left;
- mRight = right;
- mTop = top;
- mBottom = bottom;
- mViewObject = viewObject;
- mLayoutParamsObject = layoutParamsObject;
- }
-
- /**
- * Sets the list of children {@link ViewInfo}.
- */
- public void setChildren(List<ViewInfo> children) {
- if (children != null) {
- mChildren = Collections.unmodifiableList(children);
- } else {
- mChildren = Collections.emptyList();
- }
- }
-
- public void setExtendedInfo(int baseLine, int leftMargin, int topMargin,
- int rightMargin, int bottomMargin) {
- mBaseLine = baseLine;
- mLeftMargin = leftMargin;
- mTopMargin = topMargin;
- mRightMargin = rightMargin;
- mBottomMargin = bottomMargin;
- }
-
- /**
- * Returns the list of children views. This is never null, but can be empty.
- */
- public List<ViewInfo> getChildren() {
- return mChildren;
- }
-
- /**
- * Returns the cookie associated with the XML node. Can be null.
- *
- * @see ILayoutPullParser#getViewCookie()
- */
- public Object getCookie() {
- return mCookie;
- }
-
- /**
- * Returns the class name of the view object. Can be null.
- */
- public String getClassName() {
- return mName;
- }
-
- /**
- * Returns the left of the view bounds, relative to the view parent bounds.
- */
- public int getLeft() {
- return mLeft;
- }
-
- /**
- * Returns the top of the view bounds, relative to the view parent bounds.
- */
- public int getTop() {
- return mTop;
- }
-
- /**
- * Returns the right of the view bounds, relative to the view parent bounds.
- */
- public int getRight() {
- return mRight;
- }
-
- /**
- * Returns the bottom of the view bounds, relative to the view parent bounds.
- */
- public int getBottom() {
- return mBottom;
- }
-
- /**
- * Returns the actual android.view.View (or child class) object. This can be used
- * to query the object properties that are not in the XML and not available through
- * {@link RenderSession#getProperty(Object, String)}.
- */
- public Object getViewObject() {
- return mViewObject;
- }
-
- /**
- * Returns the actual android.view.ViewGroup$LayoutParams (or child class) object.
- * This can be used to query the object properties that are not in the XML and not available
- * through {@link RenderSession#getProperty(Object, String)}.
- */
- public Object getLayoutParamsObject() {
- return mLayoutParamsObject;
- }
-
- /**
- * Returns the baseline value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
- */
- public int getBaseLine() {
- return mBaseLine;
- }
-
- /**
- * Returns the left margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
- */
- public int getLeftMargin() {
- return mLeftMargin;
- }
-
- /**
- * Returns the top margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
- */
- public int getTopMargin() {
- return mTopMargin;
- }
-
- /**
- * Returns the right margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
- */
- public int getRightMargin() {
- return mRightMargin;
- }
-
- /**
- * Returns the bottom margin value. If the value is unknown, returns {@link Integer#MIN_VALUE}.
- */
- public int getBottomMargin() {
- return mBottomMargin;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/IDensityBasedResourceValue.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/IDensityBasedResourceValue.java
deleted file mode 100644
index 25d9bfb..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/IDensityBasedResourceValue.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.DensityBasedResourceValue;
-
-/**
- * Represents an Android Resources that has a density info attached to it.
- * @deprecated use {@link DensityBasedResourceValue}.
- */
-@Deprecated
-public interface IDensityBasedResourceValue extends IResourceValue {
-
- /**
- * Density.
- *
- * @deprecated use {@link com.android.resources.Density}.
- */
- @Deprecated
- public static enum Density {
- XHIGH(320),
- HIGH(240),
- MEDIUM(160),
- LOW(120),
- NODPI(0);
-
- private final int mValue;
-
- Density(int value) {
- mValue = value;
- }
-
- public int getValue() {
- return mValue;
- }
-
- /**
- * Returns the enum matching the given density value
- * @param value The density value.
- * @return the enum for the density value or null if no match was found.
- */
- public static Density getEnum(int value) {
- for (Density d : values()) {
- if (d.mValue == value) {
- return d;
- }
- }
-
- return null;
- }
- }
-
- /**
- * Returns the density associated to the resource.
- * @deprecated use {@link DensityBasedResourceValue#getResourceDensity()}
- */
- @Deprecated
- Density getDensity();
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutBridge.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutBridge.java
deleted file mode 100644
index f849cdd..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutBridge.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.Bridge;
-
-import java.util.Map;
-
-/**
- * Entry point of the Layout Lib. Implementations of this interface provide a method to compute
- * and render a layout.
- * <p/>
- * <p/>{@link #getApiLevel()} gives the ability to know which methods are available.
- * <p/>
- * Changes in API level 5:
- * <ul>
- * <li>Bridge should extend {@link Bridge} instead of implementing {@link ILayoutBridge}.</li>
- * </ul>
- * Changes in API level 4:
- * <ul>
- * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, boolean, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * </ul>
- * Changes in API level 3:
- * <ul>
- * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * </ul>
- * Changes in API level 2:
- * <ul>
- * <li>new API Level method: {@link #getApiLevel()}</li>
- * <li>new render method: {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, Map, Map, IProjectCallback, ILayoutLog)}</li>
- * </ul>
- * @deprecated Extend {@link Bridge} instead.
- */
-@Deprecated
-public interface ILayoutBridge {
-
- final int API_CURRENT = 4;
-
- /**
- * Returns the API level of the layout library.
- * While no methods will ever be removed, some may become deprecated, and some new ones
- * will appear.
- * <p/>If calling this method throws an {@link AbstractMethodError}, then the API level
- * should be considered to be 1.
- */
- int getApiLevel();
-
- /**
- * Initializes the Bridge object.
- * @param fontOsLocation the location of the fonts.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
- * @return true if success.
- * @since 1
- */
- boolean init(String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap);
-
- /**
- * Prepares the layoutlib to unloaded.
- */
- boolean dispose();
-
- /**
- * Starts a layout session by inflating and rendering it. The method returns a
- * {@link ILayoutResult} on which further actions can be taken.
- *
- * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
- * layout file.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param screenWidth the screen width
- * @param screenHeight the screen height
- * @param renderFullSize if true, the rendering will render the full size needed by the
- * layout. This size is never smaller than <var>screenWidth</var> x <var>screenHeight</var>.
- * @param density the density factor for the screen.
- * @param xdpi the screen actual dpi in X
- * @param ydpi the screen actual dpi in Y
- * @param themeName The name of the theme to use.
- * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param logger the object responsible for displaying warning/errors to the user.
- * @return a new {@link ILayoutResult} object that contains the result of the layout.
- * @deprecated use {@link Bridge#createSession(com.android.ide.common.rendering.api.SessionParams)}
- * @since 4
- */
- @Deprecated
- ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, boolean renderFullSize,
- int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback projectCallback, ILayoutLog logger);
-
- /**
- * Computes and renders a layout
- * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
- * layout file.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param screenWidth the screen width
- * @param screenHeight the screen height
- * @param density the density factor for the screen.
- * @param xdpi the screen actual dpi in X
- * @param ydpi the screen actual dpi in Y
- * @param themeName The name of the theme to use.
- * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param logger the object responsible for displaying warning/errors to the user.
- * @return a new {@link ILayoutResult} object that contains the result of the layout.
- * @deprecated use {@link Bridge#createSession(com.android.ide.common.rendering.api.SessionParams)}
- * @since 3
- */
- @Deprecated
- ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback projectCallback, ILayoutLog logger);
-
- /**
- * Computes and renders a layout
- * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
- * layout file.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param screenWidth the screen width
- * @param screenHeight the screen height
- * @param themeName The name of the theme to use.
- * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param logger the object responsible for displaying warning/errors to the user.
- * @return a new {@link ILayoutResult} object that contains the result of the layout.
- * @deprecated use {@link Bridge#createSession(com.android.ide.common.rendering.api.SessionParams)}
- * @since 2
- */
- @Deprecated
- ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback projectCallback, ILayoutLog logger);
-
- /**
- * Computes and renders a layout
- * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
- * layout file.
- * @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param screenWidth
- * @param screenHeight
- * @param themeName The name of the theme to use. In order to differentiate project and platform
- * themes sharing the same name, all project themes must be prepended with a '*' character.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param projectCallback The {@link IProjectCallback} object to get information from
- * the project.
- * @param logger the object responsible for displaying warning/errors to the user.
- * @return a new {@link ILayoutResult} object that contains the result of the layout.
- * @deprecated use {@link Bridge#createSession(com.android.ide.common.rendering.api.SessionParams)}
- * @since 1
- */
- @Deprecated
- ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, String themeName,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback projectCallback, ILayoutLog logger);
-
- /**
- * Clears the resource cache for a specific project.
- * <p/>This cache contains bitmaps and nine patches that are loaded from the disk and reused
- * until this method is called.
- * <p/>The cache is not configuration dependent and should only be cleared when a
- * resource changes (at this time only bitmaps and 9 patches go into the cache).
- * @param projectKey the key for the project.
- * @since 1
- */
- void clearCaches(Object projectKey);
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutLog.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutLog.java
deleted file mode 100644
index 38a22b8..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutLog.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-
-/**
- * Callback interface to display warnings/errors that happened during the computation and
- * rendering of the layout.
- * @deprecated use {@link LayoutLog}.
- */
-@Deprecated
-public interface ILayoutLog {
-
- /**
- * Logs a warning message.
- * @param message the message to log.
- */
- void warning(String message);
-
- /**
- * Logs an error message.
- * @param message the message to log.
- */
- void error(String message);
-
- /**
- * Logs an exception
- * @param t the {@link Throwable} to log.
- */
- void error(Throwable t);
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutResult.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutResult.java
deleted file mode 100644
index 6aeaf9f..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/ILayoutResult.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.Bridge;
-import com.android.ide.common.rendering.api.RenderSession;
-
-import java.awt.image.BufferedImage;
-
-/**
- * The result of a layout computation through {@link ILayoutBridge}.
- *
- * @since 1
- * @deprecated use {@link RenderSession} as returned by {@link Bridge#createSession(com.android.ide.common.rendering.api.SessionParams)}
- */
-@Deprecated
-public interface ILayoutResult {
- /**
- * Success return code
- */
- final static int SUCCESS = 0;
-
- /**
- * Error return code, in which case an error message is guaranteed to be defined.
- * @see #getErrorMessage()
- */
- final static int ERROR = 1;
-
- /**
- * Returns the result code.
- * @see #SUCCESS
- * @see #ERROR
- */
- int getSuccess();
-
- /**
- * Returns the {@link ILayoutViewInfo} object for the top level view.
- */
- ILayoutViewInfo getRootView();
-
- /**
- * Returns the rendering of the full layout.
- */
- BufferedImage getImage();
-
- /**
- * Returns the error message.
- * <p/>Only valid when {@link #getSuccess()} returns {@link #ERROR}
- */
- String getErrorMessage();
-
- /**
- * Layout information for a specific view.
- * @deprecated
- */
- @Deprecated
- public interface ILayoutViewInfo {
-
- /**
- * Returns the list of children views.
- */
- ILayoutViewInfo[] getChildren();
-
- /**
- * Returns the key associated with the node.
- * @see IXmlPullParser#getViewKey()
- */
- Object getViewKey();
-
- /**
- * Returns the name of the view.
- */
- String getName();
-
- /**
- * Returns the left of the view bounds.
- */
- int getLeft();
-
- /**
- * Returns the top of the view bounds.
- */
- int getTop();
-
- /**
- * Returns the right of the view bounds.
- */
- int getRight();
-
- /**
- * Returns the bottom of the view bounds.
- */
- int getBottom();
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/IProjectCallback.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/IProjectCallback.java
deleted file mode 100644
index 65e2a87..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/IProjectCallback.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-/**
- *
- * @deprecated
- *
- */
-public interface IProjectCallback {
-
- /**
- * Loads a custom view with the given constructor signature and arguments.
- * @param name The fully qualified name of the class.
- * @param constructorSignature The signature of the class to use
- * @param constructorArgs The arguments to use on the constructor
- * @return A newly instantiated android.view.View object.
- * @throws ClassNotFoundException
- * @throws Exception
- */
- @SuppressWarnings("unchecked")
- Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
- throws ClassNotFoundException, Exception;
-
- /**
- * Returns the namespace of the application.
- * <p/>This lets the Layout Lib load custom attributes for custom views.
- */
- String getNamespace();
-
- /**
- * Resolves the id of a resource Id.
- * <p/>The resource id is the value of a <code>R.&lt;type&gt;.&lt;name&gt;</code>, and
- * this method will return both the type and name of the resource.
- * @param id the Id to resolve.
- * @return an array of 2 strings containing the resource name and type, or null if the id
- * does not match any resource.
- */
- String[] resolveResourceValue(int id);
-
- /**
- * Resolves the id of a resource Id of type int[]
- * <p/>The resource id is the value of a R.styleable.&lt;name&gt;, and this method will
- * return the name of the resource.
- * @param id the Id to resolve.
- * @return the name of the resource or <code>null</code> if not found.
- */
- String resolveResourceValue(int[] id);
-
- /**
- * Returns the id of a resource.
- * <p/>The provided type and name must match an existing constant defined as
- * <code>R.&lt;type&gt;.&lt;name&gt;</code>.
- * @param type the type of the resource
- * @param name the name of the resource
- * @return an Integer containing the resource Id, or <code>null</code> if not found.
- */
- Integer getResourceValue(String type, String name);
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/IResourceValue.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/IResourceValue.java
deleted file mode 100644
index 9a00801..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/IResourceValue.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.ResourceValue;
-
-/**
- * Represents an android resource with a name and a string value.
- * @deprecated use {@link ResourceValue}.
- */
-@Deprecated
-public interface IResourceValue {
-
- /**
- * Returns the type of the resource. For instance "drawable", "color", etc...
- */
- String getType();
-
- /**
- * Returns the name of the resource, as defined in the XML.
- */
- String getName();
-
- /**
- * Returns the value of the resource, as defined in the XML. This can be <code>null</code>
- */
- String getValue();
-
- /**
- * Returns whether the resource is a framework resource (<code>true</code>) or a project
- * resource (<code>false</false>).
- */
- boolean isFramework();
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/IStyleResourceValue.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/IStyleResourceValue.java
deleted file mode 100644
index 21036ca..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/IStyleResourceValue.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import com.android.ide.common.rendering.api.StyleResourceValue;
-
-/**
- * Represents an android style resources with a name and a list of children {@link IResourceValue}.
- * @deprecated Use {@link StyleResourceValue}.
- */
-@Deprecated
-public interface IStyleResourceValue extends IResourceValue {
-
- /**
- * Returns the parent style name or <code>null</code> if unknown.
- */
- String getParentStyle();
-
- /**
- * Find an item in the list by name
- * @param name the name of the resource
- *
- * @deprecated use {@link StyleResourceValue#findValue(String)}
- */
- IResourceValue findItem(String name);
-}
diff --git a/layoutlib_api/src/main/java/com/android/layoutlib/api/IXmlPullParser.java b/layoutlib_api/src/main/java/com/android/layoutlib/api/IXmlPullParser.java
deleted file mode 100644
index e0a98a6..0000000
--- a/layoutlib_api/src/main/java/com/android/layoutlib/api/IXmlPullParser.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.layoutlib.api;
-
-import org.xmlpull.v1.XmlPullParser;
-
-/**
- * @deprecated
- */
-@Deprecated
-public interface IXmlPullParser extends XmlPullParser {
-
- /**
- * Returns a key for the current XML node.
- * <p/>This key will be passed back in the {@link com.android.ide.common.rendering.api.ViewInfo}
- * objects, allowing association of a particular XML node with its result from the
- * layout computation.
- */
- Object getViewKey();
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/Density.java b/layoutlib_api/src/main/java/com/android/resources/Density.java
deleted file mode 100644
index 1f3fb52..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/Density.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-
-/**
- * Density enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names
- * as well as other places needing to know the density values.
- */
-public enum Density implements ResourceEnum {
- XXHIGH("xxhdpi", "XX-High Density", 480, 16), //$NON-NLS-1$
- XHIGH("xhdpi", "X-High Density", 320, 8), //$NON-NLS-1$
- HIGH("hdpi", "High Density", 240, 4), //$NON-NLS-1$
- TV("tvdpi", "TV Density", 213, 13), //$NON-NLS-1$
- MEDIUM("mdpi", "Medium Density", 160, 4), //$NON-NLS-1$
- LOW("ldpi", "Low Density", 120, 4), //$NON-NLS-1$
- NODPI("nodpi", "No Density", 0, 4); //$NON-NLS-1$
-
- public final static int DEFAULT_DENSITY = 160;
-
- private final String mValue;
- private final String mDisplayValue;
- private final int mDensity;
- private final int mSince;
-
- private Density(String value, String displayValue, int density, int since) {
- mValue = value;
- mDisplayValue = displayValue;
- mDensity = density;
- mSince = since;
- }
-
- /**
- * Returns the enum matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no match was found.
- */
- public static Density getEnum(String value) {
- for (Density orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the enum matching the given density value
- * @param value The density value.
- * @return the enum for the density value or null if no match was found.
- */
- public static Density getEnum(int value) {
- for (Density d : values()) {
- if (d.mDensity == value) {
- return d;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- public int getDpiValue() {
- return mDensity;
- }
-
- public int since() {
- return mSince;
- }
-
- public String getLegacyValue() {
- if (this != NODPI) {
- return String.format("%1$ddpi", getDpiValue());
- }
-
- return "";
- }
-
- @Override
- public String getShortDisplayValue() {
- return mDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mDisplayValue;
- }
-
- public static int getIndex(Density value) {
- int i = 0;
- for (Density input : values()) {
- if (value == input) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static Density getByIndex(int index) {
- int i = 0;
- for (Density value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return this != NODPI; // nodpi is not a valid config for devices.
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/FolderTypeRelationship.java b/layoutlib_api/src/main/java/com/android/resources/FolderTypeRelationship.java
deleted file mode 100644
index 61a6d85..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/FolderTypeRelationship.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class gives access to the bidirectional relationship between {@link ResourceType} and
- * {@link ResourceFolderType}.
- */
-public final class FolderTypeRelationship {
-
- private final static Map<ResourceType, List<ResourceFolderType>> mTypeToFolderMap =
- new HashMap<ResourceType, List<ResourceFolderType>>();
-
- private final static Map<ResourceFolderType, List<ResourceType>> mFolderToTypeMap =
- new HashMap<ResourceFolderType, List<ResourceType>>();
-
- static {
- // generate the relationships in a temporary map
- add(ResourceType.ANIM, ResourceFolderType.ANIM);
- add(ResourceType.ANIMATOR, ResourceFolderType.ANIMATOR);
- add(ResourceType.ARRAY, ResourceFolderType.VALUES);
- add(ResourceType.ATTR, ResourceFolderType.VALUES);
- add(ResourceType.BOOL, ResourceFolderType.VALUES);
- add(ResourceType.COLOR, ResourceFolderType.VALUES);
- add(ResourceType.COLOR, ResourceFolderType.COLOR);
- add(ResourceType.DECLARE_STYLEABLE, ResourceFolderType.VALUES);
- add(ResourceType.DIMEN, ResourceFolderType.VALUES);
- add(ResourceType.DRAWABLE, ResourceFolderType.VALUES);
- add(ResourceType.DRAWABLE, ResourceFolderType.DRAWABLE);
- add(ResourceType.FRACTION, ResourceFolderType.VALUES);
- add(ResourceType.ID, ResourceFolderType.VALUES);
- add(ResourceType.INTEGER, ResourceFolderType.VALUES);
- add(ResourceType.INTERPOLATOR, ResourceFolderType.INTERPOLATOR);
- add(ResourceType.LAYOUT, ResourceFolderType.LAYOUT);
- add(ResourceType.ID, ResourceFolderType.LAYOUT);
- add(ResourceType.MENU, ResourceFolderType.MENU);
- add(ResourceType.ID, ResourceFolderType.MENU);
- add(ResourceType.MIPMAP, ResourceFolderType.MIPMAP);
- add(ResourceType.PLURALS, ResourceFolderType.VALUES);
- add(ResourceType.PUBLIC, ResourceFolderType.VALUES);
- add(ResourceType.RAW, ResourceFolderType.RAW);
- add(ResourceType.STRING, ResourceFolderType.VALUES);
- add(ResourceType.STYLE, ResourceFolderType.VALUES);
- add(ResourceType.STYLEABLE, ResourceFolderType.VALUES);
- add(ResourceType.XML, ResourceFolderType.XML);
-
- makeSafe();
- }
-
- /**
- * Returns a list of {@link ResourceType}s that can be generated from files inside a folder
- * of the specified type.
- * @param folderType The folder type.
- * @return a list of {@link ResourceType}, possibly empty but never null.
- */
- public static List<ResourceType> getRelatedResourceTypes(ResourceFolderType folderType) {
- List<ResourceType> list = mFolderToTypeMap.get(folderType);
- if (list != null) {
- return list;
- }
-
- return Collections.emptyList();
- }
-
- /**
- * Returns a list of {@link ResourceFolderType} that can contain files generating resources
- * of the specified type.
- * @param resType the type of resource.
- * @return a list of {@link ResourceFolderType}, possibly empty but never null.
- */
- public static List<ResourceFolderType> getRelatedFolders(ResourceType resType) {
- List<ResourceFolderType> list = mTypeToFolderMap.get(resType);
- if (list != null) {
- return list;
- }
-
- return Collections.emptyList();
- }
-
- /**
- * Returns true if the {@link ResourceType} and the {@link ResourceFolderType} values match.
- * @param resType the resource type.
- * @param folderType the folder type.
- * @return true if files inside the folder of the specified {@link ResourceFolderType}
- * could generate a resource of the specified {@link ResourceType}
- */
- public static boolean match(ResourceType resType, ResourceFolderType folderType) {
- List<ResourceFolderType> list = mTypeToFolderMap.get(resType);
-
- if (list != null) {
- return list.contains(folderType);
- }
-
- return false;
- }
-
- /**
- * Adds a {@link ResourceType} - {@link ResourceFolderType} relationship. this indicates that
- * a file in the folder can generate a resource of the specified type.
- * @param type The resourceType
- * @param folder The {@link ResourceFolderType}
- */
- private static void add(ResourceType type, ResourceFolderType folder) {
- // first we add the folder to the list associated with the type.
- List<ResourceFolderType> folderList = mTypeToFolderMap.get(type);
- if (folderList == null) {
- folderList = new ArrayList<ResourceFolderType>();
- mTypeToFolderMap.put(type, folderList);
- }
- if (folderList.indexOf(folder) == -1) {
- folderList.add(folder);
- }
-
- // now we add the type to the list associated with the folder.
- List<ResourceType> typeList = mFolderToTypeMap.get(folder);
- if (typeList == null) {
- typeList = new ArrayList<ResourceType>();
- mFolderToTypeMap.put(folder, typeList);
- }
- if (typeList.indexOf(type) == -1) {
- typeList.add(type);
- }
- }
-
- /**
- * Makes the maps safe by replacing the current list values with unmodifiable lists.
- */
- private static void makeSafe() {
- for (ResourceType type : ResourceType.values()) {
- List<ResourceFolderType> list = mTypeToFolderMap.get(type);
- if (list != null) {
- // replace with a unmodifiable list wrapper around the current list.
- mTypeToFolderMap.put(type, Collections.unmodifiableList(list));
- }
- }
-
- for (ResourceFolderType folder : ResourceFolderType.values()) {
- List<ResourceType> list = mFolderToTypeMap.get(folder);
- if (list != null) {
- // replace with a unmodifiable list wrapper around the current list.
- mFolderToTypeMap.put(folder, Collections.unmodifiableList(list));
- }
- }
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/Keyboard.java b/layoutlib_api/src/main/java/com/android/resources/Keyboard.java
deleted file mode 100644
index d6bc80a..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/Keyboard.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Keyboard enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum Keyboard implements ResourceEnum {
- NOKEY("nokeys", null, "No Keys", "No keyboard"), //$NON-NLS-1$
- QWERTY("qwerty", null, "Qwerty", "Qwerty keybard"), //$NON-NLS-1$
- TWELVEKEY("12key", "twelvekey", "12 Key", "12 key keyboard"); //$NON-NLS-1$ //$NON-NLS-2$
-
- private final String mValue, mValue2;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private Keyboard(String value, String value2, String shortDisplayValue,
- String longDisplayValue) {
- mValue = value;
- mValue2 = value2;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static Keyboard getEnum(String value) {
- for (Keyboard kbrd : values()) {
- if (kbrd.mValue.equals(value) ||
- (kbrd.mValue2 != null && kbrd.mValue2.equals(value))) {
- return kbrd;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(Keyboard value) {
- int i = 0;
- for (Keyboard input : values()) {
- if (value == input) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static Keyboard getByIndex(int index) {
- int i = 0;
- for (Keyboard value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/KeyboardState.java b/layoutlib_api/src/main/java/com/android/resources/KeyboardState.java
deleted file mode 100644
index 2eb7e00..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/KeyboardState.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Keyboard state enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum KeyboardState implements ResourceEnum {
- EXPOSED("keysexposed", "Exposed", "Exposed keyboard"), //$NON-NLS-1$
- HIDDEN("keyshidden", "Hidden", "Hidden keyboard"), //$NON-NLS-1$
- SOFT("keyssoft", "Soft", "Soft keyboard"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private KeyboardState(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static KeyboardState getEnum(String value) {
- for (KeyboardState state : values()) {
- if (state.mValue.equals(value)) {
- return state;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(KeyboardState value) {
- int i = 0;
- for (KeyboardState input : values()) {
- if (value == input) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static KeyboardState getByIndex(int index) {
- int i = 0;
- for (KeyboardState value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/LayoutDirection.java b/layoutlib_api/src/main/java/com/android/resources/LayoutDirection.java
deleted file mode 100644
index fbc386d..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/LayoutDirection.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Layout Direction enum.
- */
-public enum LayoutDirection implements ResourceEnum {
- LTR("ldltr", "LTR", "Left To Right"), //$NON-NLS-1$
- RTL("ldrtl", "RTL", "Right To Left"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private LayoutDirection(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static LayoutDirection getEnum(String value) {
- for (LayoutDirection orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(LayoutDirection orientation) {
- int i = 0;
- for (LayoutDirection orient : values()) {
- if (orient == orientation) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static LayoutDirection getByIndex(int index) {
- int i = 0;
- for (LayoutDirection orient : values()) {
- if (i == index) {
- return orient;
- }
- i++;
- }
-
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/Navigation.java b/layoutlib_api/src/main/java/com/android/resources/Navigation.java
deleted file mode 100644
index f857e5f..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/Navigation.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Navigation enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum Navigation implements ResourceEnum {
- NONAV("nonav", "None", "No navigation"), //$NON-NLS-1$
- DPAD("dpad", "D-pad", "D-pad navigation"), //$NON-NLS-1$
- TRACKBALL("trackball", "Trackball", "Trackball navigation"), //$NON-NLS-1$
- WHEEL("wheel", "Wheel", "Wheel navigation"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private Navigation(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static Navigation getEnum(String value) {
- for (Navigation nav : values()) {
- if (nav.mValue.equals(value)) {
- return nav;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(Navigation value) {
- int i = 0;
- for (Navigation nav : values()) {
- if (nav == value) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static Navigation getByIndex(int index) {
- int i = 0;
- for (Navigation value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-} \ No newline at end of file
diff --git a/layoutlib_api/src/main/java/com/android/resources/NavigationState.java b/layoutlib_api/src/main/java/com/android/resources/NavigationState.java
deleted file mode 100644
index 63b8fea..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/NavigationState.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Navigation state enum.
- * <p/>This is used in the resource folder names.
- */
-public enum NavigationState implements ResourceEnum {
- EXPOSED("navexposed", "Exposed", "Exposed navigation"), //$NON-NLS-1$
- HIDDEN("navhidden", "Hidden", "Hidden navigation"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private NavigationState(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static NavigationState getEnum(String value) {
- for (NavigationState state : values()) {
- if (state.mValue.equals(value)) {
- return state;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(NavigationState value) {
- int i = 0;
- for (NavigationState input : values()) {
- if (value == input) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static NavigationState getByIndex(int index) {
- int i = 0;
- for (NavigationState value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/NightMode.java b/layoutlib_api/src/main/java/com/android/resources/NightMode.java
deleted file mode 100644
index 8fe1dd9..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/NightMode.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Night enum.
- * <p/>This is used in the resource folder names.
- */
-public enum NightMode implements ResourceEnum {
- NOTNIGHT("notnight", "Not Night", "Day time"),
- NIGHT("night", "Night", "Night time");
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private NightMode(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static NightMode getEnum(String value) {
- for (NightMode mode : values()) {
- if (mode.mValue.equals(value)) {
- return mode;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(NightMode value) {
- int i = 0;
- for (NightMode mode : values()) {
- if (mode == value) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static NightMode getByIndex(int index) {
- int i = 0;
- for (NightMode value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ResourceConstants.java b/layoutlib_api/src/main/java/com/android/resources/ResourceConstants.java
deleted file mode 100644
index 748f88a..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ResourceConstants.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Resource Constants.
- */
-public class ResourceConstants {
-
- /** Default anim resource folder name, i.e. "anim" */
- public final static String FD_RES_ANIM = "anim"; //$NON-NLS-1$
- /** Default animator resource folder name, i.e. "animator" */
- public final static String FD_RES_ANIMATOR = "animator"; //$NON-NLS-1$
- /** Default color resource folder name, i.e. "color" */
- public final static String FD_RES_COLOR = "color"; //$NON-NLS-1$
- /** Default drawable resource folder name, i.e. "drawable" */
- public final static String FD_RES_DRAWABLE = "drawable"; //$NON-NLS-1$
- /** Default interpolator resource folder name, i.e. "interpolator" */
- public final static String FD_RES_INTERPOLATOR = "interpolator"; //$NON-NLS-1$
- /** Default layout resource folder name, i.e. "layout" */
- public final static String FD_RES_LAYOUT = "layout"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "menu" */
- public final static String FD_RES_MENU = "menu"; //$NON-NLS-1$
- /** Default menu resource folder name, i.e. "mipmap" */
- public final static String FD_RES_MIPMAP = "mipmap"; //$NON-NLS-1$
- /** Default values resource folder name, i.e. "values" */
- public final static String FD_RES_VALUES = "values"; //$NON-NLS-1$
- /** Default xml resource folder name, i.e. "xml" */
- public final static String FD_RES_XML = "xml"; //$NON-NLS-1$
- /** Default raw resource folder name, i.e. "raw" */
- public final static String FD_RES_RAW = "raw"; //$NON-NLS-1$
-
- /** Separator between the resource folder qualifier. */
- public final static String RES_QUALIFIER_SEP = "-"; //$NON-NLS-1$
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ResourceEnum.java b/layoutlib_api/src/main/java/com/android/resources/ResourceEnum.java
deleted file mode 100644
index 7f4e16a..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ResourceEnum.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * An enum representing a resource qualifier value.
- */
-public interface ResourceEnum {
-
- /**
- * Returns the resource string. This is to be used in resource folder names.
- */
- String getResourceValue();
-
- /**
- * Whether the value actually used on device. This returns true only if a device can report
- * this value, false if it's just used to qualify resources.
- */
- boolean isValidValueForDevice();
-
- /**
- * Whether the value is neither used for device nor resources. This returns false when
- * the value is only used for internal usage in the custom editors.
- */
- boolean isFakeValue();
-
- /**
- * Returns a short string for display value. The string does not need to show the context.
- * <p/>For instance "exposed", which can be the value for the keyboard state or the navigation
- * state, would be valid since something else in the UI is expected to show if this is about the
- * keyboard or the navigation state.
- *
- * @see #getLongDisplayValue()
- */
- String getShortDisplayValue();
-
- /**
- * Returns a long string for display value. This must not only include the enum value but
- * context (qualifier) about what the value represents.
- * <p/>For instance "Exposed keyboard", and "Export navigation", as "exposed" would not be
- * enough to know what qualifier the value is about.
- *
- * @see #getShortDisplayValue()
- */
- String getLongDisplayValue();
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ResourceFolderType.java b/layoutlib_api/src/main/java/com/android/resources/ResourceFolderType.java
deleted file mode 100644
index 5a271cf..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ResourceFolderType.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Enum representing a type of resource folder.
- */
-public enum ResourceFolderType {
- ANIM(ResourceConstants.FD_RES_ANIM),
- ANIMATOR(ResourceConstants.FD_RES_ANIMATOR),
- COLOR(ResourceConstants.FD_RES_COLOR),
- DRAWABLE(ResourceConstants.FD_RES_DRAWABLE),
- INTERPOLATOR(ResourceConstants.FD_RES_INTERPOLATOR),
- LAYOUT(ResourceConstants.FD_RES_LAYOUT),
- MENU(ResourceConstants.FD_RES_MENU),
- MIPMAP(ResourceConstants.FD_RES_MIPMAP),
- RAW(ResourceConstants.FD_RES_RAW),
- VALUES(ResourceConstants.FD_RES_VALUES),
- XML(ResourceConstants.FD_RES_XML);
-
- private final String mName;
-
- ResourceFolderType(String name) {
- mName = name;
- }
-
- /**
- * Returns the folder name for this resource folder type.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the enum by name.
- * @param name The enum string value.
- * @return the enum or null if not found.
- */
- public static ResourceFolderType getTypeByName(String name) {
- assert name.indexOf('-') == -1 : name; // use #getFolderType instead
- for (ResourceFolderType rType : values()) {
- if (rType.mName.equals(name)) {
- return rType;
- }
- }
- return null;
- }
-
- /**
- * Returns the {@link ResourceFolderType} from the folder name
- * @param folderName The name of the folder. This must be a valid folder name in the format
- * <code>resType[-resqualifiers[-resqualifiers[...]]</code>
- * @return the <code>ResourceFolderType</code> representing the type of the folder, or
- * <code>null</code> if no matching type was found.
- */
- public static ResourceFolderType getFolderType(String folderName) {
- int index = folderName.indexOf(ResourceConstants.RES_QUALIFIER_SEP);
- if (index != -1) {
- folderName = folderName.substring(0, index);
- }
- return getTypeByName(folderName);
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ResourceType.java b/layoutlib_api/src/main/java/com/android/resources/ResourceType.java
deleted file mode 100644
index e9d4d53..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ResourceType.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-
-/**
- * Enum representing a type of compiled resource.
- */
-public enum ResourceType {
- ANIM("anim", "Animation"), //$NON-NLS-1$
- ANIMATOR("animator", "Animator"), //$NON-NLS-1$
- ARRAY("array", "Array", "string-array", "integer-array"), //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-4$
- ATTR("attr", "Attr"), //$NON-NLS-1$
- BOOL("bool", "Boolean"), //$NON-NLS-1$
- COLOR("color", "Color"), //$NON-NLS-1$
- DECLARE_STYLEABLE("declare-styleable", "Declare Stylable"), //$NON-NLS-1$
- DIMEN("dimen", "Dimension"), //$NON-NLS-1$
- DRAWABLE("drawable", "Drawable"), //$NON-NLS-1$
- FRACTION("fraction", "Fraction"), //$NON-NLS-1$
- ID("id", "ID"), //$NON-NLS-1$
- INTEGER("integer", "Integer"), //$NON-NLS-1$
- INTERPOLATOR("interpolator", "Interpolator"), //$NON-NLS-1$
- LAYOUT("layout", "Layout"), //$NON-NLS-1$
- MENU("menu", "Menu"), //$NON-NLS-1$
- MIPMAP("mipmap", "Mip Map"), //$NON-NLS-1$
- PLURALS("plurals", "Plurals"), //$NON-NLS-1$
- RAW("raw", "Raw"), //$NON-NLS-1$
- STRING("string", "String"), //$NON-NLS-1$
- STYLE("style", "Style"), //$NON-NLS-1$
- STYLEABLE("styleable", "Styleable"), //$NON-NLS-1$
- XML("xml", "XML"), //$NON-NLS-1$
- // this is not actually used. Only there because they get parsed and since we want to
- // detect new resource type, we need to have this one exist.
- PUBLIC("public", "###"); //$NON-NLS-1$ //$NON-NLS-2$
-
- private final String mName;
- private final String mDisplayName;
- private final String[] mAlternateXmlNames;
-
- ResourceType(String name, String displayName, String... alternateXmlNames) {
- mName = name;
- mDisplayName = displayName;
- mAlternateXmlNames = alternateXmlNames;
- }
-
- /**
- * Returns the resource type name, as used by XML files.
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns a translated display name for the resource type.
- */
- public String getDisplayName() {
- return mDisplayName;
- }
-
- /**
- * Returns the enum by its name as it appears in the XML or the R class.
- * @param name name of the resource
- * @return the matching {@link ResourceType} or <code>null</code> if no match was found.
- */
- public static ResourceType getEnum(String name) {
- for (ResourceType rType : values()) {
- if (rType.mName.equals(name)) {
- return rType;
- } else if (rType.mAlternateXmlNames != null) {
- // if there are alternate Xml Names, we test those too
- for (String alternate : rType.mAlternateXmlNames) {
- if (alternate.equals(name)) {
- return rType;
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Returns an array with all the names defined by this enum.
- */
- public static String[] getNames() {
- ResourceType[] values = values();
- String[] names = new String[values.length];
- for (int i = values.length - 1; i >= 0; --i) {
- names[i] = values[i].getName();
- }
- return names;
- }
-
- @Override
- public String toString() {
- return getName();
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ScreenOrientation.java b/layoutlib_api/src/main/java/com/android/resources/ScreenOrientation.java
deleted file mode 100644
index b18753d..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ScreenOrientation.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Screen Orientation enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum ScreenOrientation implements ResourceEnum {
- PORTRAIT("port", "Portrait", "Portrait Orientation"), //$NON-NLS-1$
- LANDSCAPE("land", "Landscape", "Landscape Orientation"), //$NON-NLS-1$
- SQUARE("square", "Square", "Square Orientation"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private ScreenOrientation(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static ScreenOrientation getEnum(String value) {
- for (ScreenOrientation orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(ScreenOrientation orientation) {
- int i = 0;
- for (ScreenOrientation orient : values()) {
- if (orient == orientation) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static ScreenOrientation getByIndex(int index) {
- int i = 0;
- for (ScreenOrientation orient : values()) {
- if (i == index) {
- return orient;
- }
- i++;
- }
-
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/ScreenRatio.java b/layoutlib_api/src/main/java/com/android/resources/ScreenRatio.java
deleted file mode 100644
index bb575b0..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ScreenRatio.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Screen Ratio enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum ScreenRatio implements ResourceEnum {
- NOTLONG("notlong", "Not Long", "Short screen aspect ratio"), //$NON-NLS-1$
- LONG("long", "Long", "Long screen aspect ratio"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private ScreenRatio(String value, String displayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = displayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static ScreenRatio getEnum(String value) {
- for (ScreenRatio orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(ScreenRatio orientation) {
- int i = 0;
- for (ScreenRatio orient : values()) {
- if (orient == orientation) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static ScreenRatio getByIndex(int index) {
- int i = 0;
- for (ScreenRatio orient : values()) {
- if (i == index) {
- return orient;
- }
- i++;
- }
-
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
-
diff --git a/layoutlib_api/src/main/java/com/android/resources/ScreenSize.java b/layoutlib_api/src/main/java/com/android/resources/ScreenSize.java
deleted file mode 100644
index 4def540..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/ScreenSize.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Screen size enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum ScreenSize implements ResourceEnum {
- SMALL("small", "Small", "Small Screen"), //$NON-NLS-1$
- NORMAL("normal", "Normal", "Normal Screen"), //$NON-NLS-1$
- LARGE("large", "Large", "Large Screen"), //$NON-NLS-1$
- XLARGE("xlarge", "X-Large", "Extra Large Screen"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private ScreenSize(String value, String shortDisplayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = shortDisplayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static ScreenSize getEnum(String value) {
- for (ScreenSize orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(ScreenSize orientation) {
- int i = 0;
- for (ScreenSize orient : values()) {
- if (orient == orientation) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static ScreenSize getByIndex(int index) {
- int i = 0;
- for (ScreenSize orient : values()) {
- if (i == index) {
- return orient;
- }
- i++;
- }
-
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/TouchScreen.java b/layoutlib_api/src/main/java/com/android/resources/TouchScreen.java
deleted file mode 100644
index 7eeeb08..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/TouchScreen.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Touch screen enum.
- * <p/>This is used in the manifest in the uses-configuration node and in the resource folder names.
- */
-public enum TouchScreen implements ResourceEnum {
- NOTOUCH("notouch", "No Touch", "No-touch screen"), //$NON-NLS-1$
- STYLUS("stylus", "Stylus", "Stylus-based touchscreen"), //$NON-NLS-1$
- FINGER("finger", "Finger", "Finger-based touchscreen"); //$NON-NLS-1$
-
- private final String mValue;
- private final String mShortDisplayValue;
- private final String mLongDisplayValue;
-
- private TouchScreen(String value, String displayValue, String longDisplayValue) {
- mValue = value;
- mShortDisplayValue = displayValue;
- mLongDisplayValue = longDisplayValue;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static TouchScreen getEnum(String value) {
- for (TouchScreen orient : values()) {
- if (orient.mValue.equals(value)) {
- return orient;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mShortDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mLongDisplayValue;
- }
-
- public static int getIndex(TouchScreen touch) {
- int i = 0;
- for (TouchScreen t : values()) {
- if (t == touch) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static TouchScreen getByIndex(int index) {
- int i = 0;
- for (TouchScreen value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
-
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return true;
- }
-
-}
diff --git a/layoutlib_api/src/main/java/com/android/resources/UiMode.java b/layoutlib_api/src/main/java/com/android/resources/UiMode.java
deleted file mode 100644
index d1ddbc8..0000000
--- a/layoutlib_api/src/main/java/com/android/resources/UiMode.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * UI Mode enum.
- * <p/>This is used in the resource folder names.
- */
-public enum UiMode implements ResourceEnum {
- NORMAL("", "Normal"),
- CAR("car", "Car Dock"),
- DESK("desk", "Desk Dock"),
- TELEVISION("television", "Television");
-
- private final String mValue;
- private final String mDisplayValue;
-
- private UiMode(String value, String display) {
- mValue = value;
- mDisplayValue = display;
- }
-
- /**
- * Returns the enum for matching the provided qualifier value.
- * @param value The qualifier value.
- * @return the enum for the qualifier value or null if no matching was found.
- */
- public static UiMode getEnum(String value) {
- for (UiMode mode : values()) {
- if (mode.mValue.equals(value)) {
- return mode;
- }
- }
-
- return null;
- }
-
- @Override
- public String getResourceValue() {
- return mValue;
- }
-
- @Override
- public String getShortDisplayValue() {
- return mDisplayValue;
- }
-
- @Override
- public String getLongDisplayValue() {
- return mDisplayValue;
- }
-
- public static int getIndex(UiMode value) {
- int i = 0;
- for (UiMode mode : values()) {
- if (mode == value) {
- return i;
- }
-
- i++;
- }
-
- return -1;
- }
-
- public static UiMode getByIndex(int index) {
- int i = 0;
- for (UiMode value : values()) {
- if (i == index) {
- return value;
- }
- i++;
- }
- return null;
- }
-
- @Override
- public boolean isFakeValue() {
- return this == NORMAL; // NORMAL is not a real enum. it's used for internal state only.
- }
-
- @Override
- public boolean isValidValueForDevice() {
- return this != NORMAL;
- }
-}
diff --git a/layoutlib_api/src/main/java/com/android/util/Pair.java b/layoutlib_api/src/main/java/com/android/util/Pair.java
deleted file mode 100644
index 7e797e0..0000000
--- a/layoutlib_api/src/main/java/com/android/util/Pair.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.util;
-
-/**
- * A Pair class is simply a 2-tuple for use in this package. We might want to
- * think about adding something like this to a more central utility place, or
- * replace it by a common tuple class if one exists, or even rewrite the layout
- * classes using this Pair by a more dedicated data structure (so we don't have
- * to pass around generic signatures as is currently done, though at least the
- * construction is helped a bit by the {@link #of} factory method.
- *
- * =================================================================================================
- * WARNING
- * This copy of the class is to be used only by layoutlib and is not to be changed, EVER.
- * To use Pair outside of layoutlib, use com.android.utils.Pair, found in common.jar instead.
- * =================================================================================================
- *
- * @param <S> The type of the first value
- * @param <T> The type of the second value
- *
- * @deprecated This is used for backward compatibility with layoutlib_api. Use com.android.utils.Pair instead
- */
-@Deprecated
-public class Pair<S,T> {
- private final S mFirst;
- private final T mSecond;
-
- // Use {@link Pair#of} factory instead since it infers generic types
- private Pair(S first, T second) {
- this.mFirst = first;
- this.mSecond = second;
- }
-
- /**
- * Return the first item in the pair
- *
- * @return the first item in the pair
- */
- public S getFirst() {
- return mFirst;
- }
-
- /**
- * Return the second item in the pair
- *
- * @return the second item in the pair
- */
- public T getSecond() {
- return mSecond;
- }
-
- /**
- * Constructs a new pair of the given two objects, inferring generic types.
- *
- * @param first the first item to store in the pair
- * @param second the second item to store in the pair
- * @param <S> the type of the first item
- * @param <T> the type of the second item
- * @return a new pair wrapping the two items
- */
- public static <S,T> Pair<S,T> of(S first, T second) {
- return new Pair<S,T>(first,second);
- }
-
- @Override
- public String toString() {
- return "Pair [first=" + mFirst + ", second=" + mSecond + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mFirst == null) ? 0 : mFirst.hashCode());
- result = prime * result + ((mSecond == null) ? 0 : mSecond.hashCode());
- return result;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Pair other = (Pair) obj;
- if (mFirst == null) {
- if (other.mFirst != null)
- return false;
- } else if (!mFirst.equals(other.mFirst))
- return false;
- if (mSecond == null) {
- if (other.mSecond != null)
- return false;
- } else if (!mSecond.equals(other.mSecond))
- return false;
- return true;
- }
-}
diff --git a/layoutlib_api/src/test/.classpath b/layoutlib_api/src/test/.classpath
deleted file mode 100644
index 7564f2f..0000000
--- a/layoutlib_api/src/test/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="java"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry combineaccessrules="false" kind="src" path="/common"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/layoutlib_api/src/test/.project b/layoutlib_api/src/test/.project
deleted file mode 100644
index 9f550a3..0000000
--- a/layoutlib_api/src/test/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>common-tests</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/layoutlib_api/src/test/java/com/android/resources/FolderTypeRelationShipTest.java b/layoutlib_api/src/test/java/com/android/resources/FolderTypeRelationShipTest.java
deleted file mode 100644
index 809eae7..0000000
--- a/layoutlib_api/src/test/java/com/android/resources/FolderTypeRelationShipTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-
-import junit.framework.TestCase;
-
-public class FolderTypeRelationShipTest extends TestCase {
-
- public void testResourceType() {
- // all resource type should be in the FolderTypeRelationShip map.
- // loop on all the enum, and make sure there's at least one folder type for it.
- for (ResourceType type : ResourceType.values()) {
- assertTrue(type.getDisplayName(),
- FolderTypeRelationship.getRelatedFolders(type).size() > 0);
- }
- }
-
- public void testResourceFolderType() {
- // all resource folder type should generate at least one type of resource.
- // loop on all the enum, and make sure there's at least one res type for it.
- for (ResourceFolderType type : ResourceFolderType.values()) {
- assertTrue(type.getName(),
- FolderTypeRelationship.getRelatedResourceTypes(type).size() > 0);
- }
- }
-}
diff --git a/layoutlib_api/src/test/java/com/android/resources/ResourceFolderTypeTest.java b/layoutlib_api/src/test/java/com/android/resources/ResourceFolderTypeTest.java
deleted file mode 100644
index a3c2c51..0000000
--- a/layoutlib_api/src/test/java/com/android/resources/ResourceFolderTypeTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import junit.framework.TestCase;
-
-public class ResourceFolderTypeTest extends TestCase {
- public void test() {
- assertEquals(ResourceFolderType.LAYOUT, ResourceFolderType.getFolderType("layout"));
- assertEquals(ResourceFolderType.LAYOUT, ResourceFolderType.getFolderType("layout-port"));
- assertEquals(ResourceFolderType.LAYOUT, ResourceFolderType.getFolderType("layout-port-sw600"));
- assertEquals(ResourceFolderType.VALUES, ResourceFolderType.getFolderType("values"));
-
- assertNull(ResourceFolderType.getFolderType(""));
- assertNull(ResourceFolderType.getFolderType("foo"));
- }
-}
diff --git a/lint/cli/Android.mk b/lint/cli/Android.mk
index dcd1792..00c736b 100644
--- a/lint/cli/Android.mk
+++ b/lint/cli/Android.mk
@@ -1,14 +1,26 @@
# Copyright 2011 The Android Open Source Project
#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_RESOURCE_DIRS := src/main/java
-
-LOCAL_JAR_MANIFEST := etc/manifest.txt
+# The lint code has moved to tools/base/lint.
+# The rule below uses the prebuilt lint.jar.
+#
+# If you want to run the tests, cd to tools/base/lint
+# and run ./gradlew :lint:test
-# If the dependency list is changed, etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
common \
sdklib \
@@ -23,21 +35,8 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_MODULE := lint
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-
-# Build all sub-directories
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-# Build tests
-include $(CLEAR_VARS)
-
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
-
-LOCAL_MODULE := lint_checks-tests
-LOCAL_MODULE_TAGS := optional
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
-LOCAL_JAVA_LIBRARIES := common sdklib lint_api lint_checks lint junit easymock asm-tools asm-tree-tools guava-tools layoutlib_api sdktestutils
+include $(BUILD_HOST_PREBUILT)
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
index 43d3727..947d27b 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/ApiDetectorTest.java
@@ -874,4 +874,27 @@ public class ApiDetectorTest extends AbstractCheckTest {
"apicheck/ApiSourceCheck2.class.data=>bin/classes/test/pkg/ApiSourceCheck2.class"
));
}
+
+ public void testInheritCompatLibrary() throws Exception {
+ assertEquals(""
+ + "src/test/pkg/MyActivityImpl.java:8: Error: Call requires API level 11 (current min is 1): android.app.Activity#isChangingConfigurations [NewApi]\n"
+ + " boolean isChanging = super.isChangingConfigurations();\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "src/test/pkg/MyActivityImpl.java:13: Error: Call requires API level 11 (current min is 1): android.app.Activity#isChangingConfigurations [NewApi]\n"
+ + " return super.isChangingConfigurations();\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "src/test/pkg/MyActivityImpl.java:12: Error: This method is not overriding anything with the current build target, but will in API level 11 (current target is 3): test.pkg.MyActivityImpl#isChangingConfigurations [Override]\n"
+ + " public boolean isChangingConfigurations() {\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "3 errors, 0 warnings\n",
+
+ lintProject(
+ "apicheck/classpath=>.classpath",
+ "apicheck/minsdk1.xml=>AndroidManifest.xml",
+ "project.properties1=>project.properties",
+ "apicheck/MyActivityImpl.java.txt=>src/test/pkg/MyActivityImpl.java",
+ "apicheck/MyActivityImpl.class.data=>bin/classes/test/pkg/MyActivityImpl.class",
+ "apicheck/android-support-v4.jar.data=>libs/android-support-v4.jar"
+ ));
+ }
}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestTypoDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestTypoDetectorTest.java
new file mode 100644
index 0000000..f0ce60d
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestTypoDetectorTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.tools.lint.checks;
+
+import com.android.annotations.NonNull;
+import com.android.tools.lint.client.api.LintClient;
+import com.android.tools.lint.detector.api.Detector;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.Project;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@SuppressWarnings("javadoc")
+public class ManifestTypoDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new ManifestTypoDetector();
+ }
+
+ private Set<Issue> mEnabled = new HashSet<Issue>();
+
+ @Override
+ protected TestConfiguration getConfiguration(LintClient client, Project project) {
+ return new TestConfiguration(client, project, null) {
+ @Override
+ public boolean isEnabled(@NonNull Issue issue) {
+ return super.isEnabled(issue) && mEnabled.contains(issue);
+ }
+ };
+ }
+
+ public void testOk() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "No warnings.",
+ lintProject(
+ "typo_not_found.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesSdk() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:7: " +
+ "Warning: <use-sdk> looks like a typo; did you mean <uses-sdk> ? [ManifestTypos]\n" +
+ " <use-sdk android:minSdkVersion=\"14\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_sdk.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesSdk2() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:7: " +
+ "Warning: <user-sdk> looks like a typo; did you mean <uses-sdk> ? [ManifestTypos]\n" +
+ " <user-sdk android:minSdkVersion=\"14\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_sdk2.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesPermission() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:9: " +
+ "Warning: <use-permission> looks like a typo; " +
+ "did you mean <uses-permission> ? [ManifestTypos]\n" +
+ " <use-permission android:name=\"com.example.helloworld.permission\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_permission.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesPermission2() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:9: " +
+ "Warning: <user-permission> looks like a typo; " +
+ "did you mean <uses-permission> ? [ManifestTypos]\n" +
+ " <user-permission android:name=\"com.example.helloworld.permission\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_permission2.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesFeature() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:11: " +
+ "Warning: <use-feature> looks like a typo; " +
+ "did you mean <uses-feature> ? [ManifestTypos]\n" +
+ " <use-feature android:name=\"android.hardware.wifi\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_feature.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesFeature2() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:11: " +
+ "Warning: <user-feature> looks like a typo; " +
+ "did you mean <uses-feature> ? [ManifestTypos]\n" +
+ " <user-feature android:name=\"android.hardware.wifi\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_feature2.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesLibrary() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:16: " +
+ "Warning: <use-library> looks like a typo; " +
+ "did you mean <uses-library> ? [ManifestTypos]\n" +
+ " <use-library android:name=\"com.example.helloworld\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_library.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+
+ public void testTypoUsesLibrary2() throws Exception {
+ mEnabled = Collections.singleton(ManifestTypoDetector.ISSUE);
+ assertEquals(
+ "AndroidManifest.xml:16: " +
+ "Warning: <user-library> looks like a typo; " +
+ "did you mean <uses-library> ? [ManifestTypos]\n" +
+ " <user-library android:name=\"com.example.helloworld\" />\n" +
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
+ "0 errors, 1 warnings\n" +
+ "",
+
+ lintProject(
+ "typo_uses_library2.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
+}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.class.data b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.class.data
new file mode 100644
index 0000000..6ae6b28
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.class.data
Binary files differ
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.java.txt b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.java.txt
new file mode 100644
index 0000000..e39daf8
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/MyActivityImpl.java.txt
@@ -0,0 +1,15 @@
+package test.pkg;
+
+import android.app.Activity;
+import android.support.v4.app.FragmentActivity;
+
+public class MyActivityImpl extends FragmentActivity {
+ public void test() {
+ boolean isChanging = super.isChangingConfigurations();
+ }
+
+ @Override
+ public boolean isChangingConfigurations() {
+ return super.isChangingConfigurations();
+ }
+}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/android-support-v4.jar.data b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/android-support-v4.jar.data
new file mode 100644
index 0000000..6080877
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/apicheck/android-support-v4.jar.data
Binary files differ
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_not_found.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_not_found.xml
new file mode 100644
index 0000000..9cd3640
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_not_found.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature.xml
new file mode 100644
index 0000000..cff7f2e
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <use-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature2.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature2.xml
new file mode 100644
index 0000000..d4d8f6e
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_feature2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <user-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library.xml
new file mode 100644
index 0000000..5273642
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <use-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library2.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library2.xml
new file mode 100644
index 0000000..966caf4
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_library2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <user-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission.xml
new file mode 100644
index 0000000..18a31ae
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <use-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission2.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission2.xml
new file mode 100644
index 0000000..2f070c5
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_permission2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <user-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk.xml
new file mode 100644
index 0000000..c086515
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <use-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk2.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk2.xml
new file mode 100644
index 0000000..148a3fc
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/typo_uses_sdk2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <user-sdk android:minSdkVersion="14" />
+
+ <uses-permission android:name="com.example.helloworld.permission" />
+
+ <uses-feature android:name="android.hardware.wifi" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <uses-library android:name="com.example.helloworld" />
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/lint/libs/lint_api/Android.mk b/lint/libs/lint_api/Android.mk
index 1d70a25..3510559 100644
--- a/lint/libs/lint_api/Android.mk
+++ b/lint/libs/lint_api/Android.mk
@@ -13,12 +13,14 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
-
include $(CLEAR_VARS)
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_RESOURCE_DIRS := src/main/java
+# The lint_api code has moved to tools/base/lint_api.
+# The rule below uses the prebuilt lint_api.jar.
+#
+# If you want to run the tests, cd to tools/base/lint_api
+# and run ./gradlew :lint_api:test
+
LOCAL_JAVA_LIBRARIES := \
lombok-ast-0.2 \
common \
@@ -31,7 +33,8 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_MODULE := lint_api
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+
+include $(BUILD_HOST_PREBUILT)
-# Build all sub-directories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/AsmVisitor.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/AsmVisitor.java
deleted file mode 100644
index e8a4bb5..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/AsmVisitor.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.google.common.annotations.Beta;
-
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Specialized visitor for running detectors on a class object model.
- * <p>
- * It operates in two phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant method name to a list of detectors to consult for that method
- * name. The set of method names that a detector is interested in is provided
- * by the detectors themselves.
- * <li> Second, it iterates over the DOM a single time. For each method call it finds,
- * it dispatches to any check that has registered interest in that method name.
- * <li> Finally, it runs a full check on those class scanners that do not register
- * specific method names to be checked. This is intended for those detectors
- * that do custom work, not related specifically to method calls.
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-class AsmVisitor {
- /**
- * Number of distinct node types specified in {@link AbstractInsnNode}. Sadly
- * there isn't a max-constant there, so update this along with ASM library
- * updates.
- */
- private static final int TYPE_COUNT = AbstractInsnNode.LINE + 1;
- private final Map<String, List<ClassScanner>> mMethodNameToChecks =
- new HashMap<String, List<ClassScanner>>();
- private final Map<String, List<ClassScanner>> mMethodOwnerToChecks =
- new HashMap<String, List<ClassScanner>>();
- private final List<Detector> mFullClassChecks = new ArrayList<Detector>();
-
- private final List<? extends Detector> mAllDetectors;
- private List<ClassScanner>[] mNodeTypeDetectors;
-
- // Really want this:
- //<T extends List<Detector> & Detector.ClassScanner> ClassVisitor(T xmlDetectors) {
- // but it makes client code tricky and ugly.
- @SuppressWarnings("unchecked")
- AsmVisitor(@NonNull LintClient client, @NonNull List<? extends Detector> classDetectors) {
- mAllDetectors = classDetectors;
-
- // TODO: Check appliesTo() for files, and find a quick way to enable/disable
- // rules when running through a full project!
- for (Detector detector : classDetectors) {
- Detector.ClassScanner scanner = (Detector.ClassScanner) detector;
-
- boolean checkFullClass = true;
-
- Collection<String> names = scanner.getApplicableCallNames();
- if (names != null) {
- checkFullClass = false;
- for (String element : names) {
- List<Detector.ClassScanner> list = mMethodNameToChecks.get(element);
- if (list == null) {
- list = new ArrayList<Detector.ClassScanner>();
- mMethodNameToChecks.put(element, list);
- }
- list.add(scanner);
- }
- }
-
- Collection<String> owners = scanner.getApplicableCallOwners();
- if (owners != null) {
- checkFullClass = false;
- for (String element : owners) {
- List<Detector.ClassScanner> list = mMethodOwnerToChecks.get(element);
- if (list == null) {
- list = new ArrayList<Detector.ClassScanner>();
- mMethodOwnerToChecks.put(element, list);
- }
- list.add(scanner);
- }
- }
-
- int[] types = scanner.getApplicableAsmNodeTypes();
- if (types != null) {
- checkFullClass = false;
- for (int type : types) {
- if (type < 0 || type >= TYPE_COUNT) {
- // Can't support this node type: looks like ASM wasn't updated correctly.
- client.log(null, "Out of range node type %1$d from detector %2$s",
- type, scanner);
- continue;
- }
- if (mNodeTypeDetectors == null) {
- mNodeTypeDetectors = new List[TYPE_COUNT];
- }
- List<ClassScanner> checks = mNodeTypeDetectors[type];
- if (checks == null) {
- checks = new ArrayList<ClassScanner>();
- mNodeTypeDetectors[type] = checks;
- }
- checks.add(scanner);
- }
- }
-
- if (checkFullClass) {
- mFullClassChecks.add(detector);
- }
- }
- }
-
- @SuppressWarnings("rawtypes") // ASM API uses raw types
- void runClassDetectors(ClassContext context) {
- ClassNode classNode = context.getClassNode();
-
- for (Detector detector : mAllDetectors) {
- detector.beforeCheckFile(context);
- }
-
- for (Detector detector : mFullClassChecks) {
- Detector.ClassScanner scanner = (Detector.ClassScanner) detector;
- scanner.checkClass(context, classNode);
- detector.afterCheckFile(context);
- }
-
- if (!mMethodNameToChecks.isEmpty() || !mMethodOwnerToChecks.isEmpty() ||
- mNodeTypeDetectors != null && mNodeTypeDetectors.length > 0) {
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- InsnList nodes = method.instructions;
- for (int i = 0, n = nodes.size(); i < n; i++) {
- AbstractInsnNode instruction = nodes.get(i);
- int type = instruction.getType();
- if (type == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode call = (MethodInsnNode) instruction;
-
- String owner = call.owner;
- List<ClassScanner> scanners = mMethodOwnerToChecks.get(owner);
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkCall(context, classNode, method, call);
- }
- }
-
- String name = call.name;
- scanners = mMethodNameToChecks.get(name);
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkCall(context, classNode, method, call);
- }
- }
- }
-
- if (mNodeTypeDetectors != null && type < mNodeTypeDetectors.length) {
- List<ClassScanner> scanners = mNodeTypeDetectors[type];
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkInstruction(context, classNode, method, instruction);
- }
- }
- }
- }
- }
- }
-
- for (Detector detector : mAllDetectors) {
- detector.afterCheckFile(context);
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java
deleted file mode 100644
index 337eb27..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/CircularDependencyException.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.google.common.annotations.Beta;
-
-/**
- * Exception thrown when there is a circular dependency, such as a circular dependency
- * of library mProject references
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class CircularDependencyException extends RuntimeException {
- @Nullable
- private Project mProject;
-
- @Nullable
- private Location mLocation;
-
- CircularDependencyException(@NonNull String message) {
- super(message);
- }
-
- /**
- * Returns the associated project, if any
- *
- * @return the associated project, if any
- */
- @Nullable
- public Project getProject() {
- return mProject;
- }
-
- /**
- * Sets the associated project, if any
- *
- * @param project the associated project, if any
- */
- public void setProject(@Nullable Project project) {
- mProject = project;
- }
-
- /**
- * Returns the associated location, if any
- *
- * @return the associated location, if any
- */
- @Nullable
- public Location getLocation() {
- return mLocation;
- }
-
- /**
- * Sets the associated location, if any
- *
- * @param location the associated location, if any
- */
- public void setLocation(@Nullable Location location) {
- mLocation = location;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/Configuration.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/Configuration.java
deleted file mode 100644
index d233be7..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/Configuration.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-
-/**
- * Lint configuration for an Android project such as which specific rules to include,
- * which specific rules to exclude, and which specific errors to ignore.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class Configuration {
- /**
- * Checks whether this issue should be ignored because the user has already
- * suppressed the error? Note that this refers to individual issues being
- * suppressed/ignored, not a whole detector being disabled via something
- * like {@link #isEnabled(Issue)}.
- *
- * @param context the context used by the detector when the issue was found
- * @param issue the issue that was found
- * @param location the location of the issue
- * @param message the associated user message
- * @param data additional information about an issue (see
- * {@link LintClient#report(Context, Issue, Severity, Location, String, Object)}
- * for more information
- * @return true if this issue should be suppressed
- */
- public boolean isIgnored(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- return false;
- }
-
- /**
- * Returns false if the given issue has been disabled. This is just
- * a convenience method for {@code getSeverity(issue) != Severity.IGNORE}.
- *
- * @param issue the issue to check
- * @return false if the issue has been disabled
- */
- public boolean isEnabled(@NonNull Issue issue) {
- return getSeverity(issue) != Severity.IGNORE;
- }
-
- /**
- * Returns the severity for a given issue. This is the same as the
- * {@link Issue#getDefaultSeverity()} unless the user has selected a custom
- * severity (which is tool context dependent).
- *
- * @param issue the issue to look up the severity from
- * @return the severity use for issues for the given detector
- */
- public Severity getSeverity(@NonNull Issue issue) {
- return issue.getDefaultSeverity();
- }
-
- // Editing configurations
-
- /**
- * Marks the given warning as "ignored".
- *
- * @param context The scanning context
- * @param issue the issue to be ignored
- * @param location The location to ignore the warning at, if any
- * @param message The message for the warning
- * @param data The corresponding data, or null
- */
- public abstract void ignore(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data);
-
- /**
- * Sets the severity to be used for this issue.
- *
- * @param issue the issue to set the severity for
- * @param severity the severity to associate with this issue, or null to
- * reset the severity to the default
- */
- public abstract void setSeverity(@NonNull Issue issue, @Nullable Severity severity);
-
- // Bulk editing support
-
- /**
- * Marks the beginning of a "bulk" editing operation with repeated calls to
- * {@link #setSeverity} or {@link #ignore}. After all the values have been
- * set, the client <b>must</b> call {@link #finishBulkEditing()}. This
- * allows configurations to avoid doing expensive I/O (such as writing out a
- * config XML file) for each and every editing operation when they are
- * applied in bulk, such as from a configuration dialog's "Apply" action.
- */
- public void startBulkEditing() {
- }
-
- /**
- * Marks the end of a "bulk" editing operation, where values should be
- * committed to persistent storage. See {@link #startBulkEditing()} for
- * details.
- */
- public void finishBulkEditing() {
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultConfiguration.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultConfiguration.java
deleted file mode 100644
index db82556..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultConfiguration.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-import com.google.common.io.Closeables;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXParseException;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-/**
- * Default implementation of a {@link Configuration} which reads and writes
- * configuration data into {@code lint.xml} in the project directory.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class DefaultConfiguration extends Configuration {
- private final LintClient mClient;
- private static final String CONFIG_FILE_NAME = "lint.xml"; //$NON-NLS-1$
-
- // Lint XML File
- @NonNull
- private static final String TAG_ISSUE = "issue"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_ID = "id"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_SEVERITY = "severity"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_PATH = "path"; //$NON-NLS-1$
- @NonNull
- private static final String TAG_IGNORE = "ignore"; //$NON-NLS-1$
-
- private final Configuration mParent;
- private final Project mProject;
- private final File mConfigFile;
- private boolean mBulkEditing;
-
- /** Map from id to list of project-relative paths for suppressed warnings */
- private Map<String, List<String>> mSuppressed;
-
- /**
- * Map from id to custom {@link Severity} override
- */
- private Map<String, Severity> mSeverity;
-
- protected DefaultConfiguration(
- @NonNull LintClient client,
- @Nullable Project project,
- @Nullable Configuration parent,
- @NonNull File configFile) {
- mClient = client;
- mProject = project;
- mParent = parent;
- mConfigFile = configFile;
- }
-
- protected DefaultConfiguration(
- @NonNull LintClient client,
- @NonNull Project project,
- @Nullable Configuration parent) {
- this(client, project, parent, new File(project.getDir(), CONFIG_FILE_NAME));
- }
-
- /**
- * Creates a new {@link DefaultConfiguration}
- *
- * @param client the client to report errors to etc
- * @param project the associated project
- * @param parent the parent/fallback configuration or null
- * @return a new configuration
- */
- @NonNull
- public static DefaultConfiguration create(
- @NonNull LintClient client,
- @NonNull Project project,
- @Nullable Configuration parent) {
- return new DefaultConfiguration(client, project, parent);
- }
-
- /**
- * Creates a new {@link DefaultConfiguration} for the given lint config
- * file, not affiliated with a project. This is used for global
- * configurations.
- *
- * @param client the client to report errors to etc
- * @param lintFile the lint file containing the configuration
- * @return a new configuration
- */
- @NonNull
- public static DefaultConfiguration create(@NonNull LintClient client, @NonNull File lintFile) {
- return new DefaultConfiguration(client, null /*project*/, null /*parent*/, lintFile);
- }
-
- @Override
- public boolean isIgnored(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- ensureInitialized();
-
- String id = issue.getId();
- List<String> paths = mSuppressed.get(id);
- if (paths != null && location != null) {
- File file = location.getFile();
- String relativePath = context.getProject().getRelativePath(file);
- for (String suppressedPath : paths) {
- if (suppressedPath.equals(relativePath)) {
- return true;
- }
- }
- }
-
- if (mParent != null) {
- return mParent.isIgnored(context, issue, location, message, data);
- }
-
- return false;
- }
-
- @NonNull
- protected Severity getDefaultSeverity(@NonNull Issue issue) {
- if (!issue.isEnabledByDefault()) {
- return Severity.IGNORE;
- }
-
- return issue.getDefaultSeverity();
- }
-
- @Override
- @NonNull
- public Severity getSeverity(@NonNull Issue issue) {
- ensureInitialized();
-
- Severity severity = mSeverity.get(issue.getId());
- if (severity != null) {
- return severity;
- }
-
- if (mParent != null) {
- return mParent.getSeverity(issue);
- }
-
- return getDefaultSeverity(issue);
- }
-
- private void ensureInitialized() {
- if (mSuppressed == null) {
- readConfig();
- }
- }
-
- private void formatError(String message, Object... args) {
- if (args != null && args.length > 0) {
- message = String.format(message, args);
- }
- message = "Failed to parse lint.xml configuration file: " + message;
- LintDriver driver = new LintDriver(new IssueRegistry() {
- @Override @NonNull public List<Issue> getIssues() {
- return Collections.emptyList();
- }
- }, mClient);
- mClient.report(new Context(driver, mProject, mProject, mConfigFile),
- IssueRegistry.LINT_ERROR,
- mProject.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR),
- Location.create(mConfigFile), message, null);
- }
-
- private void readConfig() {
- mSuppressed = new HashMap<String, List<String>>();
- mSeverity = new HashMap<String, Severity>();
-
- if (!mConfigFile.exists()) {
- return;
- }
-
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables.closeQuietly
- BufferedInputStream input = null;
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- input = new BufferedInputStream(new FileInputStream(mConfigFile));
- InputSource source = new InputSource(input);
- factory.setNamespaceAware(false);
- factory.setValidating(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.parse(source);
- NodeList issues = document.getElementsByTagName(TAG_ISSUE);
- for (int i = 0, count = issues.getLength(); i < count; i++) {
- Node node = issues.item(i);
- Element element = (Element) node;
- String id = element.getAttribute(ATTR_ID);
- if (id.isEmpty()) {
- formatError("Invalid lint config file: Missing required issue id attribute");
- continue;
- }
-
- NamedNodeMap attributes = node.getAttributes();
- for (int j = 0, n = attributes.getLength(); j < n; j++) {
- Node attribute = attributes.item(j);
- String name = attribute.getNodeName();
- String value = attribute.getNodeValue();
- if (ATTR_ID.equals(name)) {
- // already handled
- } else if (ATTR_SEVERITY.equals(name)) {
- for (Severity severity : Severity.values()) {
- if (value.equalsIgnoreCase(severity.name())) {
- mSeverity.put(id, severity);
- break;
- }
- }
- } else {
- formatError("Unexpected attribute \"%1$s\"", name);
- }
- }
-
- // Look up ignored errors
- NodeList childNodes = element.getChildNodes();
- if (childNodes.getLength() > 0) {
- for (int j = 0, n = childNodes.getLength(); j < n; j++) {
- Node child = childNodes.item(j);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- Element ignore = (Element) child;
- String path = ignore.getAttribute(ATTR_PATH);
- if (path.isEmpty()) {
- formatError("Missing required %1$s attribute under %2$s",
- ATTR_PATH, id);
- } else {
- List<String> paths = mSuppressed.get(id);
- if (paths == null) {
- paths = new ArrayList<String>(n / 2 + 1);
- mSuppressed.put(id, paths);
- }
- paths.add(path);
- }
- }
- }
- }
- }
- } catch (SAXParseException e) {
- formatError(e.getMessage());
- } catch (Exception e) {
- mClient.log(e, null);
- } finally {
- Closeables.closeQuietly(input);
- }
- }
-
- private void writeConfig() {
- try {
- // Write the contents to a new file first such that we don't clobber the
- // existing file if some I/O error occurs.
- File file = new File(mConfigFile.getParentFile(),
- mConfigFile.getName() + ".new"); //$NON-NLS-1$
-
- Writer writer = new BufferedWriter(new FileWriter(file));
- writer.write(
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //$NON-NLS-1$
- "<lint>\n"); //$NON-NLS-1$
-
- if (!mSuppressed.isEmpty() || !mSeverity.isEmpty()) {
- // Process the maps in a stable sorted order such that if the
- // files are checked into version control with the project,
- // there are no random diffs just because hashing algorithms
- // differ:
- Set<String> idSet = new HashSet<String>();
- for (String id : mSuppressed.keySet()) {
- idSet.add(id);
- }
- for (String id : mSeverity.keySet()) {
- idSet.add(id);
- }
- List<String> ids = new ArrayList<String>(idSet);
- Collections.sort(ids);
-
- for (String id : ids) {
- writer.write(" <"); //$NON-NLS-1$
- writer.write(TAG_ISSUE);
- writeAttribute(writer, ATTR_ID, id);
- Severity severity = mSeverity.get(id);
- if (severity != null) {
- writeAttribute(writer, ATTR_SEVERITY,
- severity.name().toLowerCase(Locale.US));
- }
-
- List<String> paths = mSuppressed.get(id);
- if (paths != null && !paths.isEmpty()) {
- writer.write('>');
- writer.write('\n');
- // The paths are already kept in sorted order when they are modified
- // by ignore(...)
- for (String path : paths) {
- writer.write(" <"); //$NON-NLS-1$
- writer.write(TAG_IGNORE);
- writeAttribute(writer, ATTR_PATH, path);
- writer.write(" />\n"); //$NON-NLS-1$
- }
- writer.write(" </"); //$NON-NLS-1$
- writer.write(TAG_ISSUE);
- writer.write('>');
- writer.write('\n');
- } else {
- writer.write(" />\n"); //$NON-NLS-1$
- }
- }
- }
-
- writer.write("</lint>"); //$NON-NLS-1$
- writer.close();
-
- // Move file into place: move current version to lint.xml~ (removing the old ~ file
- // if it exists), then move the new version to lint.xml.
- File oldFile = new File(mConfigFile.getParentFile(),
- mConfigFile.getName() + '~'); //$NON-NLS-1$
- if (oldFile.exists()) {
- oldFile.delete();
- }
- if (mConfigFile.exists()) {
- mConfigFile.renameTo(oldFile);
- }
- boolean ok = file.renameTo(mConfigFile);
- if (ok && oldFile.exists()) {
- oldFile.delete();
- }
- } catch (Exception e) {
- mClient.log(e, null);
- }
- }
-
- private static void writeAttribute(
- @NonNull Writer writer, @NonNull String name, @NonNull String value)
- throws IOException {
- writer.write(' ');
- writer.write(name);
- writer.write('=');
- writer.write('"');
- writer.write(value);
- writer.write('"');
- }
-
- @Override
- public void ignore(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- // This configuration only supports suppressing warnings on a per-file basis
- if (location != null) {
- ignore(issue, location.getFile());
- }
- }
-
- /**
- * Marks the given issue and file combination as being ignored.
- *
- * @param issue the issue to be ignored in the given file
- * @param file the file to ignore the issue in
- */
- public void ignore(@NonNull Issue issue, @NonNull File file) {
- ensureInitialized();
-
- String path = mProject != null ? mProject.getRelativePath(file) : file.getPath();
-
- List<String> paths = mSuppressed.get(issue.getId());
- if (paths == null) {
- paths = new ArrayList<String>();
- mSuppressed.put(issue.getId(), paths);
- }
- paths.add(path);
-
- // Keep paths sorted alphabetically; makes XML output stable
- Collections.sort(paths);
-
- if (!mBulkEditing) {
- writeConfig();
- }
- }
-
- @Override
- public void setSeverity(@NonNull Issue issue, @Nullable Severity severity) {
- ensureInitialized();
-
- String id = issue.getId();
- if (severity == null) {
- mSeverity.remove(id);
- } else {
- mSeverity.put(id, severity);
- }
-
- if (!mBulkEditing) {
- writeConfig();
- }
- }
-
- @Override
- public void startBulkEditing() {
- mBulkEditing = true;
- }
-
- @Override
- public void finishBulkEditing() {
- mBulkEditing = false;
- writeConfig();
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultSdkInfo.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultSdkInfo.java
deleted file mode 100644
index 2f54659..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/DefaultSdkInfo.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
-import static com.android.SdkConstants.ABS_LIST_VIEW;
-import static com.android.SdkConstants.ABS_SEEK_BAR;
-import static com.android.SdkConstants.ABS_SPINNER;
-import static com.android.SdkConstants.ADAPTER_VIEW;
-import static com.android.SdkConstants.AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.BUTTON;
-import static com.android.SdkConstants.CHECKABLE;
-import static com.android.SdkConstants.CHECKED_TEXT_VIEW;
-import static com.android.SdkConstants.CHECK_BOX;
-import static com.android.SdkConstants.COMPOUND_BUTTON;
-import static com.android.SdkConstants.EDIT_TEXT;
-import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW;
-import static com.android.SdkConstants.FRAME_LAYOUT;
-import static com.android.SdkConstants.GALLERY;
-import static com.android.SdkConstants.GRID_VIEW;
-import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.IMAGE_BUTTON;
-import static com.android.SdkConstants.IMAGE_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.LIST_VIEW;
-import static com.android.SdkConstants.MULTI_AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.PROGRESS_BAR;
-import static com.android.SdkConstants.RADIO_BUTTON;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.SCROLL_VIEW;
-import static com.android.SdkConstants.SEEK_BAR;
-import static com.android.SdkConstants.SPINNER;
-import static com.android.SdkConstants.SURFACE_VIEW;
-import static com.android.SdkConstants.SWITCH;
-import static com.android.SdkConstants.TABLE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.TAB_HOST;
-import static com.android.SdkConstants.TAB_WIDGET;
-import static com.android.SdkConstants.TEXT_VIEW;
-import static com.android.SdkConstants.TOGGLE_BUTTON;
-import static com.android.SdkConstants.VIEW;
-import static com.android.SdkConstants.VIEW_ANIMATOR;
-import static com.android.SdkConstants.VIEW_GROUP;
-import static com.android.SdkConstants.VIEW_PKG_PREFIX;
-import static com.android.SdkConstants.VIEW_STUB;
-import static com.android.SdkConstants.VIEW_SWITCHER;
-import static com.android.SdkConstants.WEB_VIEW;
-import static com.android.SdkConstants.WIDGET_PKG_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Default simple implementation of an {@link SdkInfo}
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-class DefaultSdkInfo extends SdkInfo {
- @Override
- @Nullable
- public String getParentViewName(@NonNull String name) {
- name = getRawType(name);
-
- return PARENTS.get(name);
- }
-
- @Override
- @Nullable
- public String getParentViewClass(@NonNull String fqcn) {
- int index = fqcn.lastIndexOf('.');
- if (index != -1) {
- fqcn = fqcn.substring(index + 1);
- }
-
- String parent = PARENTS.get(fqcn);
- if (parent == null) {
- return null;
- }
- // The map only stores class names internally; correct for full package paths
- if (parent.equals(VIEW) || parent.equals(VIEW_GROUP) || parent.equals(SURFACE_VIEW)) {
- return VIEW_PKG_PREFIX + parent;
- } else {
- return WIDGET_PKG_PREFIX + parent;
- }
- }
-
- @Override
- public boolean isSubViewOf(@NonNull String parentType, @NonNull String childType) {
- String parent = getRawType(parentType);
- String child = getRawType(childType);
-
- // Do analysis just on non-fqcn paths
- if (parent.indexOf('.') != -1) {
- parent = parent.substring(parent.lastIndexOf('.') + 1);
- }
- if (child.indexOf('.') != -1) {
- child = child.substring(child.lastIndexOf('.') + 1);
- }
-
- if (parent.equals(VIEW)) {
- return true;
- }
-
- while (!child.equals(VIEW)) {
- if (parent.equals(child)) {
- return true;
- }
- if (implementsInterface(child, parentType)) {
- return true;
- }
- child = PARENTS.get(child);
- if (child == null) {
- // Unknown view - err on the side of caution
- return true;
- }
- }
-
- return false;
- }
-
- private static boolean implementsInterface(String className, String interfaceName) {
- return interfaceName.equals(INTERFACES.get(className));
- }
-
- // Strip off type parameters, e.g. AdapterView<?> => AdapterView
- private static String getRawType(String type) {
- if (type != null) {
- int index = type.indexOf('<');
- if (index != -1) {
- type = type.substring(0, index);
- }
- }
-
- return type;
- }
-
- @Override
- public boolean isLayout(@NonNull String tag) {
- // TODO: Read in widgets.txt from the platform install area to look up this information
- // dynamically instead!
-
- if (super.isLayout(tag)) {
- return true;
- }
-
- return LAYOUTS.contains(tag);
- }
-
- private static final int CLASS_COUNT = 59;
- private static final int LAYOUT_COUNT = 20;
-
- private static final Map<String,String> PARENTS = Maps.newHashMapWithExpectedSize(CLASS_COUNT);
- private static final Set<String> LAYOUTS = Sets.newHashSetWithExpectedSize(CLASS_COUNT);
-
- static {
- PARENTS.put(COMPOUND_BUTTON, BUTTON);
- PARENTS.put(ABS_SPINNER, ADAPTER_VIEW);
- PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW);
- PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW);
- PARENTS.put(ADAPTER_VIEW, VIEW_GROUP);
- PARENTS.put(VIEW_GROUP, VIEW);
-
- PARENTS.put(TEXT_VIEW, VIEW);
- PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
- PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON);
- PARENTS.put(SPINNER, ABS_SPINNER);
- PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW);
- PARENTS.put(IMAGE_VIEW, VIEW);
- PARENTS.put(EDIT_TEXT, TEXT_VIEW);
- PARENTS.put(PROGRESS_BAR, VIEW);
- PARENTS.put(TOGGLE_BUTTON, COMPOUND_BUTTON);
- PARENTS.put(VIEW_STUB, VIEW);
- PARENTS.put(BUTTON, TEXT_VIEW);
- PARENTS.put(SEEK_BAR, ABS_SEEK_BAR);
- PARENTS.put(CHECK_BOX, COMPOUND_BUTTON);
- PARENTS.put(SWITCH, COMPOUND_BUTTON);
- PARENTS.put(GALLERY, ABS_SPINNER);
- PARENTS.put(SURFACE_VIEW, VIEW);
- PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP);
- PARENTS.put(LINEAR_LAYOUT, VIEW_GROUP);
- PARENTS.put(RELATIVE_LAYOUT, VIEW_GROUP);
- PARENTS.put(LIST_VIEW, ABS_LIST_VIEW);
- PARENTS.put(VIEW_SWITCHER, VIEW_ANIMATOR);
- PARENTS.put(FRAME_LAYOUT, VIEW_GROUP);
- PARENTS.put(HORIZONTAL_SCROLL_VIEW, FRAME_LAYOUT);
- PARENTS.put(VIEW_ANIMATOR, FRAME_LAYOUT);
- PARENTS.put(TAB_HOST, FRAME_LAYOUT);
- PARENTS.put(TABLE_ROW, LINEAR_LAYOUT);
- PARENTS.put(RADIO_GROUP, LINEAR_LAYOUT);
- PARENTS.put(TAB_WIDGET, LINEAR_LAYOUT);
- PARENTS.put(EXPANDABLE_LIST_VIEW, LIST_VIEW);
- PARENTS.put(TABLE_LAYOUT, LINEAR_LAYOUT);
- PARENTS.put(SCROLL_VIEW, FRAME_LAYOUT);
- PARENTS.put(GRID_VIEW, ABS_LIST_VIEW);
- PARENTS.put(WEB_VIEW, ABSOLUTE_LAYOUT);
- PARENTS.put(AUTO_COMPLETE_TEXT_VIEW, EDIT_TEXT);
- PARENTS.put(MULTI_AUTO_COMPLETE_TEXT_VIEW, AUTO_COMPLETE_TEXT_VIEW);
- PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
-
- PARENTS.put("MediaController", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("SlidingDrawer", VIEW_GROUP); //$NON-NLS-1$
- PARENTS.put("DialerFilter", RELATIVE_LAYOUT); //$NON-NLS-1$
- PARENTS.put("DigitalClock", TEXT_VIEW); //$NON-NLS-1$
- PARENTS.put("Chronometer", TEXT_VIEW); //$NON-NLS-1$
- PARENTS.put("ImageSwitcher", VIEW_SWITCHER); //$NON-NLS-1$
- PARENTS.put("TextSwitcher", VIEW_SWITCHER); //$NON-NLS-1$
- PARENTS.put("AnalogClock", VIEW); //$NON-NLS-1$
- PARENTS.put("TwoLineListItem", RELATIVE_LAYOUT); //$NON-NLS-1$
- PARENTS.put("ZoomControls", LINEAR_LAYOUT); //$NON-NLS-1$
- PARENTS.put("DatePicker", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("TimePicker", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("VideoView", SURFACE_VIEW); //$NON-NLS-1$
- PARENTS.put("ZoomButton", IMAGE_BUTTON); //$NON-NLS-1$
- PARENTS.put("RatingBar", ABS_SEEK_BAR); //$NON-NLS-1$
- PARENTS.put("ViewFlipper", VIEW_ANIMATOR); //$NON-NLS-1$
- PARENTS.put("NumberPicker", LINEAR_LAYOUT); //$NON-NLS-1$
-
- assert PARENTS.size() <= CLASS_COUNT : PARENTS.size();
-
- /*
- // Check that all widgets lead to the root view
- if (LintUtils.assertionsEnabled()) {
- for (String key : PARENTS.keySet()) {
- String parent = PARENTS.get(key);
- if (!parent.equals(VIEW)) {
- String grandParent = PARENTS.get(parent);
- assert grandParent != null : parent;
- }
- }
- }
- */
-
- LAYOUTS.add(TAB_HOST);
- LAYOUTS.add(HORIZONTAL_SCROLL_VIEW);
- LAYOUTS.add(VIEW_SWITCHER);
- LAYOUTS.add(TAB_WIDGET);
- LAYOUTS.add(VIEW_ANIMATOR);
- LAYOUTS.add(SCROLL_VIEW);
- LAYOUTS.add(GRID_VIEW);
- LAYOUTS.add(TABLE_ROW);
- LAYOUTS.add(RADIO_GROUP);
- LAYOUTS.add(LIST_VIEW);
- LAYOUTS.add(EXPANDABLE_LIST_VIEW);
- LAYOUTS.add("MediaController"); //$NON-NLS-1$
- LAYOUTS.add("DialerFilter"); //$NON-NLS-1$
- LAYOUTS.add("ViewFlipper"); //$NON-NLS-1$
- LAYOUTS.add("SlidingDrawer"); //$NON-NLS-1$
- LAYOUTS.add("StackView"); //$NON-NLS-1$
- LAYOUTS.add("SearchView"); //$NON-NLS-1$
- LAYOUTS.add("TextSwitcher"); //$NON-NLS-1$
- LAYOUTS.add("AdapterViewFlipper"); //$NON-NLS-1$
- LAYOUTS.add("ImageSwitcher"); //$NON-NLS-1$
- assert LAYOUTS.size() <= LAYOUT_COUNT : LAYOUTS.size();
- }
-
- // Currently using a map; this should really be a list, but using a map until we actually
- // start adding more than one item
- @NonNull
- private static final Map<String, String> INTERFACES = new HashMap<String, String>(2);
- static {
- INTERFACES.put(CHECKED_TEXT_VIEW, CHECKABLE);
- INTERFACES.put(COMPOUND_BUTTON, CHECKABLE);
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IDomParser.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IDomParser.java
deleted file mode 100644
index 1a70fac..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IDomParser.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/**
- * A wrapper for an XML parser. This allows tools integrating lint to map directly
- * to builtin services, such as already-parsed data structures in XML editors.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public interface IDomParser {
- /**
- * Parse the file pointed to by the given context and return as a Document
- *
- * @param context the context pointing to the file to be parsed, typically
- * via {@link Context#getContents()} but the file handle (
- * {@link Context#file} can also be used to map to an existing
- * editor buffer in the surrounding tool, etc)
- * @return the parsed DOM document, or null if parsing fails
- */
- @Nullable
- Document parseXml(@NonNull XmlContext context);
-
- /**
- * Returns a {@link Location} for the given DOM node
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull XmlContext context, @NonNull Node node);
-
- /**
- * Returns a {@link Location} for the given DOM node. Like
- * {@link #getLocation(XmlContext, Node)}, but allows a position range that
- * is a subset of the node range.
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @param start the starting position within the node, inclusive
- * @param end the ending position within the node, exclusive
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull XmlContext context, @NonNull Node node, int start, int end);
-
- /**
- * Creates a light-weight handle to a location for the given node. It can be
- * turned into a full fledged location by
- * {@link com.android.tools.lint.detector.api.Location.Handle#resolve()}.
- *
- * @param context the context providing the node
- * @param node the node (element or attribute) to create a location handle
- * for
- * @return a location handle
- */
- @NonNull
- Location.Handle createLocationHandle(@NonNull XmlContext context, @NonNull Node node);
-
- /**
- * Dispose any data structures held for the given context.
- * @param context information about the file previously parsed
- * @param document the document that was parsed and is now being disposed
- */
- void dispose(@NonNull XmlContext context, @NonNull Document document);
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IJavaParser.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IJavaParser.java
deleted file mode 100644
index 9b74f16..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IJavaParser.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-
-import lombok.ast.Node;
-
-/**
- * A wrapper for a Java parser. This allows tools integrating lint to map directly
- * to builtin services, such as already-parsed data structures in Java editors.
- * <p/>
- * <b>NOTE: This is not a or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-public interface IJavaParser {
- /**
- * Parse the file pointed to by the given context.
- *
- * @param context the context pointing to the file to be parsed, typically
- * via {@link Context#getContents()} but the file handle (
- * {@link Context#file} can also be used to map to an existing
- * editor buffer in the surrounding tool, etc)
- * @return the compilation unit node for the file
- */
- @Nullable
- Node parseJava(@NonNull JavaContext context);
-
- /**
- * Returns a {@link Location} for the given node
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull JavaContext context, @NonNull Node node);
-
- /**
- * Creates a light-weight handle to a location for the given node. It can be
- * turned into a full fledged location by
- * {@link com.android.tools.lint.detector.api.Location.Handle#resolve()}.
- *
- * @param context the context providing the node
- * @param node the node (element or attribute) to create a location handle
- * for
- * @return a location handle
- */
- @NonNull
- Location.Handle createLocationHandle(@NonNull JavaContext context, @NonNull Node node);
-
- /**
- * Dispose any data structures held for the given context.
- * @param context information about the file previously parsed
- * @param compilationUnit the compilation unit being disposed
- */
- void dispose(@NonNull JavaContext context, @NonNull Node compilationUnit);
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IssueRegistry.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IssueRegistry.java
deleted file mode 100644
index 0b8b141..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/IssueRegistry.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Maps;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/** Registry which provides a list of checks to be performed on an Android project
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class IssueRegistry {
- private static List<Category> sCategories;
- private static Map<String, Issue> sIdToIssue;
- private static Map<EnumSet<Scope>, List<Issue>> sScopeIssues = Maps.newHashMap();
-
- /**
- * Creates a new {@linkplain IssueRegistry}
- */
- protected IssueRegistry() {
- }
-
- /**
- * Issue reported by lint (not a specific detector) when it cannot even
- * parse an XML file prior to analysis
- */
- @NonNull
- public static final Issue PARSER_ERROR = Issue.create(
- "ParserError", //$NON-NLS-1$
- "Finds files that contain fatal parser errors",
- "Lint will ignore any files that contain fatal parsing errors. These may contain " +
- "other errors, or contain code which affects issues in other files.",
- Category.CORRECTNESS,
- 10,
- Severity.ERROR,
- Detector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Issue reported by lint for various other issues which prevents lint from
- * running normally when it's not necessarily an error in the user's code base.
- */
- @NonNull
- public static final Issue LINT_ERROR = Issue.create(
- "LintError", //$NON-NLS-1$
- "Issues related to running lint itself, such as failure to read files, etc",
- "This issue type represents a problem running lint itself. Examples include " +
- "failure to find bytecode for source files (which means certain detectors " +
- "could not be run), parsing errors in lint configuration files, etc." +
- "\n" +
- "These errors are not errors in your own code, but they are shown to make " +
- "it clear that some checks were not completed.",
-
- Category.LINT,
- 10,
- Severity.ERROR,
- Detector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Returns the list of issues that can be found by all known detectors.
- *
- * @return the list of issues to be checked (including those that may be
- * disabled!)
- */
- @NonNull
- public abstract List<Issue> getIssues();
-
- /**
- * Returns all available issues of a given scope (regardless of whether
- * they are actually enabled for a given configuration etc)
- *
- * @param scope the applicable scope set
- * @return a list of issues
- */
- @NonNull
- private List<Issue> getIssuesForScope(@NonNull EnumSet<Scope> scope) {
- List<Issue> list = sScopeIssues.get(scope);
- if (list == null) {
- List<Issue> issues = getIssues();
- if (scope.equals(Scope.ALL)) {
- list = issues;
- } else {
- int initialSize = 12;
- if (scope.contains(Scope.RESOURCE_FILE)) {
- initialSize += 50;
- }
- if (scope.contains(Scope.JAVA_FILE)) {
- initialSize += 12;
- }
- if (scope.contains(Scope.CLASS_FILE)) {
- initialSize += 12;
- }
- list = new ArrayList<Issue>(initialSize);
- for (Issue issue : issues) {
- // Determine if the scope matches
- if (issue.isAdequate(scope)) {
- list.add(issue);
- }
- }
- }
- sScopeIssues.put(scope, list);
- }
-
- return list;
- }
-
- /**
- * Creates a list of detectors applicable to the given scope, and with the
- * given configuration.
- *
- * @param client the client to report errors to
- * @param configuration the configuration to look up which issues are
- * enabled etc from
- * @param scope the scope for the analysis, to filter out detectors that
- * require wider analysis than is currently being performed
- * @param scopeToDetectors an optional map which (if not null) will be
- * filled by this method to contain mappings from each scope to
- * the applicable detectors for that scope
- * @return a list of new detector instances
- */
- @NonNull
- final List<? extends Detector> createDetectors(
- @NonNull LintClient client,
- @NonNull Configuration configuration,
- @NonNull EnumSet<Scope> scope,
- @Nullable Map<Scope, List<Detector>> scopeToDetectors) {
-
- List<Issue> issues = getIssuesForScope(scope);
- if (issues.isEmpty()) {
- return Collections.emptyList();
- }
-
- Set<Class<? extends Detector>> detectorClasses = new HashSet<Class<? extends Detector>>();
- Map<Class<? extends Detector>, EnumSet<Scope>> detectorToScope =
- new HashMap<Class<? extends Detector>, EnumSet<Scope>>();
-
- for (Issue issue : issues) {
- Class<? extends Detector> detectorClass = issue.getDetectorClass();
- EnumSet<Scope> issueScope = issue.getScope();
- if (!detectorClasses.contains(detectorClass)) {
- // Determine if the issue is enabled
- if (!configuration.isEnabled(issue)) {
- continue;
- }
-
- assert issue.isAdequate(scope); // Ensured by getIssuesForScope above
-
- detectorClass = client.replaceDetector(detectorClass);
-
- assert detectorClass != null : issue.getId();
- detectorClasses.add(detectorClass);
- }
-
- if (scopeToDetectors != null) {
- EnumSet<Scope> s = detectorToScope.get(detectorClass);
- if (s == null) {
- detectorToScope.put(detectorClass, issueScope);
- } else if (!s.containsAll(issueScope)) {
- EnumSet<Scope> union = EnumSet.copyOf(s);
- union.addAll(issueScope);
- detectorToScope.put(detectorClass, union);
- }
- }
- }
-
- List<Detector> detectors = new ArrayList<Detector>(detectorClasses.size());
- for (Class<? extends Detector> clz : detectorClasses) {
- try {
- Detector detector = clz.newInstance();
- detectors.add(detector);
-
- if (scopeToDetectors != null) {
- EnumSet<Scope> union = detectorToScope.get(clz);
- for (Scope s : union) {
- List<Detector> list = scopeToDetectors.get(s);
- if (list == null) {
- list = new ArrayList<Detector>();
- scopeToDetectors.put(s, list);
- }
- list.add(detector);
- }
-
- }
- } catch (Throwable t) {
- client.log(t, "Can't initialize detector %1$s", clz.getName()); //$NON-NLS-1$
- }
- }
-
- return detectors;
- }
-
- /**
- * Returns true if the given id represents a valid issue id
- *
- * @param id the id to be checked
- * @return true if the given id is valid
- */
- public final boolean isIssueId(@NonNull String id) {
- return getIssue(id) != null;
- }
-
- /**
- * Returns true if the given category is a valid category
- *
- * @param name the category name to be checked
- * @return true if the given string is a valid category
- */
- public final boolean isCategoryName(@NonNull String name) {
- for (Category category : getCategories()) {
- if (category.getName().equals(name) || category.getFullName().equals(name)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns the available categories
- *
- * @return an iterator for all the categories, never null
- */
- @NonNull
- public List<Category> getCategories() {
- if (sCategories == null) {
- final Set<Category> categories = new HashSet<Category>();
- for (Issue issue : getIssues()) {
- categories.add(issue.getCategory());
- }
- List<Category> sorted = new ArrayList<Category>(categories);
- Collections.sort(sorted);
- sCategories = Collections.unmodifiableList(sorted);
- }
-
- return sCategories;
- }
-
- /**
- * Returns the issue for the given id, or null if it's not a valid id
- *
- * @param id the id to be checked
- * @return the corresponding issue, or null
- */
- @Nullable
- public final Issue getIssue(@NonNull String id) {
- if (sIdToIssue == null) {
- List<Issue> issues = getIssues();
- sIdToIssue = new HashMap<String, Issue>(issues.size());
- for (Issue issue : issues) {
- sIdToIssue.put(issue.getId(), issue);
- }
-
- sIdToIssue.put(PARSER_ERROR.getId(), PARSER_ERROR);
- sIdToIssue.put(LINT_ERROR.getId(), LINT_ERROR);
- }
- return sIdToIssue.get(id);
- }
-
- /**
- * Reset the registry such that it recomputes its available issues.
- * <p>
- * NOTE: This is only intended for testing purposes.
- */
- @VisibleForTesting
- protected static void reset() {
- sIdToIssue = null;
- sCategories = null;
- sScopeIssues = Maps.newHashMap();
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/JavaVisitor.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/JavaVisitor.java
deleted file mode 100644
index 81a0339..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/JavaVisitor.java
+++ /dev/null
@@ -1,1195 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import static com.android.SdkConstants.ANDROID_PKG;
-import static com.android.SdkConstants.R_CLASS;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.JavaScanner;
-import com.android.tools.lint.detector.api.Detector.XmlScanner;
-import com.android.tools.lint.detector.api.JavaContext;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import lombok.ast.AlternateConstructorInvocation;
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationDeclaration;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationMethodDeclaration;
-import lombok.ast.AnnotationValueArray;
-import lombok.ast.ArrayAccess;
-import lombok.ast.ArrayCreation;
-import lombok.ast.ArrayDimension;
-import lombok.ast.ArrayInitializer;
-import lombok.ast.Assert;
-import lombok.ast.AstVisitor;
-import lombok.ast.BinaryExpression;
-import lombok.ast.Block;
-import lombok.ast.BooleanLiteral;
-import lombok.ast.Break;
-import lombok.ast.Case;
-import lombok.ast.Cast;
-import lombok.ast.Catch;
-import lombok.ast.CharLiteral;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ClassLiteral;
-import lombok.ast.Comment;
-import lombok.ast.CompilationUnit;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Continue;
-import lombok.ast.Default;
-import lombok.ast.DoWhile;
-import lombok.ast.EmptyDeclaration;
-import lombok.ast.EmptyStatement;
-import lombok.ast.EnumConstant;
-import lombok.ast.EnumDeclaration;
-import lombok.ast.EnumTypeBody;
-import lombok.ast.Expression;
-import lombok.ast.ExpressionStatement;
-import lombok.ast.FloatingPointLiteral;
-import lombok.ast.For;
-import lombok.ast.ForEach;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Identifier;
-import lombok.ast.If;
-import lombok.ast.ImportDeclaration;
-import lombok.ast.InlineIfExpression;
-import lombok.ast.InstanceInitializer;
-import lombok.ast.InstanceOf;
-import lombok.ast.IntegralLiteral;
-import lombok.ast.InterfaceDeclaration;
-import lombok.ast.KeywordModifier;
-import lombok.ast.LabelledStatement;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Modifiers;
-import lombok.ast.Node;
-import lombok.ast.NormalTypeBody;
-import lombok.ast.NullLiteral;
-import lombok.ast.PackageDeclaration;
-import lombok.ast.Return;
-import lombok.ast.Select;
-import lombok.ast.StaticInitializer;
-import lombok.ast.StringLiteral;
-import lombok.ast.Super;
-import lombok.ast.SuperConstructorInvocation;
-import lombok.ast.Switch;
-import lombok.ast.Synchronized;
-import lombok.ast.This;
-import lombok.ast.Throw;
-import lombok.ast.Try;
-import lombok.ast.TypeReference;
-import lombok.ast.TypeReferencePart;
-import lombok.ast.TypeVariable;
-import lombok.ast.UnaryExpression;
-import lombok.ast.VariableDeclaration;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableDefinitionEntry;
-import lombok.ast.VariableReference;
-import lombok.ast.While;
-
-
-/**
- * Specialized visitor for running detectors on a Java AST.
- * It operates in three phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant AST attribute (such as method call names) to a list
- * of detectors to consult whenever that attribute is encountered.
- * Examples of "attributes" are method names, Android resource identifiers,
- * and general AST node types such as "cast" nodes etc. These are
- * defined on the {@link JavaScanner} interface.
- * <li> Second, it iterates over the document a single time, delegating to
- * the detectors found at each relevant AST attribute.
- * <li> Finally, it calls the remaining visitors (those that need to process a
- * whole document on their own).
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- */
-public class JavaVisitor {
- /** Default size of lists holding detectors of the same type for a given node type */
- private static final int SAME_TYPE_COUNT = 8;
-
- private final Map<String, List<VisitingDetector>> mMethodDetectors =
- new HashMap<String, List<VisitingDetector>>();
- private final List<VisitingDetector> mResourceFieldDetectors =
- new ArrayList<VisitingDetector>();
- private final List<VisitingDetector> mAllDetectors;
- private final List<VisitingDetector> mFullTreeDetectors;
- private final Map<Class<? extends Node>, List<VisitingDetector>> mNodeTypeDetectors =
- new HashMap<Class<? extends Node>, List<VisitingDetector>>();
- private final IJavaParser mParser;
-
- JavaVisitor(@NonNull IJavaParser parser, @NonNull List<Detector> detectors) {
- mParser = parser;
- mAllDetectors = new ArrayList<VisitingDetector>(detectors.size());
- mFullTreeDetectors = new ArrayList<VisitingDetector>(detectors.size());
-
- for (Detector detector : detectors) {
- VisitingDetector v = new VisitingDetector(detector, (JavaScanner) detector);
- mAllDetectors.add(v);
-
- List<Class<? extends Node>> nodeTypes = detector.getApplicableNodeTypes();
- if (nodeTypes != null) {
- for (Class<? extends Node> type : nodeTypes) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(type);
- if (list == null) {
- list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT);
- mNodeTypeDetectors.put(type, list);
- }
- list.add(v);
- }
- }
-
- List<String> names = detector.getApplicableMethodNames();
- if (names != null) {
- // not supported in Java visitors; adding a method invocation node is trivial
- // for that case.
- assert names != XmlScanner.ALL;
-
- for (String name : names) {
- List<VisitingDetector> list = mMethodDetectors.get(name);
- if (list == null) {
- list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT);
- mMethodDetectors.put(name, list);
- }
- list.add(v);
- }
- }
-
- if (detector.appliesToResourceRefs()) {
- mResourceFieldDetectors.add(v);
- } else if ((names == null || names.isEmpty())
- && (nodeTypes == null || nodeTypes.isEmpty())) {
- mFullTreeDetectors.add(v);
- }
- }
- }
-
- void visitFile(@NonNull JavaContext context, @NonNull File file) {
- context.parser = mParser;
-
- Node compilationUnit = null;
- try {
- compilationUnit = mParser.parseJava(context);
- if (compilationUnit == null) {
- // No need to log this; the parser should be reporting
- // a full warning (such as IssueRegistry#PARSER_ERROR)
- // with details, location, etc.
- return;
- }
- context.compilationUnit = compilationUnit;
-
- for (VisitingDetector v : mAllDetectors) {
- v.setContext(context);
- v.getDetector().beforeCheckFile(context);
- }
-
- for (VisitingDetector v : mFullTreeDetectors) {
- AstVisitor visitor = v.getVisitor();
- if (visitor != null) {
- compilationUnit.accept(visitor);
- }
- }
-
- if (!mMethodDetectors.isEmpty() || !mResourceFieldDetectors.isEmpty()) {
- AstVisitor visitor = new DelegatingJavaVisitor(context);
- compilationUnit.accept(visitor);
- } else if (!mNodeTypeDetectors.isEmpty()) {
- AstVisitor visitor = new DispatchVisitor();
- compilationUnit.accept(visitor);
- }
-
- for (VisitingDetector v : mAllDetectors) {
- v.getDetector().afterCheckFile(context);
- }
- } finally {
- if (compilationUnit != null) {
- mParser.dispose(context, compilationUnit);
- }
- }
- }
-
- private static class VisitingDetector {
- private AstVisitor mVisitor; // construct lazily, and clear out on context switch!
- private JavaContext mContext;
- public final Detector mDetector;
- public final JavaScanner mJavaScanner;
-
- public VisitingDetector(@NonNull Detector detector, @NonNull JavaScanner javaScanner) {
- mDetector = detector;
- mJavaScanner = javaScanner;
- }
-
- @NonNull
- public Detector getDetector() {
- return mDetector;
- }
-
- @NonNull
- public JavaScanner getJavaScanner() {
- return mJavaScanner;
- }
-
- public void setContext(@NonNull JavaContext context) {
- mContext = context;
-
- // The visitors are one-per-context, so clear them out here and construct
- // lazily only if needed
- mVisitor = null;
- }
-
- @NonNull
- AstVisitor getVisitor() {
- if (mVisitor == null) {
- mVisitor = mDetector.createJavaVisitor(mContext);
- if (mVisitor == null) {
- mVisitor = new ForwardingAstVisitor() {
- };
- }
- }
- return mVisitor;
- }
- }
-
- /**
- * Generic dispatcher which visits all nodes (once) and dispatches to
- * specific visitors for each node. Each visitor typically only wants to
- * look at a small part of a tree, such as a method call or a class
- * declaration, so this means we avoid visiting all "uninteresting" nodes in
- * the tree repeatedly.
- */
- private class DispatchVisitor extends AstVisitor {
- @Override
- public void endVisit(Node node) {
- for (VisitingDetector v : mAllDetectors) {
- v.getVisitor().endVisit(node);
- }
- }
-
- @Override
- public boolean visitAlternateConstructorInvocation(AlternateConstructorInvocation node) {
- List<VisitingDetector> list =
- mNodeTypeDetectors.get(AlternateConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAlternateConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotation(Annotation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Annotation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationDeclaration(AnnotationDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationElement(AnnotationElement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationElement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationElement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) {
- List<VisitingDetector> list =
- mNodeTypeDetectors.get(AnnotationMethodDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationMethodDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationValueArray(AnnotationValueArray node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationValueArray.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationValueArray(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayAccess(ArrayAccess node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayAccess.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayAccess(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayCreation(ArrayCreation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayCreation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayCreation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayDimension(ArrayDimension node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayDimension.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayDimension(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayInitializer(ArrayInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAssert(Assert node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Assert.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAssert(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBinaryExpression(BinaryExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(BinaryExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBinaryExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBlock(Block node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Block.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBlock(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBooleanLiteral(BooleanLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(BooleanLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBooleanLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBreak(Break node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Break.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBreak(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCase(Case node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Case.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCase(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCast(Cast node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Cast.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCast(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCatch(Catch node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Catch.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCatch(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCharLiteral(CharLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(CharLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCharLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitClassDeclaration(ClassDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ClassDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitClassDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitClassLiteral(ClassLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ClassLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitClassLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitComment(Comment node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Comment.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitComment(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCompilationUnit(CompilationUnit node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(CompilationUnit.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCompilationUnit(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitConstructorDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitConstructorInvocation(ConstructorInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitContinue(Continue node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Continue.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitContinue(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitDefault(Default node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Default.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitDefault(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitDoWhile(DoWhile node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(DoWhile.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitDoWhile(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEmptyDeclaration(EmptyDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEmptyDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEmptyStatement(EmptyStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEmptyStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumConstant(EnumConstant node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumConstant.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumConstant(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumDeclaration(EnumDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumTypeBody(EnumTypeBody node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumTypeBody.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumTypeBody(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitExpressionStatement(ExpressionStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ExpressionStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitExpressionStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitFloatingPointLiteral(FloatingPointLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(FloatingPointLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitFloatingPointLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitFor(For node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(For.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitFor(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitForEach(ForEach node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ForEach.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitForEach(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIdentifier(Identifier node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Identifier.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIdentifier(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIf(If node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(If.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIf(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitImportDeclaration(ImportDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ImportDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitImportDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInlineIfExpression(InlineIfExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InlineIfExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInlineIfExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInstanceInitializer(InstanceInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInstanceInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInstanceOf(InstanceOf node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceOf.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInstanceOf(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIntegralLiteral(IntegralLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(IntegralLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIntegralLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInterfaceDeclaration(InterfaceDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InterfaceDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInterfaceDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitKeywordModifier(KeywordModifier node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(KeywordModifier.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitKeywordModifier(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitLabelledStatement(LabelledStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(LabelledStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitLabelledStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitMethodDeclaration(MethodDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(MethodDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitMethodDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(MethodInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitMethodInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitModifiers(Modifiers node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Modifiers.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitModifiers(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitNormalTypeBody(NormalTypeBody node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(NormalTypeBody.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitNormalTypeBody(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitNullLiteral(NullLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(NullLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitNullLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitPackageDeclaration(PackageDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(PackageDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitPackageDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitParseArtefact(Node node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Node.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitParseArtefact(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitReturn(Return node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Return.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitReturn(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSelect(Select node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Select.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSelect(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitStaticInitializer(StaticInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(StaticInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitStaticInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitStringLiteral(StringLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(StringLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitStringLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSuper(Super node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Super.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSuper(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(SuperConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSuperConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSwitch(Switch node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Switch.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSwitch(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSynchronized(Synchronized node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Synchronized.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSynchronized(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitThis(This node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(This.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitThis(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitThrow(Throw node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Throw.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitThrow(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTry(Try node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Try.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTry(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeReference(TypeReference node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReference.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeReference(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeReferencePart(TypeReferencePart node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReferencePart.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeReferencePart(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeVariable(TypeVariable node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeVariable.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeVariable(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitUnaryExpression(UnaryExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(UnaryExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitUnaryExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDeclaration(VariableDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDefinition(VariableDefinition node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinition.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDefinition(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinitionEntry.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDefinitionEntry(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableReference(VariableReference node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableReference.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableReference(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitWhile(While node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(While.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitWhile(node);
- }
- }
- return false;
- }
- }
-
- /** Performs common AST searches for method calls and R-type-field references.
- * Note that this is a specialized form of the {@link DispatchVisitor}. */
- private class DelegatingJavaVisitor extends DispatchVisitor {
- private final JavaContext mContext;
- private final boolean mVisitResources;
- private final boolean mVisitMethods;
-
- public DelegatingJavaVisitor(JavaContext context) {
- mContext = context;
-
- mVisitMethods = !mMethodDetectors.isEmpty();
- mVisitResources = !mResourceFieldDetectors.isEmpty();
- }
-
- @Override
- public boolean visitSelect(Select node) {
- if (mVisitResources) {
- // R.type.name
- if (node.astOperand() instanceof Select) {
- Select select = (Select) node.astOperand();
- if (select.astOperand() instanceof VariableReference) {
- VariableReference reference = (VariableReference) select.astOperand();
- if (reference.astIdentifier().astValue().equals(R_CLASS)) {
- String type = select.astIdentifier().astValue();
- String name = node.astIdentifier().astValue();
-
- // R -could- be referenced locally and really have been
- // imported as "import android.R;" in the import statements,
- // but this is not recommended (and in fact there's a specific
- // lint rule warning against it)
- boolean isFramework = false;
-
- for (VisitingDetector v : mResourceFieldDetectors) {
- JavaScanner detector = v.getJavaScanner();
- detector.visitResourceReference(mContext, v.getVisitor(),
- node, type, name, isFramework);
- }
-
- return super.visitSelect(node);
- }
- }
- }
-
- // Arbitrary packages -- android.R.type.name, foo.bar.R.type.name
- if (node.astIdentifier().astValue().equals(R_CLASS)) {
- Node parent = node.getParent();
- if (parent instanceof Select) {
- Node grandParent = parent.getParent();
- if (grandParent instanceof Select) {
- Select select = (Select) grandParent;
- String name = select.astIdentifier().astValue();
- Expression typeOperand = select.astOperand();
- if (typeOperand instanceof Select) {
- Select typeSelect = (Select) typeOperand;
- String type = typeSelect.astIdentifier().astValue();
- boolean isFramework =
- node.astIdentifier().astValue().equals(ANDROID_PKG);
- for (VisitingDetector v : mResourceFieldDetectors) {
- JavaScanner detector = v.getJavaScanner();
- detector.visitResourceReference(mContext, v.getVisitor(),
- node, type, name, isFramework);
- }
- }
- }
- }
- }
- }
-
- return super.visitSelect(node);
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (mVisitMethods) {
- String methodName = node.astName().getDescription();
- List<VisitingDetector> list = mMethodDetectors.get(methodName);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getJavaScanner().visitMethod(mContext, v.getVisitor(), node);
- }
- }
- }
-
- return super.visitMethodInvocation(node);
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java
deleted file mode 100644
index b8118b7..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintClient.java
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import static com.android.SdkConstants.CLASS_FOLDER;
-import static com.android.SdkConstants.DOT_JAR;
-import static com.android.SdkConstants.GEN_FOLDER;
-import static com.android.SdkConstants.LIBS_FOLDER;
-import static com.android.SdkConstants.RES_FOLDER;
-import static com.android.SdkConstants.SRC_FOLDER;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.SdkManager;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.utils.StdLogger;
-import com.android.utils.StdLogger.Level;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.io.Files;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-/**
- * Information about the tool embedding the lint analyzer. IDEs and other tools
- * implementing lint support will extend this to integrate logging, displaying errors,
- * etc.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class LintClient {
- private static final String PROP_BIN_DIR = "com.android.tools.lint.bindir"; //$NON-NLS-1$
-
- /**
- * Returns a configuration for use by the given project. The configuration
- * provides information about which issues are enabled, any customizations
- * to the severity of an issue, etc.
- * <p>
- * By default this method returns a {@link DefaultConfiguration}.
- *
- * @param project the project to obtain a configuration for
- * @return a configuration, never null.
- */
- public Configuration getConfiguration(@NonNull Project project) {
- return DefaultConfiguration.create(this, project, null);
- }
-
- /**
- * Report the given issue. This method will only be called if the configuration
- * provided by {@link #getConfiguration(Project)} has reported the corresponding
- * issue as enabled and has not filtered out the issue with its
- * {@link Configuration#ignore(Context, Issue, Location, String, Object)} method.
- * <p>
- *
- * @param context the context used by the detector when the issue was found
- * @param issue the issue that was found
- * @param severity the severity of the issue
- * @param location the location of the issue
- * @param message the associated user message
- * @param data optional extra data for a discovered issue, or null. The
- * content depends on the specific issue. Detectors can pass
- * extra info here which automatic fix tools etc can use to
- * extract relevant information instead of relying on parsing the
- * error message text. See each detector for details on which
- * data if any is supplied for a given issue.
- */
- public abstract void report(
- @NonNull Context context,
- @NonNull Issue issue,
- @NonNull Severity severity,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data);
-
- /**
- * Send an exception or error message (with warning severity) to the log
- *
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * (though in that case the exception should not be null)
- * @param args any arguments for the format string
- */
- public void log(
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args) {
- log(Severity.WARNING, exception, format, args);
- }
-
- /**
- * Send an exception or error message to the log
- *
- * @param severity the severity of the warning
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * (though in that case the exception should not be null)
- * @param args any arguments for the format string
- */
- public abstract void log(
- @NonNull Severity severity,
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args);
-
- /**
- * Returns a {@link IDomParser} to use to parse XML
- *
- * @return a new {@link IDomParser}, or null if this client does not support
- * XML analysis
- */
- @Nullable
- public abstract IDomParser getDomParser();
-
- /**
- * Returns a {@link IJavaParser} to use to parse Java
- *
- * @return a new {@link IJavaParser}, or null if this client does not
- * support Java analysis
- */
- @Nullable
- public abstract IJavaParser getJavaParser();
-
- /**
- * Returns an optimal detector, if applicable. By default, just returns the
- * original detector, but tools can replace detectors using this hook with a version
- * that takes advantage of native capabilities of the tool.
- *
- * @param detectorClass the class of the detector to be replaced
- * @return the new detector class, or just the original detector (not null)
- */
- @NonNull
- public Class<? extends Detector> replaceDetector(
- @NonNull Class<? extends Detector> detectorClass) {
- return detectorClass;
- }
-
- /**
- * Reads the given text file and returns the content as a string
- *
- * @param file the file to read
- * @return the string to return, never null (will be empty if there is an
- * I/O error)
- */
- @NonNull
- public abstract String readFile(@NonNull File file);
-
- /**
- * Reads the given binary file and returns the content as a byte array.
- * By default this method will read the bytes from the file directly,
- * but this can be customized by a client if for example I/O could be
- * held in memory and not flushed to disk yet.
- *
- * @param file the file to read
- * @return the bytes in the file, never null
- * @throws IOException if the file does not exist, or if the file cannot be
- * read for some reason
- */
- @NonNull
- public byte[] readBytes(@NonNull File file) throws IOException {
- return Files.toByteArray(file);
- }
-
- /**
- * Returns the list of source folders for Java source files
- *
- * @param project the project to look up Java source file locations for
- * @return a list of source folders to search for .java files
- */
- @NonNull
- public List<File> getJavaSourceFolders(@NonNull Project project) {
- return getClassPath(project).getSourceFolders();
- }
-
- /**
- * Returns the list of output folders for class files
- *
- * @param project the project to look up class file locations for
- * @return a list of output folders to search for .class files
- */
- @NonNull
- public List<File> getJavaClassFolders(@NonNull Project project) {
- return getClassPath(project).getClassFolders();
-
- }
-
- /**
- * Returns the list of Java libraries
- *
- * @param project the project to look up jar dependencies for
- * @return a list of jar dependencies containing .class files
- */
- @NonNull
- public List<File> getJavaLibraries(@NonNull Project project) {
- return getClassPath(project).getLibraries();
- }
-
- /**
- * Returns the resource folders.
- *
- * @param project the project to look up the resource folder for
- * @return a list of files pointing to the resource folders, possibly empty
- */
- @NonNull
- public List<File> getResourceFolders(@NonNull Project project) {
- File res = new File(project.getDir(), RES_FOLDER);
- if (res.exists()) {
- return Collections.singletonList(res);
- }
-
- return Collections.emptyList();
- }
-
- /**
- * Returns the {@link SdkInfo} to use for the given project.
- *
- * @param project the project to look up an {@link SdkInfo} for
- * @return an {@link SdkInfo} for the project
- */
- @NonNull
- public SdkInfo getSdkInfo(@NonNull Project project) {
- // By default no per-platform SDK info
- return new DefaultSdkInfo();
- }
-
- /**
- * Returns a suitable location for storing cache files. Note that the
- * directory may not exist.
- *
- * @param create if true, attempt to create the cache dir if it does not
- * exist
- * @return a suitable location for storing cache files, which may be null if
- * the create flag was false, or if for some reason the directory
- * could not be created
- */
- @Nullable
- public File getCacheDir(boolean create) {
- String home = System.getProperty("user.home");
- String relative = ".android" + File.separator + "cache"; //$NON-NLS-1$ //$NON-NLS-2$
- File dir = new File(home, relative);
- if (create && !dir.exists()) {
- if (!dir.mkdirs()) {
- return null;
- }
- }
- return dir;
- }
-
- /**
- * Returns the File corresponding to the system property or the environment variable
- * for {@link #PROP_BIN_DIR}.
- * This property is typically set by the SDK/tools/lint[.bat] wrapper.
- * It denotes the path of the wrapper on disk.
- *
- * @return A new File corresponding to {@link LintClient#PROP_BIN_DIR} or null.
- */
- @Nullable
- private static File getLintBinDir() {
- // First check the Java properties (e.g. set using "java -jar ... -Dname=value")
- String path = System.getProperty(PROP_BIN_DIR);
- if (path == null || path.isEmpty()) {
- // If not found, check environment variables.
- path = System.getenv(PROP_BIN_DIR);
- }
- if (path != null && !path.isEmpty()) {
- return new File(path);
- }
- return null;
- }
-
- /**
- * Returns the File pointing to the user's SDK install area. This is generally
- * the root directory containing the lint tool (but also platforms/ etc).
- *
- * @return a file pointing to the user's install area
- */
- @Nullable
- public File getSdkHome() {
- File binDir = getLintBinDir();
- if (binDir != null) {
- assert binDir.getName().equals("tools");
-
- File root = binDir.getParentFile();
- if (root != null && root.isDirectory()) {
- return root;
- }
- }
-
- String home = System.getenv("ANDROID_HOME"); //$NON-NLS-1$
- if (home != null) {
- return new File(home);
- }
-
- return null;
- }
-
- /**
- * Locates an SDK resource (relative to the SDK root directory).
- * <p>
- * TODO: Consider switching to a {@link URL} return type instead.
- *
- * @param relativePath A relative path (using {@link File#separator} to
- * separate path components) to the given resource
- * @return a {@link File} pointing to the resource, or null if it does not
- * exist
- */
- @Nullable
- public File findResource(@NonNull String relativePath) {
- File top = getSdkHome();
- if (top == null) {
- throw new IllegalArgumentException("Lint must be invoked with the System property "
- + PROP_BIN_DIR + " pointing to the ANDROID_SDK tools directory");
- }
-
- File file = new File(top, relativePath);
- if (file.exists()) {
- return file;
- } else {
- return null;
- }
- }
-
- private Map<Project, ClassPathInfo> mProjectInfo;
-
- /**
- * Information about class paths (sources, class files and libraries)
- * usually associated with a project.
- */
- protected static class ClassPathInfo {
- private final List<File> mClassFolders;
- private final List<File> mSourceFolders;
- private final List<File> mLibraries;
-
- public ClassPathInfo(
- @NonNull List<File> sourceFolders,
- @NonNull List<File> classFolders,
- @NonNull List<File> libraries) {
- mSourceFolders = sourceFolders;
- mClassFolders = classFolders;
- mLibraries = libraries;
- }
-
- @NonNull
- public List<File> getSourceFolders() {
- return mSourceFolders;
- }
-
- @NonNull
- public List<File> getClassFolders() {
- return mClassFolders;
- }
-
- @NonNull
- public List<File> getLibraries() {
- return mLibraries;
- }
- }
-
- /**
- * Considers the given project as an Eclipse project and returns class path
- * information for the project - the source folder(s), the output folder and
- * any libraries.
- * <p>
- * Callers will not cache calls to this method, so if it's expensive to compute
- * the classpath info, this method should perform its own caching.
- *
- * @param project the project to look up class path info for
- * @return a class path info object, never null
- */
- @NonNull
- protected ClassPathInfo getClassPath(@NonNull Project project) {
- ClassPathInfo info;
- if (mProjectInfo == null) {
- mProjectInfo = Maps.newHashMap();
- info = null;
- } else {
- info = mProjectInfo.get(project);
- }
-
- if (info == null) {
- List<File> sources = new ArrayList<File>(2);
- List<File> classes = new ArrayList<File>(1);
- List<File> libraries = new ArrayList<File>();
-
- File projectDir = project.getDir();
- File classpathFile = new File(projectDir, ".classpath"); //$NON-NLS-1$
- if (classpathFile.exists()) {
- String classpathXml = readFile(classpathFile);
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- InputSource is = new InputSource(new StringReader(classpathXml));
- factory.setNamespaceAware(false);
- factory.setValidating(false);
- try {
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.parse(is);
- NodeList tags = document.getElementsByTagName("classpathentry"); //$NON-NLS-1$
- for (int i = 0, n = tags.getLength(); i < n; i++) {
- Element element = (Element) tags.item(i);
- String kind = element.getAttribute("kind"); //$NON-NLS-1$
- List<File> addTo = null;
- if (kind.equals("src")) { //$NON-NLS-1$
- addTo = sources;
- } else if (kind.equals("output")) { //$NON-NLS-1$
- addTo = classes;
- } else if (kind.equals("lib")) { //$NON-NLS-1$
- addTo = libraries;
- }
- if (addTo != null) {
- String path = element.getAttribute("path"); //$NON-NLS-1$
- File folder = new File(projectDir, path);
- if (folder.exists()) {
- addTo.add(folder);
- }
- }
- }
- } catch (Exception e) {
- log(null, null);
- }
- }
-
- // Add in libraries that aren't specified in the .classpath file
- File libs = new File(project.getDir(), LIBS_FOLDER);
- if (libs.isDirectory()) {
- File[] jars = libs.listFiles();
- if (jars != null) {
- for (File jar : jars) {
- if (LintUtils.endsWith(jar.getPath(), DOT_JAR)
- && !libraries.contains(jar)) {
- libraries.add(jar);
- }
- }
- }
- }
-
- if (classes.isEmpty()) {
- File folder = new File(projectDir, CLASS_FOLDER);
- if (folder.exists()) {
- classes.add(folder);
- } else {
- // Maven checks
- folder = new File(projectDir,
- "target" + File.separator + "classes"); //$NON-NLS-1$ //$NON-NLS-2$
- if (folder.exists()) {
- classes.add(folder);
-
- // If it's maven, also correct the source path, "src" works but
- // it's in a more specific subfolder
- if (sources.isEmpty()) {
- File src = new File(projectDir,
- "src" + File.separator //$NON-NLS-1$
- + "main" + File.separator //$NON-NLS-1$
- + "java"); //$NON-NLS-1$
- if (src.exists()) {
- sources.add(src);
- } else {
- src = new File(projectDir, SRC_FOLDER);
- if (src.exists()) {
- sources.add(src);
- }
- }
-
- File gen = new File(projectDir,
- "target" + File.separator //$NON-NLS-1$
- + "generated-sources" + File.separator //$NON-NLS-1$
- + "r"); //$NON-NLS-1$
- if (gen.exists()) {
- sources.add(gen);
- }
- }
- }
- }
- }
-
- // Fallback, in case there is no Eclipse project metadata here
- if (sources.isEmpty()) {
- File src = new File(projectDir, SRC_FOLDER);
- if (src.exists()) {
- sources.add(src);
- }
- File gen = new File(projectDir, GEN_FOLDER);
- if (gen.exists()) {
- sources.add(gen);
- }
- }
-
- info = new ClassPathInfo(sources, classes, libraries);
- mProjectInfo.put(project, info);
- }
-
- return info;
- }
-
- /**
- * A map from directory to existing projects, or null. Used to ensure that
- * projects are unique for a directory (in case we process a library project
- * before its including project for example)
- */
- private Map<File, Project> mDirToProject;
-
- /**
- * Returns a project for the given directory. This should return the same
- * project for the same directory if called repeatedly.
- *
- * @param dir the directory containing the project
- * @param referenceDir See {@link Project#getReferenceDir()}.
- * @return a project, never null
- */
- @NonNull
- public Project getProject(@NonNull File dir, @NonNull File referenceDir) {
- if (mDirToProject == null) {
- mDirToProject = new HashMap<File, Project>();
- }
-
- File canonicalDir = dir;
- try {
- // Attempt to use the canonical handle for the file, in case there
- // are symlinks etc present (since when handling library projects,
- // we also call getCanonicalFile to compute the result of appending
- // relative paths, which can then resolve symlinks and end up with
- // a different prefix)
- canonicalDir = dir.getCanonicalFile();
- } catch (IOException ioe) {
- // pass
- }
-
- Project project = mDirToProject.get(canonicalDir);
- if (project != null) {
- return project;
- }
-
- project = createProject(dir, referenceDir);
- mDirToProject.put(canonicalDir, project);
- return project;
- }
-
- private Set<File> mProjectDirs = Sets.newHashSet();
-
- /**
- * Create a project for the given directory
- * @param dir the root directory of the project
- * @param referenceDir See {@link Project#getReferenceDir()}.
- * @return a new project
- */
- @NonNull
- protected Project createProject(@NonNull File dir, @NonNull File referenceDir) {
- if (mProjectDirs.contains(dir)) {
- throw new CircularDependencyException(
- "Circular library dependencies; check your project.properties files carefully");
- }
- mProjectDirs.add(dir);
- return Project.create(this, dir, referenceDir);
- }
-
- /**
- * Returns the name of the given project
- *
- * @param project the project to look up
- * @return the name of the project
- */
- @NonNull
- public String getProjectName(@NonNull Project project) {
- return project.getDir().getName();
- }
-
- private IAndroidTarget[] mTargets;
-
- /**
- * Returns all the {@link IAndroidTarget} versions installed in the user's SDK install
- * area.
- *
- * @return all the installed targets
- */
- @NonNull
- public IAndroidTarget[] getTargets() {
- if (mTargets == null) {
- File sdkHome = getSdkHome();
- if (sdkHome != null) {
- StdLogger log = new StdLogger(Level.WARNING);
- SdkManager manager = SdkManager.createManager(sdkHome.getPath(), log);
- mTargets = manager.getTargets();
- } else {
- mTargets = new IAndroidTarget[0];
- }
- }
-
- return mTargets;
- }
-
- /**
- * Returns the highest known API level.
- *
- * @return the highest known API level
- */
- public int getHighestKnownApiLevel() {
- int max = SdkConstants.HIGHEST_KNOWN_API;
-
- for (IAndroidTarget target : getTargets()) {
- if (target.isPlatform()) {
- int api = target.getVersion().getApiLevel();
- if (api > max && !target.getVersion().isPreview()) {
- max = api;
- }
- }
- }
-
- return max;
- }
-
- /**
- * Returns the super class for the given class name, which should be in VM
- * format (e.g. java/lang/Integer, not java.lang.Integer, and using $ rather
- * than . for inner classes). If the super class is not known, returns null.
- * <p>
- * This is typically not necessary, since lint analyzes all the available
- * classes. However, if this lint client is invoking lint in an incremental
- * context (for example, an IDE offering incremental analysis of a single
- * source file), then lint may not see all the classes, and the client can
- * provide its own super class lookup.
- *
- * @param project the project containing the class
- * @param name the fully qualified class name
- * @return the corresponding super class name (in VM format), or null if not
- * known
- */
- @Nullable
- public String getSuperClass(@NonNull Project project, @NonNull String name) {
- return null;
- }
-
- /**
- * Checks whether the given name is a subclass of the given super class. If
- * the method does not know, it should return null, and otherwise return
- * {@link Boolean#TRUE} or {@link Boolean#FALSE}.
- * <p>
- * Note that the class names are in internal VM format (java/lang/Integer,
- * not java.lang.Integer, and using $ rather than . for inner classes).
- *
- * @param project the project context to look up the class in
- * @param name the name of the class to be checked
- * @param superClassName the name of the super class to compare to
- * @return true if the class of the given name extends the given super class
- */
- @Nullable
- public Boolean isSubclassOf(
- @NonNull Project project,
- @NonNull String name, @NonNull
- String superClassName) {
- return null;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java
deleted file mode 100644
index daf2a07..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintDriver.java
+++ /dev/null
@@ -1,2227 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ATTR_IGNORE;
-import static com.android.SdkConstants.DOT_CLASS;
-import static com.android.SdkConstants.DOT_JAR;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE;
-import static com.android.SdkConstants.OLD_PROGUARD_FILE;
-import static com.android.SdkConstants.RES_FOLDER;
-import static com.android.SdkConstants.SUPPRESS_ALL;
-import static com.android.SdkConstants.SUPPRESS_LINT;
-import static com.android.SdkConstants.TOOLS_URI;
-import static org.objectweb.asm.Opcodes.ASM4;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.resources.ResourceFolderType;
-import com.android.sdklib.IAndroidTarget;
-import com.android.tools.lint.client.api.LintListener.EventType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Closeables;
-
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationValue;
-import lombok.ast.ArrayInitializer;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.Expression;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.Modifiers;
-import lombok.ast.Node;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-import lombok.ast.TypeReference;
-import lombok.ast.VariableDefinition;
-
-/**
- * Analyzes Android projects and files
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class LintDriver {
- /**
- * Max number of passes to run through the lint runner if requested by
- * {@link #requestRepeat}
- */
- private static final int MAX_PHASES = 3;
- private static final String SUPPRESS_LINT_VMSIG = '/' + SUPPRESS_LINT + ';';
-
- private final LintClient mClient;
- private final IssueRegistry mRegistry;
- private volatile boolean mCanceled;
- private EnumSet<Scope> mScope;
- private List<? extends Detector> mApplicableDetectors;
- private Map<Scope, List<Detector>> mScopeDetectors;
- private List<LintListener> mListeners;
- private int mPhase;
- private List<Detector> mRepeatingDetectors;
- private EnumSet<Scope> mRepeatScope;
- private Project[] mCurrentProjects;
- private Project mCurrentProject;
- private boolean mAbbreviating = true;
- private boolean mParserErrors;
- private Map<Object,Object> mProperties;
-
- /**
- * Creates a new {@link LintDriver}
- *
- * @param registry The registry containing issues to be checked
- * @param client the tool wrapping the analyzer, such as an IDE or a CLI
- */
- public LintDriver(@NonNull IssueRegistry registry, @NonNull LintClient client) {
- mRegistry = registry;
- mClient = new LintClientWrapper(client);
- }
-
- /** Cancels the current lint run as soon as possible */
- public void cancel() {
- mCanceled = true;
- }
-
- /**
- * Returns the scope for the lint job
- *
- * @return the scope, never null
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mScope;
- }
-
- /**
- * Returns the lint client requesting the lint check
- *
- * @return the client, never null
- */
- @NonNull
- public LintClient getClient() {
- return mClient;
- }
-
- /**
- * Records a property for later retrieval by {@link #getProperty(Object)}
- *
- * @param key the key to associate the value with
- * @param value the value, or null to remove a previous binding
- */
- public void putProperty(@NonNull Object key, @Nullable Object value) {
- if (mProperties == null) {
- mProperties = Maps.newHashMap();
- }
- if (value == null) {
- mProperties.remove(key);
- } else {
- mProperties.put(key, value);
- }
- }
-
- /**
- * Returns the property previously stored with the given key, or null
- *
- * @param key the key
- * @return the value or null if not found
- */
- @Nullable
- public Object getProperty(@NonNull Object key) {
- if (mProperties != null) {
- return mProperties.get(key);
- }
-
- return null;
- }
-
- /**
- * Returns the current phase number. The first pass is numbered 1. Only one pass
- * will be performed, unless a {@link Detector} calls {@link #requestRepeat}.
- *
- * @return the current phase, usually 1
- */
- public int getPhase() {
- return mPhase;
- }
-
- /**
- * Returns the current {@link IssueRegistry}.
- *
- * @return the current {@link IssueRegistry}
- */
- @NonNull
- public IssueRegistry getRegistry() {
- return mRegistry;
- }
-
- /**
- * Returns the project containing a given file, or null if not found. This searches
- * only among the currently checked project and its library projects, not among all
- * possible projects being scanned sequentially.
- *
- * @param file the file to be checked
- * @return the corresponding project, or null if not found
- */
- @Nullable
- public Project findProjectFor(@NonNull File file) {
- if (mCurrentProjects != null) {
- if (mCurrentProjects.length == 1) {
- return mCurrentProjects[0];
- }
- String path = file.getPath();
- for (Project project : mCurrentProjects) {
- if (path.startsWith(project.getDir().getPath())) {
- return project;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Sets whether lint should abbreviate output when appropriate.
- *
- * @param abbreviating true to abbreviate output, false to include everything
- */
- public void setAbbreviating(boolean abbreviating) {
- mAbbreviating = abbreviating;
- }
-
- /**
- * Returns whether lint should abbreviate output when appropriate.
- *
- * @return true if lint should abbreviate output, false when including everything
- */
- public boolean isAbbreviating() {
- return mAbbreviating;
- }
-
- /**
- * Returns whether lint has encountered any files with fatal parser errors
- * (e.g. broken source code, or even broken parsers)
- * <p>
- * This is useful for checks that need to make sure they've seen all data in
- * order to be conclusive (such as an unused resource check).
- *
- * @return true if any files were not properly processed because they
- * contained parser errors
- */
- public boolean hasParserErrors() {
- return mParserErrors;
- }
-
- /**
- * Sets whether lint has encountered files with fatal parser errors.
- *
- * @see #hasParserErrors()
- * @param hasErrors whether parser errors have been encountered
- */
- public void setHasParserErrors(boolean hasErrors) {
- mParserErrors = hasErrors;
- }
-
- /**
- * Returns the projects being analyzed
- *
- * @return the projects being analyzed
- */
- @NonNull
- public List<Project> getProjects() {
- if (mCurrentProjects != null) {
- return Arrays.asList(mCurrentProjects);
- }
- return Collections.emptyList();
- }
-
- /**
- * Analyze the given file (which can point to an Android project). Issues found
- * are reported to the associated {@link LintClient}.
- *
- * @param files the files and directories to be analyzed
- * @param scope the scope of the analysis; detectors with a wider scope will
- * not be run. If null, the scope will be inferred from the files.
- */
- public void analyze(@NonNull List<File> files, @Nullable EnumSet<Scope> scope) {
- mCanceled = false;
- mScope = scope;
-
- Collection<Project> projects;
- try {
- projects = computeProjects(files);
- } catch (CircularDependencyException e) {
- mCurrentProject = e.getProject();
- if (mCurrentProject != null) {
- File file = e.getLocation().getFile();
- Context context = new Context(this, mCurrentProject, null, file);
- context.report(IssueRegistry.LINT_ERROR, e.getLocation(), e.getMessage(), null);
- mCurrentProject = null;
- }
- return;
- }
- if (projects.isEmpty()) {
- mClient.log(null, "No projects found for %1$s", files.toString());
- return;
- }
- if (mCanceled) {
- return;
- }
-
- if (mScope == null) {
- // Infer the scope
- mScope = EnumSet.noneOf(Scope.class);
- for (Project project : projects) {
- List<File> subset = project.getSubset();
- if (subset != null) {
- for (File file : subset) {
- String name = file.getName();
- if (name.equals(ANDROID_MANIFEST_XML)) {
- mScope.add(Scope.MANIFEST);
- } else if (name.endsWith(DOT_XML)) {
- mScope.add(Scope.RESOURCE_FILE);
- } else if (name.equals(RES_FOLDER)
- || file.getParent().equals(RES_FOLDER)) {
- mScope.add(Scope.ALL_RESOURCE_FILES);
- mScope.add(Scope.RESOURCE_FILE);
- } else if (name.endsWith(DOT_JAVA)) {
- mScope.add(Scope.JAVA_FILE);
- } else if (name.endsWith(DOT_CLASS)) {
- mScope.add(Scope.CLASS_FILE);
- } else if (name.equals(OLD_PROGUARD_FILE)
- || name.equals(FN_PROJECT_PROGUARD_FILE)) {
- mScope.add(Scope.PROGUARD_FILE);
- }
- }
- } else {
- // Specified a full project: just use the full project scope
- mScope = Scope.ALL;
- break;
- }
- }
- }
-
- fireEvent(EventType.STARTING, null);
-
- for (Project project : projects) {
- mPhase = 1;
-
- // The set of available detectors varies between projects
- computeDetectors(project);
-
- if (mApplicableDetectors.isEmpty()) {
- // No detectors enabled in this project: skip it
- continue;
- }
-
- checkProject(project);
- if (mCanceled) {
- break;
- }
-
- runExtraPhases(project);
- }
-
- fireEvent(mCanceled ? EventType.CANCELED : EventType.COMPLETED, null);
- }
-
- private void runExtraPhases(Project project) {
- // Did any detectors request another phase?
- if (mRepeatingDetectors != null) {
- // Yes. Iterate up to MAX_PHASES times.
-
- // During the extra phases, we might be narrowing the scope, and setting it in the
- // scope field such that detectors asking about the available scope will get the
- // correct result. However, we need to restore it to the original scope when this
- // is done in case there are other projects that will be checked after this, since
- // the repeated phases is done *per project*, not after all projects have been
- // processed.
- EnumSet<Scope> oldScope = mScope;
-
- do {
- mPhase++;
- fireEvent(EventType.NEW_PHASE,
- new Context(this, project, null, project.getDir()));
-
- // Narrow the scope down to the set of scopes requested by
- // the rules.
- if (mRepeatScope == null) {
- mRepeatScope = Scope.ALL;
- }
- mScope = Scope.intersect(mScope, mRepeatScope);
- if (mScope.isEmpty()) {
- break;
- }
-
- // Compute the detectors to use for this pass.
- // Unlike the normal computeDetectors(project) call,
- // this is going to use the existing instances, and include
- // those that apply for the configuration.
- computeRepeatingDetectors(mRepeatingDetectors, project);
-
- if (mApplicableDetectors.isEmpty()) {
- // No detectors enabled in this project: skip it
- continue;
- }
-
- checkProject(project);
- if (mCanceled) {
- break;
- }
- } while (mPhase < MAX_PHASES && mRepeatingDetectors != null);
-
- mScope = oldScope;
- }
- }
-
- private void computeRepeatingDetectors(List<Detector> detectors, Project project) {
- // Ensure that the current visitor is recomputed
- mCurrentFolderType = null;
- mCurrentVisitor = null;
-
- // Create map from detector class to issue such that we can
- // compute applicable issues for each detector in the list of detectors
- // to be repeated
- List<Issue> issues = mRegistry.getIssues();
- Multimap<Class<? extends Detector>, Issue> issueMap =
- ArrayListMultimap.create(issues.size(), 3);
- for (Issue issue : issues) {
- issueMap.put(issue.getDetectorClass(), issue);
- }
-
- Map<Class<? extends Detector>, EnumSet<Scope>> detectorToScope =
- new HashMap<Class<? extends Detector>, EnumSet<Scope>>();
- Map<Scope, List<Detector>> scopeToDetectors =
- new EnumMap<Scope, List<Detector>>(Scope.class);
-
- List<Detector> detectorList = new ArrayList<Detector>();
- // Compute the list of detectors (narrowed down from mRepeatingDetectors),
- // and simultaneously build up the detectorToScope map which tracks
- // the scopes each detector is affected by (this is used to populate
- // the mScopeDetectors map which is used during iteration).
- Configuration configuration = project.getConfiguration();
- for (Detector detector : detectors) {
- Class<? extends Detector> detectorClass = detector.getClass();
- Collection<Issue> detectorIssues = issueMap.get(detectorClass);
- if (detectorIssues != null) {
- boolean add = false;
- for (Issue issue : detectorIssues) {
- // The reason we have to check whether the detector is enabled
- // is that this is a per-project property, so when running lint in multiple
- // projects, a detector enabled only in a different project could have
- // requested another phase, and we end up in this project checking whether
- // the detector is enabled here.
- if (!configuration.isEnabled(issue)) {
- continue;
- }
-
- add = true; // Include detector if any of its issues are enabled
-
- EnumSet<Scope> s = detectorToScope.get(detectorClass);
- EnumSet<Scope> issueScope = issue.getScope();
- if (s == null) {
- detectorToScope.put(detectorClass, issueScope);
- } else if (!s.containsAll(issueScope)) {
- EnumSet<Scope> union = EnumSet.copyOf(s);
- union.addAll(issueScope);
- detectorToScope.put(detectorClass, union);
- }
- }
-
- if (add) {
- detectorList.add(detector);
- EnumSet<Scope> union = detectorToScope.get(detector.getClass());
- for (Scope s : union) {
- List<Detector> list = scopeToDetectors.get(s);
- if (list == null) {
- list = new ArrayList<Detector>();
- scopeToDetectors.put(s, list);
- }
- list.add(detector);
- }
- }
- }
- }
-
- mApplicableDetectors = detectorList;
- mScopeDetectors = scopeToDetectors;
- mRepeatingDetectors = null;
- mRepeatScope = null;
-
- validateScopeList();
- }
-
- private void computeDetectors(@NonNull Project project) {
- // Ensure that the current visitor is recomputed
- mCurrentFolderType = null;
- mCurrentVisitor = null;
-
- Configuration configuration = project.getConfiguration();
- mScopeDetectors = new EnumMap<Scope, List<Detector>>(Scope.class);
- mApplicableDetectors = mRegistry.createDetectors(mClient, configuration,
- mScope, mScopeDetectors);
-
- validateScopeList();
- }
-
- /** Development diagnostics only, run with assertions on */
- @SuppressWarnings("all") // Turn off warnings for the intentional assertion side effect below
- private void validateScopeList() {
- boolean assertionsEnabled = false;
- assert assertionsEnabled = true; // Intentional side-effect
- if (assertionsEnabled) {
- List<Detector> resourceFileDetectors = mScopeDetectors.get(Scope.RESOURCE_FILE);
- if (resourceFileDetectors != null) {
- for (Detector detector : resourceFileDetectors) {
- assert detector instanceof ResourceXmlDetector : detector;
- }
- }
-
- List<Detector> manifestDetectors = mScopeDetectors.get(Scope.MANIFEST);
- if (manifestDetectors != null) {
- for (Detector detector : manifestDetectors) {
- assert detector instanceof Detector.XmlScanner : detector;
- }
- }
- List<Detector> javaCodeDetectors = mScopeDetectors.get(Scope.ALL_JAVA_FILES);
- if (javaCodeDetectors != null) {
- for (Detector detector : javaCodeDetectors) {
- assert detector instanceof Detector.JavaScanner : detector;
- }
- }
- List<Detector> javaFileDetectors = mScopeDetectors.get(Scope.JAVA_FILE);
- if (javaFileDetectors != null) {
- for (Detector detector : javaFileDetectors) {
- assert detector instanceof Detector.JavaScanner : detector;
- }
- }
-
- List<Detector> classDetectors = mScopeDetectors.get(Scope.CLASS_FILE);
- if (classDetectors != null) {
- for (Detector detector : classDetectors) {
- assert detector instanceof Detector.ClassScanner : detector;
- }
- }
-
- List<Detector> classCodeDetectors = mScopeDetectors.get(Scope.ALL_CLASS_FILES);
- if (classCodeDetectors != null) {
- for (Detector detector : classCodeDetectors) {
- assert detector instanceof Detector.ClassScanner : detector;
- }
- }
-
- List<Detector> otherDetectors = mScopeDetectors.get(Scope.OTHER_SCOPE);
- if (otherDetectors != null) {
- for (Detector detector : otherDetectors) {
- assert detector instanceof Detector.OtherFileScanner : detector;
- }
- }
- }
- }
-
- private void registerProjectFile(
- @NonNull Map<File, Project> fileToProject,
- @NonNull File file,
- @NonNull File projectDir,
- @NonNull File rootDir) {
- fileToProject.put(file, mClient.getProject(projectDir, rootDir));
- }
-
- private Collection<Project> computeProjects(@NonNull List<File> files) {
- // Compute list of projects
- Map<File, Project> fileToProject = new HashMap<File, Project>();
-
- File sharedRoot = null;
-
- // Ensure that we have absolute paths such that if you lint
- // "foo bar" in "baz" we can show baz/ as the root
- if (files.size() > 1) {
- List<File> absolute = new ArrayList<File>(files.size());
- for (File file : files) {
- absolute.add(file.getAbsoluteFile());
- }
- files = absolute;
-
- sharedRoot = LintUtils.getCommonParent(files);
- if (sharedRoot != null && sharedRoot.getParentFile() == null) { // "/" ?
- sharedRoot = null;
- }
- }
-
-
- for (File file : files) {
- if (file.isDirectory()) {
- File rootDir = sharedRoot;
- if (rootDir == null) {
- rootDir = file;
- if (files.size() > 1) {
- rootDir = file.getParentFile();
- if (rootDir == null) {
- rootDir = file;
- }
- }
- }
-
- // Figure out what to do with a directory. Note that the meaning of the
- // directory can be ambiguous:
- // If you pass a directory which is unknown, we don't know if we should
- // search upwards (in case you're pointing at a deep java package folder
- // within the project), or if you're pointing at some top level directory
- // containing lots of projects you want to scan. We attempt to do the
- // right thing, which is to see if you're pointing right at a project or
- // right within it (say at the src/ or res/) folder, and if not, you're
- // hopefully pointing at a project tree that you want to scan recursively.
- if (LintUtils.isProjectDir(file)) {
- registerProjectFile(fileToProject, file, file, rootDir);
- continue;
- } else {
- File parent = file.getParentFile();
- if (parent != null) {
- if (LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- continue;
- } else {
- parent = parent.getParentFile();
- if (parent != null && LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- continue;
- }
- }
- }
-
- // Search downwards for nested projects
- addProjects(file, fileToProject, rootDir);
- }
- } else {
- // Pointed at a file: Search upwards for the containing project
- File parent = file.getParentFile();
- while (parent != null) {
- if (LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- break;
- }
- parent = parent.getParentFile();
- }
- }
-
- if (mCanceled) {
- return Collections.emptySet();
- }
- }
-
- for (Map.Entry<File, Project> entry : fileToProject.entrySet()) {
- File file = entry.getKey();
- Project project = entry.getValue();
- if (!file.equals(project.getDir())) {
- if (file.isDirectory()) {
- try {
- File dir = file.getCanonicalFile();
- if (dir.equals(project.getDir())) {
- continue;
- }
- } catch (IOException ioe) {
- // pass
- }
- }
-
- project.addFile(file);
- }
- }
-
- // Partition the projects up such that we only return projects that aren't
- // included by other projects (e.g. because they are library projects)
-
- Collection<Project> allProjects = fileToProject.values();
- Set<Project> roots = new HashSet<Project>(allProjects);
- for (Project project : allProjects) {
- roots.removeAll(project.getAllLibraries());
- }
-
- // Report issues for all projects that are explicitly referenced. We need to
- // do this here, since the project initialization will mark all library
- // projects as no-report projects by default.
- for (Project project : allProjects) {
- // Report issues for all projects explicitly listed or found via a directory
- // traversal -- including library projects.
- project.setReportIssues(true);
- }
-
- if (LintUtils.assertionsEnabled()) {
- // Make sure that all the project directories are unique. This ensures
- // that we didn't accidentally end up with different project instances
- // for a library project discovered as a directory as well as one
- // initialized from the library project dependency list
- IdentityHashMap<Project, Project> projects =
- new IdentityHashMap<Project, Project>();
- for (Project project : roots) {
- projects.put(project, project);
- for (Project library : project.getAllLibraries()) {
- projects.put(library, library);
- }
- }
- Set<File> dirs = new HashSet<File>();
- for (Project project : projects.keySet()) {
- assert !dirs.contains(project.getDir());
- dirs.add(project.getDir());
- }
- }
-
- return roots;
- }
-
- private void addProjects(
- @NonNull File dir,
- @NonNull Map<File, Project> fileToProject,
- @NonNull File rootDir) {
- if (mCanceled) {
- return;
- }
-
- if (LintUtils.isProjectDir(dir)) {
- registerProjectFile(fileToProject, dir, dir, rootDir);
- } else {
- File[] files = dir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isDirectory()) {
- addProjects(file, fileToProject, rootDir);
- }
- }
- }
- }
- }
-
- private void checkProject(@NonNull Project project) {
- File projectDir = project.getDir();
-
- Context projectContext = new Context(this, project, null, projectDir);
- fireEvent(EventType.SCANNING_PROJECT, projectContext);
-
- List<Project> allLibraries = project.getAllLibraries();
- Set<Project> allProjects = new HashSet<Project>(allLibraries.size() + 1);
- allProjects.add(project);
- allProjects.addAll(allLibraries);
- mCurrentProjects = allProjects.toArray(new Project[allProjects.size()]);
-
- mCurrentProject = project;
-
- for (Detector check : mApplicableDetectors) {
- check.beforeCheckProject(projectContext);
- if (mCanceled) {
- return;
- }
- }
-
- assert mCurrentProject == project;
- runFileDetectors(project, project);
-
- if (!Scope.checkSingleFile(mScope)) {
- List<Project> libraries = project.getDirectLibraries();
- for (Project library : libraries) {
- Context libraryContext = new Context(this, library, project, projectDir);
- fireEvent(EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
- mCurrentProject = library;
-
- for (Detector check : mApplicableDetectors) {
- check.beforeCheckLibraryProject(libraryContext);
- if (mCanceled) {
- return;
- }
- }
- assert mCurrentProject == library;
-
- runFileDetectors(library, project);
- if (mCanceled) {
- return;
- }
-
- assert mCurrentProject == library;
-
- for (Detector check : mApplicableDetectors) {
- check.afterCheckLibraryProject(libraryContext);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- mCurrentProject = project;
-
- for (Detector check : mApplicableDetectors) {
- check.afterCheckProject(projectContext);
- if (mCanceled) {
- return;
- }
- }
-
- if (mCanceled) {
- mClient.report(
- projectContext,
- // Must provide an issue since API guarantees that the issue parameter
- // is valid
- Issue.create("Lint", "", "", Category.PERFORMANCE, 0, Severity.INFORMATIONAL, //$NON-NLS-1$
- Detector.class, EnumSet.noneOf(Scope.class)),
- Severity.INFORMATIONAL,
- null /*range*/,
- "Lint canceled by user", null);
- }
-
- mCurrentProjects = null;
- }
-
- private void runFileDetectors(@NonNull Project project, @Nullable Project main) {
- // Look up manifest information (but not for library projects)
- File manifestFile = project.getManifestFile();
- if (manifestFile != null) {
- XmlContext context = new XmlContext(this, project, main, manifestFile, null);
- IDomParser parser = mClient.getDomParser();
- if (parser != null) {
- context.document = parser.parseXml(context);
- if (context.document != null) {
- try {
- project.readManifest(context.document);
-
- if ((!project.isLibrary() || (main != null && main.isMergingManifests()))
- && mScope.contains(Scope.MANIFEST)) {
- List<Detector> detectors = mScopeDetectors.get(Scope.MANIFEST);
- if (detectors != null) {
- XmlVisitor v = new XmlVisitor(parser, detectors);
- fireEvent(EventType.SCANNING_FILE, context);
- v.visitFile(context, manifestFile);
- }
- }
- } finally {
- if (context.document != null) { // else: freed by XmlVisitor above
- parser.dispose(context, context.document);
- }
- }
- }
- }
- }
-
- // Process both Scope.RESOURCE_FILE and Scope.ALL_RESOURCE_FILES detectors together
- // in a single pass through the resource directories.
- if (mScope.contains(Scope.ALL_RESOURCE_FILES) || mScope.contains(Scope.RESOURCE_FILE)) {
- List<Detector> checks = union(mScopeDetectors.get(Scope.RESOURCE_FILE),
- mScopeDetectors.get(Scope.ALL_RESOURCE_FILES));
- if (checks != null && !checks.isEmpty()) {
- List<ResourceXmlDetector> xmlDetectors =
- new ArrayList<ResourceXmlDetector>(checks.size());
- for (Detector detector : checks) {
- if (detector instanceof ResourceXmlDetector) {
- xmlDetectors.add((ResourceXmlDetector) detector);
- }
- }
- if (!xmlDetectors.isEmpty()) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualResources(project, main, xmlDetectors, files);
- } else {
- List<File> resourceFolders = project.getResourceFolders();
- if (!resourceFolders.isEmpty() && !xmlDetectors.isEmpty()) {
- for (File res : resourceFolders) {
- checkResFolder(project, main, res, xmlDetectors);
- }
- }
- }
- }
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- if (mScope.contains(Scope.JAVA_FILE) || mScope.contains(Scope.ALL_JAVA_FILES)) {
- List<Detector> checks = union(mScopeDetectors.get(Scope.JAVA_FILE),
- mScopeDetectors.get(Scope.ALL_JAVA_FILES));
- if (checks != null && !checks.isEmpty()) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualJavaFiles(project, main, checks, files);
- } else {
- List<File> sourceFolders = project.getJavaSourceFolders();
- checkJava(project, main, sourceFolders, checks);
- }
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- if (mScope.contains(Scope.CLASS_FILE)
- || mScope.contains(Scope.ALL_CLASS_FILES)
- || mScope.contains(Scope.JAVA_LIBRARIES)) {
- checkClasses(project, main);
- }
-
- if (mScope.contains(Scope.OTHER)) {
- List<Detector> checks = mScopeDetectors.get(Scope.OTHER);
- if (checks != null) {
- OtherFileVisitor visitor = new OtherFileVisitor(checks);
- visitor.scan(this, project, main);
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- if (project == main && mScope.contains(Scope.PROGUARD_FILE)) {
- checkProGuard(project, main);
- }
- }
-
- private void checkProGuard(Project project, Project main) {
- List<Detector> detectors = mScopeDetectors.get(Scope.PROGUARD_FILE);
- if (detectors != null) {
- Project p = main != null ? main : project;
- List<File> files = new ArrayList<File>();
- String paths = p.getProguardPath();
- if (paths != null) {
- Splitter splitter = Splitter.on(CharMatcher.anyOf(":;")); //$NON-NLS-1$
- for (String path : splitter.split(paths)) {
- if (path.contains("${")) { //$NON-NLS-1$
- // Don't analyze the global/user proguard files
- continue;
- }
- File file = new File(path);
- if (!file.isAbsolute()) {
- file = new File(project.getDir(), path);
- }
- if (file.exists()) {
- files.add(file);
- }
- }
- }
- if (files.isEmpty()) {
- File file = new File(project.getDir(), OLD_PROGUARD_FILE);
- if (file.exists()) {
- files.add(file);
- }
- file = new File(project.getDir(), FN_PROJECT_PROGUARD_FILE);
- if (file.exists()) {
- files.add(file);
- }
- }
- for (File file : files) {
- Context context = new Context(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- for (Detector detector : detectors) {
- if (detector.appliesTo(context, file)) {
- detector.beforeCheckFile(context);
- detector.run(context);
- detector.afterCheckFile(context);
- }
- }
- }
- }
- }
-
- /** True if execution has been canceled */
- boolean isCanceled() {
- return mCanceled;
- }
-
- /**
- * Map from VM class name to corresponding super class VM name, if available.
- * This map is typically null except <b>during</b> class processing.
- */
- private Map<String, String> mSuperClassMap;
-
- /**
- * Returns the super class for the given class name,
- * which should be in VM format (e.g. java/lang/Integer, not java.lang.Integer).
- * If the super class is not known, returns null. This can happen if
- * the given class is not a known class according to the project or its
- * libraries, for example because it refers to one of the core libraries which
- * are not analyzed by lint.
- *
- * @param name the fully qualified class name
- * @return the corresponding super class name (in VM format), or null if not known
- */
- @Nullable
- public String getSuperClass(@NonNull String name) {
- if (mSuperClassMap == null) {
- throw new IllegalStateException("Only callable during ClassScanner#checkClass");
- }
- assert name.indexOf('.') == -1 : "Use VM signatures, e.g. java/lang/Integer";
-
- String superClass = mSuperClassMap.get(name);
- if (superClass == null && mCurrentProject != null) {
- if ("java/lang/Object".equals(name)) { //$NON-NLS-1$
- return null;
- }
- superClass = mClient.getSuperClass(mCurrentProject, name);
- if (superClass != null) {
- mSuperClassMap.put(name, superClass);
- }
- }
-
- return superClass;
- }
-
- /**
- * Returns true if the given class is a subclass of the given super class.
- *
- * @param classNode the class to check whether it is a subclass of the given
- * super class name
- * @param superClassName the fully qualified super class name (in VM format,
- * e.g. java/lang/Integer, not java.lang.Integer.
- * @return true if the given class is a subclass of the given super class
- */
- public boolean isSubclassOf(@NonNull ClassNode classNode, @NonNull String superClassName) {
- if (superClassName.equals(classNode.superName)) {
- return true;
- }
-
- if (mCurrentProject != null) {
- Boolean isSub = mClient.isSubclassOf(mCurrentProject, classNode.name, superClassName);
- if (isSub != null) {
- return isSub.booleanValue();
- }
- }
-
- String className = classNode.name;
- while (className != null) {
- if (className.equals(superClassName)) {
- return true;
- }
- className = getSuperClass(className);
- }
-
- return false;
- }
- @Nullable
- private static List<Detector> union(
- @Nullable List<Detector> list1,
- @Nullable List<Detector> list2) {
- if (list1 == null) {
- return list2;
- } else if (list2 == null) {
- return list1;
- } else {
- // Use set to pick out unique detectors, since it's possible for there to be overlap,
- // e.g. the DuplicateIdDetector registers both a cross-resource issue and a
- // single-file issue, so it shows up on both scope lists:
- Set<Detector> set = new HashSet<Detector>(list1.size() + list2.size());
- if (list1 != null) {
- set.addAll(list1);
- }
- if (list2 != null) {
- set.addAll(list2);
- }
-
- return new ArrayList<Detector>(set);
- }
- }
-
- /** Check the classes in this project (and if applicable, in any library projects */
- private void checkClasses(Project project, Project main) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualClassFiles(project, main, files);
- return;
- }
-
- // We need to read in all the classes up front such that we can initialize
- // the parent chains (such that for example for a virtual dispatch, we can
- // also check the super classes).
-
- List<File> libraries = project.getJavaLibraries();
- List<ClassEntry> libraryEntries;
- if (!libraries.isEmpty()) {
- libraryEntries = new ArrayList<ClassEntry>(64);
- findClasses(libraryEntries, libraries);
- Collections.sort(libraryEntries);
- } else {
- libraryEntries = Collections.emptyList();
- }
-
- List<File> classFolders = project.getJavaClassFolders();
- List<ClassEntry> classEntries;
- if (classFolders.isEmpty()) {
- String message = String.format("No .class files were found in project \"%1$s\", "
- + "so none of the classfile based checks could be run. "
- + "Does the project need to be built first?", project.getName());
- Location location = Location.create(project.getDir());
- mClient.report(new Context(this, project, main, project.getDir()),
- IssueRegistry.LINT_ERROR,
- project.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR),
- location, message, null);
- classEntries = Collections.emptyList();
- } else {
- classEntries = new ArrayList<ClassEntry>(64);
- findClasses(classEntries, classFolders);
- Collections.sort(classEntries);
- }
-
- if (getPhase() == 1) {
- mSuperClassMap = getSuperMap(libraryEntries, classEntries);
- }
-
- // Actually run the detectors. Libraries should be called before the
- // main classes.
- runClassDetectors(Scope.JAVA_LIBRARIES, libraryEntries, project, main);
-
- if (mCanceled) {
- return;
- }
-
- runClassDetectors(Scope.CLASS_FILE, classEntries, project, main);
- runClassDetectors(Scope.ALL_CLASS_FILES, classEntries, project, main);
- }
-
- private void checkIndividualClassFiles(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<File> files) {
- List<ClassEntry> entries = new ArrayList<ClassEntry>(files.size());
-
- List<File> classFolders = project.getJavaClassFolders();
- if (!classFolders.isEmpty()) {
- for (File file : files) {
- String path = file.getPath();
- if (file.isFile() && path.endsWith(DOT_CLASS)) {
- try {
- byte[] bytes = mClient.readBytes(file);
- if (bytes != null) {
- for (File dir : classFolders) {
- if (path.startsWith(dir.getPath())) {
- entries.add(new ClassEntry(file, null /* jarFile*/, dir,
- bytes));
- break;
- }
- }
- }
- } catch (IOException e) {
- mClient.log(e, null);
- continue;
- }
-
- if (mCanceled) {
- return;
- }
- }
- }
-
- if (!entries.isEmpty()) {
- Collections.sort(entries);
- // No superclass info available on individual lint runs, unless
- // the client can provide it
- mSuperClassMap = Maps.newHashMap();
- runClassDetectors(Scope.CLASS_FILE, entries, project, main);
- }
- }
- }
-
- /**
- * Stack of {@link ClassNode} nodes for outer classes of the currently
- * processed class, including that class itself. Populated by
- * {@link #runClassDetectors(Scope, List, Project, Project)} and used by
- * {@link #getOuterClassNode(ClassNode)}
- */
- private Deque<ClassNode> mOuterClasses;
-
- private void runClassDetectors(Scope scope, List<ClassEntry> entries,
- Project project, Project main) {
- if (mScope.contains(scope)) {
- List<Detector> classDetectors = mScopeDetectors.get(scope);
- if (classDetectors != null && !classDetectors.isEmpty() && !entries.isEmpty()) {
- AsmVisitor visitor = new AsmVisitor(mClient, classDetectors);
-
- String sourceContents = null;
- String sourceName = "";
- mOuterClasses = new ArrayDeque<ClassNode>();
- for (ClassEntry entry : entries) {
- ClassReader reader;
- ClassNode classNode;
- try {
- reader = new ClassReader(entry.bytes);
- classNode = new ClassNode();
- reader.accept(classNode, 0 /* flags */);
- } catch (Throwable t) {
- mClient.log(null, "Error processing %1$s: broken class file?",
- entry.path());
- continue;
- }
-
- ClassNode peek;
- while ((peek = mOuterClasses.peek()) != null) {
- if (classNode.name.startsWith(peek.name)) {
- break;
- } else {
- mOuterClasses.pop();
- }
- }
- mOuterClasses.push(classNode);
-
- if (isSuppressed(null, classNode)) {
- // Class was annotated with suppress all -- no need to look any further
- continue;
- }
-
- if (sourceContents != null) {
- // Attempt to reuse the source buffer if initialized
- // This means making sure that the source files
- // foo/bar/MyClass and foo/bar/MyClass$Bar
- // and foo/bar/MyClass$3 and foo/bar/MyClass$3$1 have the same prefix.
- String newName = classNode.name;
- int newRootLength = newName.indexOf('$');
- if (newRootLength == -1) {
- newRootLength = newName.length();
- }
- int oldRootLength = sourceName.indexOf('$');
- if (oldRootLength == -1) {
- oldRootLength = sourceName.length();
- }
- if (newRootLength != oldRootLength ||
- !sourceName.regionMatches(0, newName, 0, newRootLength)) {
- sourceContents = null;
- }
- }
-
- ClassContext context = new ClassContext(this, project, main,
- entry.file, entry.jarFile, entry.binDir, entry.bytes,
- classNode, scope == Scope.JAVA_LIBRARIES /*fromLibrary*/,
- sourceContents);
-
- try {
- visitor.runClassDetectors(context);
- } catch (Exception e) {
- mClient.log(e, null);
- }
-
- if (mCanceled) {
- return;
- }
-
- sourceContents = context.getSourceContents(false/*read*/);
- sourceName = classNode.name;
- }
-
- mOuterClasses = null;
- }
- }
- }
-
- /** Returns the outer class node of the given class node
- * @param classNode the inner class node
- * @return the outer class node */
- public ClassNode getOuterClassNode(@NonNull ClassNode classNode) {
- String outerName = classNode.outerClass;
-
- Iterator<ClassNode> iterator = mOuterClasses.iterator();
- while (iterator.hasNext()) {
- ClassNode node = iterator.next();
- if (outerName != null) {
- if (node.name.equals(outerName)) {
- return node;
- }
- } else if (node == classNode) {
- return iterator.hasNext() ? iterator.next() : null;
- }
- }
-
- return null;
- }
-
- private Map<String, String> getSuperMap(List<ClassEntry> libraryEntries,
- List<ClassEntry> classEntries) {
- int size = libraryEntries.size() + classEntries.size();
- Map<String, String> map = new HashMap<String, String>(size);
-
- SuperclassVisitor visitor = new SuperclassVisitor(map);
- addSuperClasses(visitor, libraryEntries);
- addSuperClasses(visitor, classEntries);
-
- return map;
- }
-
- private void addSuperClasses(SuperclassVisitor visitor, List<ClassEntry> entries) {
- for (ClassEntry entry : entries) {
- try {
- ClassReader reader = new ClassReader(entry.bytes);
- int flags = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG
- | ClassReader.SKIP_FRAMES;
- reader.accept(visitor, flags);
- } catch (Throwable t) {
- mClient.log(null, "Error processing %1$s: broken class file?", entry.path());
- }
- }
- }
-
- /** Visitor skimming classes and initializing a map of super classes */
- private static class SuperclassVisitor extends ClassVisitor {
- private final Map<String, String> mMap;
-
- public SuperclassVisitor(Map<String, String> map) {
- super(ASM4);
- mMap = map;
- }
-
- @Override
- public void visit(int version, int access, String name, String signature, String superName,
- String[] interfaces) {
- if (superName != null) {
- mMap.put(name, superName);
- }
- }
- }
-
- private void findClasses(
- @NonNull List<ClassEntry> entries,
- @NonNull List<File> classPath) {
- for (File classPathEntry : classPath) {
- if (classPathEntry.getName().endsWith(DOT_JAR)) {
- File jarFile = classPathEntry;
- if (!jarFile.exists()) {
- continue;
- }
- ZipInputStream zis = null;
- try {
- FileInputStream fis = new FileInputStream(jarFile);
- zis = new ZipInputStream(fis);
- ZipEntry entry = zis.getNextEntry();
- while (entry != null) {
- String name = entry.getName();
- if (name.endsWith(DOT_CLASS)) {
- try {
- byte[] bytes = ByteStreams.toByteArray(zis);
- if (bytes != null) {
- File file = new File(entry.getName());
- entries.add(new ClassEntry(file, jarFile, jarFile, bytes));
- }
- } catch (Exception e) {
- mClient.log(e, null);
- continue;
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- entry = zis.getNextEntry();
- }
- } catch (IOException e) {
- mClient.log(e, "Could not read jar file contents from %1$s", jarFile);
- } finally {
- Closeables.closeQuietly(zis);
- }
-
- continue;
- } else if (classPathEntry.isDirectory()) {
- File binDir = classPathEntry;
- List<File> classFiles = new ArrayList<File>();
- addClassFiles(binDir, classFiles);
-
- for (File file : classFiles) {
- try {
- byte[] bytes = mClient.readBytes(file);
- if (bytes != null) {
- entries.add(new ClassEntry(file, null /* jarFile*/, binDir, bytes));
- }
- } catch (IOException e) {
- mClient.log(e, null);
- continue;
- }
-
- if (mCanceled) {
- return;
- }
- }
- } else {
- mClient.log(null, "Ignoring class path entry %1$s", classPathEntry);
- }
- }
- }
-
- private static void addClassFiles(@NonNull File dir, @NonNull List<File> classFiles) {
- // Process the resource folder
- File[] files = dir.listFiles();
- if (files != null && files.length > 0) {
- for (File file : files) {
- if (file.isFile() && file.getName().endsWith(DOT_CLASS)) {
- classFiles.add(file);
- } else if (file.isDirectory()) {
- // Recurse
- addClassFiles(file, classFiles);
- }
- }
- }
- }
-
- private void checkJava(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<File> sourceFolders,
- @NonNull List<Detector> checks) {
- IJavaParser javaParser = mClient.getJavaParser();
- if (javaParser == null) {
- mClient.log(null, "No java parser provided to lint: not running Java checks");
- return;
- }
-
- assert !checks.isEmpty();
-
- // Gather all Java source files in a single pass; more efficient.
- List<File> sources = new ArrayList<File>(100);
- for (File folder : sourceFolders) {
- gatherJavaFiles(folder, sources);
- }
- if (!sources.isEmpty()) {
- JavaVisitor visitor = new JavaVisitor(javaParser, checks);
- for (File file : sources) {
- JavaContext context = new JavaContext(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- private void checkIndividualJavaFiles(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<Detector> checks,
- @NonNull List<File> files) {
-
- IJavaParser javaParser = mClient.getJavaParser();
- if (javaParser == null) {
- mClient.log(null, "No java parser provided to lint: not running Java checks");
- return;
- }
-
- JavaVisitor visitor = new JavaVisitor(javaParser, checks);
-
- for (File file : files) {
- if (file.isFile() && file.getPath().endsWith(DOT_JAVA)) {
- JavaContext context = new JavaContext(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- private static void gatherJavaFiles(@NonNull File dir, @NonNull List<File> result) {
- File[] files = dir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isFile() && file.getName().endsWith(".java")) { //$NON-NLS-1$
- result.add(file);
- } else if (file.isDirectory()) {
- gatherJavaFiles(file, result);
- }
- }
- }
- }
-
- private ResourceFolderType mCurrentFolderType;
- private List<ResourceXmlDetector> mCurrentXmlDetectors;
- private XmlVisitor mCurrentVisitor;
-
- @Nullable
- private XmlVisitor getVisitor(
- @NonNull ResourceFolderType type,
- @NonNull List<ResourceXmlDetector> checks) {
- if (type != mCurrentFolderType) {
- mCurrentFolderType = type;
-
- // Determine which XML resource detectors apply to the given folder type
- List<ResourceXmlDetector> applicableChecks =
- new ArrayList<ResourceXmlDetector>(checks.size());
- for (ResourceXmlDetector check : checks) {
- if (check.appliesTo(type)) {
- applicableChecks.add(check);
- }
- }
-
- // If the list of detectors hasn't changed, then just use the current visitor!
- if (mCurrentXmlDetectors != null && mCurrentXmlDetectors.equals(applicableChecks)) {
- return mCurrentVisitor;
- }
-
- if (applicableChecks.isEmpty()) {
- mCurrentVisitor = null;
- return null;
- }
-
- IDomParser parser = mClient.getDomParser();
- if (parser != null) {
- mCurrentVisitor = new XmlVisitor(parser, applicableChecks);
- }
- }
-
- return mCurrentVisitor;
- }
-
- private void checkResFolder(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File res,
- @NonNull List<ResourceXmlDetector> checks) {
- assert res.isDirectory();
- File[] resourceDirs = res.listFiles();
- if (resourceDirs == null) {
- return;
- }
-
- // Sort alphabetically such that we can process related folder types at the
- // same time
-
- Arrays.sort(resourceDirs);
- for (File dir : resourceDirs) {
- ResourceFolderType type = ResourceFolderType.getFolderType(dir.getName());
- if (type != null) {
- checkResourceFolder(project, main, dir, type, checks);
- }
-
- if (mCanceled) {
- return;
- }
- }
- }
-
- private void checkResourceFolder(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File dir,
- @NonNull ResourceFolderType type,
- @NonNull List<ResourceXmlDetector> checks) {
- // Process the resource folder
- File[] xmlFiles = dir.listFiles();
- if (xmlFiles != null && xmlFiles.length > 0) {
- XmlVisitor visitor = getVisitor(type, checks);
- if (visitor != null) { // if not, there are no applicable rules in this folder
- for (File file : xmlFiles) {
- if (LintUtils.isXmlFile(file)) {
- XmlContext context = new XmlContext(this, project, main, file, type);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
- }
- }
-
- /** Checks individual resources */
- private void checkIndividualResources(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<ResourceXmlDetector> xmlDetectors,
- @NonNull List<File> files) {
- for (File file : files) {
- if (file.isDirectory()) {
- // Is it a resource folder?
- ResourceFolderType type = ResourceFolderType.getFolderType(file.getName());
- if (type != null && new File(file.getParentFile(), RES_FOLDER).exists()) {
- // Yes.
- checkResourceFolder(project, main, file, type, xmlDetectors);
- } else if (file.getName().equals(RES_FOLDER)) { // Is it the res folder?
- // Yes
- checkResFolder(project, main, file, xmlDetectors);
- } else {
- mClient.log(null, "Unexpected folder %1$s; should be project, " +
- "\"res\" folder or resource folder", file.getPath());
- continue;
- }
- } else if (file.isFile() && LintUtils.isXmlFile(file)) {
- // Yes, find out its resource type
- String folderName = file.getParentFile().getName();
- ResourceFolderType type = ResourceFolderType.getFolderType(folderName);
- if (type != null) {
- XmlVisitor visitor = getVisitor(type, xmlDetectors);
- if (visitor != null) {
- XmlContext context = new XmlContext(this, project, main, file, type);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- }
- }
- }
- }
- }
-
- /**
- * Adds a listener to be notified of lint progress
- *
- * @param listener the listener to be added
- */
- public void addLintListener(@NonNull LintListener listener) {
- if (mListeners == null) {
- mListeners = new ArrayList<LintListener>(1);
- }
- mListeners.add(listener);
- }
-
- /**
- * Removes a listener such that it is no longer notified of progress
- *
- * @param listener the listener to be removed
- */
- public void removeLintListener(@NonNull LintListener listener) {
- mListeners.remove(listener);
- if (mListeners.isEmpty()) {
- mListeners = null;
- }
- }
-
- /** Notifies listeners, if any, that the given event has occurred */
- private void fireEvent(@NonNull LintListener.EventType type, @Nullable Context context) {
- if (mListeners != null) {
- for (LintListener listener : mListeners) {
- listener.update(this, type, context);
- }
- }
- }
-
- /**
- * Wrapper around the lint client. This sits in the middle between a
- * detector calling for example {@link LintClient#report} and
- * the actual embedding tool, and performs filtering etc such that detectors
- * and lint clients don't have to make sure they check for ignored issues or
- * filtered out warnings.
- */
- private class LintClientWrapper extends LintClient {
- @NonNull
- private final LintClient mDelegate;
-
- public LintClientWrapper(@NonNull LintClient delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public void report(
- @NonNull Context context,
- @NonNull Issue issue,
- @NonNull Severity severity,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- assert mCurrentProject != null;
- if (!mCurrentProject.getReportIssues()) {
- return;
- }
-
- Configuration configuration = context.getConfiguration();
- if (!configuration.isEnabled(issue)) {
- if (issue != IssueRegistry.PARSER_ERROR && issue != IssueRegistry.LINT_ERROR) {
- mDelegate.log(null, "Incorrect detector reported disabled issue %1$s",
- issue.toString());
- }
- return;
- }
-
- if (configuration.isIgnored(context, issue, location, message, data)) {
- return;
- }
-
- if (severity == Severity.IGNORE) {
- return;
- }
-
- mDelegate.report(context, issue, severity, location, message, data);
- }
-
- // Everything else just delegates to the embedding lint client
-
- @Override
- @NonNull
- public Configuration getConfiguration(@NonNull Project project) {
- return mDelegate.getConfiguration(project);
- }
-
-
- @Override
- public void log(@NonNull Severity severity, @Nullable Throwable exception,
- @Nullable String format, @Nullable Object... args) {
- mDelegate.log(exception, format, args);
- }
-
- @Override
- @NonNull
- public String readFile(@NonNull File file) {
- return mDelegate.readFile(file);
- }
-
- @Override
- @NonNull
- public byte[] readBytes(@NonNull File file) throws IOException {
- return mDelegate.readBytes(file);
- }
-
- @Override
- @NonNull
- public List<File> getJavaSourceFolders(@NonNull Project project) {
- return mDelegate.getJavaSourceFolders(project);
- }
-
- @Override
- @NonNull
- public List<File> getJavaClassFolders(@NonNull Project project) {
- return mDelegate.getJavaClassFolders(project);
- }
-
- @NonNull
- @Override
- public List<File> getJavaLibraries(@NonNull Project project) {
- return mDelegate.getJavaLibraries(project);
- }
-
- @Override
- @NonNull
- public List<File> getResourceFolders(@NonNull Project project) {
- return mDelegate.getResourceFolders(project);
- }
-
- @Override
- @Nullable
- public IDomParser getDomParser() {
- return mDelegate.getDomParser();
- }
-
- @Override
- @NonNull
- public Class<? extends Detector> replaceDetector(
- @NonNull Class<? extends Detector> detectorClass) {
- return mDelegate.replaceDetector(detectorClass);
- }
-
- @Override
- @NonNull
- public SdkInfo getSdkInfo(@NonNull Project project) {
- return mDelegate.getSdkInfo(project);
- }
-
- @Override
- @NonNull
- public Project getProject(@NonNull File dir, @NonNull File referenceDir) {
- return mDelegate.getProject(dir, referenceDir);
- }
-
- @Override
- @Nullable
- public IJavaParser getJavaParser() {
- return mDelegate.getJavaParser();
- }
-
- @Override
- public File findResource(@NonNull String relativePath) {
- return mDelegate.findResource(relativePath);
- }
-
- @Override
- @Nullable
- public File getCacheDir(boolean create) {
- return mDelegate.getCacheDir(create);
- }
-
- @Override
- @NonNull
- protected ClassPathInfo getClassPath(@NonNull Project project) {
- return mDelegate.getClassPath(project);
- }
-
- @Override
- public void log(@Nullable Throwable exception, @Nullable String format,
- @Nullable Object... args) {
- mDelegate.log(exception, format, args);
- }
-
- @Override
- @Nullable
- public File getSdkHome() {
- return mDelegate.getSdkHome();
- }
-
- @Override
- @NonNull
- public IAndroidTarget[] getTargets() {
- return mDelegate.getTargets();
- }
-
- @Override
- public int getHighestKnownApiLevel() {
- return mDelegate.getHighestKnownApiLevel();
- }
-
- @Override
- @Nullable
- public String getSuperClass(@NonNull Project project, @NonNull String name) {
- return mDelegate.getSuperClass(project, name);
- }
-
- @Override
- @Nullable
- public Boolean isSubclassOf(@NonNull Project project, @NonNull String name,
- @NonNull String superClassName) {
- return mDelegate.isSubclassOf(project, name, superClassName);
- }
-
- @Override
- @NonNull
- public String getProjectName(@NonNull Project project) {
- return mDelegate.getProjectName(project);
- }
- }
-
- /**
- * Requests another pass through the data for the given detector. This is
- * typically done when a detector needs to do more expensive computation,
- * but it only wants to do this once it <b>knows</b> that an error is
- * present, or once it knows more specifically what to check for.
- *
- * @param detector the detector that should be included in the next pass.
- * Note that the lint runner may refuse to run more than a couple
- * of runs.
- * @param scope the scope to be revisited. This must be a subset of the
- * current scope ({@link #getScope()}, and it is just a performance hint;
- * in particular, the detector should be prepared to be called on other
- * scopes as well (since they may have been requested by other detectors).
- * You can pall null to indicate "all".
- */
- public void requestRepeat(@NonNull Detector detector, @Nullable EnumSet<Scope> scope) {
- if (mRepeatingDetectors == null) {
- mRepeatingDetectors = new ArrayList<Detector>();
- }
- mRepeatingDetectors.add(detector);
-
- if (scope != null) {
- if (mRepeatScope == null) {
- mRepeatScope = scope;
- } else {
- mRepeatScope = EnumSet.copyOf(mRepeatScope);
- mRepeatScope.addAll(scope);
- }
- } else {
- mRepeatScope = Scope.ALL;
- }
- }
-
- // Unfortunately, ASMs nodes do not extend a common DOM node type with parent
- // pointers, so we have to have multiple methods which pass in each type
- // of node (class, method, field) to be checked.
-
- /**
- * Returns whether the given issue is suppressed in the given method.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param classNode the class containing the issue
- * @param method the method containing the issue
- * @param instruction the instruction within the method, if any
- * @return true if there is a suppress annotation covering the specific
- * issue on this method
- */
- public boolean isSuppressed(
- @Nullable Issue issue,
- @NonNull ClassNode classNode,
- @NonNull MethodNode method,
- @Nullable AbstractInsnNode instruction) {
- if (method.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = method.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- // Initializations of fields end up placed in generated methods (<init>
- // for members and <clinit> for static fields).
- if (instruction != null && method.name.charAt(0) == '<') {
- AbstractInsnNode next = LintUtils.getNextInstruction(instruction);
- if (next != null && next.getType() == AbstractInsnNode.FIELD_INSN) {
- FieldInsnNode fieldRef = (FieldInsnNode) next;
- FieldNode field = findField(classNode, fieldRef.owner, fieldRef.name);
- if (field != null && isSuppressed(issue, field)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- @Nullable
- private FieldNode findField(ClassNode classNode, String owner, String name) {
- while (classNode != null) {
- if (owner.equals(classNode.name)) {
- @SuppressWarnings("rawtypes") // ASM API
- List fieldList = classNode.fields;
- for (Object f : fieldList) {
- FieldNode field = (FieldNode) f;
- if (field.name.equals(name)) {
- return field;
- }
- }
- return null;
- }
- classNode = getOuterClassNode(classNode);
- }
- return null;
- }
-
- /**
- * Returns whether the given issue is suppressed for the given field.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param field the field potentially annotated with a suppress annotation
- * @return true if there is a suppress annotation covering the specific
- * issue on this field
- */
- public boolean isSuppressed(@Nullable Issue issue, @NonNull FieldNode field) {
- if (field.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = field.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given class.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param classNode the class containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@Nullable Issue issue, @NonNull ClassNode classNode) {
- if (classNode.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = classNode.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- return false;
- }
-
- private static boolean isSuppressed(@Nullable Issue issue, List<AnnotationNode> annotations) {
- for (AnnotationNode annotation : annotations) {
- String desc = annotation.desc;
-
- // We could obey @SuppressWarnings("all") too, but no need to look for it
- // because that annotation only has source retention.
-
- if (desc.endsWith(SUPPRESS_LINT_VMSIG)) {
- if (annotation.values != null) {
- for (int i = 0, n = annotation.values.size(); i < n; i += 2) {
- String key = (String) annotation.values.get(i);
- if (key.equals("value")) { //$NON-NLS-1$
- Object value = annotation.values.get(i + 1);
- if (value instanceof String) {
- String id = (String) value;
- if (id.equalsIgnoreCase(SUPPRESS_ALL) ||
- issue != null && id.equalsIgnoreCase(issue.getId())) {
- return true;
- }
- } else if (value instanceof List) {
- @SuppressWarnings("rawtypes")
- List list = (List) value;
- for (Object v : list) {
- if (v instanceof String) {
- String id = (String) v;
- if (id.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && id.equalsIgnoreCase(issue.getId()))) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given parse tree node.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param scope the AST node containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@NonNull Issue issue, @Nullable Node scope) {
- while (scope != null) {
- Class<? extends Node> type = scope.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == VariableDefinition.class) {
- // Variable
- VariableDefinition declaration = (VariableDefinition) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == MethodDeclaration.class) {
- // Method
- // Look for annotations on the method
- MethodDeclaration declaration = (MethodDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == ConstructorDeclaration.class) {
- // Constructor
- // Look for annotations on the method
- ConstructorDeclaration declaration = (ConstructorDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == ClassDeclaration.class) {
- // Class
- ClassDeclaration declaration = (ClassDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- }
-
- scope = scope.getParent();
- }
-
- return false;
- }
-
- /**
- * Returns true if the given AST modifier has a suppress annotation for the
- * given issue (which can be null to check for the "all" annotation)
- *
- * @param issue the issue to be checked
- * @param modifiers the modifier to check
- * @return true if the issue or all issues should be suppressed for this
- * modifier
- */
- private static boolean isSuppressed(@Nullable Issue issue, @Nullable Modifiers modifiers) {
- if (modifiers == null) {
- return false;
- }
- StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations();
- if (annotations == null) {
- return false;
- }
-
- Iterator<Annotation> iterator = annotations.iterator();
- while (iterator.hasNext()) {
- Annotation annotation = iterator.next();
- TypeReference t = annotation.astAnnotationTypeReference();
- String typeName = t.getTypeName();
- if (typeName.endsWith(SUPPRESS_LINT)
- || typeName.endsWith("SuppressWarnings")) { //$NON-NLS-1$
- StrictListAccessor<AnnotationElement, Annotation> values =
- annotation.astElements();
- if (values != null) {
- Iterator<AnnotationElement> valueIterator = values.iterator();
- while (valueIterator.hasNext()) {
- AnnotationElement element = valueIterator.next();
- AnnotationValue valueNode = element.astValue();
- if (valueNode == null) {
- continue;
- }
- if (valueNode instanceof StringLiteral) {
- StringLiteral literal = (StringLiteral) valueNode;
- String value = literal.astValue();
- if (value.equalsIgnoreCase(SUPPRESS_ALL) ||
- issue != null && issue.getId().equalsIgnoreCase(value)) {
- return true;
- }
- } else if (valueNode instanceof ArrayInitializer) {
- ArrayInitializer array = (ArrayInitializer) valueNode;
- StrictListAccessor<Expression, ArrayInitializer> expressions =
- array.astExpressions();
- if (expressions == null) {
- continue;
- }
- Iterator<Expression> arrayIterator = expressions.iterator();
- while (arrayIterator.hasNext()) {
- Expression arrayElement = arrayIterator.next();
- if (arrayElement instanceof StringLiteral) {
- String value = ((StringLiteral) arrayElement).astValue();
- if (value.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(value))) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given XML DOM node.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param node the DOM node containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@NonNull Issue issue, @Nullable org.w3c.dom.Node node) {
- if (node instanceof Attr) {
- node = ((Attr) node).getOwnerElement();
- }
- while (node != null) {
- if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
- Element element = (Element) node;
- if (element.hasAttributeNS(TOOLS_URI, ATTR_IGNORE)) {
- String ignore = element.getAttributeNS(TOOLS_URI, ATTR_IGNORE);
- if (ignore.indexOf(',') == -1) {
- if (ignore.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(ignore))) {
- return true;
- }
- } else {
- for (String id : ignore.split(",")) { //$NON-NLS-1$
- if (id.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(id))) {
- return true;
- }
- }
- }
- }
- }
-
- node = node.getParentNode();
- }
-
- return false;
- }
-
- /** A pending class to be analyzed by {@link #checkClasses} */
- @VisibleForTesting
- static class ClassEntry implements Comparable<ClassEntry> {
- public final File file;
- public final File jarFile;
- public final File binDir;
- public final byte[] bytes;
-
- public ClassEntry(File file, File jarFile, File binDir, byte[] bytes) {
- super();
- this.file = file;
- this.jarFile = jarFile;
- this.binDir = binDir;
- this.bytes = bytes;
- }
-
- public String path() {
- if (jarFile != null) {
- return jarFile.getPath() + ':' + file.getPath();
- } else {
- return file.getPath();
- }
- }
-
- @Override
- public int compareTo(ClassEntry other) {
- String p1 = file.getPath();
- String p2 = other.file.getPath();
- int m1 = p1.length();
- int m2 = p2.length();
- int m = Math.min(m1, m2);
-
- for (int i = 0; i < m; i++) {
- char c1 = p1.charAt(i);
- char c2 = p2.charAt(i);
- if (c1 != c2) {
- // Sort Foo$Bar.class *after* Foo.class, even though $ < .
- if (c1 == '.' && c2 == '$') {
- return -1;
- }
- if (c1 == '$' && c2 == '.') {
- return 1;
- }
- return c1 - c2;
- }
- }
-
- return (m == m1) ? -1 : 1;
- }
-
- @Override
- public String toString() {
- return file.getPath();
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintListener.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintListener.java
deleted file mode 100644
index 8195d36..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/LintListener.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.google.common.annotations.Beta;
-
-/**
- * Interface implemented by listeners to be notified of lint events
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public interface LintListener {
- /** The various types of events provided to lint listeners */
- enum EventType {
- /** A lint check is about to begin */
- STARTING,
-
- /** Lint is about to check the given project, see {@link Context#getProject()} */
- SCANNING_PROJECT,
-
- /** Lint is about to check the given library project, see {@link Context#getProject()} */
- SCANNING_LIBRARY_PROJECT,
-
- /** Lint is about to check the given file, see {@link Context#file} */
- SCANNING_FILE,
-
- /** A new pass was initiated */
- NEW_PHASE,
-
- /** The lint check was canceled */
- CANCELED,
-
- /** The lint check is done */
- COMPLETED,
- }
-
- /**
- * Notifies listeners that the event of the given type has occurred.
- * Additional information, such as the file being scanned, or the project
- * being scanned, is available in the {@link Context} object (except for the
- * {@link EventType#STARTING}, {@link EventType#CANCELED} or
- * {@link EventType#COMPLETED} events which are fired outside of project
- * contexts.)
- *
- * @param driver the driver running through the checks
- * @param type the type of event that occurred
- * @param context the context providing additional information
- */
- void update(@NonNull LintDriver driver, @NonNull EventType type,
- @Nullable Context context);
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/OtherFileVisitor.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/OtherFileVisitor.java
deleted file mode 100644
index 573d4f0..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/OtherFileVisitor.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.DOT_CLASS;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.FD_ASSETS;
-import static com.android.tools.lint.detector.api.Detector.OtherFileScanner;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.utils.SdkUtils;
-import com.google.common.collect.Lists;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Visitor for "other" files: files that aren't java sources,
- * XML sources, etc -- or which should have custom handling in some
- * other way.
- */
-class OtherFileVisitor {
- @NonNull
- private final List<Detector> mDetectors;
-
- @NonNull
- private Map<Scope, List<File>> mFiles = new EnumMap<Scope, List<File>>(Scope.class);
-
- OtherFileVisitor(@NonNull List<Detector> detectors) {
- mDetectors = detectors;
- }
-
- /** Analyze other files in the given project */
- void scan(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main) {
- // Collect all project files
- File projectFolder = project.getDir();
-
- EnumSet<Scope> scopes = EnumSet.noneOf(Scope.class);
- for (Detector detector : mDetectors) {
- OtherFileScanner fileScanner = (OtherFileScanner) detector;
- EnumSet<Scope> applicable = fileScanner.getApplicableFiles();
- if (applicable.contains(Scope.OTHER)) {
- scopes = Scope.ALL;
- break;
- }
- scopes.addAll(applicable);
- }
-
- List<File> subset = project.getSubset();
-
- if (scopes.contains(Scope.RESOURCE_FILE)) {
- if (subset != null && !subset.isEmpty()) {
- List<File> files = new ArrayList<File>(subset.size());
- for (File file : subset) {
- if (SdkUtils.endsWith(file.getPath(), DOT_XML) &&
- !file.getName().equals(ANDROID_MANIFEST_XML)) {
- files.add(file);
- }
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.RESOURCE_FILE, files);
- }
- } else {
- List<File> files = Lists.newArrayListWithExpectedSize(100);
- for (File res : project.getResourceFolders()) {
- collectFiles(files, res);
- }
- File assets = new File(projectFolder, FD_ASSETS);
- if (assets.exists()) {
- collectFiles(files, assets);
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.RESOURCE_FILE, files);
- }
- }
- }
-
- if (scopes.contains(Scope.JAVA_FILE)) {
- if (subset != null && !subset.isEmpty()) {
- List<File> files = new ArrayList<File>(subset.size());
- for (File file : subset) {
- if (file.getPath().endsWith(DOT_JAVA)) {
- files.add(file);
- }
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.JAVA_FILE, files);
- }
- } else {
- List<File> files = Lists.newArrayListWithExpectedSize(100);
- for (File srcFolder : project.getJavaSourceFolders()) {
- collectFiles(files, srcFolder);
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.JAVA_FILE, files);
- }
- }
- }
-
- if (scopes.contains(Scope.CLASS_FILE)) {
- if (subset != null && !subset.isEmpty()) {
- List<File> files = new ArrayList<File>(subset.size());
- for (File file : subset) {
- if (file.getPath().endsWith(DOT_CLASS)) {
- files.add(file);
- }
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.CLASS_FILE, files);
- }
- } else {
- List<File> files = Lists.newArrayListWithExpectedSize(100);
- for (File classFolder : project.getJavaClassFolders()) {
- collectFiles(files, classFolder);
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.CLASS_FILE, files);
- }
- }
- }
-
- if (scopes.contains(Scope.MANIFEST)) {
- if (subset != null && !subset.isEmpty()) {
- List<File> files = new ArrayList<File>(subset.size());
- for (File file : subset) {
- if (file.getName().equals(ANDROID_MANIFEST_XML)) {
- files.add(file);
- }
- }
- if (!files.isEmpty()) {
- mFiles.put(Scope.MANIFEST, files);
- }
- } else {
- File manifestFile = project.getManifestFile();
- if (manifestFile != null) {
- mFiles.put(Scope.MANIFEST, Collections.<File>singletonList(manifestFile));
- }
- }
- }
-
- for (Map.Entry<Scope, List<File>> entry : mFiles.entrySet()) {
- Scope scope = entry.getKey();
- List<File> files = entry.getValue();
- List<Detector> applicable = new ArrayList<Detector>(mDetectors.size());
- for (Detector detector : mDetectors) {
- OtherFileScanner fileScanner = (OtherFileScanner) detector;
- EnumSet<Scope> appliesTo = fileScanner.getApplicableFiles();
- if (appliesTo.contains(Scope.OTHER) || appliesTo.contains(scope)) {
- applicable.add(detector);
- }
- }
- if (!applicable.isEmpty()) {
- for (File file : files) {
- Context context = new Context(driver, project, main, file);
- for (Detector detector : applicable) {
- detector.beforeCheckFile(context);
- detector.run(context);
- detector.afterCheckFile(context);
- }
- if (driver.isCanceled()) {
- return;
- }
- }
- }
- }
- }
-
- private static void collectFiles(List<File> files, File file) {
- if (file.isDirectory()) {
- File[] children = file.listFiles();
- if (children != null) {
- for (File child : children) {
- collectFiles(files, child);
- }
- }
- } else {
- files.add(file);
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/SdkInfo.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/SdkInfo.java
deleted file mode 100644
index 8b3d1e9..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/SdkInfo.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-/**
- * Information about SDKs
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class SdkInfo {
- /**
- * Returns true if the given child view is the same class or a sub class of
- * the given parent view class
- *
- * @param parentViewFqcn the fully qualified class name of the parent view
- * @param childViewFqcn the fully qualified class name of the child view
- * @return true if the child view is a sub view of (or the same class as)
- * the parent view
- */
- public boolean isSubViewOf(@NonNull String parentViewFqcn, @NonNull String childViewFqcn) {
- while (!childViewFqcn.equals("android.view.View")) { //$NON-NLS-1$
- if (parentViewFqcn.equals(childViewFqcn)) {
- return true;
- }
- String parent = getParentViewClass(childViewFqcn);
- if (parent == null) {
- // Unknown view - err on the side of caution
- return true;
- }
- childViewFqcn = parent;
- }
-
- return false;
- }
-
-
- /**
- * Returns the fully qualified name of the parent view, or null if the view
- * is the root android.view.View class.
- *
- * @param fqcn the fully qualified class name of the view
- * @return the fully qualified class name of the parent view, or null
- */
- @Nullable
- public abstract String getParentViewClass(@NonNull String fqcn);
-
- /**
- * Returns the class name of the parent view, or null if the view is the
- * root android.view.View class. This is the same as the
- * {@link #getParentViewClass(String)} but without the package.
- *
- * @param name the view class name to look up the parent for (not including
- * package)
- * @return the view name of the parent
- */
- @Nullable
- public abstract String getParentViewName(@NonNull String name);
-
- /**
- * Returns true if the given widget name is a layout
- *
- * @param tag the XML tag for the view
- * @return true if the given tag corresponds to a layout
- */
- public boolean isLayout(@NonNull String tag) {
- return tag.endsWith("Layout"); //$NON-NLS-1$
- }
-
- // TODO: Add access to resource resolution here.
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/XmlVisitor.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/XmlVisitor.java
deleted file mode 100644
index 2e64118..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/client/api/XmlVisitor.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.XmlScanner;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.RandomAccess;
-
-/**
- * Specialized visitor for running detectors on an XML document.
- * It operates in two phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant element name, and each significant attribute name, to a list
- * of detectors to consult for that element or attribute name.
- * The set of element names or attribute names (or both) that a detector
- * is interested in is provided by the detectors themselves.
- * <li> Second, it iterates over the document a single time. For each element and
- * attribute it looks up the list of interested detectors, and runs them.
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-class XmlVisitor {
- private final Map<String, List<Detector.XmlScanner>> mElementToCheck =
- new HashMap<String, List<Detector.XmlScanner>>();
- private final Map<String, List<Detector.XmlScanner>> mAttributeToCheck =
- new HashMap<String, List<Detector.XmlScanner>>();
- private final List<Detector.XmlScanner> mDocumentDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<Detector.XmlScanner> mAllElementDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<Detector.XmlScanner> mAllAttributeDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<? extends Detector> mAllDetectors;
- private final IDomParser mParser;
-
- // Really want this:
- //<T extends List<Detector> & Detector.XmlScanner> XmlVisitor(IDomParser parser,
- // T xmlDetectors) {
- // but it makes client code tricky and ugly.
- XmlVisitor(@NonNull IDomParser parser, @NonNull List<? extends Detector> xmlDetectors) {
- mParser = parser;
- mAllDetectors = xmlDetectors;
-
- // TODO: Check appliesTo() for files, and find a quick way to enable/disable
- // rules when running through a full project!
- for (Detector detector : xmlDetectors) {
- Detector.XmlScanner xmlDetector = (XmlScanner) detector;
- Collection<String> attributes = xmlDetector.getApplicableAttributes();
- if (attributes == XmlScanner.ALL) {
- mAllAttributeDetectors.add(xmlDetector);
- } else if (attributes != null) {
- for (String attribute : attributes) {
- List<Detector.XmlScanner> list = mAttributeToCheck.get(attribute);
- if (list == null) {
- list = new ArrayList<Detector.XmlScanner>();
- mAttributeToCheck.put(attribute, list);
- }
- list.add(xmlDetector);
- }
- }
- Collection<String> elements = xmlDetector.getApplicableElements();
- if (elements == XmlScanner.ALL) {
- mAllElementDetectors.add(xmlDetector);
- } else if (elements != null) {
- for (String element : elements) {
- List<Detector.XmlScanner> list = mElementToCheck.get(element);
- if (list == null) {
- list = new ArrayList<Detector.XmlScanner>();
- mElementToCheck.put(element, list);
- }
- list.add(xmlDetector);
- }
- }
-
- if ((attributes == null || (attributes.isEmpty()
- && attributes != XmlScanner.ALL))
- && (elements == null || (elements.isEmpty()
- && elements != XmlScanner.ALL))) {
- mDocumentDetectors.add(xmlDetector);
- }
- }
- }
-
- void visitFile(@NonNull XmlContext context, @NonNull File file) {
- assert LintUtils.isXmlFile(file);
- context.parser = mParser;
-
- try {
- if (context.document == null) {
- context.document = mParser.parseXml(context);
- if (context.document == null) {
- // No need to log this; the parser should be reporting
- // a full warning (such as IssueRegistry#PARSER_ERROR)
- // with details, location, etc.
- return;
- }
- if (context.document.getDocumentElement() == null) {
- // Ignore empty documents
- return;
- }
- }
-
- for (Detector check : mAllDetectors) {
- check.beforeCheckFile(context);
- }
-
- for (Detector.XmlScanner check : mDocumentDetectors) {
- check.visitDocument(context, context.document);
- }
-
- if (!mElementToCheck.isEmpty() || !mAttributeToCheck.isEmpty()
- || !mAllAttributeDetectors.isEmpty() || !mAllElementDetectors.isEmpty()) {
- visitElement(context, context.document.getDocumentElement());
- }
-
- for (Detector check : mAllDetectors) {
- check.afterCheckFile(context);
- }
- } finally {
- if (context.document != null) {
- mParser.dispose(context, context.document);
- context.document = null;
- }
- }
- }
-
- private void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- List<Detector.XmlScanner> elementChecks = mElementToCheck.get(element.getTagName());
- if (elementChecks != null) {
- assert elementChecks instanceof RandomAccess;
- for (XmlScanner check : elementChecks) {
- check.visitElement(context, element);
- }
- }
- if (!mAllElementDetectors.isEmpty()) {
- for (XmlScanner check : mAllElementDetectors) {
- check.visitElement(context, element);
- }
- }
-
- if (!mAttributeToCheck.isEmpty() || !mAllAttributeDetectors.isEmpty()) {
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- String name = attribute.getLocalName();
- if (name == null) {
- name = attribute.getName();
- }
- List<Detector.XmlScanner> list = mAttributeToCheck.get(name);
- if (list != null) {
- for (XmlScanner check : list) {
- check.visitAttribute(context, attribute);
- }
- }
- if (!mAllAttributeDetectors.isEmpty()) {
- for (XmlScanner check : mAllAttributeDetectors) {
- check.visitAttribute(context, attribute);
- }
- }
- }
- }
-
- // Visit children
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- visitElement(context, (Element) child);
- }
- }
-
- // Post hooks
- if (elementChecks != null) {
- for (XmlScanner check : elementChecks) {
- check.visitElementAfter(context, element);
- }
- }
- if (!mAllElementDetectors.isEmpty()) {
- for (XmlScanner check : mAllElementDetectors) {
- check.visitElementAfter(context, element);
- }
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Category.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Category.java
deleted file mode 100644
index c267420..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Category.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-/**
- * A category is a container for related issues.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public final class Category implements Comparable<Category> {
- private final String mName;
- private final int mPriority;
- private final Category mParent;
-
- /**
- * Creates a new {@link Category}.
- *
- * @param parent the name of a parent category, or null
- * @param name the name of the category
- * @param priority a sorting priority, with higher being more important
- */
- private Category(
- @Nullable Category parent,
- @NonNull String name,
- int priority) {
- mParent = parent;
- mName = name;
- mPriority = priority;
- }
-
- /**
- * Creates a new top level {@link Category} with the given sorting priority.
- *
- * @param name the name of the category
- * @param priority a sorting priority, with higher being more important
- * @return a new category
- */
- @NonNull
- public static Category create(@NonNull String name, int priority) {
- return new Category(null, name, priority);
- }
-
- /**
- * Creates a new top level {@link Category} with the given sorting priority.
- *
- * @param parent the name of a parent category, or null
- * @param name the name of the category
- * @param priority a sorting priority, with higher being more important
- * @return a new category
- */
- @NonNull
- public static Category create(@Nullable Category parent, @NonNull String name, int priority) {
- return new Category(parent, name, priority);
- }
-
- /**
- * Returns the parent category, or null if this is a top level category
- *
- * @return the parent category, or null if this is a top level category
- */
- public Category getParent() {
- return mParent;
- }
-
- /**
- * Returns the name of this category
- *
- * @return the name of this category
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns a full name for this category. For a top level category, this is just
- * the {@link #getName()} value, but for nested categories it will include the parent
- * names as well.
- *
- * @return a full name for this category
- */
- public String getFullName() {
- if (mParent != null) {
- return mParent.getFullName() + ':' + mName;
- } else {
- return mName;
- }
- }
-
- @Override
- public int compareTo(Category other) {
- if (other.mPriority == mPriority) {
- if (mParent == other) {
- return 1;
- } else if (other.mParent == this) {
- return -1;
- }
- }
- return other.mPriority - mPriority;
- }
-
- /** Issues related to running lint itself */
- public static final Category LINT = create("Lint", 110);
-
- /** Issues related to correctness */
- public static final Category CORRECTNESS = create("Correctness", 100);
-
- /** Issues related to security */
- public static final Category SECURITY = create("Security", 90);
-
- /** Issues related to performance */
- public static final Category PERFORMANCE = create("Performance", 80);
-
- /** Issues related to usability */
- public static final Category USABILITY = create("Usability", 70);
-
- /** Issues related to accessibility */
- public static final Category A11Y = create("Accessibility", 60);
-
- /** Issues related to internationalization */
- public static final Category I18N = create("Internationalization", 50);
-
- // Sub categories
-
- /** Issues related to icons */
- public static final Category ICONS = create(USABILITY, "Icons", 73);
-
- /** Issues related to typography */
- public static final Category TYPOGRAPHY = create(USABILITY, "Typography", 76);
-
- /** Issues related to messages/strings */
- public static final Category MESSAGES = create(CORRECTNESS, "Messages", 95);
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ClassContext.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ClassContext.java
deleted file mode 100644
index 5150eff..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ClassContext.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.DOT_CLASS;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.EOL_BACKWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.FORWARD;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Location.SearchDirection;
-import com.android.tools.lint.detector.api.Location.SearchHints;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Splitter;
-
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.objectweb.asm.tree.LineNumberNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * A {@link Context} used when checking .class files.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class ClassContext extends Context {
- private final File mBinDir;
- /** The class file DOM root node */
- private final ClassNode mClassNode;
- /** The class file byte data */
- private final byte[] mBytes;
- /** The source file, if known/found */
- private File mSourceFile;
- /** The contents of the source file, if source file is known/found */
- private String mSourceContents;
- /** Whether we've searched for the source file (used to avoid repeated failed searches) */
- private boolean mSearchedForSource;
- /** If the file is a relative path within a jar file, this is the jar file, otherwise null */
- private final File mJarFile;
- /** Whether this class is part of a library (rather than corresponding to one of the
- * source files in this project */
- private final boolean mFromLibrary;
-
- /**
- * Construct a new {@link ClassContext}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is the
- * root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- * @param jarFile If the file is a relative path within a jar file, this is
- * the jar file, otherwise null
- * @param binDir the root binary directory containing this .class file.
- * @param bytes the bytecode raw data
- * @param classNode the bytecode object model
- * @param fromLibrary whether this class is from a library rather than part
- * of this project
- * @param sourceContents initial contents of the Java source, if known, or
- * null
- */
- public ClassContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file,
- @Nullable File jarFile,
- @NonNull File binDir,
- @NonNull byte[] bytes,
- @NonNull ClassNode classNode,
- boolean fromLibrary,
- @Nullable String sourceContents) {
- super(driver, project, main, file);
- mJarFile = jarFile;
- mBinDir = binDir;
- mBytes = bytes;
- mClassNode = classNode;
- mFromLibrary = fromLibrary;
- mSourceContents = sourceContents;
- }
-
- /**
- * Returns the raw bytecode data for this class file
- *
- * @return the byte array containing the bytecode data
- */
- @NonNull
- public byte[] getBytecode() {
- return mBytes;
- }
-
- /**
- * Returns the bytecode object model
- *
- * @return the bytecode object model, never null
- */
- @NonNull
- public ClassNode getClassNode() {
- return mClassNode;
- }
-
- /**
- * Returns the jar file, if any. If this is null, the .class file is a real file
- * on disk, otherwise it represents a relative path within the jar file.
- *
- * @return the jar file, or null
- */
- @Nullable
- public File getJarFile() {
- return mJarFile;
- }
-
- /**
- * Returns whether this class is part of a library (not this project).
- *
- * @return true if this class is part of a library
- */
- public boolean isFromClassLibrary() {
- return mFromLibrary;
- }
-
- /**
- * Returns the source file for this class file, if possible.
- *
- * @return the source file, or null
- */
- @Nullable
- public File getSourceFile() {
- if (mSourceFile == null && !mSearchedForSource) {
- mSearchedForSource = true;
-
- String source = mClassNode.sourceFile;
- if (source == null) {
- source = file.getName();
- if (source.endsWith(DOT_CLASS)) {
- source = source.substring(0, source.length() - DOT_CLASS.length()) + DOT_JAVA;
- }
- int index = source.indexOf('$');
- if (index != -1) {
- source = source.substring(0, index) + DOT_JAVA;
- }
- }
- if (source != null) {
- if (mJarFile != null) {
- String relative = file.getParent() + File.separator + source;
- List<File> sources = getProject().getJavaSourceFolders();
- for (File dir : sources) {
- File sourceFile = new File(dir, relative);
- if (sourceFile.exists()) {
- mSourceFile = sourceFile;
- break;
- }
- }
- } else {
- // Determine package
- String topPath = mBinDir.getPath();
- String parentPath = file.getParentFile().getPath();
- if (parentPath.startsWith(topPath)) {
- int start = topPath.length() + 1;
- String relative = start > parentPath.length() ? // default package?
- "" : parentPath.substring(start);
- List<File> sources = getProject().getJavaSourceFolders();
- for (File dir : sources) {
- File sourceFile = new File(dir, relative + File.separator + source);
- if (sourceFile.exists()) {
- mSourceFile = sourceFile;
- break;
- }
- }
- }
- }
- }
- }
-
- return mSourceFile;
- }
-
- /**
- * Returns the contents of the source file for this class file, if found.
- *
- * @return the source contents, or ""
- */
- @NonNull
- public String getSourceContents() {
- if (mSourceContents == null) {
- File sourceFile = getSourceFile();
- if (sourceFile != null) {
- mSourceContents = getClient().readFile(mSourceFile);
- }
-
- if (mSourceContents == null) {
- mSourceContents = "";
- }
- }
-
- return mSourceContents;
- }
-
- /**
- * Returns the contents of the source file for this class file, if found. If
- * {@code read} is false, do not read the source contents if it has not
- * already been read. (This is primarily intended for the lint
- * infrastructure; most client code would call {@link #getSourceContents()}
- * .)
- *
- * @param read whether to read the source contents if it has not already
- * been initialized
- * @return the source contents, which will never be null if {@code read} is
- * true, or null if {@code read} is false and the source contents
- * hasn't already been read.
- */
- @Nullable
- public String getSourceContents(boolean read) {
- if (read) {
- return getSourceContents();
- } else {
- return mSourceContents;
- }
- }
-
- /**
- * Returns a location for the given source line number in this class file's
- * source file, if available.
- *
- * @param line the line number (1-based, which is what ASM uses)
- * @param patternStart optional pattern to search for in the source for
- * range start
- * @param patternEnd optional pattern to search for in the source for range
- * end
- * @param hints additional hints about the pattern search (provided
- * {@code patternStart} is non null)
- * @return a location, never null
- */
- @NonNull
- public Location getLocationForLine(int line, @Nullable String patternStart,
- @Nullable String patternEnd, @Nullable SearchHints hints) {
- File sourceFile = getSourceFile();
- if (sourceFile != null) {
- // ASM line numbers are 1-based, and lint line numbers are 0-based
- if (line != -1) {
- return Location.create(sourceFile, getSourceContents(), line - 1,
- patternStart, patternEnd, hints);
- } else {
- return Location.create(sourceFile);
- }
- }
-
- return Location.create(file);
- }
-
- /**
- * Reports an issue.
- * <p>
- * Detectors should only call this method if an error applies to the whole class
- * scope and there is no specific method or field that applies to the error.
- * If so, use
- * {@link #report(Issue, MethodNode, AbstractInsnNode, Location, String, Object)} or
- * {@link #report(Issue, FieldNode, Location, String, Object)}, such that
- * suppress annotations are checked.
- *
- * @param issue the issue to report
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- @Override
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (mDriver.isSuppressed(issue, mClassNode)) {
- return;
- }
- ClassNode curr = mClassNode;
- while (curr != null) {
- ClassNode prev = curr;
- curr = mDriver.getOuterClassNode(curr);
- if (curr != null) {
- if (prev.outerMethod != null) {
- @SuppressWarnings("rawtypes") // ASM API
- List methods = curr.methods;
- for (Object m : methods) {
- MethodNode method = (MethodNode) m;
- if (method.name.equals(prev.outerMethod)
- && method.desc.equals(prev.outerMethodDesc)) {
- // Found the outer method for this anonymous class; continue
- // reporting on it (which will also work its way up the parent
- // class hierarchy)
- if (method != null && mDriver.isSuppressed(issue, mClassNode, method,
- null)) {
- return;
- }
- break;
- }
- }
- }
- if (mDriver.isSuppressed(issue, curr)) {
- return;
- }
- }
- }
-
- super.report(issue, location, message, data);
- }
-
- // Unfortunately, ASMs nodes do not extend a common DOM node type with parent
- // pointers, so we have to have multiple methods which pass in each type
- // of node (class, method, field) to be checked.
-
- /**
- * Reports an issue applicable to a given method node.
- *
- * @param issue the issue to report
- * @param method the method scope the error applies to. The lint
- * infrastructure will check whether there are suppress
- * annotations on this method (or its enclosing class) and if so
- * suppress the warning without involving the client.
- * @param instruction the instruction within the method the error applies
- * to. You cannot place annotations on individual method
- * instructions (for example, annotations on local variables are
- * allowed, but are not kept in the .class file). However, this
- * instruction is needed to handle suppressing errors on field
- * initializations; in that case, the errors may be reported in
- * the {@code <clinit>} method, but the annotation is found not
- * on that method but for the {@link FieldNode}'s.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable MethodNode method,
- @Nullable AbstractInsnNode instruction,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (method != null && mDriver.isSuppressed(issue, mClassNode, method, instruction)) {
- return;
- }
- report(issue, location, message, data); // also checks the class node
- }
-
- /**
- * Reports an issue applicable to a given method node.
- *
- * @param issue the issue to report
- * @param field the scope the error applies to. The lint infrastructure
- * will check whether there are suppress annotations on this field (or its enclosing
- * class) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable FieldNode field,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (field != null && mDriver.isSuppressed(issue, field)) {
- return;
- }
- report(issue, location, message, data); // also checks the class node
- }
-
- /**
- * Finds the line number closest to the given node
- *
- * @param node the instruction node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull AbstractInsnNode node) {
- AbstractInsnNode curr = node;
-
- // First search backwards
- while (curr != null) {
- if (curr.getType() == AbstractInsnNode.LINE) {
- return ((LineNumberNode) curr).line;
- }
- curr = curr.getPrevious();
- }
-
- // Then search forwards
- curr = node;
- while (curr != null) {
- if (curr.getType() == AbstractInsnNode.LINE) {
- return ((LineNumberNode) curr).line;
- }
- curr = curr.getNext();
- }
-
- return -1;
- }
-
- /**
- * Finds the line number closest to the given method declaration
- *
- * @param node the method node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull MethodNode node) {
- if (node.instructions != null && node.instructions.size() > 0) {
- return findLineNumber(node.instructions.get(0));
- }
-
- return -1;
- }
-
- /**
- * Finds the line number closest to the given class declaration
- *
- * @param node the method node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull ClassNode node) {
- if (node.methods != null && !node.methods.isEmpty()) {
- MethodNode firstMethod = getFirstRealMethod(node);
- if (firstMethod != null) {
- return findLineNumber(firstMethod);
- }
- }
-
- return -1;
- }
-
- /**
- * Returns a location for the given {@link ClassNode}, where class node is
- * either the top level class, or an inner class, in the current context.
- *
- * @param classNode the class in the current context
- * @return a location pointing to the class declaration, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull ClassNode classNode) {
- // Attempt to find a proper location for this class. This is tricky
- // since classes do not have line number entries in the class file; we need
- // to find a method, look up the corresponding line number then search
- // around it for a suitable tag, such as the class name.
- String pattern;
- if (isAnonymousClass(classNode.name)) {
- pattern = classNode.superName;
- } else {
- pattern = classNode.name;
- }
- int index = pattern.lastIndexOf('$');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- index = pattern.lastIndexOf('/');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
-
- return getLocationForLine(findLineNumber(classNode), pattern, null,
- SearchHints.create(BACKWARD).matchJavaSymbol());
- }
-
- @Nullable
- private static MethodNode getFirstRealMethod(@NonNull ClassNode classNode) {
- // Return the first method in the class for line number purposes. Skip <init>,
- // since it's typically not located near the real source of the method.
- if (classNode.methods != null) {
- @SuppressWarnings("rawtypes") // ASM API
- List methods = classNode.methods;
- for (Object m : methods) {
- MethodNode method = (MethodNode) m;
- if (method.name.charAt(0) != '<') {
- return method;
- }
- }
-
- if (!classNode.methods.isEmpty()) {
- return (MethodNode) classNode.methods.get(0);
- }
- }
-
- return null;
- }
-
- /**
- * Returns a location for the given {@link MethodNode}.
- *
- * @param methodNode the class in the current context
- * @param classNode the class containing the method
- * @return a location pointing to the class declaration, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull MethodNode methodNode,
- @NonNull ClassNode classNode) {
- // Attempt to find a proper location for this class. This is tricky
- // since classes do not have line number entries in the class file; we need
- // to find a method, look up the corresponding line number then search
- // around it for a suitable tag, such as the class name.
- String pattern;
- SearchDirection searchMode;
- if (methodNode.name.equals(CONSTRUCTOR_NAME)) {
- searchMode = EOL_BACKWARD;
- if (isAnonymousClass(classNode.name)) {
- pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1);
- } else {
- pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1);
- }
- } else {
- searchMode = BACKWARD;
- pattern = methodNode.name;
- }
-
- return getLocationForLine(findLineNumber(methodNode), pattern, null,
- SearchHints.create(searchMode).matchJavaSymbol());
- }
-
- /**
- * Returns a location for the given {@link AbstractInsnNode}.
- *
- * @param instruction the instruction to look up the location for
- * @return a location pointing to the instruction, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull AbstractInsnNode instruction) {
- SearchHints hints = SearchHints.create(FORWARD).matchJavaSymbol();
- String pattern = null;
- if (instruction instanceof MethodInsnNode) {
- MethodInsnNode call = (MethodInsnNode) instruction;
- if (call.name.equals(CONSTRUCTOR_NAME)) {
- pattern = call.owner;
- hints = hints.matchConstructor();
- } else {
- pattern = call.name;
- }
- int index = pattern.lastIndexOf('$');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- index = pattern.lastIndexOf('/');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- }
-
- int line = findLineNumber(instruction);
- return getLocationForLine(line, pattern, null, hints);
- }
-
- private static boolean isAnonymousClass(@NonNull String fqcn) {
- int lastIndex = fqcn.lastIndexOf('$');
- if (lastIndex != -1 && lastIndex < fqcn.length() - 1) {
- if (Character.isDigit(fqcn.charAt(lastIndex + 1))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Converts from a VM owner name (such as foo/bar/Foo$Baz) to a
- * fully qualified class name (such as foo.bar.Foo.Baz).
- *
- * @param owner the owner name to convert
- * @return the corresponding fully qualified class name
- */
- @NonNull
- public static String getFqcn(@NonNull String owner) {
- return owner.replace('/', '.').replace('$','.');
- }
-
- /**
- * Computes a user-readable type signature from the given class owner, name
- * and description. For example, for owner="foo/bar/Foo$Baz", name="foo",
- * description="(I)V", it returns "void foo.bar.Foo.Bar#foo(int)".
- *
- * @param owner the class name
- * @param name the method name
- * @param desc the method description
- * @return a user-readable string
- */
- public static String createSignature(String owner, String name, String desc) {
- StringBuilder sb = new StringBuilder(100);
-
- if (desc != null) {
- Type returnType = Type.getReturnType(desc);
- sb.append(getTypeString(returnType));
- sb.append(' ');
- }
-
- if (owner != null) {
- sb.append(getFqcn(owner));
- }
- if (name != null) {
- sb.append('#');
- sb.append(name);
- if (desc != null) {
- Type[] argumentTypes = Type.getArgumentTypes(desc);
- if (argumentTypes != null && argumentTypes.length > 0) {
- sb.append('(');
- boolean first = true;
- for (Type type : argumentTypes) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(getTypeString(type));
- }
- sb.append(')');
- }
- }
- }
-
- return sb.toString();
- }
-
- private static String getTypeString(Type type) {
- String s = type.getClassName();
- if (s.startsWith("java.lang.")) { //$NON-NLS-1$
- s = s.substring("java.lang.".length()); //$NON-NLS-1$
- }
-
- return s;
- }
-
- /**
- * Computes the internal class name of the given fully qualified class name.
- * For example, it converts foo.bar.Foo.Bar into foo/bar/Foo$Bar
- *
- * @param fqcn the fully qualified class name
- * @return the internal class name
- */
- @NonNull
- public static String getInternalName(@NonNull String fqcn) {
- if (fqcn.indexOf('.') == -1) {
- return fqcn;
- }
-
- StringBuilder sb = new StringBuilder(fqcn.length());
- String prev = null;
- for (String part : Splitter.on('.').split(fqcn)) {
- if (prev != null && prev.length() > 0) {
- if (Character.isUpperCase(prev.charAt(0))) {
- sb.append('$');
- } else {
- sb.append('/');
- }
- }
- sb.append(part);
- prev = part;
- }
-
- return sb.toString();
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Context.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Context.java
deleted file mode 100644
index a379dd0..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Context.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.Configuration;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Splitter;
-
-import java.io.File;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Context passed to the detectors during an analysis run. It provides
- * information about the file being analyzed, it allows shared properties (so
- * the detectors can share results), etc.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class Context {
- /**
- * The file being checked. Note that this may not always be to a concrete
- * file. For example, in the {@link Detector#beforeCheckProject(Context)}
- * method, the context file is the directory of the project.
- */
- public final File file;
-
- /** The driver running through the checks */
- protected final LintDriver mDriver;
-
- /** The project containing the file being checked */
- @NonNull
- private final Project mProject;
-
- /**
- * The "main" project. For normal projects, this is the same as {@link #mProject},
- * but for library projects, it's the root project that includes (possibly indirectly)
- * the various library projects and their library projects.
- * <p>
- * Note that this is a property on the {@link Context}, not the
- * {@link Project}, since a library project can be included from multiple
- * different top level projects, so there isn't <b>one</b> main project,
- * just one per main project being analyzed with its library projects.
- */
- private final Project mMainProject;
-
- /** The current configuration controlling which checks are enabled etc */
- private final Configuration mConfiguration;
-
- /** The contents of the file */
- private String mContents;
-
- /**
- * Whether the lint job has been canceled.
- * <p>
- * Slow-running detectors should check this flag via
- * {@link AtomicBoolean#get()} and abort if canceled
- */
- @NonNull
- public final AtomicBoolean canceled = new AtomicBoolean();
-
- /** Map of properties to share results between detectors */
- private Map<String, Object> mProperties;
-
- /**
- * Construct a new {@link Context}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- */
- public Context(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file) {
- this.file = file;
-
- mDriver = driver;
- mProject = project;
- mMainProject = main;
- mConfiguration = project.getConfiguration();
- }
-
- /**
- * Returns the scope for the lint job
- *
- * @return the scope, never null
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mDriver.getScope();
- }
-
- /**
- * Returns the configuration for this project.
- *
- * @return the configuration, never null
- */
- @NonNull
- public Configuration getConfiguration() {
- return mConfiguration;
- }
-
- /**
- * Returns the project containing the file being checked
- *
- * @return the project, never null
- */
- @NonNull
- public Project getProject() {
- return mProject;
- }
-
- /**
- * Returns the main project if this project is a library project, or self
- * if this is not a library project. The main project is the root project
- * of all library projects, not necessarily the directly including project.
- *
- * @return the main project, never null
- */
- @NonNull
- public Project getMainProject() {
- return mMainProject != null ? mMainProject : mProject;
- }
-
- /**
- * Returns the lint client requesting the lint check
- *
- * @return the client, never null
- */
- @NonNull
- public LintClient getClient() {
- return mDriver.getClient();
- }
-
- /**
- * Returns the driver running through the lint checks
- *
- * @return the driver
- */
- @NonNull
- public LintDriver getDriver() {
- return mDriver;
- }
-
- /**
- * Returns the contents of the file. This may not be the contents of the
- * file on disk, since it delegates to the {@link LintClient}, which in turn
- * may decide to return the current edited contents of the file open in an
- * editor.
- *
- * @return the contents of the given file, or null if an error occurs.
- */
- @Nullable
- public String getContents() {
- if (mContents == null) {
- mContents = mDriver.getClient().readFile(file);
- }
-
- return mContents;
- }
-
- /**
- * Returns the value of the given named property, or null.
- *
- * @param name the name of the property
- * @return the corresponding value, or null
- */
- @Nullable
- public Object getProperty(String name) {
- if (mProperties == null) {
- return null;
- }
-
- return mProperties.get(name);
- }
-
- /**
- * Sets the value of the given named property.
- *
- * @param name the name of the property
- * @param value the corresponding value
- */
- public void setProperty(@NonNull String name, @Nullable Object value) {
- if (value == null) {
- if (mProperties != null) {
- mProperties.remove(name);
- }
- } else {
- if (mProperties == null) {
- mProperties = new HashMap<String, Object>();
- }
- mProperties.put(name, value);
- }
- }
-
- /**
- * Gets the SDK info for the current project.
- *
- * @return the SDK info for the current project, never null
- */
- @NonNull
- public SdkInfo getSdkInfo() {
- return mProject.getSdkInfo();
- }
-
- // ---- Convenience wrappers ---- (makes the detector code a bit leaner)
-
- /**
- * Returns false if the given issue has been disabled. Convenience wrapper
- * around {@link Configuration#getSeverity(Issue)}.
- *
- * @param issue the issue to check
- * @return false if the issue has been disabled
- */
- public boolean isEnabled(@NonNull Issue issue) {
- return mConfiguration.isEnabled(issue);
- }
-
- /**
- * Reports an issue. Convenience wrapper around {@link LintClient#report}
- *
- * @param issue the issue to report
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- Configuration configuration = mConfiguration;
-
- // If this error was computed for a context where the context corresponds to
- // a project instead of a file, the actual error may be in a different project (e.g.
- // a library project), so adjust the configuration as necessary.
- if (location != null && location.getFile() != null) {
- Project project = mDriver.findProjectFor(location.getFile());
- if (project != null) {
- configuration = project.getConfiguration();
- }
- }
-
- // If an error occurs in a library project, but you've disabled that check in the
- // main project, disable it in the library project too. (In some cases you don't
- // control the lint.xml of a library project, and besides, if you're not interested in
- // a check for your main project you probably don't care about it in the library either.)
- if (configuration != mConfiguration
- && mConfiguration.getSeverity(issue) == Severity.IGNORE) {
- return;
- }
-
- Severity severity = configuration.getSeverity(issue);
- if (severity == Severity.IGNORE) {
- return;
- }
-
- mDriver.getClient().report(this, issue, severity, location, message, data);
- }
-
- /**
- * Send an exception to the log. Convenience wrapper around {@link LintClient#log}.
- *
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * @param args any arguments for the format string
- */
- public void log(
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args) {
- mDriver.getClient().log(exception, format, args);
- }
-
- /**
- * Returns the current phase number. The first pass is numbered 1. Only one pass
- * will be performed, unless a {@link Detector} calls {@link #requestRepeat}.
- *
- * @return the current phase, usually 1
- */
- public int getPhase() {
- return mDriver.getPhase();
- }
-
- /**
- * Requests another pass through the data for the given detector. This is
- * typically done when a detector needs to do more expensive computation,
- * but it only wants to do this once it <b>knows</b> that an error is
- * present, or once it knows more specifically what to check for.
- *
- * @param detector the detector that should be included in the next pass.
- * Note that the lint runner may refuse to run more than a couple
- * of runs.
- * @param scope the scope to be revisited. This must be a subset of the
- * current scope ({@link #getScope()}, and it is just a performance hint;
- * in particular, the detector should be prepared to be called on other
- * scopes as well (since they may have been requested by other detectors).
- * You can pall null to indicate "all".
- */
- public void requestRepeat(@NonNull Detector detector, @Nullable EnumSet<Scope> scope) {
- mDriver.requestRepeat(detector, scope);
- }
-
- /** Pattern for version qualifiers */
- private static final Pattern VERSION_PATTERN = Pattern.compile("^v(\\d+)$"); //$NON-NLS-1$
-
- private static File sCachedFolder = null;
- private static int sCachedFolderVersion = -1;
-
- /**
- * Returns the folder version. For example, for the file values-v14/foo.xml,
- * it returns 14.
- *
- * @return the folder version, or -1 if no specific version was specified
- */
- public int getFolderVersion() {
- return getFolderVersion(file);
- }
-
- /**
- * Returns the folder version of the given file. For example, for the file values-v14/foo.xml,
- * it returns 14.
- *
- * @param file the file to be checked
- * @return the folder version, or -1 if no specific version was specified
- */
- public static int getFolderVersion(File file) {
- File parent = file.getParentFile();
- if (parent.equals(sCachedFolder)) {
- return sCachedFolderVersion;
- }
-
- sCachedFolder = parent;
- sCachedFolderVersion = -1;
-
- for (String qualifier : Splitter.on('-').split(parent.getName())) {
- Matcher matcher = VERSION_PATTERN.matcher(qualifier);
- if (matcher.matches()) {
- sCachedFolderVersion = Integer.parseInt(matcher.group(1));
- break;
- }
- }
-
- return sCachedFolderVersion;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/DefaultPosition.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/DefaultPosition.java
deleted file mode 100644
index 72c8ee7..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/DefaultPosition.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.google.common.annotations.Beta;
-
-/**
- * A simple offset-based position *
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class DefaultPosition extends Position {
- /** The line number (0-based where the first line is line 0) */
- private final int mLine;
-
- /**
- * The column number (where the first character on the line is 0), or -1 if
- * unknown
- */
- private final int mColumn;
-
- /** The character offset */
- private final int mOffset;
-
- /**
- * Creates a new {@link DefaultPosition}
- *
- * @param line the 0-based line number, or -1 if unknown
- * @param column the 0-based column number, or -1 if unknown
- * @param offset the offset, or -1 if unknown
- */
- public DefaultPosition(int line, int column, int offset) {
- mLine = line;
- mColumn = column;
- mOffset = offset;
- }
-
- @Override
- public int getLine() {
- return mLine;
- }
-
- @Override
- public int getOffset() {
- return mOffset;
- }
-
- @Override
- public int getColumn() {
- return mColumn;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Detector.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Detector.java
deleted file mode 100644
index a3412cf..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Detector.java
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.LintDriver;
-import com.google.common.annotations.Beta;
-import lombok.ast.AstVisitor;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.List;
-
-/**
- * A detector is able to find a particular problem. It might also be thought of as enforcing
- * a rule, but "rule" is a bit overloaded in ADT terminology since ViewRules are used in
- * the Rules API to allow views to specify designtime behavior in the graphical layout editor.
- * <p>
- * Each detector provides information about the issues it can find, such as an explanation
- * of how to fix the issue, the priority, the category, etc. It also has an id which is
- * used to persistently identify a particular type of error.
- * <p>
- * Detectors will be called in a predefined order:
- * <ol>
- * <li> Manifest file
- * <li> Resource files, in alphabetical order by resource type
- * (therefore, "layout" is checked before "values", "values-de" is checked before
- * "values-en" but after "values", and so on.
- * <li> Java sources
- * <li> Java classes
- * <li> Proguard files
- * </ol>
- * If a detector needs information when processing a file type that comes from a type of
- * file later in the order above, they can request a second phase; see
- * {@link LintDriver#requestRepeat}.
- * <p>
- * NOTE: Detectors might be constructed just once and shared between lint runs, so
- * any per-detector state should be initialized and reset via the before/after
- * methods.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class Detector {
- /** Specialized interface for detectors that scan Java source file parse trees */
- public interface JavaScanner {
- /**
- * Create a parse tree visitor to process the parse tree. All
- * {@link JavaScanner} detectors must provide a visitor, unless they
- * either return true from {@link #appliesToResourceRefs()} or return
- * non null from {@link #getApplicableMethodNames()}.
- * <p>
- * If you return specific AST node types from
- * {@link #getApplicableNodeTypes()}, then the visitor will <b>only</b>
- * be called for the specific requested node types. This is more
- * efficient, since it allows many detectors that apply to only a small
- * part of the AST (such as method call nodes) to share iteration of the
- * majority of the parse tree.
- * <p>
- * If you return null from {@link #getApplicableNodeTypes()}, then your
- * visitor will be called from the top and all node types visited.
- * <p>
- * Note that a new visitor is created for each separate compilation
- * unit, so you can store per file state in the visitor.
- *
- * @param context the {@link Context} for the file being analyzed
- * @return a visitor, or null.
- */
- @Nullable
- AstVisitor createJavaVisitor(@NonNull JavaContext context);
-
- /**
- * Return the types of AST nodes that the visitor returned from
- * {@link #createJavaVisitor(JavaContext)} should visit. See the
- * documentation for {@link #createJavaVisitor(JavaContext)} for details
- * on how the shared visitor is used.
- * <p>
- * If you return null from this method, then the visitor will process
- * the full tree instead.
- * <p>
- * Note that for the shared visitor, the return codes from the visit
- * methods are ignored: returning true will <b>not</b> prune iteration
- * of the subtree, since there may be other node types interested in the
- * children. If you need to ensure that your visitor only processes a
- * part of the tree, use a full visitor instead. See the
- * OverdrawDetector implementation for an example of this.
- *
- * @return the list of applicable node types (AST node classes), or null
- */
- @Nullable
- List<Class<? extends Node>> getApplicableNodeTypes();
-
- /**
- * Return the list of method names this detector is interested in, or
- * null. If this method returns non-null, then any AST nodes that match
- * a method call in the list will be passed to the
- * {@link #visitMethod(JavaContext, AstVisitor, MethodInvocation)}
- * method for processing. The visitor created by
- * {@link #createJavaVisitor(JavaContext)} is also passed to that
- * method, although it can be null.
- * <p>
- * This makes it easy to write detectors that focus on some fixed calls.
- * For example, the StringFormatDetector uses this mechanism to look for
- * "format" calls, and when found it looks around (using the AST's
- * {@link Node#getParent()} method) to see if it's called on
- * a String class instance, and if so do its normal processing. Note
- * that since it doesn't need to do any other AST processing, that
- * detector does not actually supply a visitor.
- *
- * @return a set of applicable method names, or null.
- */
- @Nullable
- List<String> getApplicableMethodNames();
-
- /**
- * Method invoked for any method calls found that matches any names
- * returned by {@link #getApplicableMethodNames()}. This also passes
- * back the visitor that was created by
- * {@link #createJavaVisitor(JavaContext)}, but a visitor is not
- * required. It is intended for detectors that need to do additional AST
- * processing, but also want the convenience of not having to look for
- * method names on their own.
- *
- * @param context the context of the lint request
- * @param visitor the visitor created from
- * {@link #createJavaVisitor(JavaContext)}, or null
- * @param node the {@link MethodInvocation} node for the invoked method
- */
- void visitMethod(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node);
-
- /**
- * Returns whether this detector cares about Android resource references
- * (such as {@code R.layout.main} or {@code R.string.app_name}). If it
- * does, then the visitor will look for these patterns, and if found, it
- * will invoke {@link #visitResourceReference} passing the resource type
- * and resource name. It also passes the visitor, if any, that was
- * created by {@link #createJavaVisitor(JavaContext)}, such that a
- * detector can do more than just look for resources.
- *
- * @return true if this detector wants to be notified of R resource
- * identifiers found in the code.
- */
- boolean appliesToResourceRefs();
-
- /**
- * Called for any resource references (such as {@code R.layout.main}
- * found in Java code, provided this detector returned {@code true} from
- * {@link #appliesToResourceRefs()}.
- *
- * @param context the lint scanning context
- * @param visitor the visitor created from
- * {@link #createJavaVisitor(JavaContext)}, or null
- * @param node the variable reference for the resource
- * @param type the resource type, such as "layout" or "string"
- * @param name the resource name, such as "main" from
- * {@code R.layout.main}
- * @param isFramework whether the resource is a framework resource
- * (android.R) or a local project resource (R)
- */
- void visitResourceReference(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull Node node,
- @NonNull String type,
- @NonNull String name,
- boolean isFramework);
- }
-
- /** Specialized interface for detectors that scan Java class files */
- public interface ClassScanner {
- /**
- * Checks the given class' bytecode for issues.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- */
- void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode);
-
- /**
- * Returns the list of node types (corresponding to the constants in the
- * {@link AbstractInsnNode} class) that this scanner applies to. The
- * {@link #checkInstruction(ClassContext, ClassNode, MethodNode, AbstractInsnNode)}
- * method will be called for each match.
- *
- * @return an array containing all the node types this detector should be
- * called for, or null if none.
- */
- @Nullable
- int[] getApplicableAsmNodeTypes();
-
- /**
- * Process a given instruction node, and register lint issues if
- * applicable.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- * @param method the method node containing the call
- * @param instruction the actual instruction
- */
- void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull AbstractInsnNode instruction);
-
- /**
- * Return the list of method call names (in VM format, e.g. "<init>" for
- * constructors, etc) for method calls this detector is interested in,
- * or null. T his will be used to dispatch calls to
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * for only the method calls in owners that the detector is interested
- * in.
- * <p>
- * <b>NOTE</b>: If you return non null from this method, then <b>only</b>
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * will be called if a suitable method is found;
- * {@link #checkClass(ClassContext, ClassNode)} will not be called under
- * any circumstances.
- * <p>
- * This makes it easy to write detectors that focus on some fixed calls,
- * and allows lint to make a single pass over the bytecode over a class,
- * and efficiently dispatch method calls to any detectors that are
- * interested in it. Without this, each new lint check interested in a
- * single method, would be doing a complete pass through all the
- * bytecode instructions of the class via the
- * {@link #checkClass(ClassContext, ClassNode)} method, which would make
- * each newly added lint check make lint slower. Now a single dispatch
- * map is used instead, and for each encountered call in the single
- * dispatch, it looks up in the map which if any detectors are
- * interested in the given call name, and dispatches to each one in
- * turn.
- *
- * @return a list of applicable method names, or null.
- */
- @Nullable
- List<String> getApplicableCallNames();
-
- /**
- * Just like {@link Detector#getApplicableCallNames()}, but for the owner
- * field instead. The
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * method will be called for all {@link MethodInsnNode} instances where the
- * owner field matches any of the members returned in this node.
- * <p>
- * Note that if your detector provides both a name and an owner, the
- * method will be called for any nodes matching either the name <b>or</b>
- * the owner, not only where they match <b>both</b>. Note also that it will
- * be called twice - once for the name match, and (at least once) for the owner
- * match.
- *
- * @return a list of applicable owner names, or null.
- */
- @Nullable
- List<String> getApplicableCallOwners();
-
- /**
- * Process a given method call node, and register lint issues if
- * applicable. This is similar to the
- * {@link #checkInstruction(ClassContext, ClassNode, MethodNode, AbstractInsnNode)}
- * method, but has the additional advantage that it is only called for known
- * method names or method owners, according to
- * {@link #getApplicableCallNames()} and {@link #getApplicableCallOwners()}.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- * @param method the method node containing the call
- * @param call the actual method call node
- */
- void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call);
- }
-
- /** Specialized interface for detectors that scan XML files */
- public interface XmlScanner {
- /**
- * Visit the given document. The detector is responsible for its own iteration
- * through the document.
- * @param context information about the document being analyzed
- * @param document the document to examine
- */
- void visitDocument(@NonNull XmlContext context, @NonNull Document document);
-
- /**
- * Visit the given element.
- * @param context information about the document being analyzed
- * @param element the element to examine
- */
- void visitElement(@NonNull XmlContext context, @NonNull Element element);
-
- /**
- * Visit the given element after its children have been analyzed.
- * @param context information about the document being analyzed
- * @param element the element to examine
- */
- void visitElementAfter(@NonNull XmlContext context, @NonNull Element element);
-
- /**
- * Visit the given attribute.
- * @param context information about the document being analyzed
- * @param attribute the attribute node to examine
- */
- void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute);
-
- /**
- * Returns the list of elements that this detector wants to analyze. If non
- * null, this detector will be called (specifically, the
- * {@link #visitElement} method) for each matching element in the document.
- * <p>
- * If this method returns null, and {@link #getApplicableAttributes()} also returns
- * null, then the {@link #visitDocument} method will be called instead.
- *
- * @return a collection of elements, or null, or the special
- * {@link XmlScanner#ALL} marker to indicate that every single
- * element should be analyzed.
- */
- @Nullable
- Collection<String> getApplicableElements();
-
- /**
- * Returns the list of attributes that this detector wants to analyze. If non
- * null, this detector will be called (specifically, the
- * {@link #visitAttribute} method) for each matching attribute in the document.
- * <p>
- * If this method returns null, and {@link #getApplicableElements()} also returns
- * null, then the {@link #visitDocument} method will be called instead.
- *
- * @return a collection of attributes, or null, or the special
- * {@link XmlScanner#ALL} marker to indicate that every single
- * attribute should be analyzed.
- */
- @Nullable
- Collection<String> getApplicableAttributes();
-
- /**
- * Special marker collection returned by {@link #getApplicableElements()} or
- * {@link #getApplicableAttributes()} to indicate that the check should be
- * invoked on all elements or all attributes
- */
- @NonNull
- List<String> ALL = new ArrayList<String>(0); // NOT Collections.EMPTY!
- // We want to distinguish this from just an *empty* list returned by the caller!
- }
-
- /** Specialized interface for detectors that scan other files */
- public interface OtherFileScanner {
- /**
- * Returns the set of files this scanner wants to consider. If this includes
- * {@link Scope#OTHER} then all source files will be checked. Note that the
- * set of files will not just include files of the indicated type, but all files
- * within the relevant source folder. For example, returning {@link Scope#JAVA_FILE}
- * will not just return {@code .java} files, but also other resource files such as
- * {@code .html} and other files found within the Java source folders.
- * <p>
- * Lint will call the {@link #run(Context)}} method when the file should be checked.
- *
- * @return set of scopes that define the types of source files the
- * detector wants to consider
- */
- @NonNull
- EnumSet<Scope> getApplicableFiles();
- }
-
- /**
- * Runs the detector. This method will not be called for certain specialized
- * detectors, such as {@link XmlScanner} and {@link JavaScanner}, where
- * there are specialized analysis methods instead such as
- * {@link XmlScanner#visitElement(XmlContext, Element)}.
- *
- * @param context the context describing the work to be done
- */
- public void run(@NonNull Context context) {
- }
-
- /**
- * Returns true if this detector applies to the given file
- *
- * @param context the context to check
- * @param file the file in the context to check
- * @return true if this detector applies to the given context and file
- */
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return false;
- }
-
- /**
- * Analysis is about to begin, perform any setup steps.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void beforeCheckProject(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for the whole project, perform any
- * cleanup or report issues that require project-wide analysis.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void afterCheckProject(@NonNull Context context) {
- }
-
- /**
- * Analysis is about to begin for the given library project, perform any setup steps.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void beforeCheckLibraryProject(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for the given library project, perform any
- * cleanup or report issues that require library-project-wide analysis.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void afterCheckLibraryProject(@NonNull Context context) {
- }
-
- /**
- * Analysis is about to be performed on a specific file, perform any setup
- * steps.
- * <p>
- * Note: When this method is called at the beginning of checking an XML
- * file, the context is guaranteed to be an instance of {@link XmlContext},
- * and similarly for a Java source file, the context will be a
- * {@link JavaContext} and so on.
- *
- * @param context the context for the check referencing the file to be
- * checked, the project, etc.
- */
- public void beforeCheckFile(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for a specific file, perform any cleanup
- * or report issues found
- * <p>
- * Note: When this method is called at the end of checking an XML
- * file, the context is guaranteed to be an instance of {@link XmlContext},
- * and similarly for a Java source file, the context will be a
- * {@link JavaContext} and so on.
- *
- * @param context the context for the check referencing the file to be
- * checked, the project, etc.
- */
- public void afterCheckFile(@NonNull Context context) {
- }
-
- /**
- * Returns the expected speed of this detector
- *
- * @return the expected speed of this detector
- */
- @NonNull
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- // ---- Dummy implementations to make implementing XmlScanner easier: ----
-
- @SuppressWarnings("javadoc")
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- // This method must be overridden if your detector does
- // not return something from getApplicableElements or
- // getApplicableAttributes
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- // This method must be overridden if your detector returns
- // tag names from getApplicableElements
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) {
- }
-
- @SuppressWarnings("javadoc")
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- // This method must be overridden if your detector returns
- // attribute names from getApplicableAttributes
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public Collection<String> getApplicableElements() {
- return null;
- }
-
- @Nullable
- @SuppressWarnings("javadoc")
- public Collection<String> getApplicableAttributes() {
- return null;
- }
-
- // ---- Dummy implementations to make implementing JavaScanner easier: ----
-
- @Nullable @SuppressWarnings("javadoc")
- public List<String> getApplicableMethodNames() {
- return null;
- }
-
- @Nullable @SuppressWarnings("javadoc")
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return null;
- }
-
- @Nullable @SuppressWarnings("javadoc")
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- }
-
- @SuppressWarnings("javadoc")
- public boolean appliesToResourceRefs() {
- return false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull Node node, @NonNull String type, @NonNull String name,
- boolean isFramework) {
- }
-
- // ---- Dummy implementations to make implementing a ClassScanner easier: ----
-
- @SuppressWarnings("javadoc")
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public List<String> getApplicableCallNames() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public List<String> getApplicableCallOwners() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public int[] getApplicableAsmNodeTypes() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull AbstractInsnNode instruction) {
- }
-
- // ---- Dummy implementations to make implementing an OtherFileScanner easier: ----
-
- public boolean appliesToFolder(@NonNull Scope scope, @Nullable ResourceFolderType folderType) {
- return false;
- }
-
- @NonNull
- public EnumSet<Scope> getApplicableFiles() {
- return Scope.OTHER_SCOPE;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Issue.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Issue.java
deleted file mode 100644
index ceca9ca..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Issue.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.Configuration;
-import com.android.tools.lint.client.api.IssueRegistry;
-import com.google.common.annotations.Beta;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.List;
-
-
-/**
- * An issue is a potential bug in an Android application. An issue is discovered
- * by a {@link Detector}, and has an associated {@link Severity}.
- * <p>
- * Issues and detectors are separate classes because a detector can discover
- * multiple different issues as it's analyzing code, and we want to be able to
- * different severities for different issues, the ability to suppress one but
- * not other issues from the same detector, and so on.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public final class Issue implements Comparable<Issue> {
- private static final String HTTP_PREFIX = "http://"; //$NON-NLS-1$
-
- private final String mId;
- private final String mDescription;
- private final String mExplanation;
- private final Category mCategory;
- private final int mPriority;
- private final Severity mSeverity;
- private String mMoreInfoUrl;
- private boolean mEnabledByDefault = true;
- private final EnumSet<Scope> mScope;
- private List<EnumSet<Scope>> mAnalysisScopes;
- private final Class<? extends Detector> mClass;
-
- // Use factory methods
- private Issue(
- @NonNull String id,
- @NonNull String description,
- @NonNull String explanation,
- @NonNull Category category,
- int priority,
- @NonNull Severity severity,
- @NonNull Class<? extends Detector> detectorClass,
- @NonNull EnumSet<Scope> scope) {
- super();
- mId = id;
- mDescription = description;
- mExplanation = explanation;
- mCategory = category;
- mPriority = priority;
- mSeverity = severity;
- mClass = detectorClass;
- mScope = scope;
- }
-
- /**
- * Creates a new issue
- *
- * @param id the fixed id of the issue
- * @param description the quick summary of the issue (one line)
- * @param explanation a full explanation of the issue, with suggestions for
- * how to fix it
- * @param category the associated category, if any
- * @param priority the priority, a number from 1 to 10 with 10 being most
- * important/severe
- * @param severity the default severity of the issue
- * @param detectorClass the class of the detector to find this issue
- * @param scope the scope of files required to analyze this issue
- * @return a new {@link Issue}
- */
- @NonNull
- public static Issue create(
- @NonNull String id,
- @NonNull String description,
- @NonNull String explanation,
- @NonNull Category category,
- int priority,
- @NonNull Severity severity,
- @NonNull Class<? extends Detector> detectorClass,
- @NonNull EnumSet<Scope> scope) {
- return new Issue(id, description, explanation, category, priority, severity,
- detectorClass, scope);
- }
-
- /**
- * Returns the unique id of this issue. These should not change over time
- * since they are used to persist the names of issues suppressed by the user
- * etc. It is typically a single camel-cased word.
- *
- * @return the associated fixed id, never null and always unique
- */
- @NonNull
- public String getId() {
- return mId;
- }
-
- /**
- * Briefly (one line) describes the kinds of checks performed by this rule
- *
- * @return a quick summary of the issue, never null
- */
- @NonNull
- public String getDescription() {
- return mDescription;
- }
-
- /**
- * Describes the error found by this rule, e.g.
- * "Buttons must define contentDescriptions". Preferably the explanation
- * should also contain a description of how the problem should be solved.
- * Additional info can be provided via {@link #getMoreInfo()}.
- * <p>
- * Note that the text may contain some simple markup, such as *'s around sentences
- * for bold text, and back quotes (`) for code fragments. You can obtain
- * the text without this markup by calling {@link #getExplanationAsSimpleText()},
- * and you can obtain the text as annotated HTML by calling
- * {@link #getExplanationAsHtml()}.
- *
- * @return an explanation of the issue, never null.
- */
- @NonNull
- public String getExplanation() {
- return mExplanation;
- }
-
- /**
- * Like {@link #getExplanation()}, but returns the text as properly escaped
- * and marked up HTML, where http URLs are linked, where words with asterisks
- * such as *this* are shown in bold, etc.
- *
- * @return the explanation of the issue, never null
- */
- @NonNull
- public String getExplanationAsHtml() {
- return convertMarkup(mExplanation, true /* html */);
- }
-
- /**
- * Like {@link #getExplanation()}, but returns the text as properly escaped
- * and marked up HTML, where http URLs are linked, where words with asterisks
- * such as *this* are shown in bold, etc.
- *
- * @return the explanation of the issue, never null
- */
- @NonNull
- public String getExplanationAsSimpleText() {
- return convertMarkup(mExplanation, false /* not html = text */);
- }
-
- /**
- * The primary category of the issue
- *
- * @return the primary category of the issue, never null
- */
- @NonNull
- public Category getCategory() {
- return mCategory;
- }
-
- /**
- * Returns a priority, in the range 1-10, with 10 being the most severe and
- * 1 the least
- *
- * @return a priority from 1 to 10
- */
- public int getPriority() {
- return mPriority;
- }
-
- /**
- * Returns the default severity of the issues found by this detector (some
- * tools may allow the user to specify custom severities for detectors).
- * <p>
- * Note that even though the normal way for an issue to be disabled is for
- * the {@link Configuration} to return {@link Severity#IGNORE}, there is a
- * {@link #isEnabledByDefault()} method which can be used to turn off issues
- * by default. This is done rather than just having the severity as the only
- * attribute on the issue such that an issue can be configured with an
- * appropriate severity (such as {@link Severity#ERROR}) even when issues
- * are disabled by default for example because they are experimental or not
- * yet stable.
- *
- * @return the severity of the issues found by this detector
- */
- @NonNull
- public Severity getDefaultSeverity() {
- return mSeverity;
- }
-
- /**
- * Returns a link (a URL string) to more information, or null
- *
- * @return a link to more information, or null
- */
- @Nullable
- public String getMoreInfo() {
- return mMoreInfoUrl;
- }
-
- /**
- * Returns whether this issue should be enabled by default, unless the user
- * has explicitly disabled it.
- *
- * @return true if this issue should be enabled by default
- */
- public boolean isEnabledByDefault() {
- return mEnabledByDefault;
- }
-
- /**
- * Returns the scope required to analyze the code to detect this issue.
- * This is determined by the detectors which reports the issue.
- *
- * @return the required scope
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mScope;
- }
-
- /**
- * Sorts the detectors alphabetically by id. This is intended to make it
- * convenient to store settings for detectors in a fixed order. It is not
- * intended as the order to be shown to the user; for that, a tool embedding
- * lint might consider the priorities, categories, severities etc of the
- * various detectors.
- *
- * @param other the {@link Issue} to compare this issue to
- */
- @Override
- public int compareTo(Issue other) {
- return getId().compareTo(other.getId());
- }
-
- /**
- * Sets a more info URL string
- *
- * @param moreInfoUrl url string
- * @return this, for constructor chaining
- */
- @NonNull
- public Issue setMoreInfo(@NonNull String moreInfoUrl) {
- mMoreInfoUrl = moreInfoUrl;
- return this;
- }
-
- /**
- * Sets whether this issue is enabled by default.
- *
- * @param enabledByDefault whether the issue should be enabled by default
- * @return this, for constructor chaining
- */
- @NonNull
- public Issue setEnabledByDefault(boolean enabledByDefault) {
- mEnabledByDefault = enabledByDefault;
- return this;
- }
-
- /**
- * Returns the sets of scopes required to analyze this issue, or null if all
- * scopes named by {@link Issue#getScope()} are necessary. Note that only
- * <b>one</b> match out of this collection is required, not all, and that
- * the scope set returned by {@link #getScope()} does not have to be returned
- * by this method, but is always implied to be included.
- * <p>
- * The scopes returned by {@link Issue#getScope()} list all the various
- * scopes that are <b>affected</b> by this issue, meaning the detector
- * should consider it. Frequently, the detector must analyze all these
- * scopes in order to properly decide whether an issue is found. For
- * example, the unused resource detector needs to consider both the XML
- * resource files and the Java source files in order to decide if a resource
- * is unused. If it analyzes just the Java files for example, it might
- * incorrectly conclude that a resource is unused because it did not
- * discover a resource reference in an XML file.
- * <p>
- * However, there are other issues where the issue can occur in a variety of
- * files, but the detector can consider each in isolation. For example, the
- * API checker is affected by both XML files and Java class files (detecting
- * both layout constructor references in XML layout files as well as code
- * references in .class files). It doesn't have to analyze both; it is
- * capable of incrementally analyzing just an XML file, or just a class
- * file, without considering the other.
- * <p>
- * The required scope list provides a list of scope sets that can be used to
- * analyze this issue. For each scope set, all the scopes must be matched by
- * the incremental analysis, but any one of the scope sets can be analyzed
- * in isolation.
- * <p>
- * The required scope list is not required to include the full scope set
- * returned by {@link #getScope()}; that set is always assumed to be
- * included.
- * <p>
- * NOTE: You would normally call {@link #isAdequate(EnumSet)} rather
- * than calling this method directly.
- *
- * @return a list of required scopes, or null.
- */
- @Nullable
- public Collection<EnumSet<Scope>> getAnalysisScopes() {
- return mAnalysisScopes;
- }
-
- /**
- * Sets the collection of scopes that are allowed to be analyzed independently.
- * See the {@link #getAnalysisScopes()} method for a full explanation.
- * Note that you usually want to just call {@link #addAnalysisScope(EnumSet)}
- * instead of constructing a list up front and passing it in here. This
- * method exists primarily such that commonly used share sets of analysis
- * scopes can be reused and set directly.
- *
- * @param required the collection of scopes
- * @return this, for constructor chaining
- */
- @NonNull
- public Issue setAnalysisScopes(@Nullable List<EnumSet<Scope>> required) {
- mAnalysisScopes = required;
-
- return this;
- }
-
- /**
- * Returns true if the given scope is adequate for analyzing this issue.
- * This looks through the analysis scopes (see
- * {@link #addAnalysisScope(EnumSet)}) and if the scope passed in fully
- * covers at least one of them, or if it covers the scope of the issue
- * itself (see {@link #getScope()}, which should be a superset of all the
- * analysis scopes) returns true.
- * <p>
- * The scope set returned by {@link Issue#getScope()} lists all the various
- * scopes that are <b>affected</b> by this issue, meaning the detector
- * should consider it. Frequently, the detector must analyze all these
- * scopes in order to properly decide whether an issue is found. For
- * example, the unused resource detector needs to consider both the XML
- * resource files and the Java source files in order to decide if a resource
- * is unused. If it analyzes just the Java files for example, it might
- * incorrectly conclude that a resource is unused because it did not
- * discover a resource reference in an XML file.
- * <p>
- * However, there are other issues where the issue can occur in a variety of
- * files, but the detector can consider each in isolation. For example, the
- * API checker is affected by both XML files and Java class files (detecting
- * both layout constructor references in XML layout files as well as code
- * references in .class files). It doesn't have to analyze both; it is
- * capable of incrementally analyzing just an XML file, or just a class
- * file, without considering the other.
- * <p>
- * An issue can register additional scope sets that can are adequate
- * for analyzing the issue, by calling {@link #addAnalysisScope(EnumSet)}.
- * This method returns true if the given scope matches one or more analysis
- * scope, or the overall scope.
- *
- * @param scope the scope available for analysis
- * @return true if this issue can be analyzed with the given available scope
- */
- public boolean isAdequate(@NonNull EnumSet<Scope> scope) {
- if (scope.containsAll(mScope)) {
- return true;
- }
-
- if (mAnalysisScopes != null) {
- for (EnumSet<Scope> analysisScope : mAnalysisScopes) {
- if (mScope.containsAll(analysisScope)) {
- return true;
- }
- }
- }
-
- if (this == IssueRegistry.LINT_ERROR || this == IssueRegistry.PARSER_ERROR) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Adds a scope set that can be analyzed independently to uncover this issue.
- * See the {@link #getAnalysisScopes()} method for a full explanation.
- * Note that the {@link #getScope()} does not have to be added here; it is
- * always considered an analysis scope.
- *
- * @param scope the additional scope which can analyze this issue independently
- * @return this, for constructor chaining
- */
- public Issue addAnalysisScope(@Nullable EnumSet<Scope> scope) {
- if (mAnalysisScopes == null) {
- mAnalysisScopes = new ArrayList<EnumSet<Scope>>(2);
- }
- mAnalysisScopes.add(scope);
-
- return this;
- }
-
- /**
- * Returns the class of the detector to use to find this issue
- *
- * @return the class of the detector to use to find this issue
- */
- @NonNull
- public Class<? extends Detector> getDetectorClass() {
- return mClass;
- }
-
- @Override
- public String toString() {
- return mId;
- }
-
- /**
- * Converts the given markup text to HTML or text, depending on the.
- * <p>
- * This will recognize the following formatting conventions:
- * <ul>
- * <li>HTTP urls (http://...)
- * <li>Sentences immediately surrounded by * will be shown as bold.
- * <li>Sentences immediately surrounded by ` will be shown using monospace
- * fonts
- * </ul>
- * Furthermore, newlines are converted to br's when converting newlines.
- * Note: It does not insert {@code <html>} tags around the fragment for HTML output.
- * <p>
- * TODO: Consider switching to the restructured text format -
- * http://docutils.sourceforge.net/docs/user/rst/quickstart.html
- *
- * @param text the text to be formatted
- * @param html whether to convert into HTML or text
- * @return the corresponding HTML or text properly formatted
- */
- @NonNull
- public static String convertMarkup(@NonNull String text, boolean html) {
- StringBuilder sb = new StringBuilder(3 * text.length() / 2);
-
- char prev = 0;
- int flushIndex = 0;
- int n = text.length();
- for (int i = 0; i < n; i++) {
- char c = text.charAt(i);
- if ((c == '*' || c == '`' && i < n - 1)) {
- // Scout ahead for range end
- if (!Character.isLetterOrDigit(prev)
- && !Character.isWhitespace(text.charAt(i + 1))) {
- // Found * or ~ immediately before a letter, and not in the middle of a word
- // Find end
- int end = text.indexOf(c, i + 1);
- if (end != -1 && (end == n - 1 || !Character.isLetter(text.charAt(end + 1)))) {
- if (i > flushIndex) {
- appendEscapedText(sb, text, html, flushIndex, i);
- }
- if (html) {
- String tag = c == '*' ? "b" : "code"; //$NON-NLS-1$ //$NON-NLS-2$
- sb.append('<').append(tag).append('>');
- appendEscapedText(sb, text, html, i + 1, end);
- sb.append('<').append('/').append(tag).append('>');
- } else {
- appendEscapedText(sb, text, html, i + 1, end);
- }
- flushIndex = end + 1;
- i = flushIndex - 1; // -1: account for the i++ in the loop
- }
- }
- } else if (html && c == 'h' && i < n - 1 && text.charAt(i + 1) == 't'
- && text.startsWith(HTTP_PREFIX, i) && !Character.isLetterOrDigit(prev)) {
- // Find url end
- int end = i + HTTP_PREFIX.length();
- while (end < n) {
- char d = text.charAt(end);
- if (Character.isWhitespace(d)) {
- break;
- }
- end++;
- }
- char last = text.charAt(end - 1);
- if (last == '.' || last == ')' || last == '!') {
- end--;
- }
- if (end > i + HTTP_PREFIX.length()) {
- if (i > flushIndex) {
- appendEscapedText(sb, text, html, flushIndex, i);
- }
-
- String url = text.substring(i, end);
- sb.append("<a href=\""); //$NON-NLS-1$
- sb.append(url);
- sb.append('"').append('>');
- sb.append(url);
- sb.append("</a>"); //$NON-NLS-1$
-
- flushIndex = end;
- i = flushIndex - 1; // -1: account for the i++ in the loop
- }
- }
- prev = c;
- }
-
- if (flushIndex < n) {
- appendEscapedText(sb, text, html, flushIndex, n);
- }
-
- return sb.toString();
- }
-
- private static void appendEscapedText(StringBuilder sb, String text, boolean html,
- int start, int end) {
- if (html) {
- for (int i = start; i < end; i++) {
- char c = text.charAt(i);
- if (c == '<') {
- sb.append("&lt;"); //$NON-NLS-1$
- } else if (c == '&') {
- sb.append("&amp;"); //$NON-NLS-1$
- } else if (c == '\n') {
- sb.append("<br/>\n");
- } else {
- if (c > 255) {
- sb.append("&#"); //$NON-NLS-1$
- sb.append(Integer.toString(c));
- sb.append(';');
- } else {
- sb.append(c);
- }
- }
- }
- } else {
- for (int i = start; i < end; i++) {
- char c = text.charAt(i);
- sb.append(c);
- }
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/JavaContext.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/JavaContext.java
deleted file mode 100644
index d91f423..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/JavaContext.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.IJavaParser;
-import com.android.tools.lint.client.api.LintDriver;
-
-import java.io.File;
-
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.Node;
-
-/**
- * A {@link Context} used when checking Java files.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-public class JavaContext extends Context {
- /** The parse tree */
- public Node compilationUnit;
- /** The parser which produced the parse tree */
- public IJavaParser parser;
-
- /**
- * Constructs a {@link JavaContext} for running lint on the given file, with
- * the given scope, in the given project reporting errors to the given
- * client.
- *
- * @param driver the driver running through the checks
- * @param project the project to run lint on which contains the given file
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file to be analyzed
- */
- public JavaContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file) {
- super(driver, project, main, file);
- }
-
- /**
- * Returns a location for the given node
- *
- * @param node the AST node to get a location for
- * @return a location for the given node
- */
- @NonNull
- public Location getLocation(@NonNull Node node) {
- if (parser != null) {
- return parser.getLocation(this, node);
- }
-
- return new Location(file, null, null);
- }
-
- @Override
- public void report(@NonNull Issue issue, @Nullable Location location,
- @NonNull String message, @Nullable Object data) {
- if (mDriver.isSuppressed(issue, compilationUnit)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-
- /**
- * Reports an issue applicable to a given AST node. The AST node is used as the
- * scope to check for suppress lint annotations.
- *
- * @param issue the issue to report
- * @param scope the AST node scope the error applies to. The lint infrastructure
- * will check whether there are suppress annotations on this node (or its enclosing
- * nodes) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Node scope,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (scope != null && mDriver.isSuppressed(issue, scope)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-
-
- @Nullable
- public static Node findSurroundingMethod(Node scope) {
- while (scope != null) {
- Class<? extends Node> type = scope.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == MethodDeclaration.class || type == ConstructorDeclaration.class) {
- return scope;
- }
-
- scope = scope.getParent();
- }
-
- return null;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LayoutDetector.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LayoutDetector.java
deleted file mode 100644
index b24c1a9..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LayoutDetector.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-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_PADDING;
-import static com.android.SdkConstants.ATTR_PADDING_BOTTOM;
-import static com.android.SdkConstants.ATTR_PADDING_LEFT;
-import static com.android.SdkConstants.ATTR_PADDING_RIGHT;
-import static com.android.SdkConstants.ATTR_PADDING_TOP;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Element;
-
-/**
- * Abstract class specifically intended for layout detectors which provides some
- * common utility methods shared by layout detectors.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class LayoutDetector extends ResourceXmlDetector {
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT;
- }
-
- private static boolean isFillParent(@NonNull Element element, @NonNull String dimension) {
- String width = element.getAttributeNS(ANDROID_URI, dimension);
- return width.equals(VALUE_MATCH_PARENT) || width.equals(VALUE_FILL_PARENT);
- }
-
- protected static boolean isWidthFillParent(@NonNull Element element) {
- return isFillParent(element, ATTR_LAYOUT_WIDTH);
- }
-
- protected static boolean isHeightFillParent(@NonNull Element element) {
- return isFillParent(element, ATTR_LAYOUT_HEIGHT);
- }
-
- protected boolean hasPadding(@NonNull Element root) {
- return root.hasAttributeNS(ANDROID_URI, ATTR_PADDING)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_LEFT)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_RIGHT)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_TOP)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_BOTTOM);
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java
deleted file mode 100644
index 9dec569..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/LintUtils.java
+++ /dev/null
@@ -1,798 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.BIN_FOLDER;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.utils.PositionXmlParser;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-
-import lombok.ast.ImportDeclaration;
-
-
-/**
- * Useful utility methods related to lint.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class LintUtils {
- // Utility class, do not instantiate
- private LintUtils() {
- }
-
- /**
- * Format a list of strings, and cut of the list at {@code maxItems} if the
- * number of items are greater.
- *
- * @param strings the list of strings to print out as a comma separated list
- * @param maxItems the maximum number of items to print
- * @return a comma separated list
- */
- @NonNull
- public static String formatList(@NonNull List<String> strings, int maxItems) {
- StringBuilder sb = new StringBuilder(20 * strings.size());
-
- for (int i = 0, n = strings.size(); i < n; i++) {
- if (sb.length() > 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(strings.get(i));
-
- if (maxItems > 0 && i == maxItems - 1 && n > maxItems) {
- sb.append(String.format("... (%1$d more)", n - i - 1));
- break;
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Determine if the given type corresponds to a resource that has a unique
- * file
- *
- * @param type the resource type to check
- * @return true if the given type corresponds to a file-type resource
- */
- public static boolean isFileBasedResourceType(@NonNull ResourceType type) {
- List<ResourceFolderType> folderTypes = FolderTypeRelationship.getRelatedFolders(type);
- for (ResourceFolderType folderType : folderTypes) {
- if (folderType != ResourceFolderType.VALUES) {
- if (type == ResourceType.ID) {
- return false;
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if the given file represents an XML file
- *
- * @param file the file to be checked
- * @return true if the given file is an xml file
- */
- public static boolean isXmlFile(@NonNull File file) {
- String string = file.getName();
- return string.regionMatches(true, string.length() - DOT_XML.length(),
- DOT_XML, 0, DOT_XML.length());
- }
-
- /**
- * Case insensitive ends with
- *
- * @param string the string to be tested whether it ends with the given
- * suffix
- * @param suffix the suffix to check
- * @return true if {@code string} ends with {@code suffix},
- * case-insensitively.
- */
- public static boolean endsWith(@NonNull String string, @NonNull String suffix) {
- return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
- suffix, 0, suffix.length());
- }
-
- /**
- * Case insensitive starts with
- *
- * @param string the string to be tested whether it starts with the given prefix
- * @param prefix the prefix to check
- * @param offset the offset to start checking with
- * @return true if {@code string} starts with {@code prefix},
- * case-insensitively.
- */
- public static boolean startsWith(@NonNull String string, @NonNull String prefix, int offset) {
- return string.regionMatches(true /* ignoreCase */, offset, prefix, 0, prefix.length());
- }
-
- /**
- * Returns the basename of the given filename, unless it's a dot-file such as ".svn".
- *
- * @param fileName the file name to extract the basename from
- * @return the basename (the filename without the file extension)
- */
- public static String getBaseName(@NonNull String fileName) {
- int extension = fileName.indexOf('.');
- if (extension > 0) {
- return fileName.substring(0, extension);
- } else {
- return fileName;
- }
- }
-
- /**
- * Returns the children elements of the given node
- *
- * @param node the parent node
- * @return a list of element children, never null
- */
- @NonNull
- public static List<Element> getChildren(@NonNull Node node) {
- NodeList childNodes = node.getChildNodes();
- List<Element> children = new ArrayList<Element>(childNodes.getLength());
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- children.add((Element) child);
- }
- }
-
- return children;
- }
-
- /**
- * Returns the <b>number</b> of children of the given node
- *
- * @param node the parent node
- * @return the count of element children
- */
- public static int getChildCount(@NonNull Node node) {
- NodeList childNodes = node.getChildNodes();
- int childCount = 0;
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- childCount++;
- }
- }
-
- return childCount;
- }
-
- /**
- * Returns true if the given element is the root element of its document
- *
- * @param element the element to test
- * @return true if the element is the root element
- */
- public static boolean isRootElement(Element element) {
- return element == element.getOwnerDocument().getDocumentElement();
- }
-
- /**
- * Returns the given id without an {@code @id/} or {@code @+id} prefix
- *
- * @param id the id to strip
- * @return the stripped id, never null
- */
- @NonNull
- public static String stripIdPrefix(@Nullable String id) {
- if (id == null) {
- return "";
- } else if (id.startsWith(NEW_ID_PREFIX)) {
- return id.substring(NEW_ID_PREFIX.length());
- } else if (id.startsWith(ID_PREFIX)) {
- return id.substring(ID_PREFIX.length());
- }
-
- return id;
- }
-
- /**
- * Returns true if the given two id references match. This is similar to
- * String equality, but it also considers "{@code @+id/foo == @id/foo}.
- *
- * @param id1 the first id to compare
- * @param id2 the second id to compare
- * @return true if the two id references refer to the same id
- */
- public static boolean idReferencesMatch(String id1, String id2) {
- if (id1.startsWith(NEW_ID_PREFIX)) {
- if (id2.startsWith(NEW_ID_PREFIX)) {
- return id1.equals(id2);
- } else {
- assert id2.startsWith(ID_PREFIX);
- return ((id1.length() - id2.length())
- == (NEW_ID_PREFIX.length() - ID_PREFIX.length()))
- && id1.regionMatches(NEW_ID_PREFIX.length(), id2,
- ID_PREFIX.length(),
- id2.length() - ID_PREFIX.length());
- }
- } else {
- assert id1.startsWith(ID_PREFIX);
- if (id2.startsWith(ID_PREFIX)) {
- return id1.equals(id2);
- } else {
- assert id2.startsWith(NEW_ID_PREFIX);
- return (id2.length() - id1.length()
- == (NEW_ID_PREFIX.length() - ID_PREFIX.length()))
- && id2.regionMatches(NEW_ID_PREFIX.length(), id1,
- ID_PREFIX.length(),
- id1.length() - ID_PREFIX.length());
- }
- }
- }
-
- /**
- * Computes the edit distance (number of insertions, deletions or substitutions
- * to edit one string into the other) between two strings. In particular,
- * this will compute the Levenshtein distance.
- * <p>
- * See http://en.wikipedia.org/wiki/Levenshtein_distance for details.
- *
- * @param s the first string to compare
- * @param t the second string to compare
- * @return the edit distance between the two strings
- */
- public static int editDistance(@NonNull String s, @NonNull String t) {
- int m = s.length();
- int n = t.length();
- int[][] d = new int[m + 1][n + 1];
- for (int i = 0; i <= m; i++) {
- d[i][0] = i;
- }
- for (int j = 0; j <= n; j++) {
- d[0][j] = j;
- }
- for (int j = 1; j <= n; j++) {
- for (int i = 1; i <= m; i++) {
- if (s.charAt(i - 1) == t.charAt(j - 1)) {
- d[i][j] = d[i - 1][j - 1];
- } else {
- int deletion = d[i - 1][j] + 1;
- int insertion = d[i][j - 1] + 1;
- int substitution = d[i - 1][j - 1] + 1;
- d[i][j] = Math.min(deletion, Math.min(insertion, substitution));
- }
- }
- }
-
- return d[m][n];
- }
-
- /**
- * Returns true if assertions are enabled
- *
- * @return true if assertions are enabled
- */
- @SuppressWarnings("all")
- public static boolean assertionsEnabled() {
- boolean assertionsEnabled = false;
- assert assertionsEnabled = true; // Intentional side-effect
- return assertionsEnabled;
- }
-
- /**
- * Returns the layout resource name for the given layout file
- *
- * @param layoutFile the file pointing to the layout
- * @return the layout resource name, not including the {@code @layout}
- * prefix
- */
- public static String getLayoutName(File layoutFile) {
- String name = layoutFile.getName();
- int dotIndex = name.indexOf('.');
- if (dotIndex != -1) {
- name = name.substring(0, dotIndex);
- }
- return name;
- }
-
- /**
- * Splits the given path into its individual parts, attempting to be
- * tolerant about path separators (: or ;). It can handle possibly ambiguous
- * paths, such as {@code c:\foo\bar:\other}, though of course these are to
- * be avoided if possible.
- *
- * @param path the path variable to split, which can use both : and ; as
- * path separators.
- * @return the individual path components as an Iterable of strings
- */
- public static Iterable<String> splitPath(String path) {
- if (path.indexOf(';') != -1) {
- return Splitter.on(';').omitEmptyStrings().trimResults().split(path);
- }
-
- List<String> combined = new ArrayList<String>();
- Iterables.addAll(combined, Splitter.on(':').omitEmptyStrings().trimResults().split(path));
- for (int i = 0, n = combined.size(); i < n; i++) {
- String p = combined.get(i);
- if (p.length() == 1 && i < n - 1 && Character.isLetter(p.charAt(0))
- // Technically, Windows paths do not have to have a \ after the :,
- // which means it would be using the current directory on that drive,
- // but that's unlikely to be the case in a path since it would have
- // unpredictable results
- && !combined.get(i+1).isEmpty() && combined.get(i+1).charAt(0) == '\\') {
- combined.set(i, p + ':' + combined.get(i+1));
- combined.remove(i+1);
- n--;
- continue;
- }
- }
-
- return combined;
- }
-
- /**
- * Computes the shared parent among a set of files (which may be null).
- *
- * @param files the set of files to be checked
- * @return the closest common ancestor file, or null if none was found
- */
- @Nullable
- public static File getCommonParent(@NonNull List<File> files) {
- int fileCount = files.size();
- if (fileCount == 0) {
- return null;
- } else if (fileCount == 1) {
- return files.get(0);
- } else if (fileCount == 2) {
- return getCommonParent(files.get(0), files.get(1));
- } else {
- File common = files.get(0);
- for (int i = 1; i < fileCount; i++) {
- common = getCommonParent(common, files.get(i));
- if (common == null) {
- return null;
- }
- }
-
- return common;
- }
- }
-
- /**
- * Computes the closest common parent path between two files.
- *
- * @param file1 the first file to be compared
- * @param file2 the second file to be compared
- * @return the closest common ancestor file, or null if the two files have
- * no common parent
- */
- @Nullable
- public static File getCommonParent(@NonNull File file1, @NonNull File file2) {
- if (file1.equals(file2)) {
- return file1;
- } else if (file1.getPath().startsWith(file2.getPath())) {
- return file2;
- } else if (file2.getPath().startsWith(file1.getPath())) {
- return file1;
- } else {
- // Dumb and simple implementation
- File first = file1.getParentFile();
- while (first != null) {
- File second = file2.getParentFile();
- while (second != null) {
- if (first.equals(second)) {
- return first;
- }
- second = second.getParentFile();
- }
-
- first = first.getParentFile();
- }
- }
- return null;
- }
-
- private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
- private static final String UTF_16 = "UTF_16"; //$NON-NLS-1$
- private static final String UTF_16LE = "UTF_16LE"; //$NON-NLS-1$
-
- /**
- * Returns the encoded String for the given file. This is usually the
- * same as {@code Files.toString(file, Charsets.UTF8}, but if there's a UTF byte order mark
- * (for UTF8, UTF_16 or UTF_16LE), use that instead.
- *
- * @param client the client to use for I/O operations
- * @param file the file to read from
- * @return the string
- * @throws IOException if the file cannot be read properly
- */
- @NonNull
- public static String getEncodedString(
- @NonNull LintClient client,
- @NonNull File file) throws IOException {
- byte[] bytes = client.readBytes(file);
- if (endsWith(file.getName(), DOT_XML)) {
- return PositionXmlParser.getXmlString(bytes);
- }
-
- return getEncodedString(bytes);
- }
-
- /**
- * Returns the String corresponding to the given data. This is usually the
- * same as {@code new String(data)}, but if there's a UTF byte order mark
- * (for UTF8, UTF_16 or UTF_16LE), use that instead.
- * <p>
- * NOTE: For XML files, there is the additional complication that there
- * could be a {@code encoding=} attribute in the prologue. For those files,
- * use {@link PositionXmlParser#getXmlString(byte[])} instead.
- *
- * @param data the byte array to construct the string from
- * @return the string
- */
- @NonNull
- public static String getEncodedString(@Nullable byte[] data) {
- if (data == null) {
- return "";
- }
-
- int offset = 0;
- String defaultCharset = UTF_8;
- String charset = null;
- // Look for the byte order mark, to see if we need to remove bytes from
- // the input stream (and to determine whether files are big endian or little endian) etc
- // for files which do not specify the encoding.
- // See http://unicode.org/faq/utf_bom.html#BOM for more.
- if (data.length > 4) {
- if (data[0] == (byte)0xef && data[1] == (byte)0xbb && data[2] == (byte)0xbf) {
- // UTF-8
- defaultCharset = charset = UTF_8;
- offset += 3;
- } else if (data[0] == (byte)0xfe && data[1] == (byte)0xff) {
- // UTF-16, big-endian
- defaultCharset = charset = UTF_16;
- offset += 2;
- } else if (data[0] == (byte)0x0 && data[1] == (byte)0x0
- && data[2] == (byte)0xfe && data[3] == (byte)0xff) {
- // UTF-32, big-endian
- defaultCharset = charset = "UTF_32"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe
- && data[2] == (byte)0x0 && data[3] == (byte)0x0) {
- // UTF-32, little-endian. We must check for this *before* looking for
- // UTF_16LE since UTF_32LE has the same prefix!
- defaultCharset = charset = "UTF_32LE"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe) {
- // UTF-16, little-endian
- defaultCharset = charset = UTF_16LE;
- offset += 2;
- }
- }
- int length = data.length - offset;
-
- // Guess encoding by searching for an encoding= entry in the first line.
- boolean seenOddZero = false;
- boolean seenEvenZero = false;
- for (int lineEnd = offset; lineEnd < data.length; lineEnd++) {
- if (data[lineEnd] == 0) {
- if ((lineEnd - offset) % 2 == 0) {
- seenEvenZero = true;
- } else {
- seenOddZero = true;
- }
- } else if (data[lineEnd] == '\n' || data[lineEnd] == '\r') {
- break;
- }
- }
-
- if (charset == null) {
- charset = seenOddZero ? UTF_16LE : seenEvenZero ? UTF_16 : UTF_8;
- }
-
- String text = null;
- try {
- text = new String(data, offset, length, charset);
- } catch (UnsupportedEncodingException e) {
- try {
- if (charset != defaultCharset) {
- text = new String(data, offset, length, defaultCharset);
- }
- } catch (UnsupportedEncodingException u) {
- // Just use the default encoding below
- }
- }
- if (text == null) {
- text = new String(data, offset, length);
- }
- return text;
- }
-
- /**
- * Returns true if the given class node represents a static inner class.
- *
- * @param classNode the inner class to be checked
- * @return true if the class node represents an inner class that is static
- */
- public static boolean isStaticInnerClass(@NonNull ClassNode classNode) {
- // Note: We can't just filter out static inner classes like this:
- // (classNode.access & Opcodes.ACC_STATIC) != 0
- // because the static flag only appears on methods and fields in the class
- // file. Instead, look for the synthetic this pointer.
-
- @SuppressWarnings("rawtypes") // ASM API
- List fieldList = classNode.fields;
- for (Object f : fieldList) {
- FieldNode field = (FieldNode) f;
- if (field.name.startsWith("this$") && (field.access & Opcodes.ACC_SYNTHETIC) != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the previous opcode prior to the given node, ignoring label and
- * line number nodes
- *
- * @param node the node to look up the previous opcode for
- * @return the previous opcode, or {@link Opcodes#NOP} if no previous node
- * was found
- */
- public static int getPrevOpcode(@NonNull AbstractInsnNode node) {
- AbstractInsnNode prev = getPrevInstruction(node);
- if (prev != null) {
- return prev.getOpcode();
- } else {
- return Opcodes.NOP;
- }
- }
-
- /**
- * Returns the previous instruction prior to the given node, ignoring label
- * and line number nodes.
- *
- * @param node the node to look up the previous instruction for
- * @return the previous instruction, or null if no previous node was found
- */
- @Nullable
- public static AbstractInsnNode getPrevInstruction(@NonNull AbstractInsnNode node) {
- AbstractInsnNode prev = node;
- while (true) {
- prev = prev.getPrevious();
- if (prev == null) {
- return null;
- } else {
- int type = prev.getType();
- if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL
- && type != AbstractInsnNode.FRAME) {
- return prev;
- }
- }
- }
- }
-
- /**
- * Returns the next opcode after to the given node, ignoring label and line
- * number nodes
- *
- * @param node the node to look up the next opcode for
- * @return the next opcode, or {@link Opcodes#NOP} if no next node was found
- */
- public static int getNextOpcode(@NonNull AbstractInsnNode node) {
- AbstractInsnNode next = getNextInstruction(node);
- if (next != null) {
- return next.getOpcode();
- } else {
- return Opcodes.NOP;
- }
- }
-
- /**
- * Returns the next instruction after to the given node, ignoring label and
- * line number nodes.
- *
- * @param node the node to look up the next node for
- * @return the next instruction, or null if no next node was found
- */
- @Nullable
- public static AbstractInsnNode getNextInstruction(@NonNull AbstractInsnNode node) {
- AbstractInsnNode next = node;
- while (true) {
- next = next.getNext();
- if (next == null) {
- return null;
- } else {
- int type = next.getType();
- if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL
- && type != AbstractInsnNode.FRAME) {
- return next;
- }
- }
- }
- }
-
- /**
- * Returns true if the given directory represents an Android project
- * directory. Note: This doesn't necessarily mean it's an Eclipse directory,
- * only that it looks like it contains a logical Android project -- one
- * including a manifest file, a resource folder, etc.
- *
- * @param dir the directory to check
- * @return true if the directory looks like an Android project
- */
- public static boolean isProjectDir(@NonNull File dir) {
- boolean hasManifest = new File(dir, ANDROID_MANIFEST_XML).exists();
- if (hasManifest) {
- // Special case: the bin/ folder can also contain a copy of the
- // manifest file, but this is *not* a project directory
- if (dir.getName().equals(BIN_FOLDER)) {
- // ...unless of course it just *happens* to be a project named bin, in
- // which case we peek at its parent to see if this is the case
- dir = dir.getParentFile();
- if (dir != null && isProjectDir(dir)) {
- // Yes, it's a bin/ directory inside a real project: ignore this dir
- return false;
- }
- }
- } else if (Project.isAospFrameworksProject(dir)) {
- // Hardcoded AOSP support for the frameworks project
- return true;
- }
-
- return hasManifest;
- }
-
- /**
- * Look up the locale and region from the given parent folder name and
- * return it as a combined string, such as "en", "en-rUS", etc, or null if
- * no language is specified.
- *
- * @param folderName the folder name
- * @return the locale+region string or null
- */
- @Nullable
- public static String getLocaleAndRegion(@NonNull String folderName) {
- if (folderName.equals("values")) { //$NON-NLS-1$
- return null;
- }
-
- String locale = null;
-
- for (String qualifier : Splitter.on('-').split(folderName)) {
- int qualifierLength = qualifier.length();
- if (qualifierLength == 2) {
- char first = qualifier.charAt(0);
- char second = qualifier.charAt(1);
- if (first >= 'a' && first <= 'z' && second >= 'a' && second <= 'z') {
- locale = qualifier;
- }
- } else if (qualifierLength == 3 && qualifier.charAt(0) == 'r' && locale != null) {
- char first = qualifier.charAt(1);
- char second = qualifier.charAt(2);
- if (first >= 'A' && first <= 'Z' && second >= 'A' && second <= 'Z') {
- return locale + '-' + qualifier;
- }
- break;
- }
- }
-
- return locale;
- }
-
- /**
- * Returns true if the given class (specified by a fully qualified class
- * name) name is imported in the given compilation unit either through a fully qualified
- * import or by a wildcard import.
- *
- * @param compilationUnit the compilation unit
- * @param fullyQualifiedName the fully qualified class name
- * @return true if the given imported name refers to the given fully
- * qualified name
- */
- public static boolean isImported(
- @NonNull lombok.ast.Node compilationUnit,
- @NonNull String fullyQualifiedName) {
- int dotIndex = fullyQualifiedName.lastIndexOf('.');
- int dotLength = fullyQualifiedName.length() - dotIndex;
-
- boolean imported = false;
- for (lombok.ast.Node rootNode : compilationUnit.getChildren()) {
- if (rootNode instanceof ImportDeclaration) {
- ImportDeclaration importDeclaration = (ImportDeclaration) rootNode;
- String fqn = importDeclaration.asFullyQualifiedName();
- if (fqn.equals(fullyQualifiedName)) {
- return true;
- } else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
- fqn.length() - dotLength, dotLength)) {
- // This import is importing the class name using some other prefix, so there
- // fully qualified class name cannot be imported under that name
- return false;
- } else if (importDeclaration.astStarImport()
- && fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
- imported = true;
- // but don't break -- keep searching in case there's a non-wildcard
- // import of the specific class name, e.g. if we're looking for
- // android.content.SharedPreferences.Editor, don't match on the following:
- // import android.content.SharedPreferences.*;
- // import foo.bar.Editor;
- }
- }
- }
-
- return imported;
- }
-
- /**
- * Returns the applicable build code (for
- * {@code android.os.Build.VERSION_CODES}) for the corresponding API level,
- * or null if it's unknown.
- *
- * @param api the API level to look up a version code for
- * @return the corresponding build code field name, or null
- */
- @Nullable
- public static String getBuildCode(int api) {
- // See http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
- switch (api) {
- case 1: return "BASE"; //$NON-NLS-1$
- case 2: return "BASE_1_1"; //$NON-NLS-1$
- case 3: return "CUPCAKE"; //$NON-NLS-1$
- case 4: return "DONUT"; //$NON-NLS-1$
- case 5: return "ECLAIR"; //$NON-NLS-1$
- case 6: return "ECLAIR_0_1"; //$NON-NLS-1$
- case 7: return "ECLAIR_MR1"; //$NON-NLS-1$
- case 8: return "FROYO"; //$NON-NLS-1$
- case 9: return "GINGERBREAD"; //$NON-NLS-1$
- case 10: return "GINGERBREAD_MR1"; //$NON-NLS-1$
- case 11: return "HONEYCOMB"; //$NON-NLS-1$
- case 12: return "HONEYCOMB_MR1"; //$NON-NLS-1$
- case 13: return "HONEYCOMB_MR2"; //$NON-NLS-1$
- case 14: return "ICE_CREAM_SANDWICH"; //$NON-NLS-1$
- case 15: return "ICE_CREAM_SANDWICH_MR1"; //$NON-NLS-1$
- case 16: return "JELLY_BEAN"; //$NON-NLS-1$
- case 17: return "JELLY_BEAN_MR1"; //$NON-NLS-1$
- // If you add more versions here, also update AdtUtils#getAndroidName and
- // SdkConstants#HIGHEST_KNOWN_API
- }
-
- return null;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Location.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Location.java
deleted file mode 100644
index 34116d0..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Location.java
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-
-/**
- * Location information for a warning
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class Location {
- private static final String SUPER_KEYWORD = "super"; //$NON-NLS-1$
-
- private final File mFile;
- private final Position mStart;
- private final Position mEnd;
- private String mMessage;
- private Location mSecondary;
- private Object mClientData;
-
- /**
- * (Private constructor, use one of the factory methods
- * {@link Location#create(File)},
- * {@link Location#create(File, Position, Position)}, or
- * {@link Location#create(File, String, int, int)}.
- * <p>
- * Constructs a new location range for the given file, from start to end. If
- * the length of the range is not known, end may be null.
- *
- * @param file the associated file (but see the documentation for
- * {@link #getFile()} for more information on what the file
- * represents)
- * @param start the starting position, or null
- * @param end the ending position, or null
- */
- protected Location(@NonNull File file, @Nullable Position start, @Nullable Position end) {
- super();
- mFile = file;
- mStart = start;
- mEnd = end;
- }
-
- /**
- * Returns the file containing the warning. Note that the file *itself* may
- * not yet contain the error. When editing a file in the IDE for example,
- * the tool could generate warnings in the background even before the
- * document is saved. However, the file is used as a identifying token for
- * the document being edited, and the IDE integration can map this back to
- * error locations in the editor source code.
- *
- * @return the file handle for the location
- */
- @NonNull
- public File getFile() {
- return mFile;
- }
-
- /**
- * The start position of the range
- *
- * @return the start position of the range, or null
- */
- @Nullable
- public Position getStart() {
- return mStart;
- }
-
- /**
- * The end position of the range
- *
- * @return the start position of the range, may be null for an empty range
- */
- @Nullable
- public Position getEnd() {
- return mEnd;
- }
-
- /**
- * Returns a secondary location associated with this location (if
- * applicable), or null.
- *
- * @return a secondary location or null
- */
- @Nullable
- public Location getSecondary() {
- return mSecondary;
- }
-
- /**
- * Sets a secondary location for this location.
- *
- * @param secondary a secondary location associated with this location
- */
- public void setSecondary(@Nullable Location secondary) {
- mSecondary = secondary;
- }
-
- /**
- * Sets a custom message for this location. This is typically used for
- * secondary locations, to describe the significance of this alternate
- * location. For example, for a duplicate id warning, the primary location
- * might say "This is a duplicate id", pointing to the second occurrence of
- * id declaration, and then the secondary location could point to the
- * original declaration with the custom message "Originally defined here".
- *
- * @param message the message to apply to this location
- */
- public void setMessage(@NonNull String message) {
- mMessage = message;
- }
-
- /**
- * Returns the custom message for this location, if any. This is typically
- * used for secondary locations, to describe the significance of this
- * alternate location. For example, for a duplicate id warning, the primary
- * location might say "This is a duplicate id", pointing to the second
- * occurrence of id declaration, and then the secondary location could point
- * to the original declaration with the custom message
- * "Originally defined here".
- *
- * @return the custom message for this location, or null
- */
- @Nullable
- public String getMessage() {
- return mMessage;
- }
-
- /**
- * Sets the client data associated with this location. This is an optional
- * field which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @param clientData the data to store with this location
- */
- public void setClientData(@Nullable Object clientData) {
- mClientData = clientData;
- }
-
- /**
- * Returns the client data associated with this location - an optional field
- * which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @return the data associated with this location
- */
- @Nullable
- public Object getClientData() {
- return mClientData;
- }
-
- @Override
- public String toString() {
- return "Location [file=" + mFile + ", start=" + mStart + ", end=" + mEnd + ", message="
- + mMessage + ']';
- }
-
- /**
- * Creates a new location for the given file
- *
- * @param file the file to create a location for
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file) {
- return new Location(file, null /*start*/, null /*end*/);
- }
-
- /**
- * Creates a new location for the given file and starting and ending
- * positions.
- *
- * @param file the file containing the positions
- * @param start the starting position
- * @param end the ending position
- * @return a new location
- */
- @NonNull
- public static Location create(
- @NonNull File file,
- @NonNull Position start,
- @Nullable Position end) {
- return new Location(file, start, end);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given offset range.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param startOffset the starting offset
- * @param endOffset the ending offset
- * @return a new location
- */
- @NonNull
- public static Location create(
- @NonNull File file,
- @Nullable String contents,
- int startOffset,
- int endOffset) {
- if (startOffset < 0 || endOffset < startOffset) {
- throw new IllegalArgumentException("Invalid offsets");
- }
-
- if (contents == null) {
- return new Location(file,
- new DefaultPosition(-1, -1, startOffset),
- new DefaultPosition(-1, -1, endOffset));
- }
-
- int size = contents.length();
- endOffset = Math.min(endOffset, size);
- startOffset = Math.min(startOffset, endOffset);
- Position start = null;
- int line = 0;
- int lineOffset = 0;
- char prev = 0;
- for (int offset = 0; offset <= size; offset++) {
- if (offset == startOffset) {
- start = new DefaultPosition(line, offset - lineOffset, offset);
- }
- if (offset == endOffset) {
- Position end = new DefaultPosition(line, offset - lineOffset, offset);
- return new Location(file, start, end);
- }
- char c = contents.charAt(offset);
- if (c == '\n') {
- lineOffset = offset + 1;
- if (prev != '\r') {
- line++;
- }
- } else if (c == '\r') {
- line++;
- lineOffset = offset + 1;
- }
- prev = c;
- }
- return create(file);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given line number.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param line the line number (0-based) for the position
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file, @NonNull String contents, int line) {
- return create(file, contents, line, null, null, null);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given line number.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param line the line number (0-based) for the position
- * @param patternStart an optional pattern to search for from the line
- * match; if found, adjust the column and offsets to begin at the
- * pattern start
- * @param patternEnd an optional pattern to search for behind the start
- * pattern; if found, adjust the end offset to match the end of
- * the pattern
- * @param hints optional additional information regarding the pattern search
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file, @NonNull String contents, int line,
- @Nullable String patternStart, @Nullable String patternEnd,
- @Nullable SearchHints hints) {
- int currentLine = 0;
- int offset = 0;
- while (currentLine < line) {
- offset = contents.indexOf('\n', offset);
- if (offset == -1) {
- return create(file);
- }
- currentLine++;
- offset++;
- }
-
- if (line == currentLine) {
- if (patternStart != null) {
- SearchDirection direction = SearchDirection.NEAREST;
- if (hints != null) {
- direction = hints.mDirection;
- }
-
- int index;
- if (direction == SearchDirection.BACKWARD) {
- index = findPreviousMatch(contents, offset, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else if (direction == SearchDirection.EOL_BACKWARD) {
- int lineEnd = contents.indexOf('\n', offset);
- if (lineEnd == -1) {
- lineEnd = contents.length();
- }
-
- index = findPreviousMatch(contents, lineEnd, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else if (direction == SearchDirection.FORWARD) {
- index = findNextMatch(contents, offset, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else {
- assert direction == SearchDirection.NEAREST;
-
- int before = findPreviousMatch(contents, offset, patternStart, hints);
- int after = findNextMatch(contents, offset, patternStart, hints);
-
- if (before == -1) {
- index = after;
- line = adjustLine(contents, line, offset, index);
- } else if (after == -1) {
- index = before;
- line = adjustLine(contents, line, offset, index);
- } else if (offset - before < after - offset) {
- index = before;
- line = adjustLine(contents, line, offset, index);
- } else {
- index = after;
- line = adjustLine(contents, line, offset, index);
- }
- }
-
- if (index != -1) {
- int lineStart = contents.lastIndexOf('\n', index);
- if (lineStart == -1) {
- lineStart = 0;
- } else {
- lineStart++; // was pointing to the previous line's CR, not line start
- }
- int column = index - lineStart;
- if (patternEnd != null) {
- int end = contents.indexOf(patternEnd, offset + patternStart.length());
- if (end != -1) {
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, -1, end + patternEnd.length()));
- }
- } else if (hints != null && (hints.isJavaSymbol() || hints.isWholeWord())) {
- if (hints.isConstructor() && contents.startsWith(SUPER_KEYWORD, index)) {
- patternStart = SUPER_KEYWORD;
- }
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, column + patternStart.length(),
- index + patternStart.length()));
- }
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, column, index + patternStart.length()));
- }
- }
-
- Position position = new DefaultPosition(line, -1, offset);
- return new Location(file, position, position);
- }
-
- return create(file);
- }
-
- private static int findPreviousMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- while (true) {
- int index = contents.lastIndexOf(pattern, offset);
- if (index == -1) {
- return -1;
- } else {
- if (isMatch(contents, index, pattern, hints)) {
- return index;
- } else {
- offset = index - pattern.length();
- }
- }
- }
- }
-
- private static int findNextMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- int constructorIndex = -1;
- if (hints != null && hints.isConstructor()) {
- // Special condition: See if the call is referenced as "super" instead.
- assert hints.isWholeWord();
- int index = contents.indexOf(SUPER_KEYWORD, offset);
- if (index != -1 && isMatch(contents, index, SUPER_KEYWORD, hints)) {
- constructorIndex = index;
- }
- }
-
- while (true) {
- int index = contents.indexOf(pattern, offset);
- if (index == -1) {
- return constructorIndex;
- } else {
- if (isMatch(contents, index, pattern, hints)) {
- if (constructorIndex != -1) {
- return Math.min(constructorIndex, index);
- }
- return index;
- } else {
- offset = index + pattern.length();
- }
- }
- }
- }
-
- private static boolean isMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- if (!contents.startsWith(pattern, offset)) {
- return false;
- }
-
- if (hints != null) {
- char prevChar = offset > 0 ? contents.charAt(offset - 1) : 0;
- int lastIndex = offset + pattern.length() - 1;
- char nextChar = lastIndex < contents.length() - 1 ? contents.charAt(lastIndex + 1) : 0;
-
- if (hints.isWholeWord() && (Character.isLetter(prevChar)
- || Character.isLetter(nextChar))) {
- return false;
-
- }
-
- if (hints.isJavaSymbol()) {
- if (Character.isJavaIdentifierPart(prevChar)
- || Character.isJavaIdentifierPart(nextChar)) {
- return false;
- }
-
- if (prevChar == '"') {
- return false;
- }
-
- // TODO: Additional validation to see if we're in a comment, string, etc.
- // This will require lexing from the beginning of the buffer.
- }
-
- if (hints.isConstructor() && SUPER_KEYWORD.equals(pattern)) {
- // Only looking for super(), not super.x, so assert that the next
- // non-space character is (
- int index = lastIndex + 1;
- while (index < contents.length() - 1) {
- char c = contents.charAt(index);
- if (c == '(') {
- break;
- } else if (!Character.isWhitespace(c)) {
- return false;
- }
- index++;
- }
- }
- }
-
- return true;
- }
-
- private static int adjustLine(String doc, int line, int offset, int newOffset) {
- if (newOffset == -1) {
- return line;
- }
-
- if (newOffset < offset) {
- return line - countLines(doc, newOffset, offset);
- } else {
- return line + countLines(doc, offset, newOffset);
- }
- }
-
- private static int countLines(String doc, int start, int end) {
- int lines = 0;
- for (int offset = start; offset < end; offset++) {
- char c = doc.charAt(offset);
- if (c == '\n') {
- lines++;
- }
- }
-
- return lines;
- }
-
- /**
- * Reverses the secondary location list initiated by the given location
- *
- * @param location the first location in the list
- * @return the first location in the reversed list
- */
- public static Location reverse(Location location) {
- Location next = location.getSecondary();
- location.setSecondary(null);
- while (next != null) {
- Location nextNext = next.getSecondary();
- next.setSecondary(location);
- location = next;
- next = nextNext;
- }
-
- return location;
- }
-
- /**
- * A {@link Handle} is a reference to a location. The point of a location
- * handle is to be able to create them cheaply, and then resolve them into
- * actual locations later (if needed). This makes it possible to for example
- * delay looking up line numbers, for locations that are offset based.
- */
- public interface Handle {
- /**
- * Compute a full location for the given handle
- *
- * @return create a location for this handle
- */
- @NonNull
- Location resolve();
-
- /**
- * Sets the client data associated with this location. This is an optional
- * field which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @param clientData the data to store with this location
- */
- void setClientData(@Nullable Object clientData);
-
- /**
- * Returns the client data associated with this location - an optional field
- * which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @return the data associated with this location
- */
- @Nullable
- Object getClientData();
- }
-
- /** A default {@link Handle} implementation for simple file offsets */
- public static class DefaultLocationHandle implements Handle {
- private final File mFile;
- private final String mContents;
- private final int mStartOffset;
- private final int mEndOffset;
- private Object mClientData;
-
- /**
- * Constructs a new {@link DefaultLocationHandle}
- *
- * @param context the context pointing to the file and its contents
- * @param startOffset the start offset within the file
- * @param endOffset the end offset within the file
- */
- public DefaultLocationHandle(@NonNull Context context, int startOffset, int endOffset) {
- mFile = context.file;
- mContents = context.getContents();
- mStartOffset = startOffset;
- mEndOffset = endOffset;
- }
-
- @Override
- @NonNull
- public Location resolve() {
- return create(mFile, mContents, mStartOffset, mEndOffset);
- }
-
- @Override
- public void setClientData(@Nullable Object clientData) {
- mClientData = clientData;
- }
-
- @Override
- @Nullable
- public Object getClientData() {
- return mClientData;
- }
- }
-
- /**
- * Whether to look forwards, or backwards, or in both directions, when
- * searching for a pattern in the source code to determine the right
- * position range for a given symbol.
- * <p>
- * When dealing with bytecode for example, there are only line number entries
- * within method bodies, so when searching for the method declaration, we should only
- * search backwards from the first line entry in the method.
- */
- public enum SearchDirection {
- /** Only search forwards */
- FORWARD,
-
- /** Only search backwards */
- BACKWARD,
-
- /** Search backwards from the current end of line (normally it's the beginning of
- * the current line) */
- EOL_BACKWARD,
-
- /**
- * Search both forwards and backwards from the given line, and prefer
- * the match that is closest
- */
- NEAREST,
- }
-
- /**
- * Extra information pertaining to finding a symbol in a source buffer,
- * used by {@link Location#create(File, String, int, String, String, SearchHints)}
- */
- public static class SearchHints {
- /**
- * the direction to search for the nearest match in (provided
- * {@code patternStart} is non null)
- */
- @NonNull
- private final SearchDirection mDirection;
-
- /** Whether the matched pattern should be a whole word */
- private boolean mWholeWord;
-
- /**
- * Whether the matched pattern should be a Java symbol (so for example,
- * a match inside a comment or string literal should not be used)
- */
- private boolean mJavaSymbol;
-
- /**
- * Whether the matched pattern corresponds to a constructor; if so, look for
- * some other possible source aliases too, such as "super".
- */
- private boolean mConstructor;
-
- private SearchHints(@NonNull SearchDirection direction) {
- super();
- mDirection = direction;
- }
-
- /**
- * Constructs a new {@link SearchHints} object
- *
- * @param direction the direction to search in for the pattern
- * @return a new @link SearchHints} object
- */
- @NonNull
- public static SearchHints create(@NonNull SearchDirection direction) {
- return new SearchHints(direction);
- }
-
- /**
- * Indicates that pattern matches should apply to whole words only
-
- * @return this, for constructor chaining
- */
- @NonNull
- public SearchHints matchWholeWord() {
- mWholeWord = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for whole words only */
- public boolean isWholeWord() {
- return mWholeWord;
- }
-
- /**
- * Indicates that pattern matches should apply to Java symbols only
- *
- * @return this, for constructor chaining
- */
- @NonNull
- public SearchHints matchJavaSymbol() {
- mJavaSymbol = true;
- mWholeWord = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for Java symbols only */
- public boolean isJavaSymbol() {
- return mJavaSymbol;
- }
-
- /**
- * Indicates that pattern matches should apply to constructors. If so, look for
- * some other possible source aliases too, such as "super".
- *
- * @return this, for constructor chaining
- */
- @NonNull
- public SearchHints matchConstructor() {
- mConstructor = true;
- mWholeWord = true;
- mJavaSymbol = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for a constructor */
- public boolean isConstructor() {
- return mConstructor;
- }
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Position.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Position.java
deleted file mode 100644
index 6407cc9..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Position.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.google.common.annotations.Beta;
-
-/**
- * Information about a position in a file/document.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class Position {
- /**
- * Returns the line number (0-based where the first line is line 0)
- *
- * @return the 0-based line number
- */
- public abstract int getLine();
-
- /**
- * The character offset
- *
- * @return the 0-based character offset
- */
- public abstract int getOffset();
-
- /**
- * Returns the column number (where the first character on the line is 0),
- * or -1 if unknown
- *
- * @return the 0-based column number
- */
- public abstract int getColumn();
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java
deleted file mode 100644
index 968b9b1..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Project.java
+++ /dev/null
@@ -1,929 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import static com.android.SdkConstants.ANDROID_LIBRARY;
-import static com.android.SdkConstants.ANDROID_LIBRARY_REFERENCE_FORMAT;
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_MIN_SDK_VERSION;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.ATTR_TARGET_SDK_VERSION;
-import static com.android.SdkConstants.PROGUARD_CONFIG;
-import static com.android.SdkConstants.PROJECT_PROPERTIES;
-import static com.android.SdkConstants.RES_FOLDER;
-import static com.android.SdkConstants.TAG_USES_SDK;
-import static com.android.SdkConstants.VALUE_TRUE;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.CircularDependencyException;
-import com.android.tools.lint.client.api.Configuration;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
-import com.google.common.io.Closeables;
-import com.google.common.io.Files;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A project contains information about an Android project being scanned for
- * Lint errors.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class Project {
- private final LintClient mClient;
- private final File mDir;
- private final File mReferenceDir;
- private Configuration mConfiguration;
- private String mPackage;
- private int mMinSdk = 1;
- private int mTargetSdk = -1;
- private int mBuildSdk = -1;
- private boolean mLibrary;
- private String mName;
- private String mProguardPath;
- private boolean mMergeManifests;
-
- /** The SDK info, if any */
- private SdkInfo mSdkInfo;
-
- /**
- * If non null, specifies a non-empty list of specific files under this
- * project which should be checked.
- */
- private List<File> mFiles;
- private List<File> mJavaSourceFolders;
- private List<File> mJavaClassFolders;
- private List<File> mJavaLibraries;
- private List<Project> mDirectLibraries;
- private List<Project> mAllLibraries;
- private boolean mReportIssues = true;
-
- /**
- * Creates a new {@link Project} for the given directory.
- *
- * @param client the tool running the lint check
- * @param dir the root directory of the project
- * @param referenceDir See {@link #getReferenceDir()}.
- * @return a new {@link Project}
- */
- @NonNull
- public static Project create(
- @NonNull LintClient client,
- @NonNull File dir,
- @NonNull File referenceDir) {
- return new Project(client, dir, referenceDir);
- }
-
- /** Creates a new Project. Use one of the factory methods to create. */
- private Project(
- @NonNull LintClient client,
- @NonNull File dir,
- @NonNull File referenceDir) {
- mClient = client;
- mDir = dir;
- mReferenceDir = referenceDir;
-
- try {
- // Read properties file and initialize library state
- Properties properties = new Properties();
- File propFile = new File(dir, PROJECT_PROPERTIES);
- if (propFile.exists()) {
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables.closeQuietly
- BufferedInputStream is = new BufferedInputStream(new FileInputStream(propFile));
- try {
- properties.load(is);
- String value = properties.getProperty(ANDROID_LIBRARY);
- mLibrary = VALUE_TRUE.equals(value);
- mProguardPath = properties.getProperty(PROGUARD_CONFIG);
- mMergeManifests = VALUE_TRUE.equals(properties.getProperty(
- "manifestmerger.enabled")); //$NON-NLS-1$
- String target = properties.getProperty("target"); //$NON-NLS-1$
- if (target != null) {
- int index = target.lastIndexOf('-');
- if (index == -1) {
- index = target.lastIndexOf(':');
- }
- if (index != -1) {
- String versionString = target.substring(index + 1);
- try {
- mBuildSdk = Integer.parseInt(versionString);
- } catch (NumberFormatException nufe) {
- mClient.log(Severity.WARNING, null,
- "Unexpected build target format: %1$s", target);
- }
- }
- }
-
- for (int i = 1; i < 1000; i++) {
- String key = String.format(ANDROID_LIBRARY_REFERENCE_FORMAT, i);
- String library = properties.getProperty(key);
- if (library == null || library.isEmpty()) {
- // No holes in the numbering sequence is allowed
- break;
- }
-
- File libraryDir = new File(dir, library).getCanonicalFile();
-
- if (mDirectLibraries == null) {
- mDirectLibraries = new ArrayList<Project>();
- }
-
- // Adjust the reference dir to be a proper prefix path of the
- // library dir
- File libraryReferenceDir = referenceDir;
- if (!libraryDir.getPath().startsWith(referenceDir.getPath())) {
- // Symlinks etc might have been resolved, so do those to
- // the reference dir as well
- libraryReferenceDir = libraryReferenceDir.getCanonicalFile();
- if (!libraryDir.getPath().startsWith(referenceDir.getPath())) {
- File file = libraryReferenceDir;
- while (file != null && !file.getPath().isEmpty()) {
- if (libraryDir.getPath().startsWith(file.getPath())) {
- libraryReferenceDir = file;
- break;
- }
- file = file.getParentFile();
- }
- }
- }
-
- try {
- Project libraryPrj = client.getProject(libraryDir, libraryReferenceDir);
- mDirectLibraries.add(libraryPrj);
- // By default, we don't report issues in inferred library projects.
- // The driver will set report = true for those library explicitly
- // requested.
- libraryPrj.setReportIssues(false);
- } catch (CircularDependencyException e) {
- e.setProject(this);
- e.setLocation(Location.create(propFile));
- throw e;
- }
- }
- } finally {
- Closeables.closeQuietly(is);
- }
- }
- } catch (IOException ioe) {
- client.log(ioe, "Initializing project state");
- }
-
- if (mDirectLibraries != null) {
- mDirectLibraries = Collections.unmodifiableList(mDirectLibraries);
- } else {
- mDirectLibraries = Collections.emptyList();
- }
- }
-
- @Override
- public String toString() {
- return "Project [dir=" + mDir + ']';
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mDir == null) ? 0 : mDir.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Project other = (Project) obj;
- if (mDir == null) {
- if (other.mDir != null)
- return false;
- } else if (!mDir.equals(other.mDir))
- return false;
- return true;
- }
-
- /**
- * Adds the given file to the list of files which should be checked in this
- * project. If no files are added, the whole project will be checked.
- *
- * @param file the file to be checked
- */
- public void addFile(@NonNull File file) {
- if (mFiles == null) {
- mFiles = new ArrayList<File>();
- }
- mFiles.add(file);
- }
-
- /**
- * The list of files to be checked in this project. If null, the whole
- * project should be checked.
- *
- * @return the subset of files to be checked, or null for the whole project
- */
- @Nullable
- public List<File> getSubset() {
- return mFiles;
- }
-
- /**
- * Returns the list of source folders for Java source files
- *
- * @return a list of source folders to search for .java files
- */
- @NonNull
- public List<File> getJavaSourceFolders() {
- if (mJavaSourceFolders == null) {
- if (isAospFrameworksProject(mDir)) {
- return Collections.singletonList(new File(mDir, "java")); //$NON-NLS-1$
- }
- if (isAospBuildEnvironment()) {
- String top = getAospTop();
- if (mDir.getAbsolutePath().startsWith(top)) {
- mJavaSourceFolders = getAospJavaSourcePath();
- return mJavaSourceFolders;
- }
- }
-
- mJavaSourceFolders = mClient.getJavaSourceFolders(this);
- }
-
- return mJavaSourceFolders;
- }
-
- /**
- * Returns the list of output folders for class files
- * @return a list of output folders to search for .class files
- */
- @NonNull
- public List<File> getJavaClassFolders() {
- if (mJavaClassFolders == null) {
- if (isAospFrameworksProject(mDir)) {
- File top = mDir.getParentFile().getParentFile().getParentFile();
- if (top != null) {
- File out = new File(top, "out");
- if (out.exists()) {
- String relative =
- "target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar";
- File jar = new File(out, relative.replace('/', File.separatorChar));
- if (jar.exists()) {
- mJavaClassFolders = Collections.singletonList(jar);
- return mJavaClassFolders;
- }
- }
- }
- }
- if (isAospBuildEnvironment()) {
- String top = getAospTop();
- if (mDir.getAbsolutePath().startsWith(top)) {
- mJavaClassFolders = getAospJavaClassPath();
- return mJavaClassFolders;
- }
- }
-
- mJavaClassFolders = mClient.getJavaClassFolders(this);
- }
- return mJavaClassFolders;
- }
-
- /**
- * Returns the list of Java libraries (typically .jar files) that this
- * project depends on. Note that this refers to jar libraries, not Android
- * library projects which are processed in a separate pass with their own
- * source and class folders.
- *
- * @return a list of .jar files (or class folders) that this project depends
- * on.
- */
- @NonNull
- public List<File> getJavaLibraries() {
- if (mJavaLibraries == null) {
- // AOSP builds already merge libraries and class folders into
- // the single classes.jar file, so these have already been processed
- // in getJavaClassFolders.
-
- mJavaLibraries = mClient.getJavaLibraries(this);
- }
-
- return mJavaLibraries;
- }
-
- /**
- * Returns the resource folder.
- *
- * @return a file pointing to the resource folder, or null if the project
- * does not contain any resources
- */
- @NonNull
- public List<File> getResourceFolders() {
- List<File> folders = mClient.getResourceFolders(this);
-
- if (folders.size() == 1 && isAospFrameworksProject(mDir)) {
- // No manifest file for this project: just init the manifest values here
- mMinSdk = mTargetSdk = SdkConstants.HIGHEST_KNOWN_API;
- File folder = new File(folders.get(0), RES_FOLDER);
- if (!folder.exists()) {
- folders = Collections.emptyList();
- }
- }
-
- return folders;
- }
-
- /**
- * Returns the relative path of a given file relative to the user specified
- * directory (which is often the project directory but sometimes a higher up
- * directory when a directory tree is being scanned
- *
- * @param file the file under this project to check
- * @return the path relative to the reference directory (often the project directory)
- */
- @NonNull
- public String getDisplayPath(@NonNull File file) {
- String path = file.getPath();
- String referencePath = mReferenceDir.getPath();
- if (path.startsWith(referencePath)) {
- int length = referencePath.length();
- if (path.length() > length && path.charAt(length) == File.separatorChar) {
- length++;
- }
-
- return path.substring(length);
- }
-
- return path;
- }
-
- /**
- * Returns the relative path of a given file within the current project.
- *
- * @param file the file under this project to check
- * @return the path relative to the project
- */
- @NonNull
- public String getRelativePath(@NonNull File file) {
- String path = file.getPath();
- String referencePath = mDir.getPath();
- if (path.startsWith(referencePath)) {
- int length = referencePath.length();
- if (path.length() > length && path.charAt(length) == File.separatorChar) {
- length++;
- }
-
- return path.substring(length);
- }
-
- return path;
- }
-
- /**
- * Returns the project root directory
- *
- * @return the dir
- */
- @NonNull
- public File getDir() {
- return mDir;
- }
-
- /**
- * Returns the original user supplied directory where the lint search
- * started. For example, if you run lint against {@code /tmp/foo}, and it
- * finds a project to lint in {@code /tmp/foo/dev/src/project1}, then the
- * {@code dir} is {@code /tmp/foo/dev/src/project1} and the
- * {@code referenceDir} is {@code /tmp/foo/}.
- *
- * @return the reference directory, never null
- */
- @NonNull
- public File getReferenceDir() {
- return mReferenceDir;
- }
-
- /**
- * Gets the configuration associated with this project
- *
- * @return the configuration associated with this project
- */
- @NonNull
- public Configuration getConfiguration() {
- if (mConfiguration == null) {
- mConfiguration = mClient.getConfiguration(this);
- }
- return mConfiguration;
- }
-
- /**
- * Returns the application package specified by the manifest
- *
- * @return the application package, or null if unknown
- */
- @Nullable
- public String getPackage() {
- //assert !mLibrary; // Should call getPackage on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mPackage;
- }
-
- /**
- * Returns the minimum API level requested by the manifest, or -1 if not
- * specified
- *
- * @return the minimum API level or -1 if unknown
- */
- public int getMinSdk() {
- //assert !mLibrary; // Should call getMinSdk on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mMinSdk;
- }
-
- /**
- * Returns the target API level specified by the manifest, or -1 if not
- * specified
- *
- * @return the target API level or -1 if unknown
- */
- public int getTargetSdk() {
- //assert !mLibrary; // Should call getTargetSdk on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mTargetSdk;
- }
-
- /**
- * Returns the target API used to build the project, or -1 if not known
- *
- * @return the build target API or -1 if unknown
- */
- public int getBuildSdk() {
- return mBuildSdk;
- }
-
- /**
- * Initialized the manifest state from the given manifest model
- *
- * @param document the DOM document for the manifest XML document
- */
- public void readManifest(@NonNull Document document) {
- Element root = document.getDocumentElement();
- if (root == null) {
- return;
- }
-
- mPackage = root.getAttribute(ATTR_PACKAGE);
-
- // Initialize minSdk and targetSdk
- NodeList usesSdks = root.getElementsByTagName(TAG_USES_SDK);
- if (usesSdks.getLength() > 0) {
- Element element = (Element) usesSdks.item(0);
-
- String minSdk = null;
- if (element.hasAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION)) {
- minSdk = element.getAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION);
- }
- if (minSdk != null) {
- try {
- mMinSdk = Integer.valueOf(minSdk);
- } catch (NumberFormatException e) {
- mMinSdk = 1;
- }
- }
-
- String targetSdk = null;
- if (element.hasAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION)) {
- targetSdk = element.getAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION);
- } else if (minSdk != null) {
- targetSdk = minSdk;
- }
- if (targetSdk != null) {
- try {
- mTargetSdk = Integer.valueOf(targetSdk);
- } catch (NumberFormatException e) {
- // TODO: Handle codenames?
- mTargetSdk = -1;
- }
- }
- } else if (isAospBuildEnvironment()) {
- extractAospMinSdkVersion();
- }
- }
-
- /**
- * Returns true if this project is an Android library project
- *
- * @return true if this project is an Android library project
- */
- public boolean isLibrary() {
- return mLibrary;
- }
-
- /**
- * Returns the list of library projects referenced by this project
- *
- * @return the list of library projects referenced by this project, never
- * null
- */
- @NonNull
- public List<Project> getDirectLibraries() {
- return mDirectLibraries;
- }
-
- /**
- * Returns the transitive closure of the library projects for this project
- *
- * @return the transitive closure of the library projects for this project
- */
- @NonNull
- public List<Project> getAllLibraries() {
- if (mAllLibraries == null) {
- if (mDirectLibraries.isEmpty()) {
- return mDirectLibraries;
- }
-
- List<Project> all = new ArrayList<Project>();
- addLibraryProjects(all);
- mAllLibraries = all;
- }
-
- return mAllLibraries;
- }
-
- /**
- * Adds this project's library project and their library projects
- * recursively into the given collection of projects
- *
- * @param collection the collection to add the projects into
- */
- private void addLibraryProjects(@NonNull Collection<Project> collection) {
- for (Project library : mDirectLibraries) {
- collection.add(library);
- // Recurse
- library.addLibraryProjects(collection);
- }
- }
-
- /**
- * Gets the SDK info for the current project.
- *
- * @return the SDK info for the current project, never null
- */
- @NonNull
- public SdkInfo getSdkInfo() {
- if (mSdkInfo == null) {
- mSdkInfo = mClient.getSdkInfo(this);
- }
-
- return mSdkInfo;
- }
-
- /**
- * Gets the path to the manifest file in this project, if it exists
- *
- * @return the path to the manifest file, or null if it does not exist
- */
- @Nullable
- public File getManifestFile() {
- File manifestFile = new File(mDir, ANDROID_MANIFEST_XML);
- if (manifestFile.exists()) {
- return manifestFile;
- }
-
- return null;
- }
-
- /**
- * Returns the proguard path configured for this project, or null if ProGuard is
- * not configured.
- *
- * @return the proguard path, or null
- */
- @Nullable
- public String getProguardPath() {
- return mProguardPath;
- }
-
- /**
- * Returns the name of the project
- *
- * @return the name of the project, never null
- */
- @NonNull
- public String getName() {
- if (mName == null) {
- mName = mClient.getProjectName(this);
- }
-
- return mName;
- }
-
- /**
- * Sets the name of the project
- *
- * @param name the name of the project, never null
- */
- public void setName(@NonNull String name) {
- assert !name.isEmpty();
- mName = name;
- }
-
- /**
- * Sets whether lint should report issues in this project. See
- * {@link #getReportIssues()} for a full description of what that means.
- *
- * @param reportIssues whether lint should report issues in this project
- */
- public void setReportIssues(boolean reportIssues) {
- mReportIssues = reportIssues;
- }
-
- /**
- * Returns whether lint should report issues in this project.
- * <p>
- * If a user specifies a project and its library projects for analysis, then
- * those library projects are all "included", and all errors found in all
- * the projects are reported. But if the user is only running lint on the
- * main project, we shouldn't report errors in any of the library projects.
- * We still need to <b>consider</b> them for certain types of checks, such
- * as determining whether resources found in the main project are unused, so
- * the detectors must still get a chance to look at these projects. The
- * {@code #getReportIssues()} attribute is used for this purpose.
- *
- * @return whether lint should report issues in this project
- */
- public boolean getReportIssues() {
- return mReportIssues;
- }
-
- /**
- * Sets whether manifest merging is in effect.
- *
- * @param merging whether manifest merging is in effect
- */
- public void setMergingManifests(boolean merging) {
- mMergeManifests = merging;
- }
-
- /**
- * Returns whether manifest merging is in effect
- *
- * @return true if manifests in library projects should be merged into main projects
- */
- public boolean isMergingManifests() {
- return mMergeManifests;
- }
-
-
- // ---------------------------------------------------------------------------
- // Support for running lint on the AOSP source tree itself
-
- private static Boolean sAospBuild;
-
- /** Is lint running in an AOSP build environment */
- private static boolean isAospBuildEnvironment() {
- if (sAospBuild == null) {
- sAospBuild = getAospTop() != null;
- }
-
- return sAospBuild.booleanValue();
- }
-
- /**
- * Is this the frameworks AOSP project? Needs some hardcoded support since
- * it doesn't have a manifest file, etc.
- *
- * @param dir the project directory to check
- * @return true if this looks like the frameworks/base/core project
- */
- static boolean isAospFrameworksProject(@NonNull File dir) {
- if (!dir.getPath().endsWith("core")) { //$NON-NLS-1$
- return false;
- }
-
- File parent = dir.getParentFile();
- if (parent == null || !parent.getName().equals("base")) { //$NON-NLS-1$
- return false;
- }
-
- parent = parent.getParentFile();
- if (parent == null || !parent.getName().equals("frameworks")) { //$NON-NLS-1$
- return false;
- }
-
- return true;
- }
-
- /** Get the root AOSP dir, if any */
- private static String getAospTop() {
- return System.getenv("ANDROID_BUILD_TOP"); //$NON-NLS-1$
- }
-
- /** Get the host out directory in AOSP, if any */
- private static String getAospHostOut() {
- return System.getenv("ANDROID_HOST_OUT"); //$NON-NLS-1$
- }
-
- /** Get the product out directory in AOSP, if any */
- private static String getAospProductOut() {
- return System.getenv("ANDROID_PRODUCT_OUT"); //$NON-NLS-1$
- }
-
- private List<File> getAospJavaSourcePath() {
- List<File> sources = new ArrayList<File>(2);
- // Normal sources
- File src = new File(mDir, "src"); //$NON-NLS-1$
- if (src.exists()) {
- sources.add(src);
- }
-
- // Generates sources
- for (File dir : getIntermediateDirs()) {
- File classes = new File(dir, "src"); //$NON-NLS-1$
- if (classes.exists()) {
- sources.add(classes);
- }
- }
-
- if (sources.isEmpty()) {
- mClient.log(null,
- "Warning: Could not find sources or generated sources for project %1$s",
- getName());
- }
-
- return sources;
- }
-
- private List<File> getAospJavaClassPath() {
- List<File> classDirs = new ArrayList<File>(1);
-
- for (File dir : getIntermediateDirs()) {
- File classes = new File(dir, "classes"); //$NON-NLS-1$
- if (classes.exists()) {
- classDirs.add(classes);
- } else {
- classes = new File(dir, "classes.jar"); //$NON-NLS-1$
- if (classes.exists()) {
- classDirs.add(classes);
- }
- }
- }
-
- if (classDirs.isEmpty()) {
- mClient.log(null,
- "No bytecode found: Has the project been built? (%1$s)", getName());
- }
-
- return classDirs;
- }
-
- /** Find the _intermediates directories for a given module name */
- private List<File> getIntermediateDirs() {
- // See build/core/definitions.mk and in particular the "intermediates-dir-for" definition
- List<File> intermediates = new ArrayList<File>();
-
- // TODO: Look up the module name, e.g. LOCAL_MODULE. However,
- // some Android.mk files do some complicated things with it - and most
- // projects use the same module name as the directory name.
- String moduleName = mDir.getName();
-
- String top = getAospTop();
- final String[] outFolders = new String[] {
- top + "/out/host/common/obj", //$NON-NLS-1$
- top + "/out/target/common/obj", //$NON-NLS-1$
- getAospHostOut() + "/obj", //$NON-NLS-1$
- getAospProductOut() + "/obj" //$NON-NLS-1$
- };
- final String[] moduleClasses = new String[] {
- "APPS", //$NON-NLS-1$
- "JAVA_LIBRARIES", //$NON-NLS-1$
- };
-
- for (String out : outFolders) {
- assert new File(out.replace('/', File.separatorChar)).exists() : out;
- for (String moduleClass : moduleClasses) {
- String path = out + '/' + moduleClass + '/' + moduleName
- + "_intermediates"; //$NON-NLS-1$
- File file = new File(path.replace('/', File.separatorChar));
- if (file.exists()) {
- intermediates.add(file);
- }
- }
- }
-
- return intermediates;
- }
-
- private void extractAospMinSdkVersion() {
- // Is the SDK level specified by a Makefile?
- boolean found = false;
- File makefile = new File(mDir, "Android.mk"); //$NON-NLS-1$
- if (makefile.exists()) {
- try {
- List<String> lines = Files.readLines(makefile, Charsets.UTF_8);
- Pattern p = Pattern.compile("LOCAL_SDK_VERSION\\s*:=\\s*(.*)"); //$NON-NLS-1$
- for (String line : lines) {
- line = line.trim();
- Matcher matcher = p.matcher(line);
- if (matcher.matches()) {
- found = true;
- String version = matcher.group(1);
- if (version.equals("current")) { //$NON-NLS-1$
- mMinSdk = findCurrentAospVersion();
- } else {
- try {
- mMinSdk = Integer.valueOf(version);
- } catch (NumberFormatException e) {
- // Codename - just use current
- mMinSdk = findCurrentAospVersion();
- }
- }
- break;
- }
- }
- } catch (IOException ioe) {
- mClient.log(ioe, null);
- }
- }
-
- if (!found) {
- mMinSdk = findCurrentAospVersion();
- }
- }
-
- /** Cache for {@link #findCurrentAospVersion()} */
- private static int sCurrentVersion;
-
- /** In an AOSP build environment, identify the currently built image version, if available */
- private static int findCurrentAospVersion() {
- if (sCurrentVersion < 1) {
- File apiDir = new File(getAospTop(), "frameworks/base/api" //$NON-NLS-1$
- .replace('/', File.separatorChar));
- File[] apiFiles = apiDir.listFiles();
- if (apiFiles == null) {
- sCurrentVersion = 1;
- return sCurrentVersion;
- }
- int max = 1;
- for (File apiFile : apiFiles) {
- String name = apiFile.getName();
- int index = name.indexOf('.');
- if (index > 0) {
- String base = name.substring(0, index);
- if (Character.isDigit(base.charAt(0))) {
- try {
- int version = Integer.parseInt(base);
- if (version > max) {
- max = version;
- }
- } catch (NumberFormatException nufe) {
- // pass
- }
- }
- }
- }
- sCurrentVersion = max;
- }
-
- return sCurrentVersion;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ResourceXmlDetector.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ResourceXmlDetector.java
deleted file mode 100644
index 68685c6..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/ResourceXmlDetector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-
-/**
- * Specialized detector intended for XML resources. Detectors that apply to XML
- * resources should extend this detector instead since it provides special
- * iteration hooks that are more efficient.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public abstract class ResourceXmlDetector extends Detector implements Detector.XmlScanner {
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return LintUtils.isXmlFile(file);
- }
-
- /**
- * Returns whether this detector applies to the given folder type. This
- * allows the detectors to be pruned from iteration, so for example when we
- * are analyzing a string value file we don't need to look up detectors
- * related to layout.
- *
- * @param folderType the folder type to be visited
- * @return true if this detector can apply to resources in folders of the
- * given type
- */
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return true;
- }
-
- @Override
- public void run(@NonNull Context context) {
- // The infrastructure should never call this method on an xml detector since
- // it will run the various visitors instead
- assert false;
- }
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Scope.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Scope.java
deleted file mode 100644
index 0e33f1b..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Scope.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-import java.util.EnumSet;
-
-/**
- * The scope of a detector is the set of files a detector must consider when
- * performing its analysis. This can be used to determine when issues are
- * potentially obsolete, whether a detector should re-run on a file save, etc.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public enum Scope {
- /**
- * The analysis only considers a single XML resource file at a time.
- * <p>
- * Issues which are only affected by a single resource file can be checked
- * for incrementally when a file is edited.
- */
- RESOURCE_FILE,
-
- /**
- * The analysis considers <b>all</b> the resource file. This scope must not
- * be used in conjunction with {@link #RESOURCE_FILE}; an issue scope is
- * either considering just a single resource file or all the resources, not
- * both.
- */
- ALL_RESOURCE_FILES,
-
- /**
- * The analysis only considers a single Java source file at a time.
- * <p>
- * Issues which are only affected by a single Java source file can be
- * checked for incrementally when a Java source file is edited.
- */
- JAVA_FILE,
-
- /**
- * The analysis considers <b>all</b> the Java source files together.
- * <p>
- * This flag is mutually exclusive with {@link #JAVA_FILE}.
- */
- ALL_JAVA_FILES,
-
- /**
- * The analysis only considers a single Java class file at a time.
- * <p>
- * Issues which are only affected by a single Java class file can be checked
- * for incrementally when a Java source file is edited and then recompiled.
- */
- CLASS_FILE,
-
- /**
- * The analysis considers <b>all</b> the Java class files together.
- * <p>
- * This flag is mutually exclusive with {@link #CLASS_FILE}.
- */
- ALL_CLASS_FILES,
-
- /** The analysis considers the manifest file */
- MANIFEST,
-
- /** The analysis considers the Proguard configuration file */
- PROGUARD_FILE,
-
- /**
- * The analysis considers classes in the libraries for this project. These
- * will be analyzed before the classes themselves.
- */
- JAVA_LIBRARIES,
-
- /**
- * Scope for other files. Issues that specify a custom scope will be called unconditionally.
- * This will call {@link Detector#run(Context)}} on the detectors unconditionally.
- */
- OTHER;
-
- /**
- * Returns true if the given scope set corresponds to scanning a single file
- * rather than a whole project
- *
- * @param scopes the scope set to check
- * @return true if the scope set references a single file
- */
- public static boolean checkSingleFile(@NonNull EnumSet<Scope> scopes) {
- int size = scopes.size();
- if (size == 2) {
- // When single checking a Java source file, we check both its Java source
- // and the associated class files
- return scopes.contains(JAVA_FILE) && scopes.contains(CLASS_FILE);
- } else {
- return size == 1 &&
- (scopes.contains(JAVA_FILE)
- || scopes.contains(CLASS_FILE)
- || scopes.contains(RESOURCE_FILE)
- || scopes.contains(PROGUARD_FILE)
- || scopes.contains(MANIFEST));
- }
- }
-
- /**
- * Returns the intersection of two scope sets
- *
- * @param scope1 the first set to intersect
- * @param scope2 the second set to intersect
- * @return the intersection of the two sets
- */
- @NonNull
- public static EnumSet<Scope> intersect(
- @NonNull EnumSet<Scope> scope1,
- @NonNull EnumSet<Scope> scope2) {
- EnumSet<Scope> scope = EnumSet.copyOf(scope1);
- scope.retainAll(scope2);
-
- return scope;
- }
-
- /** All scopes: running lint on a project will check these scopes */
- public static final EnumSet<Scope> ALL = EnumSet.allOf(Scope.class);
- /** Scope-set used for detectors which are affected by a single resource file */
- public static final EnumSet<Scope> RESOURCE_FILE_SCOPE = EnumSet.of(RESOURCE_FILE);
- /** Scope-set used for detectors which scan all resources */
- public static final EnumSet<Scope> ALL_RESOURCES_SCOPE = EnumSet.of(ALL_RESOURCE_FILES);
- /** Scope-set used for detectors which are affected by a single Java source file */
- public static final EnumSet<Scope> JAVA_FILE_SCOPE = EnumSet.of(JAVA_FILE);
- /** Scope-set used for detectors which are affected by a single Java class file */
- public static final EnumSet<Scope> CLASS_FILE_SCOPE = EnumSet.of(CLASS_FILE);
- /** Scope-set used for detectors which are affected by the manifest only */
- public static final EnumSet<Scope> MANIFEST_SCOPE = EnumSet.of(MANIFEST);
- /** Scope-set used for detectors which correspond to some other context */
- public static final EnumSet<Scope> OTHER_SCOPE = EnumSet.of(OTHER);
-}
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Severity.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Severity.java
deleted file mode 100644
index f74e6b5..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Severity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-/**
- * Severity of an issue found by lint
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public enum Severity {
- /**
- * Fatal: Use sparingly because a warning marked as fatal will be
- * considered critical and will abort Export APK etc in ADT
- */
- @NonNull
- FATAL("Fatal"),
-
- /**
- * Errors: The issue is known to be a real error that must be addressed.
- */
- @NonNull
- ERROR("Error"),
-
- /**
- * Warning: Probably a problem.
- */
- @NonNull
- WARNING("Warning"),
-
- /**
- * Information only: Might not be a problem, but the check has found
- * something interesting to say about the code.
- */
- @NonNull
- INFORMATIONAL("Information"),
-
- /**
- * Ignore: The user doesn't want to see this issue
- */
- @NonNull
- IGNORE("Ignore");
-
- @NonNull
- private final String mDisplay;
-
- Severity(@NonNull String display) {
- mDisplay = display;
- }
-
- /**
- * Returns a description of this severity suitable for display to the user
- *
- * @return a description of the severity
- */
- @NonNull
- public String getDescription() {
- return mDisplay;
- }
-} \ No newline at end of file
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Speed.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Speed.java
deleted file mode 100644
index c68dab0..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/Speed.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-/**
- * Enum which describes the different computation speeds of various detectors
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public enum Speed {
- /** The detector can run very quickly */
- FAST("Fast"),
-
- /** The detector runs reasonably fast */
- NORMAL("Normal"),
-
- /** The detector might take a long time to run */
- SLOW("Slow");
-
- private final String mDisplayName;
-
- Speed(@NonNull String displayName) {
- mDisplayName = displayName;
- }
-
- /**
- * Returns the user-visible description of the speed of the given
- * detector
- *
- * @return the description of the speed to display to the user
- */
- @NonNull
- public String getDisplayName() {
- return mDisplayName;
- }
-} \ No newline at end of file
diff --git a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/XmlContext.java b/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/XmlContext.java
deleted file mode 100644
index 34d6816..0000000
--- a/lint/libs/lint_api/src/main/java/com/android/tools/lint/detector/api/XmlContext.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.detector.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.IDomParser;
-import com.android.tools.lint.client.api.LintDriver;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import java.io.File;
-
-/**
- * A {@link Context} used when checking XML files.
- * <p/>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class XmlContext extends Context {
- /** The XML parser */
- public IDomParser parser;
- /** The XML document */
- public Document document;
- private final ResourceFolderType mFolderType;
-
- /**
- * Construct a new {@link XmlContext}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- * @param folderType the {@link ResourceFolderType} of this file, if any
- */
- public XmlContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file,
- @Nullable ResourceFolderType folderType) {
- super(driver, project, main, file);
- mFolderType = folderType;
- }
-
- /**
- * Returns the location for the given node, which may be an element or an attribute.
- *
- * @param node the node to look up the location for
- * @return the location for the node
- */
- @NonNull
- public Location getLocation(@NonNull Node node) {
- if (parser != null) {
- return parser.getLocation(this, node);
- }
-
- return Location.create(file);
- }
-
- /**
- * Creates a new location within an XML text node
- *
- * @param textNode the text node
- * @param begin the start offset within the text node (inclusive)
- * @param end the end offset within the text node (exclusive)
- * @return a new location
- */
- @NonNull
- public Location getLocation(@NonNull Node textNode, int begin, int end) {
- assert textNode.getNodeType() == Node.TEXT_NODE;
- if (parser != null) {
- return parser.getLocation(this, textNode, begin, end);
- }
-
- return Location.create(file);
- }
-
-
- /**
- * Reports an issue applicable to a given DOM node. The DOM node is used as the
- * scope to check for suppress lint annotations.
- *
- * @param issue the issue to report
- * @param scope the DOM node scope the error applies to. The lint infrastructure
- * will check whether there are suppress directives on this node (or its enclosing
- * nodes) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Node scope,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (scope != null && mDriver.isSuppressed(issue, scope)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-
- @Override
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- // Warn if clients use the non-scoped form? No, there are cases where an
- // XML detector's error isn't applicable to one particular location (or it's
- // not feasible to compute it cheaply)
- //mDriver.getClient().log(null, "Warning: Issue " + issue
- // + " was reported without a scope node: Can't be suppressed.");
-
- // For now just check the document root itself
- if (document != null && mDriver.isSuppressed(issue, document)) {
- return;
- }
-
- super.report(issue, location, message, data);
- }
-
- /**
- * Returns the resource folder type of this XML file, if any.
- *
- * @return the resource folder type or null
- */
- @Nullable
- public ResourceFolderType getResourceFolderType() {
- return mFolderType;
- }
-}
diff --git a/lint/libs/lint_checks/Android.mk b/lint/libs/lint_checks/Android.mk
index 30fc979..1382715 100644
--- a/lint/libs/lint_checks/Android.mk
+++ b/lint/libs/lint_checks/Android.mk
@@ -1,13 +1,27 @@
# Copyright 2011 The Android Open Source Project
#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+# The lint_checks code has moved to tools/base/lint_checks.
+# The rule below uses the prebuilt lint_checks.jar.
+#
+# If you want to run the tests, cd to tools/base/lint_checks
+# and run ./gradlew :lint_checks:test
# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_RESOURCE_DIRS := src/main/java
-# If the dependency list is changed, etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
common \
sdklib \
@@ -22,5 +36,8 @@ LOCAL_JAVA_LIBRARIES := \
LOCAL_MODULE := lint_checks
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+
+include $(BUILD_HOST_PREBUILT)
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AccessibilityDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AccessibilityDetector.java
deleted file mode 100644
index 4d069cc..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AccessibilityDetector.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
-import static com.android.SdkConstants.ATTR_HINT;
-import static com.android.SdkConstants.ATTR_IMPORTANT_FOR_ACCESSIBILITY;
-import static com.android.SdkConstants.IMAGE_BUTTON;
-import static com.android.SdkConstants.IMAGE_VIEW;
-import static com.android.SdkConstants.VALUE_NO;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check which looks for accessibility problems like missing content descriptions
- * <p>
- * TODO: Resolve styles and don't warn where styles are defining the content description
- * (though this seems unusual; content descriptions are not typically generic enough to
- * put in styles)
- */
-public class AccessibilityDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ContentDescription", //$NON-NLS-1$
- "Ensures that image widgets provide a contentDescription",
- "Non-textual widgets like ImageViews and ImageButtons should use the " +
- "`contentDescription` attribute to specify a textual description of " +
- "the widget such that screen readers and other accessibility tools " +
- "can adequately describe the user interface.\n" +
- "\n" +
- "Note that elements in application screens that are purely decorative " +
- "and do not provide any content or enable a user action should not " +
- "have accessibility content descriptions. In this case, just suppress the " +
- "lint warning with a tools:ignore=\"ContentDescription\" attribute.\n" +
- "\n" +
- "Note that for text fields, you should not set both the `hint` and the " +
- "`contentDescription` attributes since the hint will never be shown. Just " +
- "set the `hint`. See " +
- "http://developer.android.com/guide/topics/ui/accessibility/checklist.html#special-cases.",
-
- Category.A11Y,
- 3,
- Severity.WARNING,
- AccessibilityDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link AccessibilityDetector} */
- public AccessibilityDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- IMAGE_BUTTON,
- IMAGE_VIEW
- );
- }
-
- @Override
- @Nullable
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_CONTENT_DESCRIPTION);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- Element element = attribute.getOwnerElement();
- if (element.hasAttributeNS(ANDROID_URI, ATTR_HINT)) {
- context.report(ISSUE, element, context.getLocation(attribute),
- "Do not set both contentDescription and hint: the contentDescription " +
- "will mask the hint", null);
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_CONTENT_DESCRIPTION)) {
- // Ignore views that are explicitly not important for accessibility
- if (VALUE_NO.equals(element.getAttributeNS(ANDROID_URI,
- ATTR_IMPORTANT_FOR_ACCESSIBILITY))) {
- return;
- }
- context.report(ISSUE, element, context.getLocation(element),
- "[Accessibility] Missing contentDescription attribute on image", null);
- } else {
- Attr attributeNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_CONTENT_DESCRIPTION);
- String attribute = attributeNode.getValue();
- if (attribute.isEmpty() || attribute.equals("TODO")) { //$NON-NLS-1$
- context.report(ISSUE, attributeNode, context.getLocation(attributeNode),
- "[Accessibility] Empty contentDescription attribute on image", null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AlwaysShowActionDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AlwaysShowActionDetector.java
deleted file mode 100644
index 34a3f10..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AlwaysShowActionDetector.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_SHOW_AS_ACTION;
-import static com.android.SdkConstants.VALUE_ALWAYS;
-import static com.android.SdkConstants.VALUE_IF_ROOM;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector.JavaScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Node;
-import lombok.ast.Select;
-
-/**
- * Check which looks for usage of showAsAction="always" in menus (or
- * MenuItem.SHOW_AS_ACTION_ALWAYS in code), which is usually a style guide violation.
- * (Use ifRoom instead).
- */
-public class AlwaysShowActionDetector extends ResourceXmlDetector implements JavaScanner {
-
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "AlwaysShowAction", //$NON-NLS-1$
- "Checks for uses of showAsAction=\"always\" and suggests showAsAction=\"ifRoom\" " +
- "instead",
-
- "Using `showAsAction=\"always\"` in menu XML, or `MenuItem.SHOW_AS_ACTION_ALWAYS` in " +
- "Java code is usually a deviation from the user interface style guide." +
- "Use `ifRoom` or the corresponding `MenuItem.SHOW_AS_ACTION_IF_ROOM` instead.\n" +
- "\n" +
- "If `always` is used sparingly there are usually no problems and behavior is " +
- "roughly equivalent to `ifRoom` but with preference over other `ifRoom` " +
- "items. Using it more than twice in the same menu is a bad idea.\n" +
- "\n" +
- "This check looks for menu XML files that contain more than two `always` " +
- "actions, or some `always` actions and no `ifRoom` actions. In Java code, " +
- "it looks for projects that contain references to `MenuItem.SHOW_AS_ACTION_ALWAYS` " +
- "and no references to `MenuItem.SHOW_AS_ACTION_IF_ROOM`.",
-
- Category.USABILITY,
- 3,
- Severity.WARNING,
- AlwaysShowActionDetector.class,
- EnumSet.of(Scope.RESOURCE_FILE, Scope.JAVA_FILE)).setMoreInfo(
- "http://developer.android.com/design/patterns/actionbar.html"); //$NON-NLS-1$
-
- /** List of showAsAction attributes appearing in the current menu XML file */
- private List<Attr> mFileAttributes;
- /** If at least one location has been marked ignore in this file, ignore all */
- private boolean mIgnoreFile;
- /** List of locations of MenuItem.SHOW_AS_ACTION_ALWAYS references in Java code */
- private List<Location> mAlwaysFields;
- /** True if references to MenuItem.SHOW_AS_ACTION_IF_ROOM were found */
- private boolean mHasIfRoomRefs;
-
- /** Constructs a new {@link AlwaysShowActionDetector} */
- public AlwaysShowActionDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.MENU;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_SHOW_AS_ACTION);
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- mFileAttributes = null;
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- if (mIgnoreFile) {
- mFileAttributes = null;
- return;
- }
- if (mFileAttributes != null) {
- assert context instanceof XmlContext; // mFileAttributes is only set in XML files
-
- List<Attr> always = new ArrayList<Attr>();
- List<Attr> ifRoom = new ArrayList<Attr>();
- for (Attr attribute : mFileAttributes) {
- String value = attribute.getValue();
- if (value.equals(VALUE_ALWAYS)) {
- always.add(attribute);
- } else if (value.equals(VALUE_IF_ROOM)) {
- ifRoom.add(attribute);
- } else if (value.indexOf('|') != -1) {
- String[] flags = value.split("\\|"); //$NON-NLS-1$
- for (String flag : flags) {
- if (flag.equals(VALUE_ALWAYS)) {
- always.add(attribute);
- break;
- } else if (flag.equals(VALUE_IF_ROOM)) {
- ifRoom.add(attribute);
- break;
- }
- }
- }
- }
-
- if (!always.isEmpty() && mFileAttributes.size() > 1) {
- // Complain if you're using more than one "always", or if you're
- // using "always" and aren't using "ifRoom" at all (and provided you
- // have more than a single item)
- if (always.size() > 2 || ifRoom.isEmpty()) {
- XmlContext xmlContext = (XmlContext) context;
- Location location = null;
- for (int i = always.size() - 1; i >= 0; i--) {
- Location next = location;
- location = xmlContext.getLocation(always.get(i));
- if (next != null) {
- location.setSecondary(next);
- }
- }
- context.report(ISSUE, location,
- "Prefer \"ifRoom\" instead of \"always\"", null);
- }
- }
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mAlwaysFields != null && !mHasIfRoomRefs) {
- for (Location location : mAlwaysFields) {
- context.report(ISSUE, location,
- "Prefer \"SHOW_AS_ACTION_IF_ROOM\" instead of \"SHOW_AS_ACTION_ALWAYS\"",
- null);
- }
- }
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (context.getDriver().isSuppressed(ISSUE, attribute)) {
- mIgnoreFile = true;
- return;
- }
-
- if (mFileAttributes == null) {
- mFileAttributes = new ArrayList<Attr>();
- }
- mFileAttributes.add(attribute);
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public
- List<Class<? extends Node>> getApplicableNodeTypes() {
- return Collections.<Class<? extends Node>>singletonList(Select.class);
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new FieldAccessChecker(context);
- }
-
- private class FieldAccessChecker extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public FieldAccessChecker(JavaContext context) {
- mContext = context;
- }
-
- @Override
- public boolean visitSelect(Select node) {
- String description = node.astIdentifier().getDescription();
- boolean isIfRoom = description.equals("SHOW_AS_ACTION_IF_ROOM"); //$NON-NLS-1$
- boolean isAlways = description.equals("SHOW_AS_ACTION_ALWAYS"); //$NON-NLS-1$
- if ((isIfRoom || isAlways)
- && node.astOperand().toString().equals("MenuItem")) { //$NON-NLS-1$
- if (isAlways) {
- if (mContext.getDriver().isSuppressed(ISSUE, node)) {
- return super.visitSelect(node);
- }
- if (mAlwaysFields == null) {
- mAlwaysFields = new ArrayList<Location>();
- }
- mAlwaysFields.add(mContext.getLocation(node));
- } else {
- mHasIfRoomRefs = true;
- }
- }
-
- return super.visitSelect(node);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java
deleted file mode 100644
index eca9256..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/AnnotationDetector.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.FQCN_SUPPRESS_LINT;
-import static com.android.SdkConstants.SUPPRESS_LINT;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.IssueRegistry;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationValue;
-import lombok.ast.ArrayInitializer;
-import lombok.ast.AstVisitor;
-import lombok.ast.Block;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.Modifiers;
-import lombok.ast.Node;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-import lombok.ast.TypeBody;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableDefinitionEntry;
-
-/**
- * Checks annotations to make sure they are valid
- */
-public class AnnotationDetector extends Detector implements Detector.JavaScanner {
- /** Placing SuppressLint on a local variable doesn't work for class-file based checks */
- public static final Issue ISSUE = Issue.create(
- "LocalSuppress", //$NON-NLS-1$
- "Looks for @SuppressLint annotations in locations where it doesn't work for class based checks",
-
- "The `@SuppressAnnotation` is used to suppress Lint warnings in Java files. However, " +
- "while many lint checks analyzes the Java source code, where they can find " +
- "annotations on (for example) local variables, some checks are analyzing the " +
- "`.class` files. And in class files, annotations only appear on classes, fields " +
- "and methods. Annotations placed on local variables disappear. If you attempt " +
- "to suppress a lint error for a class-file based lint check, the suppress " +
- "annotation not work. You must move the annotation out to the surrounding method.",
-
- Category.CORRECTNESS,
- 3,
- Severity.ERROR,
- AnnotationDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Constructs a new {@link AnnotationDetector} check */
- public AnnotationDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- return Collections.<Class<? extends Node>>singletonList(Annotation.class);
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new AnnotationChecker(context);
- }
-
- private static class AnnotationChecker extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public AnnotationChecker(JavaContext context) {
- mContext = context;
- }
-
- @Override
- public boolean visitAnnotation(Annotation node) {
- String type = node.astAnnotationTypeReference().getTypeName();
- if (SUPPRESS_LINT.equals(type) || FQCN_SUPPRESS_LINT.equals(type)) {
- Node parent = node.getParent();
- if (parent instanceof Modifiers) {
- parent = parent.getParent();
- if (parent instanceof VariableDefinition) {
- for (AnnotationElement element : node.astElements()) {
- AnnotationValue valueNode = element.astValue();
- if (valueNode == null) {
- continue;
- }
- if (valueNode instanceof StringLiteral) {
- StringLiteral literal = (StringLiteral) valueNode;
- String id = literal.astValue();
- if (!checkId(node, id)) {
- return super.visitAnnotation(node);
- }
- } else if (valueNode instanceof ArrayInitializer) {
- ArrayInitializer array = (ArrayInitializer) valueNode;
- StrictListAccessor<Expression, ArrayInitializer> expressions =
- array.astExpressions();
- if (expressions == null) {
- continue;
- }
- Iterator<Expression> arrayIterator = expressions.iterator();
- while (arrayIterator.hasNext()) {
- Expression arrayElement = arrayIterator.next();
- if (arrayElement instanceof StringLiteral) {
- String id = ((StringLiteral) arrayElement).astValue();
- if (!checkId(node, id)) {
- return super.visitAnnotation(node);
- }
- }
- }
- }
- }
- }
- }
- }
-
- return super.visitAnnotation(node);
- }
-
- private boolean checkId(Annotation node, String id) {
- IssueRegistry registry = mContext.getDriver().getRegistry();
- Issue issue = registry.getIssue(id);
- // Special-case the ApiDetector issue, since it does both source file analysis
- // only on field references, and class file analysis on the rest, so we allow
- // annotations outside of methods only on fields
- if (issue != null && !issue.getScope().contains(Scope.JAVA_FILE)
- || issue == ApiDetector.UNSUPPORTED) {
- // Ensure that this isn't a field
- Node parent = node.getParent();
- while (parent != null) {
- if (parent instanceof MethodDeclaration
- || parent instanceof ConstructorDeclaration
- || parent instanceof Block) {
- break;
- } else if (parent instanceof TypeBody) { // It's a field
- return true;
- } else if (issue == ApiDetector.UNSUPPORTED
- && parent instanceof VariableDefinition) {
- VariableDefinition definition = (VariableDefinition) parent;
- for (VariableDefinitionEntry entry : definition.astVariables()) {
- Expression initializer = entry.astInitializer();
- if (initializer instanceof Select) {
- return true;
- }
- }
- }
- parent = parent.getParent();
- if (parent == null) {
- return true;
- }
- }
-
- // This issue doesn't have AST access: annotations are not
- // available for local variables or parameters
- mContext.report(ISSUE, node, mContext.getLocation(node), String.format(
- "The @SuppressLint annotation cannot be used on a local " +
- "variable with the lint check '%1$s': move out to the " +
- "surrounding method", id),
- null);
- return false;
- }
-
- return true;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Api.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Api.java
deleted file mode 100644
index ca84b27..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Api.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-
-import org.xml.sax.SAXException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Main entry point for API description.
- *
- * To create the {@link Api}, use {@link #parseApi(File)}
- *
- */
-public class Api {
-
- /**
- * Parses simplified API file.
- * @param apiFile the file to read
- * @return a new ApiInfo
- */
- public static Api parseApi(File apiFile) {
- FileInputStream fileInputStream = null;
- try {
- fileInputStream = new FileInputStream(apiFile);
- SAXParserFactory parserFactory = SAXParserFactory.newInstance();
- SAXParser parser = parserFactory.newSAXParser();
- ApiParser apiParser = new ApiParser();
- parser.parse(fileInputStream, apiParser);
- return new Api(apiParser.getClasses());
- } catch (ParserConfigurationException e) {
- e.printStackTrace();
- } catch (SAXException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (fileInputStream != null) {
- try {
- fileInputStream.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
-
- return null;
- }
-
- private final Map<String, ApiClass> mClasses;
-
- private Api(Map<String, ApiClass> classes) {
- mClasses = new HashMap<String, ApiClass>(classes);
- }
-
- ApiClass getClass(String fqcn) {
- return mClasses.get(fqcn);
- }
-
- Map<String, ApiClass> getClasses() {
- return Collections.unmodifiableMap(mClasses);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiClass.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiClass.java
deleted file mode 100644
index 3e0fb9d..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiClass.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-
-import com.android.annotations.Nullable;
-import com.android.utils.Pair;
-import com.google.common.collect.Lists;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Represents a class and its methods/fields.
- *
- * {@link #getSince()} gives the API level it was introduced.
- *
- * {@link #getMethod} returns when the method was introduced.
- * {@link #getField} returns when the field was introduced.
- */
-public class ApiClass {
-
- private final String mName;
- private final int mSince;
-
- private final List<Pair<String, Integer>> mSuperClasses = Lists.newArrayList();
- private final List<Pair<String, Integer>> mInterfaces = Lists.newArrayList();
-
- private final Map<String, Integer> mFields = new HashMap<String, Integer>();
- private final Map<String, Integer> mMethods = new HashMap<String, Integer>();
-
- ApiClass(String name, int since) {
- mName = name;
- mSince = since;
- }
-
- /**
- * Returns the name of the class.
- * @return the name of the class
- */
- String getName() {
- return mName;
- }
-
- /**
- * Returns when the class was introduced.
- * @return the api level the class was introduced.
- */
- int getSince() {
- return mSince;
- }
-
- /**
- * Returns when a field was added, or null if it doesn't exist.
- * @param name the name of the field.
- * @param info the corresponding info
- */
- Integer getField(String name, Api info) {
- // The field can come from this class or from a super class or an interface
- // The value can never be lower than this introduction of this class.
- // When looking at super classes and interfaces, it can never be lower than when the
- // super class or interface was added as a super class or interface to this class.
- // Look at all the values and take the lowest.
- // For instance:
- // This class A is introduced in 5 with super class B.
- // In 10, the interface C was added.
- // Looking for SOME_FIELD we get the following:
- // Present in A in API 15
- // Present in B in API 11
- // Present in C in API 7.
- // The answer is 10, which is when C became an interface
- int min = Integer.MAX_VALUE;
- Integer i = mFields.get(name);
- if (i != null) {
- min = i;
- }
-
- // now look at the super classes
- for (Pair<String, Integer> superClassPair : mSuperClasses) {
- ApiClass superClass = info.getClass(superClassPair.getFirst());
- if (superClass != null) {
- i = superClass.getField(name, info);
- if (i != null) {
- int tmp = superClassPair.getSecond() > i ? superClassPair.getSecond() : i;
- if (tmp < min) {
- min = tmp;
- }
- }
- }
- }
-
- // now look at the interfaces
- for (Pair<String, Integer> superClassPair : mInterfaces) {
- ApiClass superClass = info.getClass(superClassPair.getFirst());
- if (superClass != null) {
- i = superClass.getField(name, info);
- if (i != null) {
- int tmp = superClassPair.getSecond() > i ? superClassPair.getSecond() : i;
- if (tmp < min) {
- min = tmp;
- }
- }
- }
- }
-
- return min;
- }
-
- /**
- * Returns when a method was added, or null if it doesn't exist. This goes through the super
- * class to find method only present there.
- * @param methodSignature the method signature
- */
- int getMethod(String methodSignature, Api info) {
- // The method can come from this class or from a super class.
- // The value can never be lower than this introduction of this class.
- // When looking at super classes, it can never be lower than when the super class became
- // a super class of this class.
- // Look at all the values and take the lowest.
- // For instance:
- // This class A is introduced in 5 with super class B.
- // In 10, the super class changes to C.
- // Looking for foo() we get the following:
- // Present in A in API 15
- // Present in B in API 11
- // Present in C in API 7.
- // The answer is 10, which is when C became the super class.
- int min = Integer.MAX_VALUE;
- Integer i = mMethods.get(methodSignature);
- if (i != null) {
- min = i;
-
- // Constructors aren't inherited
- if (methodSignature.startsWith(CONSTRUCTOR_NAME)) {
- return i;
- }
- }
-
- // now look at the super classes
- for (Pair<String, Integer> superClassPair : mSuperClasses) {
- ApiClass superClass = info.getClass(superClassPair.getFirst());
- if (superClass != null) {
- i = superClass.getMethod(methodSignature, info);
- if (i != null) {
- int tmp = superClassPair.getSecond() > i ? superClassPair.getSecond() : i;
- if (tmp < min) {
- min = tmp;
- }
- }
- }
- }
-
- // now look at the interfaces classes
- for (Pair<String, Integer> interfacePair : mInterfaces) {
- ApiClass superClass = info.getClass(interfacePair.getFirst());
- if (superClass != null) {
- i = superClass.getMethod(methodSignature, info);
- if (i != null) {
- int tmp = interfacePair.getSecond() > i ? interfacePair.getSecond() : i;
- if (tmp < min) {
- min = tmp;
- }
- }
- }
- }
-
- return min;
- }
-
- void addField(String name, int since) {
- Integer i = mFields.get(name);
- if (i == null || i.intValue() > since) {
- mFields.put(name, Integer.valueOf(since));
- }
- }
-
- void addMethod(String name, int since) {
- // Strip off the method type at the end to ensure that the code which
- // produces inherited methods doesn't get confused and end up multiple entries.
- // For example, java/nio/Buffer has the method "array()Ljava/lang/Object;",
- // and the subclass java/nio/ByteBuffer has the method "array()[B". We want
- // the lookup on mMethods to associate the ByteBuffer array method to be
- // considered overriding the Buffer method.
- int index = name.indexOf(')');
- if (index != -1) {
- name = name.substring(0, index + 1);
- }
-
- Integer i = mMethods.get(name);
- if (i == null || i.intValue() > since) {
- mMethods.put(name, Integer.valueOf(since));
- }
- }
-
- void addSuperClass(String superClass, int since) {
- addToArray(mSuperClasses, superClass, since);
- }
-
- void addInterface(String interfaceClass, int since) {
- addToArray(mInterfaces, interfaceClass, since);
- }
-
- void addToArray(List<Pair<String, Integer>> list, String name, int value) {
- // check if we already have that name (at a lower level)
- for (Pair<String, Integer> pair : list) {
- if (name.equals(pair.getFirst())) {
- return;
- }
- }
-
- list.add(Pair.of(name, Integer.valueOf(value)));
-
- }
-
- @Nullable
- public String getPackage() {
- int index = mName.lastIndexOf('/');
- if (index != -1) {
- return mName.substring(0, index);
- }
-
- return null;
- }
-
- @Override
- public String toString() {
- return mName;
- }
-
- /**
- * Returns the set of all methods, including inherited
- * ones.
- *
- * @param info the api to look up super classes from
- * @return a set containing all the members fields
- */
- Set<String> getAllMethods(Api info) {
- Set<String> members = new HashSet<String>(100);
- addAllMethods(info, members, true /*includeConstructors*/);
-
- return members;
- }
-
- private void addAllMethods(Api info, Set<String> set, boolean includeConstructors) {
- if (!includeConstructors) {
- for (String method : mMethods.keySet()) {
- if (!method.startsWith(CONSTRUCTOR_NAME)) {
- set.add(method);
- }
- }
- } else {
- for (String method : mMethods.keySet()) {
- set.add(method);
- }
- }
-
- for (Pair<String, Integer> superClass : mSuperClasses) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- clz.addAllMethods(info, set, false);
- }
- }
-
- // Get methods from implemented interfaces as well;
- for (Pair<String, Integer> superClass : mInterfaces) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- clz.addAllMethods(info, set, false);
- }
- }
- }
-
- /**
- * Returns the set of all fields, including inherited
- * ones.
- *
- * @param info the api to look up super classes from
- * @return a set containing all the fields
- */
- Set<String> getAllFields(Api info) {
- Set<String> members = new HashSet<String>(100);
- addAllFields(info, members);
-
- return members;
- }
-
- private void addAllFields(Api info, Set<String> set) {
- for (String field : mFields.keySet()) {
- set.add(field);
- }
-
- for (Pair<String, Integer> superClass : mSuperClasses) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- clz.addAllFields(info, set);
- }
- }
-
- // Get methods from implemented interfaces as well;
- for (Pair<String, Integer> superClass : mInterfaces) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- clz.addAllFields(info, set);
- }
- }
- }
-
- /* This code can be used to scan through all the fields and look for fields
- that have moved to a higher class:
- Field android/view/MotionEvent#CREATOR has api=1 but parent android/view/InputEvent provides it as 9
- Field android/provider/ContactsContract$CommonDataKinds$Organization#PHONETIC_NAME has api=5 but parent android/provider/ContactsContract$ContactNameColumns provides it as 11
- Field android/widget/ListView#CHOICE_MODE_MULTIPLE has api=1 but parent android/widget/AbsListView provides it as 11
- Field android/widget/ListView#CHOICE_MODE_NONE has api=1 but parent android/widget/AbsListView provides it as 11
- Field android/widget/ListView#CHOICE_MODE_SINGLE has api=1 but parent android/widget/AbsListView provides it as 11
- Field android/view/KeyEvent#CREATOR has api=1 but parent android/view/InputEvent provides it as 9
- This is used for example in the ApiDetector to filter out warnings which result
- when people follow Eclipse's advice to replace
- ListView.CHOICE_MODE_MULTIPLE
- references with
- AbsListView.CHOICE_MODE_MULTIPLE
- since the latter has API=11 and the former has API=1; since the constant is unchanged
- between the two, and the literal is copied into the class, using the AbsListView
- reference works.
- public void checkFields(Api info) {
- fieldLoop:
- for (String field : mFields.keySet()) {
- Integer since = getField(field, info);
- if (since == null || since == Integer.MAX_VALUE) {
- continue;
- }
-
- for (Pair<String, Integer> superClass : mSuperClasses) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- Integer superSince = clz.getField(field, info);
- if (superSince == Integer.MAX_VALUE) {
- continue;
- }
-
- if (superSince != null && superSince > since) {
- String declaredIn = clz.findFieldDeclaration(info, field);
- System.out.println("Field " + getName() + "#" + field + " has api="
- + since + " but parent " + declaredIn + " provides it as "
- + superSince);
- continue fieldLoop;
- }
- }
- }
-
- // Get methods from implemented interfaces as well;
- for (Pair<String, Integer> superClass : mInterfaces) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- Integer superSince = clz.getField(field, info);
- if (superSince == Integer.MAX_VALUE) {
- continue;
- }
- if (superSince != null && superSince > since) {
- String declaredIn = clz.findFieldDeclaration(info, field);
- System.out.println("Field " + getName() + "#" + field + " has api="
- + since + " but parent " + declaredIn + " provides it as "
- + superSince);
- continue fieldLoop;
- }
- }
- }
- }
- }
-
- private String findFieldDeclaration(Api info, String name) {
- if (mFields.containsKey(name)) {
- return getName();
- }
- for (Pair<String, Integer> superClass : mSuperClasses) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- String declaredIn = clz.findFieldDeclaration(info, name);
- if (declaredIn != null) {
- return declaredIn;
- }
- }
- }
-
- // Get methods from implemented interfaces as well;
- for (Pair<String, Integer> superClass : mInterfaces) {
- ApiClass clz = info.getClass(superClass.getFirst());
- assert clz != null : superClass.getSecond();
- if (clz != null) {
- String declaredIn = clz.findFieldDeclaration(info, name);
- if (declaredIn != null) {
- return declaredIn;
- }
- }
- }
-
- return null;
- }
- */
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java
deleted file mode 100644
index 146e9e1..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiDetector.java
+++ /dev/null
@@ -1,1562 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_PREFIX;
-import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
-import static com.android.SdkConstants.ATTR_CLASS;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TARGET_API;
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.PREFIX_ANDROID;
-import static com.android.SdkConstants.R_CLASS;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_STYLE;
-import static com.android.SdkConstants.TARGET_API;
-import static com.android.SdkConstants.TOOLS_URI;
-import static com.android.SdkConstants.VIEW_TAG;
-import static com.android.tools.lint.detector.api.ClassContext.getFqcn;
-import static com.android.tools.lint.detector.api.ClassContext.getInternalName;
-import static com.android.tools.lint.detector.api.LintUtils.getNextInstruction;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.FORWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.NEAREST;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.DefaultPosition;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.SearchHints;
-import com.android.tools.lint.detector.api.Position;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.IntInsnNode;
-import org.objectweb.asm.tree.LdcInsnNode;
-import org.objectweb.asm.tree.LocalVariableNode;
-import org.objectweb.asm.tree.LookupSwitchInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationValue;
-import lombok.ast.AstVisitor;
-import lombok.ast.BinaryExpression;
-import lombok.ast.Case;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.If;
-import lombok.ast.ImportDeclaration;
-import lombok.ast.InlineIfExpression;
-import lombok.ast.IntegralLiteral;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Modifiers;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-import lombok.ast.SuperConstructorInvocation;
-import lombok.ast.Switch;
-import lombok.ast.TypeReference;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableDefinitionEntry;
-import lombok.ast.VariableReference;
-
-/**
- * Looks for usages of APIs that are not supported in all the versions targeted
- * by this application (according to its minimum API requirement in the manifest).
- */
-public class ApiDetector extends ResourceXmlDetector
- implements Detector.ClassScanner, Detector.JavaScanner {
- /**
- * Whether we flag variable, field, parameter and return type declarations of a type
- * not yet available. It appears Dalvik is very forgiving and doesn't try to preload
- * classes until actually needed, so there is no need to flag these, and in fact,
- * patterns used for supporting new and old versions sometimes declares these methods
- * and only conditionally end up actually accessing methods and fields, so only check
- * method and field accesses.
- */
- private static final boolean CHECK_DECLARATIONS = false;
-
- private static final boolean AOSP_BUILD = System.getenv("ANDROID_BUILD_TOP") != null; //$NON-NLS-1$
-
- /** Accessing an unsupported API */
- public static final Issue UNSUPPORTED = Issue.create("NewApi", //$NON-NLS-1$
- "Finds API accesses to APIs that are not supported in all targeted API versions",
-
- "This check scans through all the Android API calls in the application and " +
- "warns about any calls that are not available on *all* versions targeted " +
- "by this application (according to its minimum SDK attribute in the manifest).\n"
- +
- "\n" +
- "If you really want to use this API and don't need to support older devices just "
- +
- "set the `minSdkVersion` in your `AndroidManifest.xml` file." +
- "\n" +
- "If your code is *deliberately* accessing newer APIs, and you have ensured " +
- "(e.g. with conditional execution) that this code will only ever be called on a "
- +
- "supported platform, then you can annotate your class or method with the " +
- "`@TargetApi` annotation specifying the local minimum SDK to apply, such as " +
- "`@TargetApi(11)`, such that this check considers 11 rather than your manifest "
- +
- "file's minimum SDK as the required API level.\n" +
- "\n" +
- "If you are deliberately setting `android:` attributes in style definitions, " +
- "make sure you place this in a `values-v11` folder in order to avoid running " +
- "into runtime conflicts on certain devices where manufacturers have added " +
- "custom attributes whose ids conflict with the new ones on later platforms.\n" +
- "\n" +
- "Similarly, you can use tools:targetApi=\"11\" in an XML file to indicate that "
- +
- "the element will only be inflated in an adequate context.",
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- ApiDetector.class,
- EnumSet.of(Scope.CLASS_FILE, Scope.RESOURCE_FILE, Scope.MANIFEST))
- .addAnalysisScope(Scope.RESOURCE_FILE_SCOPE)
- .addAnalysisScope(Scope.CLASS_FILE_SCOPE);
-
- /** Accessing an inlined API on older platforms */
- public static final Issue INLINED = Issue.create("InlinedApi", //$NON-NLS-1$
- "Finds inlined fields that may or may not work on older platforms",
-
- "This check scans through all the Android API field references in the application " +
- "and flags certain constants, such as static final integers and Strings, " +
- "which were introduced in later versions. These will actually be copied " +
- "into the class files rather than being referenced, which means that " +
- "the value is available even when running on older devices. In some " +
- "cases that's fine, and in other cases it can result in a runtime " +
- "crash or incorrect behavior. It depends on the context, so consider " +
- "the code carefully and device whether it's safe and can be suppressed " +
- "or whether the code needs tbe guarded.\n" +
- "\n" +
- "If you really want to use this API and don't need to support older devices just "
- +
- "set the `minSdkVersion` in your `AndroidManifest.xml` file." +
- "\n" +
- "If your code is *deliberately* accessing newer APIs, and you have ensured " +
- "(e.g. with conditional execution) that this code will only ever be called on a "
- +
- "supported platform, then you can annotate your class or method with the " +
- "`@TargetApi` annotation specifying the local minimum SDK to apply, such as " +
- "`@TargetApi(11)`, such that this check considers 11 rather than your manifest "
- +
- "file's minimum SDK as the required API level.\n",
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- ApiDetector.class,
- EnumSet.of(Scope.JAVA_FILE))
- .addAnalysisScope(Scope.JAVA_FILE_SCOPE);
-
- /** Accessing an unsupported API */
- public static final Issue OVERRIDE = Issue.create("Override", //$NON-NLS-1$
- "Finds method declarations that will accidentally override methods in later versions",
-
- "Suppose you are building against Android API 8, and you've subclassed Activity. " +
- "In your subclass you add a new method called `isDestroyed`(). At some later point, " +
- "a method of the same name and signature is added to Android. Your method will " +
- "now override the Android method, and possibly break its contract. Your method " +
- "is not calling `super.isDestroyed()`, since your compilation target doesn't " +
- "know about the method.\n" +
- "\n" +
- "The above scenario is what this lint detector looks for. The above example is " +
- "real, since `isDestroyed()` was added in API 17, but it will be true for *any* " +
- "method you have added to a subclass of an Android class where your build target " +
- "is lower than the version the method was introduced in.\n" +
- "\n" +
- "To fix this, either rename your method, or if you are really trying to augment " +
- "the builtin method if available, switch to a higher build target where you can " +
- "deliberately add `@Override` on your overriding method, and call `super` if " +
- "appropriate etc.\n",
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- ApiDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- private static final String TARGET_API_VMSIG = '/' + TARGET_API + ';';
- private static final String SWITCH_TABLE_PREFIX = "$SWITCH_TABLE$"; //$NON-NLS-1$
- private static final String ORDINAL_METHOD = "ordinal"; //$NON-NLS-1$
-
- protected ApiLookup mApiDatabase;
- private int mMinApi = -1;
- private Map<String, List<Pair<String, Location>>> mPendingFields;
-
- /** Constructs a new API check */
- public ApiDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.SLOW;
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- mApiDatabase = ApiLookup.get(context.getClient());
- // We can't look up the minimum API required by the project here:
- // The manifest file hasn't been processed yet in the -before- project hook.
- // For now it's initialized lazily in getMinSdk(Context), but the
- // lint infrastructure should be fixed to parse manifest file up front.
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return true;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return ALL;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (mApiDatabase == null) {
- return;
- }
-
- String value = attribute.getValue();
-
- String owner = null;
- String name = null;
-
- String prefix;
- if (value.startsWith(ANDROID_PREFIX)) {
- prefix = ANDROID_PREFIX;
- } else if (value.startsWith(ANDROID_THEME_PREFIX)) {
- prefix = ANDROID_THEME_PREFIX;
- } else if (value.startsWith(PREFIX_ANDROID) && ATTR_NAME.equals(attribute.getName())
- && TAG_ITEM.equals(attribute.getOwnerElement().getTagName())
- && attribute.getOwnerElement().getParentNode() != null
- && TAG_STYLE.equals(attribute.getOwnerElement().getParentNode().getNodeName())) {
- owner = "android/R$attr"; //$NON-NLS-1$
- name = value.substring(PREFIX_ANDROID.length());
- prefix = PREFIX_ANDROID;
- } else {
- return;
- }
-
- if (owner == null) {
- // Convert @android:type/foo into android/R$type and "foo"
- int index = value.indexOf('/', prefix.length());
- if (index != -1) {
- owner = "android/R$" //$NON-NLS-1$
- + value.substring(prefix.length(), index);
- name = value.substring(index + 1);
- if (name.indexOf('.') != -1) {
- name = name.replace('.', '_');
- }
- } else if (value.startsWith(ANDROID_THEME_PREFIX)) {
- owner = "android/R$attr"; //$NON-NLS-1$
- name = value.substring(ANDROID_THEME_PREFIX.length());
- } else {
- return;
- }
- }
- assert name != null; // Eclipse can't infer this
- int api = mApiDatabase.getFieldVersion(owner, name);
- int minSdk = getMinSdk(context);
- if (api > minSdk && api > context.getFolderVersion()
- && api > getLocalMinSdk(attribute.getOwnerElement())) {
- // Don't complain about resource references in the tools namespace,
- // such as for example "tools:layout="@android:layout/list_content",
- // used only for designtime previews
- if (TOOLS_URI.equals(attribute.getNamespaceURI())) {
- return;
- }
-
- Location location = context.getLocation(attribute);
- String message = String.format(
- "%1$s requires API level %2$d (current min is %3$d)",
- value, api, minSdk);
- context.report(UNSUPPORTED, attribute, location, message, null);
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (mApiDatabase == null) {
- return;
- }
-
- String tag = element.getTagName();
-
- ResourceFolderType folderType = context.getResourceFolderType();
- if (folderType != ResourceFolderType.LAYOUT) {
- if (element.getParentNode().getNodeType() != Node.ELEMENT_NODE) {
- // Root node
- return;
- }
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node textNode = childNodes.item(i);
- if (textNode.getNodeType() == Node.TEXT_NODE) {
- String text = textNode.getNodeValue();
- if (text.indexOf(ANDROID_PREFIX) != -1) {
- text = text.trim();
- // Convert @android:type/foo into android/R$type and "foo"
- int index = text.indexOf('/', ANDROID_PREFIX.length());
- if (index != -1) {
- String owner = "android/R$" //$NON-NLS-1$
- + text.substring(ANDROID_PREFIX.length(), index);
- String name = text.substring(index + 1);
- if (name.indexOf('.') != -1) {
- name = name.replace('.', '_');
- }
- int api = mApiDatabase.getFieldVersion(owner, name);
- int minSdk = getMinSdk(context);
- if (api > minSdk && api > context.getFolderVersion()
- && api > getLocalMinSdk(element)) {
- Location location = context.getLocation(textNode);
- String message = String.format(
- "%1$s requires API level %2$d (current min is %3$d)",
- text, api, minSdk);
- context.report(UNSUPPORTED, element, location, message, null);
- }
- }
- }
- }
- }
- } else if (folderType == ResourceFolderType.LAYOUT) {
- if (VIEW_TAG.equals(tag)) {
- tag = element.getAttribute(ATTR_CLASS);
- if (tag == null || tag.isEmpty()) {
- return;
- }
- }
-
- // Check widgets to make sure they're available in this version of the SDK.
- if (tag.indexOf('.') != -1 ||
- folderType != ResourceFolderType.LAYOUT) {
- // Custom views aren't in the index
- return;
- }
- // TODO: Consider other widgets outside of android.widget.*
- int api = mApiDatabase.getCallVersion("android/widget/" + tag, //$NON-NLS-1$
- CONSTRUCTOR_NAME,
- // Not all views provided this constructor right away, for example,
- // LinearLayout added it in API 11 yet LinearLayout is much older:
- // "(Landroid/content/Context;Landroid/util/AttributeSet;I)V"); //$NON-NLS-1$
- "(Landroid/content/Context;)"); //$NON-NLS-1$
- int minSdk = getMinSdk(context);
- if (api > minSdk && api > context.getFolderVersion()
- && api > getLocalMinSdk(element)) {
- Location location = context.getLocation(element);
- String message = String.format(
- "View requires API level %1$d (current min is %2$d): <%3$s>",
- api, minSdk, tag);
- context.report(UNSUPPORTED, element, location, message, null);
- }
- }
- }
-
- protected int getMinSdk(Context context) {
- if (mMinApi == -1) {
- mMinApi = context.getMainProject().getMinSdk();
- }
-
- return mMinApi;
- }
-
- // ---- Implements ClassScanner ----
-
- @SuppressWarnings("rawtypes") // ASM API
- @Override
- public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
- if (mApiDatabase == null) {
- return;
- }
-
- if (AOSP_BUILD && classNode.name.startsWith("android/support/")) { //$NON-NLS-1$
- return;
- }
-
- // Requires util package (add prebuilts/tools/common/asm-tools/asm-debug-all-4.0.jar)
- //classNode.accept(new TraceClassVisitor(new PrintWriter(System.out)));
-
- int classMinSdk = getClassMinSdk(context, classNode);
- if (classMinSdk == -1) {
- classMinSdk = getMinSdk(context);
- }
-
- List methodList = classNode.methods;
- if (methodList.isEmpty()) {
- return;
- }
-
- boolean checkCalls = context.isEnabled(UNSUPPORTED)
- || context.isEnabled(INLINED);
- boolean checkMethods = context.isEnabled(OVERRIDE)
- && context.getMainProject().getBuildSdk() >= 1;
- String frameworkParent = null;
- if (checkMethods) {
- LintDriver driver = context.getDriver();
- String owner = classNode.superName;
- while (owner != null) {
- // For virtual dispatch, walk up the inheritance chain checking
- // each inherited method
- if (owner.startsWith("android/") //$NON-NLS-1$
- || owner.startsWith("java/") //$NON-NLS-1$
- || owner.startsWith("javax/")) { //$NON-NLS-1$
- frameworkParent = owner;
- break;
- }
- owner = driver.getSuperClass(owner);
- }
- if (frameworkParent == null) {
- checkMethods = false;
- }
- }
-
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
-
- int minSdk = getLocalMinSdk(method.invisibleAnnotations);
- if (minSdk == -1) {
- minSdk = classMinSdk;
- }
-
- InsnList nodes = method.instructions;
-
- if (checkMethods && Character.isJavaIdentifierStart(method.name.charAt(0))) {
- int buildSdk = context.getMainProject().getBuildSdk();
- String name = method.name;
- assert frameworkParent != null;
- int api = mApiDatabase.getCallVersion(frameworkParent, name, method.desc);
- if (api > buildSdk && buildSdk != -1) {
- // TODO: Don't complain if it's annotated with @Override; that means
- // somehow the build target isn't correct.
- String fqcn;
- String owner = classNode.name;
- if (CONSTRUCTOR_NAME.equals(name)) {
- fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
- } else {
- fqcn = ClassContext.getFqcn(owner) + '#' + name;
- }
- String message = String.format(
- "This method is not overriding anything with the current build " +
- "target, but will in API level %1$d (current target is %2$d): %3$s",
- api, buildSdk, fqcn);
-
- Location location = context.getLocation(method, classNode);
- context.report(OVERRIDE, method, null, location, message, null);
- }
- }
-
- if (!checkCalls) {
- continue;
- }
-
- if (CHECK_DECLARATIONS) {
- // Check types in parameter list and types of local variables
- List localVariables = method.localVariables;
- if (localVariables != null) {
- for (Object v : localVariables) {
- LocalVariableNode var = (LocalVariableNode) v;
- String desc = var.desc;
- if (desc.charAt(0) == 'L') {
- // "Lpackage/Class;" => "package/Bar"
- String className = desc.substring(1, desc.length() - 1);
- int api = mApiDatabase.getClassVersion(className);
- if (api > minSdk) {
- String fqcn = ClassContext.getFqcn(className);
- String message = String.format(
- "Class requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
- report(context, message, var.start, method,
- className.substring(className.lastIndexOf('/') + 1), null,
- SearchHints.create(NEAREST).matchJavaSymbol());
- }
- }
- }
- }
-
- // Check return type
- // The parameter types are already handled as local variables so we can skip
- // right to the return type.
- // Check types in parameter list
- String signature = method.desc;
- if (signature != null) {
- int args = signature.indexOf(')');
- if (args != -1 && signature.charAt(args + 1) == 'L') {
- String type = signature.substring(args + 2, signature.length() - 1);
- int api = mApiDatabase.getClassVersion(type);
- if (api > minSdk) {
- String fqcn = ClassContext.getFqcn(type);
- String message = String.format(
- "Class requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
- AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
- report(context, message, first, method, method.name, null,
- SearchHints.create(BACKWARD).matchJavaSymbol());
- }
- }
- }
- }
-
- for (int i = 0, n = nodes.size(); i < n; i++) {
- AbstractInsnNode instruction = nodes.get(i);
- int type = instruction.getType();
- if (type == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode node = (MethodInsnNode) instruction;
- String name = node.name;
- String owner = node.owner;
- String desc = node.desc;
-
- // No need to check methods in this local class; we know they
- // won't be an API match
- if (node.getOpcode() == Opcodes.INVOKEVIRTUAL
- && owner.equals(classNode.name)) {
- owner = classNode.superName;
- }
-
- boolean checkingSuperClass = false;
- while (owner != null) {
- int api = mApiDatabase.getCallVersion(owner, name, desc);
- if (api > minSdk) {
- if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
- // We're in a compiler-generated method to generate an
- // array indexed by enum ordinal values to enum values. The enum
- // itself must be requiring a higher API number than is
- // currently used, but the call site for the switch statement
- // will also be referencing it, so no need to report these
- // calls.
- break;
- }
-
- if (!checkingSuperClass
- && node.getOpcode() == Opcodes.INVOKEVIRTUAL
- && methodDefinedLocally(classNode, name, desc)) {
- break;
- }
-
- String fqcn;
- if (CONSTRUCTOR_NAME.equals(name)) {
- fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
- } else {
- fqcn = ClassContext.getFqcn(owner) + '#' + name;
- }
- String message = String.format(
- "Call requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
-
- if (name.equals(ORDINAL_METHOD)
- && instruction.getNext() != null
- && instruction.getNext().getNext() != null
- && instruction.getNext().getOpcode() == Opcodes.IALOAD
- && instruction.getNext().getNext().getOpcode()
- == Opcodes.TABLESWITCH) {
- message = String.format(
- "Enum for switch requires API level %1$d " +
- "(current min is %2$d): %3$s",
- api, minSdk, ClassContext.getFqcn(owner));
- }
-
- report(context, message, node, method, name, null,
- SearchHints.create(FORWARD).matchJavaSymbol());
- }
-
- // For virtual dispatch, walk up the inheritance chain checking
- // each inherited method
- if (owner.startsWith("android/") //$NON-NLS-1$
- || owner.startsWith("javax/")) { //$NON-NLS-1$
- // The API map has already inlined all inherited methods
- // so no need to keep checking up the chain
- owner = null;
- } else if (owner.startsWith("java/")) { //$NON-NLS-1$
- if (owner.equals(LocaleDetector.DATE_FORMAT_OWNER)) {
- checkSimpleDateFormat(context, method, node, minSdk);
- }
- // Already inlined; see comment above
- owner = null;
- } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
- owner = context.getDriver().getSuperClass(owner);
- } else if (node.getOpcode() == Opcodes.INVOKESTATIC && api == -1) {
- // Inherit through static classes as well
- owner = context.getDriver().getSuperClass(owner);
- } else {
- owner = null;
- }
-
- checkingSuperClass = true;
- }
- } else if (type == AbstractInsnNode.FIELD_INSN) {
- FieldInsnNode node = (FieldInsnNode) instruction;
- String name = node.name;
- String owner = node.owner;
- int api = mApiDatabase.getFieldVersion(owner, name);
- if (api > minSdk) {
- if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
- checkSwitchBlock(context, classNode, node, method, name, owner,
- api, minSdk);
- continue;
- }
- String fqcn = ClassContext.getFqcn(owner) + '#' + name;
- if (mPendingFields != null) {
- mPendingFields.remove(fqcn);
- }
- String message = String.format(
- "Field requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
- report(context, message, node, method, name, null,
- SearchHints.create(FORWARD).matchJavaSymbol());
- }
- } else if (type == AbstractInsnNode.LDC_INSN) {
- LdcInsnNode node = (LdcInsnNode) instruction;
- if (node.cst instanceof Type) {
- Type t = (Type) node.cst;
- String className = t.getInternalName();
-
- int api = mApiDatabase.getClassVersion(className);
- if (api > minSdk) {
- String fqcn = ClassContext.getFqcn(className);
- String message = String.format(
- "Class requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
- report(context, message, node, method,
- className.substring(className.lastIndexOf('/') + 1), null,
- SearchHints.create(FORWARD).matchJavaSymbol());
- }
- }
- }
- }
- }
- }
-
- private static void checkSimpleDateFormat(ClassContext context, MethodNode method,
- MethodInsnNode node, int minSdk) {
- if (minSdk >= 9) {
- // Already OK
- return;
- }
- if (node.name.equals(CONSTRUCTOR_NAME) && !node.desc.equals("()V")) { //$NON-NLS-1$
- // Check first argument
- AbstractInsnNode prev = LintUtils.getPrevInstruction(node);
- if (prev != null && !node.desc.equals("(Ljava/lang/String;)V")) { //$NON-NLS-1$
- prev = LintUtils.getPrevInstruction(prev);
- }
- if (prev != null && prev.getOpcode() == Opcodes.LDC) {
- LdcInsnNode ldc = (LdcInsnNode) prev;
- Object cst = ldc.cst;
- if (cst instanceof String) {
- String pattern = (String) cst;
- boolean isEscaped = false;
- for (int i = 0; i < pattern.length(); i++) {
- char c = pattern.charAt(i);
- if (c == '\'') {
- isEscaped = !isEscaped;
- } else if (!isEscaped && (c == 'L' || c == 'c')) {
- String message = String.format(
- "The pattern character '%1$c' requires API level 9 (current " +
- "min is %2$d) : \"%3$s\"", c, minSdk, pattern);
- report(context, message, node, method, pattern, null,
- SearchHints.create(FORWARD));
- return;
- }
- }
- }
- }
- }
- }
-
- @SuppressWarnings("rawtypes") // ASM API
- private static boolean methodDefinedLocally(ClassNode classNode, String name, String desc) {
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- if (name.equals(method.name) && desc.equals(method.desc)) {
- return true;
- }
- }
-
- return false;
- }
-
- @SuppressWarnings("rawtypes") // ASM API
- private static void checkSwitchBlock(ClassContext context, ClassNode classNode,
- FieldInsnNode field, MethodNode method, String name, String owner, int api,
- int minSdk) {
- // Switch statements on enums are tricky. The compiler will generate a method
- // which returns an array of the enum constants, indexed by their ordinal() values.
- // However, we only want to complain if the code is actually referencing one of
- // the non-available enum fields.
- //
- // For the android.graphics.PorterDuff.Mode enum for example, the first few items
- // in the array are populated like this:
- //
- // L0
- // ALOAD 0
- // GETSTATIC android/graphics/PorterDuff$Mode.ADD : Landroid/graphics/PorterDuff$Mode;
- // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
- // ICONST_1
- // IASTORE
- // L1
- // GOTO L3
- // L2
- // FRAME FULL [[I] [java/lang/NoSuchFieldError]
- // POP
- // L3
- // FRAME SAME
- // ALOAD 0
- // GETSTATIC android/graphics/PorterDuff$Mode.CLEAR : Landroid/graphics/PorterDuff$Mode;
- // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
- // ICONST_2
- // IASTORE
- // ...
- // So if we for example find that the "ADD" field isn't accessible, since it requires
- // API 11, we need to
- // (1) First find out what its ordinal number is. We can look at the following
- // instructions to discover this; it's the "ICONST_1" and "IASTORE" instructions.
- // (After ICONST_5 it moves on to BIPUSH 6, BIPUSH 7, etc.)
- // (2) Find the corresponding *usage* of this switch method. For the above enum,
- // the switch ordinal lookup method will be called
- // "$SWITCH_TABLE$android$graphics$PorterDuff$Mode" with desc "()[I".
- // This means we will be looking for an invocation in some other method which looks
- // like this:
- // INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
- // (obviously, it can be invoked more than once)
- // Note that it can be used more than once in this class and all sites should be
- // checked!
- // (3) Look up the corresponding table switch, which should look something like this:
- // INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
- // ALOAD 0
- // INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
- // IALOAD
- // LOOKUPSWITCH
- // 2: L1
- // 11: L2
- // default: L3
- // Here we need to see if the LOOKUPSWITCH instruction is referencing our target
- // case. Above we were looking for the "ADD" case which had ordinal 1. Since this
- // isn't explicitly referenced, we can ignore this field reference.
- AbstractInsnNode next = field.getNext();
- if (next == null || next.getOpcode() != Opcodes.INVOKEVIRTUAL) {
- return;
- }
- next = next.getNext();
- if (next == null) {
- return;
- }
- int ordinal;
- switch (next.getOpcode()) {
- case Opcodes.ICONST_0: ordinal = 0; break;
- case Opcodes.ICONST_1: ordinal = 1; break;
- case Opcodes.ICONST_2: ordinal = 2; break;
- case Opcodes.ICONST_3: ordinal = 3; break;
- case Opcodes.ICONST_4: ordinal = 4; break;
- case Opcodes.ICONST_5: ordinal = 5; break;
- case Opcodes.BIPUSH: {
- IntInsnNode iin = (IntInsnNode) next;
- ordinal = iin.operand;
- break;
- }
- default:
- return;
- }
-
- // Find usages of this call site
- List methodList = classNode.methods;
- for (Object m : methodList) {
- InsnList nodes = ((MethodNode) m).instructions;
- for (int i = 0, n = nodes.size(); i < n; i++) {
- AbstractInsnNode instruction = nodes.get(i);
- if (instruction.getOpcode() != Opcodes.INVOKESTATIC){
- continue;
- }
- MethodInsnNode node = (MethodInsnNode) instruction;
- if (node.name.equals(method.name)
- && node.desc.equals(method.desc)
- && node.owner.equals(classNode.name)) {
- // Find lookup switch
- AbstractInsnNode target = getNextInstruction(node);
- while (target != null) {
- if (target.getOpcode() == Opcodes.LOOKUPSWITCH) {
- LookupSwitchInsnNode lookup = (LookupSwitchInsnNode) target;
- @SuppressWarnings("unchecked") // ASM API
- List<Integer> keys = lookup.keys;
- if (keys != null && keys.contains(ordinal)) {
- String fqcn = ClassContext.getFqcn(owner) + '#' + name;
- String message = String.format(
- "Enum value requires API level %1$d " +
- "(current min is %2$d): %3$s",
- api, minSdk, fqcn);
- report(context, message, lookup, (MethodNode) m, name, null,
- SearchHints.create(FORWARD).matchJavaSymbol());
-
- // Break out of the inner target search only; the switch
- // statement could be used in other places in this class as
- // well and we want to report all problematic usages.
- break;
- }
- }
- target = getNextInstruction(target);
- }
- }
- }
- }
- }
-
- /**
- * Return the {@code @TargetApi} level to use for the given {@code classNode};
- * this will be the {@code @TargetApi} annotation on the class, or any outer
- * methods (for anonymous inner classes) or outer classes (for inner classes)
- * of the given class.
- */
- private static int getClassMinSdk(ClassContext context, ClassNode classNode) {
- int classMinSdk = getLocalMinSdk(classNode.invisibleAnnotations);
- if (classMinSdk != -1) {
- return classMinSdk;
- }
-
- LintDriver driver = context.getDriver();
- while (classNode != null) {
- ClassNode prev = classNode;
- classNode = driver.getOuterClassNode(classNode);
- if (classNode != null) {
- // TODO: Should this be "curr" instead?
- if (prev.outerMethod != null) {
- @SuppressWarnings("rawtypes") // ASM API
- List methods = classNode.methods;
- for (Object m : methods) {
- MethodNode method = (MethodNode) m;
- if (method.name.equals(prev.outerMethod)
- && method.desc.equals(prev.outerMethodDesc)) {
- // Found the outer method for this anonymous class; check method
- // annotations on it, then continue up the class hierarchy
- int methodMinSdk = getLocalMinSdk(method.invisibleAnnotations);
- if (methodMinSdk != -1) {
- return methodMinSdk;
- }
-
- break;
- }
- }
- }
-
- classMinSdk = getLocalMinSdk(classNode.invisibleAnnotations);
- if (classMinSdk != -1) {
- return classMinSdk;
- }
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the minimum SDK to use according to the given annotation list, or
- * -1 if no annotation was found.
- *
- * @param annotations a list of annotation nodes from ASM
- * @return the API level to use for this node, or -1
- */
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static int getLocalMinSdk(List annotations) {
- if (annotations != null) {
- for (AnnotationNode annotation : (List<AnnotationNode>)annotations) {
- String desc = annotation.desc;
- if (desc.endsWith(TARGET_API_VMSIG)) {
- if (annotation.values != null) {
- for (int i = 0, n = annotation.values.size(); i < n; i += 2) {
- String key = (String) annotation.values.get(i);
- if (key.equals("value")) { //$NON-NLS-1$
- Object value = annotation.values.get(i + 1);
- if (value instanceof Integer) {
- return ((Integer) value).intValue();
- }
- }
- }
- }
- }
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the minimum SDK to use in the given element context, or -1 if no
- * {@code tools:targetApi} attribute was found.
- *
- * @param element the element to look at, including parents
- * @return the API level to use for this element, or -1
- */
- private static int getLocalMinSdk(@NonNull Element element) {
- while (element != null) {
- String targetApi = element.getAttributeNS(TOOLS_URI, ATTR_TARGET_API);
- if (targetApi != null && !targetApi.isEmpty()) {
- if (Character.isDigit(targetApi.charAt(0))) {
- try {
- return Integer.parseInt(targetApi);
- } catch (NumberFormatException nufe) {
- break;
- }
- }
-
- for (int api = 1; api <= SdkConstants.HIGHEST_KNOWN_API; api++) {
- String code = LintUtils.getBuildCode(api);
- if (code != null && code.equalsIgnoreCase(targetApi)) {
- return api;
- }
- }
- }
-
- Node parent = element.getParentNode();
- if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
- element = (Element) parent;
- } else {
- break;
- }
- }
-
- return -1;
- }
-
- private static void report(final ClassContext context, String message, AbstractInsnNode node,
- MethodNode method, String patternStart, String patternEnd, SearchHints hints) {
- int lineNumber = node != null ? ClassContext.findLineNumber(node) : -1;
-
- // If looking for a constructor, the string we'll see in the source is not the
- // method name (<init>) but the class name
- if (patternStart != null && patternStart.equals(CONSTRUCTOR_NAME)
- && node instanceof MethodInsnNode) {
- if (hints != null) {
- hints = hints.matchConstructor();
- }
- patternStart = ((MethodInsnNode) node).owner;
- }
-
- if (patternStart != null) {
- int index = patternStart.lastIndexOf('$');
- if (index != -1) {
- patternStart = patternStart.substring(index + 1);
- }
- index = patternStart.lastIndexOf('/');
- if (index != -1) {
- patternStart = patternStart.substring(index + 1);
- }
- }
-
- Location location = context.getLocationForLine(lineNumber, patternStart, patternEnd,
- hints);
- context.report(UNSUPPORTED, method, node, location, message, null);
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mPendingFields != null) {
- for (List<Pair<String, Location>> list : mPendingFields.values()) {
- for (Pair<String, Location> pair : list) {
- String message = pair.getFirst();
- Location location = pair.getSecond();
- context.report(INLINED, location, message, null);
- }
- }
- }
-
- super.afterCheckProject(context);
- }
-
-// ---- Implements JavaScanner ----
-
- @Nullable
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new ApiVisitor(context);
- }
-
- @Nullable
- @Override
- public List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes() {
- List<Class<? extends lombok.ast.Node>> types =
- new ArrayList<Class<? extends lombok.ast.Node>>(2);
- types.add(ImportDeclaration.class);
- types.add(Select.class);
- types.add(MethodDeclaration.class);
- types.add(ConstructorDeclaration.class);
- types.add(VariableDefinitionEntry.class);
- types.add(VariableReference.class);
- return types;
- }
-
- /**
- * Checks whether the given instruction is a benign usage of a constant defined in
- * a later version of Android than the application's {@code minSdkVersion}.
- *
- * @param node the instruction to check
- * @param name the name of the constant
- * @param owner the field owner
- * @return true if the given usage is safe on older versions than the introduction
- * level of the constant
- */
- public boolean isBenignConstantUsage(
- @Nullable lombok.ast.Node node,
- @NonNull String name,
- @NonNull String owner) {
- if (owner.equals("android/os/Build$VERSION_CODES")) { //$NON-NLS-1$
- // These constants are required for compilation, not execution
- // and valid code checks it even on older platforms
- return true;
- }
- if (owner.equals("android/view/ViewGroup$LayoutParams") //$NON-NLS-1$
- && name.equals("MATCH_PARENT")) { //$NON-NLS-1$
- return true;
- }
- if (owner.equals("android/widget/AbsListView") //$NON-NLS-1$
- && ((name.equals("CHOICE_MODE_NONE") //$NON-NLS-1$
- || name.equals("CHOICE_MODE_MULTIPLE") //$NON-NLS-1$
- || name.equals("CHOICE_MODE_SINGLE")))) { //$NON-NLS-1$
- // android.widget.ListView#CHOICE_MODE_MULTIPLE and friends have API=1,
- // but in API 11 it was moved up to the parent class AbsListView.
- // Referencing AbsListView#CHOICE_MODE_MULTIPLE technically requires API 11,
- // but the constant is the same as the older version, so accept this without
- // warning.
- return true;
- }
-
- if (node == null) {
- return false;
- }
-
- // It's okay to reference the constant as a case constant (since that
- // code path won't be taken) or in a condition of an if statement
- lombok.ast.Node curr = node.getParent();
- while (curr != null) {
- Class<? extends lombok.ast.Node> nodeType = curr.getClass();
- if (nodeType == Case.class) {
- Case caseStatement = (Case) curr;
- Expression condition = caseStatement.astCondition();
- return condition != null && isAncestor(condition, node);
- } else if (nodeType == If.class) {
- If ifStatement = (If) curr;
- Expression condition = ifStatement.astCondition();
- return condition != null && isAncestor(condition, node);
- } else if (nodeType == InlineIfExpression.class) {
- InlineIfExpression ifStatement = (InlineIfExpression) curr;
- Expression condition = ifStatement.astCondition();
- return condition != null && isAncestor(condition, node);
- }
- curr = curr.getParent();
- }
-
- return false;
- }
-
- private static boolean isAncestor(
- @NonNull lombok.ast.Node ancestor,
- @Nullable lombok.ast.Node node) {
- while (node != null) {
- if (node == ancestor) {
- return true;
- }
- node = node.getParent();
- }
-
- return false;
- }
-
- private final class ApiVisitor extends ForwardingAstVisitor {
- private JavaContext mContext;
- private Map<String, String> mClassToImport = Maps.newHashMap();
- private List<String> mStarImports;
- private Set<String> mLocalVars;
- private lombok.ast.Node mCurrentMethod;
- private Set<String> mFields;
- private List<String> mStaticStarImports;
-
- private ApiVisitor(JavaContext context) {
- mContext = context;
- }
-
- @Override
- public boolean visitImportDeclaration(ImportDeclaration node) {
- if (node.astStarImport()) {
- // Similarly, if you're inheriting from a constants class, figure out
- // how that works... :=(
- String fqcn = node.asFullyQualifiedName();
- int strip = fqcn.lastIndexOf('*');
- if (strip != -1) {
- strip = fqcn.lastIndexOf('.', strip);
- if (strip != -1) {
- String pkgName = getInternalName(fqcn.substring(0, strip));
- if (ApiLookup.isRelevantOwner(pkgName)) {
- if (node.astStaticImport()) {
- if (mStaticStarImports == null) {
- mStaticStarImports = Lists.newArrayList();
- }
- mStaticStarImports.add(pkgName);
- } else {
- if (mStarImports == null) {
- mStarImports = Lists.newArrayList();
- }
- mStarImports.add(pkgName);
- }
- }
- }
- }
- } else if (node.astStaticImport()) {
- String fqcn = node.asFullyQualifiedName();
- String fieldName = getInternalName(fqcn);
- int index = fieldName.lastIndexOf('$');
- if (index != -1) {
- String owner = fieldName.substring(0, index);
- String name = fieldName.substring(index + 1);
- checkField(node, name, owner);
- }
- } else {
- // Store in map -- if it's "one of ours"
- // Use override detector's map for that purpose
- String fqcn = node.asFullyQualifiedName();
-
- int last = fqcn.lastIndexOf('.');
- if (last != -1) {
- String className = fqcn.substring(last + 1);
- mClassToImport.put(className, fqcn);
- }
- }
-
- return super.visitImportDeclaration(node);
- }
-
- @Override
- public boolean visitSelect(Select node) {
- boolean result = super.visitSelect(node);
-
- if (node.getParent() instanceof Select) {
- // We only want to look at the leaf expressions; e.g. if you have
- // "foo.bar.baz" we only care about the select foo.bar.baz, not foo.bar
- return result;
- }
-
- // See if this corresponds to a field reference. We assume it's a field if
- // it's a select (x.y) and either the identifier y is capitalized (e.g.
- // foo.VIEW_MASK) or if it's a member of an R class (R.id.foo).
- String name = node.astIdentifier().astValue();
- boolean isField = Character.isUpperCase(name.charAt(0));
- if (!isField) {
- // See if there's an R class
- Select current = node;
- while (current != null) {
- Expression operand = current.astOperand();
- if (operand instanceof Select) {
- current = (Select) operand;
- if (R_CLASS.equals(current.astIdentifier().astValue())) {
- isField = true;
- break;
- }
- } else if (operand instanceof VariableReference) {
- VariableReference reference = (VariableReference) operand;
- if (R_CLASS.equals(reference.astIdentifier().astValue())) {
- isField = true;
- }
- break;
- } else {
- break;
- }
- }
- }
-
- if (isField) {
- Expression operand = node.astOperand();
- if (operand.getClass() == Select.class) {
- // Possibly a fully qualified name in place
- String cls = operand.toString();
-
- // See if it's an imported class with an inner class
- // (e.g. Manifest.permission.FIELD)
- if (Character.isUpperCase(cls.charAt(0))) {
- int firstDot = cls.indexOf('.');
- if (firstDot != -1) {
- String base = cls.substring(0, firstDot);
- String fqcn = mClassToImport.get(base);
- if (fqcn != null) {
- // Yes imported
- String owner = getInternalName(fqcn + cls.substring(firstDot));
- checkField(node, name, owner);
- return result;
- }
-
- // Might be a star import: have to iterate and check here
- if (mStarImports != null) {
- for (String packagePrefix : mStarImports) {
- String owner = getInternalName(packagePrefix + '/' + cls);
- if (checkField(node, name, owner)) {
- mClassToImport.put(name, owner);
- return result;
- }
- }
- }
- }
- }
-
- // See if it's a fully qualified reference in place
- String owner = getInternalName(cls);
- checkField(node, name, owner);
- return result;
- } else if (operand.getClass() == VariableReference.class) {
- String className = ((VariableReference) operand).astIdentifier().astValue();
- // Not a FQCN that we care about: look in imports
- String fqcn = mClassToImport.get(className);
- if (fqcn != null) {
- // Yes imported
- String owner = getInternalName(fqcn);
- checkField(node, name, owner);
- return result;
- }
-
- if (Character.isUpperCase(className.charAt(0))) {
- // Might be a star import: have to iterate and check here
- if (mStarImports != null) {
- for (String packagePrefix : mStarImports) {
- String owner = getInternalName(packagePrefix) + '/' + className;
- if (checkField(node, name, owner)) {
- mClassToImport.put(name, owner);
- return result;
- }
- }
- }
- }
- }
- }
- return result;
- }
-
- @Override
- public boolean visitVariableReference(VariableReference node) {
- boolean result = super.visitVariableReference(node);
-
- if (node.getParent() != null) {
- lombok.ast.Node parent = node.getParent();
- Class<? extends lombok.ast.Node> parentClass = parent.getClass();
- if (parentClass == Select.class
- || parentClass == Switch.class // look up on the switch expression type
- || parentClass == Case.class
- || parentClass == ConstructorInvocation.class
- || parentClass == SuperConstructorInvocation.class
- || parentClass == AnnotationElement.class) {
- return result;
- }
-
- if (parent instanceof MethodInvocation &&
- ((MethodInvocation) parent).astOperand() == node) {
- return result;
- } else if (parent instanceof BinaryExpression) {
- BinaryExpression expression = (BinaryExpression) parent;
- if (expression.astLeft() == node) {
- return result;
- }
- }
- }
-
- String name = node.astIdentifier().astValue();
- if (Character.isUpperCase(name.charAt(0))
- && (mLocalVars == null || !mLocalVars.contains(name))
- && (mFields == null || !mFields.contains(name))) {
- // Potential field reference: check it
- if (mStaticStarImports != null) {
- for (String owner : mStaticStarImports) {
- if (checkField(node, name, owner)) {
- break;
- }
- }
- }
- }
-
- return result;
- }
-
- @Override
- public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
- if (mCurrentMethod != null) {
- if (mLocalVars == null) {
- mLocalVars = Sets.newHashSet();
- }
- mLocalVars.add(node.astName().astValue());
- } else {
- if (mFields == null) {
- mFields = Sets.newHashSet();
- }
- mFields.add(node.astName().astValue());
- }
- return super.visitVariableDefinitionEntry(node);
- }
-
- @Override
- public boolean visitMethodDeclaration(MethodDeclaration node) {
- mLocalVars = null;
- mCurrentMethod = node;
- return super.visitMethodDeclaration(node);
- }
-
- @Override
- public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
- mLocalVars = null;
- mCurrentMethod = node;
- return super.visitConstructorDeclaration(node);
- }
-
- @Override
- public void endVisit(lombok.ast.Node node) {
- if (node == mCurrentMethod) {
- mCurrentMethod = null;
- }
- super.endVisit(node);
- }
-
- /**
- * Checks a Java source field reference. Returns true if the field is known
- * regardless of whether it's an invalid field or not
- */
- private boolean checkField(
- @NonNull lombok.ast.Node node,
- @NonNull String name,
- @NonNull String owner) {
- int api = mApiDatabase.getFieldVersion(owner, name);
- if (api != -1) {
- int minSdk = getMinSdk(mContext);
- if (api > minSdk
- && api > getLocalMinSdk(node)) {
- if (isBenignConstantUsage(node, name, owner)) {
- return true;
- }
-
- Location location = mContext.getLocation(node);
- String fqcn = getFqcn(owner) + '#' + name;
-
- if (node instanceof ImportDeclaration) {
- // Replace import statement location range with just
- // the identifier part
- ImportDeclaration d = (ImportDeclaration) node;
- int startOffset = d.astParts().first().getPosition().getStart();
- Position start = location.getStart();
- int startColumn = start.getColumn();
- int startLine = start.getLine();
- start = new DefaultPosition(startLine,
- startColumn + startOffset - start.getOffset(), startOffset);
- int fqcnLength = fqcn.length();
- Position end = new DefaultPosition(startLine,
- start.getColumn() + fqcnLength,
- start.getOffset() + fqcnLength);
- location = Location.create(location.getFile(), start, end);
- }
-
- String message = String.format(
- "Field requires API level %1$d (current min is %2$d): %3$s",
- api, minSdk, fqcn);
-
- LintDriver driver = mContext.getDriver();
- if (driver.isSuppressed(INLINED, node)) {
- return true;
- }
-
- // Also allow to suppress these issues with NewApi, since some
- // fields used to get identified that way
- if (driver.isSuppressed(UNSUPPORTED, node)) {
- return true;
- }
-
- // We can't report the issue right away; we don't yet know if
- // this is an actual inlined (static primitive or String) yet.
- // So just make a note of it, and report these after the project
- // checking has finished; any fields that aren't inlined will be
- // cleared when they're noticed by the class check.
- if (mPendingFields == null) {
- mPendingFields = Maps.newHashMapWithExpectedSize(20);
- }
- List<Pair<String, Location>> list = mPendingFields.get(fqcn);
- if (list == null) {
- list = new ArrayList<Pair<String, Location>>();
- mPendingFields.put(fqcn, list);
- }
- list.add(Pair.of(message, location));
- }
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns the minimum SDK to use according to the given AST node, or null
- * if no {@code TargetApi} annotations were found
- *
- * @return the API level to use for this node, or -1
- */
- public int getLocalMinSdk(@Nullable lombok.ast.Node scope) {
- while (scope != null) {
- Class<? extends lombok.ast.Node> type = scope.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == VariableDefinition.class) {
- // Variable
- VariableDefinition declaration = (VariableDefinition) scope;
- int targetApi = getLocalMinSdk(declaration.astModifiers());
- if (targetApi != -1) {
- return targetApi;
- }
- } else if (type == MethodDeclaration.class) {
- // Method
- // Look for annotations on the method
- MethodDeclaration declaration = (MethodDeclaration) scope;
- int targetApi = getLocalMinSdk(declaration.astModifiers());
- if (targetApi != -1) {
- return targetApi;
- }
- } else if (type == ConstructorDeclaration.class) {
- // Constructor
- // Look for annotations on the method
- ConstructorDeclaration declaration = (ConstructorDeclaration) scope;
- int targetApi = getLocalMinSdk(declaration.astModifiers());
- if (targetApi != -1) {
- return targetApi;
- }
- } else if (type == ClassDeclaration.class) {
- // Class
- ClassDeclaration declaration = (ClassDeclaration) scope;
- int targetApi = getLocalMinSdk(declaration.astModifiers());
- if (targetApi != -1) {
- return targetApi;
- }
- }
-
- scope = scope.getParent();
- }
-
- return -1;
- }
-
- /**
- * Returns true if the given AST modifier has a suppress annotation for the
- * given issue (which can be null to check for the "all" annotation)
- *
- * @param modifiers the modifier to check
- * @return true if the issue or all issues should be suppressed for this
- * modifier
- */
- private int getLocalMinSdk(@Nullable Modifiers modifiers) {
- if (modifiers == null) {
- return -1;
- }
- StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations();
- if (annotations == null) {
- return -1;
- }
-
- Iterator<Annotation> iterator = annotations.iterator();
- while (iterator.hasNext()) {
- Annotation annotation = iterator.next();
- TypeReference t = annotation.astAnnotationTypeReference();
- String typeName = t.getTypeName();
- if (typeName.endsWith(TARGET_API)) {
- StrictListAccessor<AnnotationElement, Annotation> values =
- annotation.astElements();
- if (values != null) {
- Iterator<AnnotationElement> valueIterator = values.iterator();
- while (valueIterator.hasNext()) {
- AnnotationElement element = valueIterator.next();
- AnnotationValue valueNode = element.astValue();
- if (valueNode == null) {
- continue;
- }
- if (valueNode instanceof IntegralLiteral) {
- IntegralLiteral literal = (IntegralLiteral) valueNode;
- return literal.astIntValue();
- } else if (valueNode instanceof StringLiteral) {
- String value = ((StringLiteral) valueNode).astValue();
- return codeNameToApi(value);
- } else if (valueNode instanceof Select) {
- Select select = (Select) valueNode;
- String codename = select.astIdentifier().astValue();
- return codeNameToApi(codename);
- } else if (valueNode instanceof VariableReference) {
- VariableReference reference = (VariableReference) valueNode;
- String codename = reference.astIdentifier().astValue();
- return codeNameToApi(codename);
- }
- }
- }
- }
- }
-
- return -1;
- }
- }
-
- private static int codeNameToApi(String codename) {
- for (int api = 1; api <= SdkConstants.HIGHEST_KNOWN_API; api++) {
- String code = LintUtils.getBuildCode(api);
- if (code != null && code.equalsIgnoreCase(codename)) {
- return api;
- }
- }
-
- return -1;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiLookup.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiLookup.java
deleted file mode 100644
index 6a4de6e..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiLookup.java
+++ /dev/null
@@ -1,971 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_PKG;
-import static com.android.SdkConstants.DOT_XML;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.google.common.base.Charsets;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.io.Files;
-import com.google.common.primitives.UnsignedBytes;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel.MapMode;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Database for API checking: Allows quick lookup of a given class, method or field
- * to see which API level it was introduced in.
- * <p>
- * This class is optimized for quick bytecode lookup used in conjunction with the
- * ASM library: It has lookup methods that take internal JVM signatures, and for a method
- * call for example it processes the owner, name and description parameters separately
- * the way they are provided from ASM.
- * <p>
- * The {@link Api} class provides access to the full Android API along with version
- * information, initialized from an XML file. This lookup class adds a binary cache around
- * the API to make initialization faster and to require fewer objects. It creates
- * a binary cache data structure, which fits in a single byte array, which means that
- * to open the database you can just read in the byte array and go. On one particular
- * machine, this takes about 30-50 ms versus 600-800ms for the full parse. It also
- * helps memory by placing everything in a compact byte array instead of needing separate
- * strings (2 bytes per character in a char[] for the 25k method entries, 11k field entries
- * and 6k class entries) - and it also avoids the same number of Map.Entry objects.
- * When creating the memory data structure it performs a few other steps to help memory:
- * <ul>
- * <li> It stores the strings as single bytes, since all the JVM signatures are in ASCII
- * <li> It strips out the method return types (which takes the binary size down from
- * about 4.7M to 4.0M)
- * <li> It strips out all APIs that have since=1, since the lookup only needs to find
- * classes, methods and fields that have an API level *higher* than 1. This drops
- * the memory use down from 4.0M to 1.7M.
- * </ul>
- */
-public class ApiLookup {
- /** Relative path to the api-versions.xml database file within the Lint installation */
- private static final String XML_FILE_PATH = "platform-tools/api/api-versions.xml"; //$NON-NLS-1$
- private static final String FILE_HEADER = "API database used by Android lint\000";
- private static final int BINARY_FORMAT_VERSION = 5;
- private static final boolean DEBUG_FORCE_REGENERATE_BINARY = false;
- private static final boolean DEBUG_SEARCH = false;
- private static final boolean WRITE_STATS = false;
- /** Default size to reserve for each API entry when creating byte buffer to build up data */
- private static final int BYTES_PER_ENTRY = 36;
-
- private final LintClient mClient;
- private final File mXmlFile;
- private final File mBinaryFile;
- private final Api mInfo;
- private byte[] mData;
- private int[] mIndices;
- private int mClassCount;
- private String[] mJavaPackages;
-
- private static WeakReference<ApiLookup> sInstance =
- new WeakReference<ApiLookup>(null);
-
- /**
- * Returns an instance of the API database
- *
- * @param client the client to associate with this database - used only for
- * logging. The database object may be shared among repeated invocations,
- * and in that case client used will be the one originally passed in.
- * In other words, this parameter may be ignored if the client created
- * is not new.
- * @return a (possibly shared) instance of the API database, or null
- * if its data can't be found
- */
- public static ApiLookup get(LintClient client) {
- synchronized (ApiLookup.class) {
- ApiLookup db = sInstance.get();
- if (db == null) {
- File file = client.findResource(XML_FILE_PATH);
- if (file == null) {
- // AOSP build environment?
- String build = System.getenv("ANDROID_BUILD_TOP"); //$NON-NLS-1$
- if (build != null) {
- file = new File(build, "development/sdk/api-versions.xml" //$NON-NLS-1$
- .replace('/', File.separatorChar));
- }
- }
-
- if (file == null || !file.exists()) {
- client.log(null, "Fatal error: No API database found at %1$s", file);
- return null;
- } else {
- db = get(client, file);
- }
- sInstance = new WeakReference<ApiLookup>(db);
- }
-
- return db;
- }
- }
-
- @VisibleForTesting
- static String getCacheFileName(String xmlFileName) {
- if (LintUtils.endsWith(xmlFileName, DOT_XML)) {
- xmlFileName = xmlFileName.substring(0, xmlFileName.length() - DOT_XML.length());
- }
-
- // Incorporate version number in the filename to avoid upgrade filename
- // conflicts on Windows (such as issue #26663)
- return xmlFileName + '-' + BINARY_FORMAT_VERSION + ".bin"; //$NON-NLS-1$
- }
-
- /**
- * Returns an instance of the API database
- *
- * @param client the client to associate with this database - used only for
- * logging
- * @param xmlFile the XML file containing configuration data to use for this
- * database
- * @return a (possibly shared) instance of the API database, or null
- * if its data can't be found
- */
- private static ApiLookup get(LintClient client, File xmlFile) {
- if (!xmlFile.exists()) {
- client.log(null, "The API database file %1$s does not exist", xmlFile);
- return null;
- }
-
- File cacheDir = client.getCacheDir(true/*create*/);
- if (cacheDir == null) {
- cacheDir = xmlFile.getParentFile();
- }
-
- File binaryData = new File(cacheDir, getCacheFileName(xmlFile.getName()));
-
- if (DEBUG_FORCE_REGENERATE_BINARY) {
- System.err.println("\nTemporarily regenerating binary data unconditionally \nfrom "
- + xmlFile + "\nto " + binaryData);
- if (!createCache(client, xmlFile, binaryData)) {
- return null;
- }
- } else if (!binaryData.exists() || binaryData.lastModified() < xmlFile.lastModified()
- || binaryData.length() == 0) {
- if (!createCache(client, xmlFile, binaryData)) {
- return null;
- }
- }
-
- if (!binaryData.exists()) {
- client.log(null, "The API database file %1$s does not exist", binaryData);
- return null;
- }
-
- return new ApiLookup(client, xmlFile, binaryData, null);
- }
-
- private static boolean createCache(LintClient client, File xmlFile, File binaryData) {
- long begin = 0;
- if (WRITE_STATS) {
- begin = System.currentTimeMillis();
- }
-
- Api info = Api.parseApi(xmlFile);
-
- if (WRITE_STATS) {
- long end = System.currentTimeMillis();
- System.out.println("Reading XML data structures took " + (end - begin) + " ms)");
- }
-
- if (info != null) {
- try {
- writeDatabase(binaryData, info);
- return true;
- } catch (IOException ioe) {
- client.log(ioe, "Can't write API cache file");
- }
- }
-
- return false;
- }
-
- /** Use one of the {@link #get} factory methods instead */
- private ApiLookup(
- @NonNull LintClient client,
- @NonNull File xmlFile,
- @Nullable File binaryFile,
- @Nullable Api info) {
- mClient = client;
- mXmlFile = xmlFile;
- mBinaryFile = binaryFile;
- mInfo = info;
-
- if (binaryFile != null) {
- readData();
- }
- }
-
- /**
- * Database format:
- * <pre>
- * 1. A file header, which is the exact contents of {@link #FILE_HEADER} encoded
- * as ASCII characters. The purpose of the header is to identify what the file
- * is for, for anyone attempting to open the file.
- * 2. A file version number. If the binary file does not match the reader's expected
- * version, it can ignore it (and regenerate the cache from XML).
- * 3. The number of classes [1 int]
- * 4. The number of members (across all classes) [1 int].
- * 5. The number of java/javax packages [1 int]
- * 6. The java/javax package name table. Each item consists of a byte count for
- * the package string (as 1 byte) followed by the UTF-8 encoded bytes for each package.
- * These are in sorted order.
- * 7. Class offset table (one integer per class, pointing to the byte offset in the
- * file (relative to the beginning of the file) where each class begins.
- * The classes are always sorted alphabetically by fully qualified name.
- * 8. Member offset table (one integer per member, pointing to the byte offset in the
- * file (relative to the beginning of the file) where each member entry begins.
- * The members are always sorted alphabetically.
- * 9. Class entry table. Each class entry consists of the fully qualified class name,
- * in JVM format (using / instead of . in package names and $ for inner classes),
- * followed by the byte 0 as a terminator, followed by the API version as a byte.
- * 10. Member entry table. Each member entry consists of the class number (as a short),
- * followed by the JVM method/field signature, encoded as UTF-8, followed by a 0 byte
- * signature terminator, followed by the API level as a byte.
- * <p>
- * TODO: Pack the offsets: They increase by a small amount for each entry, so no need
- * to spend 4 bytes on each. These will need to be processed when read back in anyway,
- * so consider storing the offset -deltas- as single bytes and adding them up cumulatively
- * in readData().
- * </pre>
- */
- private void readData() {
- if (!mBinaryFile.exists()) {
- mClient.log(null, "%1$s does not exist", mBinaryFile);
- return;
- }
- long start = System.currentTimeMillis();
- try {
- MappedByteBuffer buffer = Files.map(mBinaryFile, MapMode.READ_ONLY);
- assert buffer.order() == ByteOrder.BIG_ENDIAN;
-
- // First skip the header
- byte[] expectedHeader = FILE_HEADER.getBytes(Charsets.US_ASCII);
- buffer.rewind();
- for (int offset = 0; offset < expectedHeader.length; offset++) {
- if (expectedHeader[offset] != buffer.get()) {
- mClient.log(null, "Incorrect file header: not an API database cache " +
- "file, or a corrupt cache file");
- return;
- }
- }
-
- // Read in the format number
- if (buffer.get() != BINARY_FORMAT_VERSION) {
- // Force regeneration of new binary data with up to date format
- if (createCache(mClient, mXmlFile, mBinaryFile)) {
- readData(); // Recurse
- }
-
- return;
- }
-
- mClassCount = buffer.getInt();
- int methodCount = buffer.getInt();
-
- int javaPackageCount = buffer.getInt();
- // Read in the Java packages
- mJavaPackages = new String[javaPackageCount];
- for (int i = 0; i < javaPackageCount; i++) {
- int count = UnsignedBytes.toInt(buffer.get());
- byte[] bytes = new byte[count];
- buffer.get(bytes, 0, count);
- mJavaPackages[i] = new String(bytes, Charsets.UTF_8);
- }
-
- // Read in the class table indices;
- int count = mClassCount + methodCount;
- int[] offsets = new int[count];
-
- // Another idea: I can just store the DELTAS in the file (and add them up
- // when reading back in) such that it takes just ONE byte instead of four!
-
- for (int i = 0; i < count; i++) {
- offsets[i] = buffer.getInt();
- }
-
- // No need to read in the rest -- we'll just keep the whole byte array in memory
- // TODO: Make this code smarter/more efficient.
- int size = buffer.limit();
- byte[] b = new byte[size];
- buffer.rewind();
- buffer.get(b);
- mData = b;
- mIndices = offsets;
-
- // TODO: We only need to keep the data portion here since we've initialized
- // the offset array separately.
- // TODO: Investigate (profile) accessing the byte buffer directly instead of
- // accessing a byte array.
- } catch (Throwable e) {
- mClient.log(null, "Failure reading binary cache file %1$s", mBinaryFile.getPath());
- mClient.log(null, "Please delete the file and restart the IDE/lint: %1$s",
- mBinaryFile.getPath());
- mClient.log(e, null);
- }
- if (WRITE_STATS) {
- long end = System.currentTimeMillis();
- System.out.println("\nRead API database in " + (end - start)
- + " milliseconds.");
- System.out.println("Size of data table: " + mData.length + " bytes ("
- + Integer.toString(mData.length / 1024) + "k)\n");
- }
- }
-
- /** See the {@link #readData()} for documentation on the data format. */
- private static void writeDatabase(File file, Api info) throws IOException {
- /*
- * 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded
- * as ASCII characters. The purpose of the header is to identify what the file
- * is for, for anyone attempting to open the file.
- * 2. A file version number. If the binary file does not match the reader's expected
- * version, it can ignore it (and regenerate the cache from XML).
- */
- Map<String, ApiClass> classMap = info.getClasses();
- // Write the class table
-
- List<String> classes = new ArrayList<String>(classMap.size());
- Map<ApiClass, List<String>> memberMap =
- Maps.newHashMapWithExpectedSize(classMap.size());
- int memberCount = 0;
- Set<String> javaPackageSet = Sets.newHashSetWithExpectedSize(70);
- for (Map.Entry<String, ApiClass> entry : classMap.entrySet()) {
- String className = entry.getKey();
- ApiClass apiClass = entry.getValue();
-
- if (className.startsWith("java/") //$NON-NLS-1$
- || className.startsWith("javax/")) { //$NON-NLS-1$
- String pkg = apiClass.getPackage();
- javaPackageSet.add(pkg);
- }
-
- if (!isRelevantOwner(className)) {
- System.out.println("Warning: The isRelevantOwner method does not pass "
- + className);
- }
-
- Set<String> allMethods = apiClass.getAllMethods(info);
- Set<String> allFields = apiClass.getAllFields(info);
-
- // Strip out all members that have been supported since version 1.
- // This makes the database *much* leaner (down from about 4M to about
- // 1.7M), and this just fills the table with entries that ultimately
- // don't help the API checker since it just needs to know if something
- // requires a version *higher* than the minimum. If in the future the
- // database needs to answer queries about whether a method is public
- // or not, then we'd need to put this data back in.
- List<String> members = new ArrayList<String>(allMethods.size() + allFields.size());
- for (String member : allMethods) {
-
- Integer since = apiClass.getMethod(member, info);
- if (since == null) {
- assert false : className + ':' + member;
- since = 1;
- }
- if (since != 1) {
- members.add(member);
- }
- }
-
- // Strip out all members that have been supported since version 1.
- // This makes the database *much* leaner (down from about 4M to about
- // 1.7M), and this just fills the table with entries that ultimately
- // don't help the API checker since it just needs to know if something
- // requires a version *higher* than the minimum. If in the future the
- // database needs to answer queries about whether a method is public
- // or not, then we'd need to put this data back in.
- for (String member : allFields) {
- Integer since = apiClass.getField(member, info);
- if (since == null) {
- assert false : className + ':' + member;
- since = 1;
- }
- if (since != 1) {
- members.add(member);
- }
- }
-
- // Only include classes that have one or more members requiring version 2 or higher:
- if (!members.isEmpty()) {
- classes.add(className);
- memberMap.put(apiClass, members);
- memberCount += members.size();
- }
- }
- Collections.sort(classes);
-
- List<String> javaPackages = Lists.newArrayList(javaPackageSet);
- Collections.sort(javaPackages);
- int javaPackageCount = javaPackages.size();
-
- int entryCount = classMap.size() + memberCount;
- int capacity = entryCount * BYTES_PER_ENTRY;
- ByteBuffer buffer = ByteBuffer.allocate(capacity);
- buffer.order(ByteOrder.BIG_ENDIAN);
- // 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded
- // as ASCII characters. The purpose of the header is to identify what the file
- // is for, for anyone attempting to open the file.
-
- buffer.put(FILE_HEADER.getBytes(Charsets.US_ASCII));
-
- // 2. A file version number. If the binary file does not match the reader's expected
- // version, it can ignore it (and regenerate the cache from XML).
- buffer.put((byte) BINARY_FORMAT_VERSION);
-
- // 3. The number of classes [1 int]
- buffer.putInt(classes.size());
-
- // 4. The number of members (across all classes) [1 int].
- buffer.putInt(memberCount);
-
- // 5. The number of Java packages [1 int].
- buffer.putInt(javaPackageCount);
-
- // 6. The Java package table. There are javaPackage.size() entries, where each entry
- // consists of a string length, as a byte, followed by the bytes in the package.
- // There is no terminating 0.
- for (String pkg : javaPackages) {
- byte[] bytes = pkg.getBytes(Charsets.UTF_8);
- assert bytes.length < 255 : pkg;
- buffer.put((byte) bytes.length);
- buffer.put(bytes);
- }
-
- // 7. Class offset table (one integer per class, pointing to the byte offset in the
- // file (relative to the beginning of the file) where each class begins.
- // The classes are always sorted alphabetically by fully qualified name.
- int classOffsetTable = buffer.position();
-
- // Reserve enough room for the offset table here: we will backfill it with pointers
- // as we're writing out the data structures below
- for (int i = 0, n = classes.size(); i < n; i++) {
- buffer.putInt(0);
- }
-
- // 8. Member offset table (one integer per member, pointing to the byte offset in the
- // file (relative to the beginning of the file) where each member entry begins.
- // The members are always sorted alphabetically.
- int methodOffsetTable = buffer.position();
- for (int i = 0, n = memberCount; i < n; i++) {
- buffer.putInt(0);
- }
-
- int nextEntry = buffer.position();
- int nextOffset = classOffsetTable;
-
- // 9. Class entry table. Each class entry consists of the fully qualified class name,
- // in JVM format (using / instead of . in package names and $ for inner classes),
- // followed by the byte 0 as a terminator, followed by the API version as a byte.
- for (String clz : classes) {
- buffer.position(nextOffset);
- buffer.putInt(nextEntry);
- nextOffset = buffer.position();
- buffer.position(nextEntry);
- buffer.put(clz.getBytes(Charsets.UTF_8));
- buffer.put((byte) 0);
-
- ApiClass apiClass = classMap.get(clz);
- assert apiClass != null : clz;
- int since = apiClass.getSince();
- assert since == UnsignedBytes.toInt((byte) since) : since; // make sure it fits
- buffer.put((byte) since);
-
- nextEntry = buffer.position();
- }
-
- // 10. Member entry table. Each member entry consists of the class number (as a short),
- // followed by the JVM method/field signature, encoded as UTF-8, followed by a 0 byte
- // signature terminator, followed by the API level as a byte.
- assert nextOffset == methodOffsetTable;
-
- for (int classNumber = 0, n = classes.size(); classNumber < n; classNumber++) {
- String clz = classes.get(classNumber);
- ApiClass apiClass = classMap.get(clz);
- assert apiClass != null : clz;
- List<String> members = memberMap.get(apiClass);
- Collections.sort(members);
-
- for (String member : members) {
- buffer.position(nextOffset);
- buffer.putInt(nextEntry);
- nextOffset = buffer.position();
- buffer.position(nextEntry);
-
- Integer since;
- if (member.indexOf('(') != -1) {
- since = apiClass.getMethod(member, info);
- } else {
- since = apiClass.getField(member, info);
- }
- if (since == null) {
- assert false : clz + ':' + member;
- since = 1;
- }
-
- assert classNumber == (short) classNumber;
- buffer.putShort((short) classNumber);
- byte[] signature = member.getBytes(Charsets.UTF_8);
- for (int i = 0; i < signature.length; i++) {
- // Make sure all signatures are really just simple ASCII
- byte b = signature[i];
- assert b == (b & 0x7f) : member;
- buffer.put(b);
- // Skip types on methods
- if (b == (byte) ')') {
- break;
- }
- }
- buffer.put((byte) 0);
- int api = since;
- assert api == UnsignedBytes.toInt((byte) api);
- //assert api >= 1 && api < 0xFF; // max that fits in a byte
- buffer.put((byte) api);
- nextEntry = buffer.position();
- }
- }
-
- int size = buffer.position();
- assert size <= buffer.limit();
- buffer.mark();
-
- if (WRITE_STATS) {
- System.out.println("Wrote " + classes.size() + " classes and "
- + memberCount + " member entries");
- System.out.print("Actual binary size: " + size + " bytes");
- System.out.println(String.format(" (%.1fM)", size/(1024*1024.f)));
-
- System.out.println("Allocated size: " + (entryCount * BYTES_PER_ENTRY) + " bytes");
- System.out.println("Required bytes per entry: " + (size/ entryCount) + " bytes");
- }
-
- // Now dump this out as a file
- // There's probably an API to do this more efficiently; TODO: Look into this.
- byte[] b = new byte[size];
- buffer.rewind();
- buffer.get(b);
- if (file.exists()) {
- file.delete();
- }
- FileOutputStream output = Files.newOutputStreamSupplier(file).getOutput();
- output.write(b);
- output.close();
- }
-
- // For debugging only
- private String dumpEntry(int offset) {
- if (DEBUG_SEARCH) {
- StringBuilder sb = new StringBuilder(200);
- for (int i = offset; i < mData.length; i++) {
- if (mData[i] == 0) {
- break;
- }
- char c = (char) UnsignedBytes.toInt(mData[i]);
- sb.append(c);
- }
-
- return sb.toString();
- } else {
- return "<disabled>"; //$NON-NLS-1$
- }
- }
-
- private static int compare(byte[] data, int offset, byte terminator, String s, int max) {
- int i = offset;
- int j = 0;
- for (; j < max; i++, j++) {
- byte b = data[i];
- char c = s.charAt(j);
- // TODO: Check somewhere that the strings are purely in the ASCII range; if not
- // they're not a match in the database
- byte cb = (byte) c;
- int delta = b - cb;
- if (delta != 0) {
- return delta;
- }
- }
-
- return data[i] - terminator;
- }
-
- /**
- * Quick determination whether a given class name is possibly interesting; this
- * is a quick package prefix check to determine whether we need to consider
- * the class at all. This let's us do less actual searching for the vast majority
- * of APIs (in libraries, application code etc) that have nothing to do with the
- * APIs in our packages.
- * @param name the class name in VM format (e.g. using / instead of .)
- * @return true if the owner is <b>possibly</b> relevant
- */
- public boolean isRelevantClass(String name) {
- // TODO: Add quick switching here. This is tied to the database file so if
- // we end up with unexpected prefixes there, this could break. For that reason,
- // for now we consider everything relevant.
- return true;
- }
-
- /**
- * Returns the API version required by the given class reference,
- * or -1 if this is not a known API class. Note that it may return -1
- * for classes introduced in version 1; internally the database only
- * stores version data for version 2 and up.
- *
- * @param className the internal name of the class, e.g. its
- * fully qualified name (as returned by Class.getName(), but with
- * '.' replaced by '/'.
- * @return the minimum API version the method is supported for, or -1 if
- * it's unknown <b>or version 1</b>.
- */
- public int getClassVersion(@NonNull String className) {
- if (!isRelevantClass(className)) {
- return -1;
- }
-
- if (mData != null) {
- int classNumber = findClass(className);
- if (classNumber != -1) {
- int offset = mIndices[classNumber];
- while (mData[offset] != 0) {
- offset++;
- }
- offset++;
- return UnsignedBytes.toInt(mData[offset]);
- }
- } else {
- ApiClass clz = mInfo.getClass(className);
- if (clz != null) {
- int since = clz.getSince();
- if (since == Integer.MAX_VALUE) {
- since = -1;
- }
- return since;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the API version required by the given method call. The method is
- * referred to by its {@code owner}, {@code name} and {@code desc} fields.
- * If the method is unknown it returns -1. Note that it may return -1 for
- * classes introduced in version 1; internally the database only stores
- * version data for version 2 and up.
- *
- * @param owner the internal name of the method's owner class, e.g. its
- * fully qualified name (as returned by Class.getName(), but with
- * '.' replaced by '/'.
- * @param name the method's name
- * @param desc the method's descriptor - see {@link org.objectweb.asm.Type}
- * @return the minimum API version the method is supported for, or -1 if
- * it's unknown <b>or version 1</b>.
- */
- public int getCallVersion(
- @NonNull String owner,
- @NonNull String name,
- @NonNull String desc) {
- if (!isRelevantClass(owner)) {
- return -1;
- }
-
- if (mData != null) {
- int classNumber = findClass(owner);
- if (classNumber != -1) {
- return findMember(classNumber, name, desc);
- }
- } else {
- ApiClass clz = mInfo.getClass(owner);
- if (clz != null) {
- String signature = name + desc;
- int since = clz.getMethod(signature, mInfo);
- if (since == Integer.MAX_VALUE) {
- since = -1;
- }
- return since;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the API version required to access the given field, or -1 if this
- * is not a known API method. Note that it may return -1 for classes
- * introduced in version 1; internally the database only stores version data
- * for version 2 and up.
- *
- * @param owner the internal name of the method's owner class, e.g. its
- * fully qualified name (as returned by Class.getName(), but with
- * '.' replaced by '/'.
- * @param name the method's name
- * @return the minimum API version the method is supported for, or -1 if
- * it's unknown <b>or version 1</b>
- */
- public int getFieldVersion(
- @NonNull String owner,
- @NonNull String name) {
- if (!isRelevantClass(owner)) {
- return -1;
- }
-
- if (mData != null) {
- int classNumber = findClass(owner);
- if (classNumber != -1) {
- return findMember(classNumber, name, null);
- }
- } else {
- ApiClass clz = mInfo.getClass(owner);
- if (clz != null) {
- int since = clz.getField(name, mInfo);
- if (since == Integer.MAX_VALUE) {
- since = -1;
- }
- return since;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns true if the given owner (in VM format) is relevant to the database.
- * This allows quick filtering out of owners that won't return any data
- * for the various {@code #getFieldVersion} etc methods.
- *
- * @param owner the owner to look up
- * @return true if the owner might be relevant to the API database
- */
- public static boolean isRelevantOwner(@NonNull String owner) {
- if (owner.startsWith("java")) { //$NON-NLS-1$ // includes javax/
- return true;
- }
- if (owner.startsWith(ANDROID_PKG)) {
- if (owner.startsWith("/support/", 7)) { //$NON-NLS-1$
- return false;
- }
- return true;
- } else if (owner.startsWith("org/")) { //$NON-NLS-1$
- if (owner.startsWith("xml", 4) //$NON-NLS-1$
- || owner.startsWith("w3c/", 4) //$NON-NLS-1$
- || owner.startsWith("json/", 4) //$NON-NLS-1$
- || owner.startsWith("apache/", 4)) { //$NON-NLS-1$
- return true;
- }
- } else if (owner.startsWith("com/")) { //$NON-NLS-1$
- if (owner.startsWith("google/", 4) //$NON-NLS-1$
- || owner.startsWith("android/", 4)) { //$NON-NLS-1$
- return true;
- }
- } else if (owner.startsWith("junit") //$NON-NLS-1$
- || owner.startsWith("dalvik")) { //$NON-NLS-1$
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Returns true if the given owner (in VM format) is a valid Java package supported
- * in any version of Android.
- *
- * @param owner the package, in VM format
- * @return true if the package is included in one or more versions of Android
- */
- public boolean isValidJavaPackage(@NonNull String owner) {
- int packageLength = owner.lastIndexOf('/');
- if (packageLength == -1) {
- return false;
- }
-
- // The index array contains class indexes from 0 to classCount and
- // member indices from classCount to mIndices.length.
- int low = 0;
- int high = mJavaPackages.length - 1;
- while (low <= high) {
- int middle = (low + high) >>> 1;
- int offset = middle;
-
- if (DEBUG_SEARCH) {
- System.out.println("Comparing string " + owner + " with entry at " + offset
- + ": " + mJavaPackages[offset]);
- }
-
- // Compare the api info at the given index.
- int compare = comparePackage(mJavaPackages[offset], owner, packageLength);
- if (compare == 0) {
- return true;
- }
-
- if (compare < 0) {
- low = middle + 1;
- } else if (compare > 0) {
- high = middle - 1;
- } else {
- assert false; // compare == 0 already handled above
- return false;
- }
- }
-
- return false;
- }
-
- private static int comparePackage(String s1, String s2, int max) {
- for (int i = 0; i < max; i++) {
- if (i == s1.length()) {
- return -1;
- }
- char c1 = s1.charAt(i);
- char c2 = s2.charAt(i);
- if (c1 != c2) {
- return c1 - c2;
- }
- }
-
- if (s1.length() > max) {
- return 1;
- }
-
- return 0;
- }
-
- /** Returns the class number of the given class, or -1 if it is unknown */
- private int findClass(@NonNull String owner) {
- assert owner.indexOf('.') == -1 : "Should use / instead of . in owner: " + owner;
-
- // The index array contains class indexes from 0 to classCount and
- // member indices from classCount to mIndices.length.
- int low = 0;
- int high = mClassCount - 1;
- // Compare the api info at the given index.
- int classNameLength = owner.length();
- while (low <= high) {
- int middle = (low + high) >>> 1;
- int offset = mIndices[middle];
-
- if (DEBUG_SEARCH) {
- System.out.println("Comparing string " + owner + " with entry at " + offset
- + ": " + dumpEntry(offset));
- }
-
- int compare = compare(mData, offset, (byte) 0, owner, classNameLength);
- if (compare == 0) {
- return middle;
- }
-
- if (compare < 0) {
- low = middle + 1;
- } else if (compare > 0) {
- high = middle - 1;
- } else {
- assert false; // compare == 0 already handled above
- return -1;
- }
- }
-
- return -1;
- }
-
- private int findMember(int classNumber, @NonNull String name, @Nullable String desc) {
- // The index array contains class indexes from 0 to classCount and
- // member indices from classCount to mIndices.length.
- int low = mClassCount;
- int high = mIndices.length - 1;
- while (low <= high) {
- int middle = (low + high) >>> 1;
- int offset = mIndices[middle];
-
- if (DEBUG_SEARCH) {
- System.out.println("Comparing string " + (name + ';' + desc) +
- " with entry at " + offset + ": " + dumpEntry(offset));
- }
-
- // Check class number: read short. The byte data is always big endian.
- int entryClass = (mData[offset++] & 0xFF) << 8 | (mData[offset++] & 0xFF);
- int compare = entryClass - classNumber;
- if (compare == 0) {
- if (desc != null) {
- // Method
- int nameLength = name.length();
- compare = compare(mData, offset, (byte) '(', name, nameLength);
- if (compare == 0) {
- offset += nameLength;
- int argsEnd = desc.indexOf(')');
- // Only compare up to the ) -- after that we have a return value in the
- // input description, which isn't there in the database
- compare = compare(mData, offset, (byte) ')', desc, argsEnd);
- if (compare == 0) {
- offset += argsEnd + 1;
-
- if (mData[offset++] == 0) {
- // Yes, terminated argument list: get the API level
- return UnsignedBytes.toInt(mData[offset]);
- }
- }
- }
- } else {
- // Field
- int nameLength = name.length();
- compare = compare(mData, offset, (byte) 0, name, nameLength);
- if (compare == 0) {
- offset += nameLength;
- if (mData[offset++] == 0) {
- // Yes, terminated argument list: get the API level
- return UnsignedBytes.toInt(mData[offset]);
- }
- }
- }
- }
-
- if (compare < 0) {
- low = middle + 1;
- } else if (compare > 0) {
- high = middle - 1;
- } else {
- assert false; // compare == 0 already handled above
- return -1;
- }
- }
-
- return -1;
- }
-
- /** Clears out any existing lookup instances */
- @VisibleForTesting
- static void dispose() {
- sInstance.clear();
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiParser.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiParser.java
deleted file mode 100644
index b3c2f2a..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ApiParser.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Parser for the simplified XML API format version 1.
- */
-public class ApiParser extends DefaultHandler {
-
- private static final String NODE_API = "api";
- private static final String NODE_CLASS = "class";
- private static final String NODE_FIELD = "field";
- private static final String NODE_METHOD = "method";
- private static final String NODE_EXTENDS = "extends";
- private static final String NODE_IMPLEMENTS = "implements";
-
- private static final String ATTR_NAME = "name";
- private static final String ATTR_SINCE = "since";
-
- private final Map<String, ApiClass> mClasses = new HashMap<String, ApiClass>();
-
- private ApiClass mCurrentClass;
-
- ApiParser() {
- }
-
- Map<String, ApiClass> getClasses() {
- return mClasses;
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
-
- if (localName == null || localName.isEmpty()) {
- localName = qName;
- }
-
- try {
- if (NODE_API.equals(localName)) {
- // do nothing.
-
- } else if (NODE_CLASS.equals(localName)) {
- String name = attributes.getValue(ATTR_NAME);
- int since = Integer.parseInt(attributes.getValue(ATTR_SINCE));
-
- mCurrentClass = addClass(name, since);
-
- } else if (NODE_EXTENDS.equals(localName)) {
- String name = attributes.getValue(ATTR_NAME);
- int since = getSince(attributes);
-
- mCurrentClass.addSuperClass(name, since);
-
- } else if (NODE_IMPLEMENTS.equals(localName)) {
- String name = attributes.getValue(ATTR_NAME);
- int since = getSince(attributes);
-
- mCurrentClass.addInterface(name, since);
-
- } else if (NODE_METHOD.equals(localName)) {
- String name = attributes.getValue(ATTR_NAME);
- int since = getSince(attributes);
-
- mCurrentClass.addMethod(name, since);
-
- } else if (NODE_FIELD.equals(localName)) {
- String name = attributes.getValue(ATTR_NAME);
- int since = getSince(attributes);
-
- mCurrentClass.addField(name, since);
-
- }
-
- } finally {
- super.startElement(uri, localName, qName, attributes);
- }
- }
-
- private ApiClass addClass(String name, int apiLevel) {
- ApiClass theClass = mClasses.get(name);
- if (theClass == null) {
- theClass = new ApiClass(name, apiLevel);
- mClasses.put(name, theClass);
- }
-
- return theClass;
- }
-
- private int getSince(Attributes attributes) {
- int since = mCurrentClass.getSince();
- String sinceAttr = attributes.getValue(ATTR_SINCE);
-
- if (sinceAttr != null) {
- since = Integer.parseInt(sinceAttr);
- }
-
- return since;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ArraySizeDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ArraySizeDetector.java
deleted file mode 100644
index 8bbcffb..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ArraySizeDetector.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.TAG_ARRAY;
-import static com.android.SdkConstants.TAG_INTEGER_ARRAY;
-import static com.android.SdkConstants.TAG_STRING_ARRAY;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Checks for arrays with inconsistent item counts
- */
-public class ArraySizeDetector extends ResourceXmlDetector {
-
- /** Are there differences in how many array elements are declared? */
- public static final Issue INCONSISTENT = Issue.create(
- "InconsistentArrays", //$NON-NLS-1$
- "Checks for inconsistencies in the number of elements in arrays",
- "When an array is translated in a different locale, it should normally have " +
- "the same number of elements as the original array. When adding or removing " +
- "elements to an array, it is easy to forget to update all the locales, and this " +
- "lint warning finds inconsistencies like these.\n" +
- "\n" +
- "Note however that there may be cases where you really want to declare a " +
- "different number of array items in each configuration (for example where " +
- "the array represents available options, and those options differ for " +
- "different layout orientations and so on), so use your own judgement to " +
- "decide if this is really an error.\n" +
- "\n" +
- "You can suppress this error type if it finds false errors in your project.",
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- ArraySizeDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- private Multimap<File, Pair<String, Integer>> mFileToArrayCount;
-
- /** Locations for each array name. Populated during phase 2, if necessary */
- private Map<String, Location> mLocations;
-
- /** Error messages for each array name. Populated during phase 2, if necessary */
- private Map<String, String> mDescriptions;
-
- /** Constructs a new {@link ArraySizeDetector} */
- public ArraySizeDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_ARRAY,
- TAG_STRING_ARRAY,
- TAG_INTEGER_ARRAY
- );
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mFileToArrayCount = ArrayListMultimap.create(30, 5);
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- // Check that all arrays for the same name have the same number of translations
-
- Set<String> alreadyReported = new HashSet<String>();
- Map<String, Integer> countMap = new HashMap<String, Integer>();
- Map<String, File> fileMap = new HashMap<String, File>();
-
- // Process the file in sorted file order to ensure stable output
- List<File> keys = new ArrayList<File>(mFileToArrayCount.keySet());
- Collections.sort(keys);
-
- for (File file : keys) {
- Collection<Pair<String, Integer>> pairs = mFileToArrayCount.get(file);
- for (Pair<String, Integer> pair : pairs) {
- String name = pair.getFirst();
-
- if (alreadyReported.contains(name)) {
- continue;
- }
- Integer count = pair.getSecond();
-
- Integer current = countMap.get(name);
- if (current == null) {
- countMap.put(name, count);
- fileMap.put(name, file);
- } else if (!count.equals(current)) {
- alreadyReported.add(name);
-
- if (mLocations == null) {
- mLocations = new HashMap<String, Location>();
- mDescriptions = new HashMap<String, String>();
- }
- mLocations.put(name, null);
-
- String thisName = file.getParentFile().getName() + File.separator
- + file.getName();
- File otherFile = fileMap.get(name);
- String otherName = otherFile.getParentFile().getName() + File.separator
- + otherFile.getName();
- String message = String.format(
- "Array %1$s has an inconsistent number of items (%2$d in %3$s, %4$d in %5$s)",
- name, count, thisName, current, otherName);
- mDescriptions.put(name, message);
- }
- }
- }
-
- if (mLocations != null) {
- // Request another scan through the resources such that we can
- // gather the actual locations
- context.getDriver().requestRepeat(this, Scope.ALL_RESOURCES_SCOPE);
- }
- mFileToArrayCount = null;
- } else {
- if (mLocations != null) {
- List<String> names = new ArrayList<String>(mLocations.keySet());
- Collections.sort(names);
- for (String name : names) {
- Location location = mLocations.get(name);
- // We were prepending locations, but we want to prefer the base folders
- location = Location.reverse(location);
-
- // Make sure we still have a conflict, in case one or more of the
- // elements were marked with tools:ignore
- int count = -1;
- LintDriver driver = context.getDriver();
- boolean foundConflict = false;
- Location curr;
- for (curr = location; curr != null; curr = curr.getSecondary()) {
- Object clientData = curr.getClientData();
- if (clientData instanceof Node) {
- Node node = (Node) clientData;
- if (driver.isSuppressed(INCONSISTENT, node)) {
- continue;
- }
- int newCount = LintUtils.getChildCount(node);
- if (newCount != count) {
- if (count == -1) {
- count = newCount; // first number encountered
- } else {
- foundConflict = true;
- break;
- }
- }
- } else {
- foundConflict = true;
- break;
- }
- }
-
- // Through one or more tools:ignore, there is no more conflict so
- // ignore this element
- if (!foundConflict) {
- continue;
- }
-
- String message = mDescriptions.get(name);
- context.report(INCONSISTENT, location, message, null);
- }
- }
-
- mLocations = null;
- mDescriptions = null;
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- int phase = context.getPhase();
-
- Attr attribute = element.getAttributeNode(ATTR_NAME);
- if (attribute == null || attribute.getValue().isEmpty()) {
- if (phase != 1) {
- return;
- }
- context.report(INCONSISTENT, element, context.getLocation(element),
- String.format("Missing name attribute in %1$s declaration", element.getTagName()),
- null);
- } else {
- String name = attribute.getValue();
- if (phase == 1) {
- if (context.getProject().getReportIssues()) {
- int childCount = LintUtils.getChildCount(element);
- mFileToArrayCount.put(context.file, Pair.of(name, childCount));
- }
- } else {
- assert phase == 2;
- if (mLocations.containsKey(name)) {
- if (context.getDriver().isSuppressed(INCONSISTENT, element)) {
- return;
- }
- Location location = context.getLocation(element);
- location.setClientData(element);
- location.setMessage(String.format("Declaration with array size (%1$d)",
- LintUtils.getChildCount(element)));
- location.setSecondary(mLocations.get(name));
- mLocations.put(name, location);
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java
deleted file mode 100644
index 90ebfd8..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.tools.lint.detector.api.LintUtils.assertionsEnabled;
-import static com.android.tools.lint.detector.api.LintUtils.endsWith;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.prefs.AndroidLocation;
-import com.android.prefs.AndroidLocation.AndroidLocationException;
-import com.android.tools.lint.client.api.IssueRegistry;
-import com.android.tools.lint.detector.api.Issue;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-
-/** Registry which provides a list of checks to be performed on an Android project */
-public class BuiltinIssueRegistry extends IssueRegistry {
- /** Folder name in the .android dir where additional detector jars are found */
- private static final String LINT_FOLDER = "lint"; //$NON-NLS-1$
-
- /**
- * Manifest constant for declaring an issue provider. Example:
- * Lint-Registry: foo.bar.CustomIssueRegistry
- */
- private static final String MF_LINT_REGISTRY = "Lint-Registry"; //$NON-NLS-1$
-
- private static final List<Issue> sIssues;
-
- static {
- final int initialCapacity = 140;
- List<Issue> issues = new ArrayList<Issue>(initialCapacity);
-
- issues.add(AccessibilityDetector.ISSUE);
- issues.add(LabelForDetector.ISSUE);
- issues.add(MathDetector.ISSUE);
- issues.add(FieldGetterDetector.ISSUE);
- issues.add(SdCardDetector.ISSUE);
- issues.add(ApiDetector.UNSUPPORTED);
- issues.add(ApiDetector.INLINED);
- issues.add(ApiDetector.OVERRIDE);
- issues.add(InvalidPackageDetector.ISSUE);
- issues.add(DuplicateIdDetector.CROSS_LAYOUT);
- issues.add(DuplicateIdDetector.WITHIN_LAYOUT);
- issues.add(DuplicateResourceDetector.ISSUE);
- issues.add(WrongIdDetector.UNKNOWN_ID);
- issues.add(WrongIdDetector.UNKNOWN_ID_LAYOUT);
- issues.add(StateListDetector.ISSUE);
- issues.add(StyleCycleDetector.ISSUE);
- issues.add(InefficientWeightDetector.INEFFICIENT_WEIGHT);
- issues.add(InefficientWeightDetector.NESTED_WEIGHTS);
- issues.add(InefficientWeightDetector.BASELINE_WEIGHTS);
- issues.add(InefficientWeightDetector.WRONG_0DP);
- issues.add(InefficientWeightDetector.ORIENTATION);
- issues.add(ScrollViewChildDetector.ISSUE);
- issues.add(DeprecationDetector.ISSUE);
- issues.add(ObsoleteLayoutParamsDetector.ISSUE);
- issues.add(MergeRootFrameLayoutDetector.ISSUE);
- issues.add(NestedScrollingWidgetDetector.ISSUE);
- issues.add(ChildCountDetector.SCROLLVIEW_ISSUE);
- issues.add(ChildCountDetector.ADAPTERVIEW_ISSUE);
- issues.add(UseCompoundDrawableDetector.ISSUE);
- issues.add(UselessViewDetector.USELESS_PARENT);
- issues.add(UselessViewDetector.USELESS_LEAF);
- issues.add(TooManyViewsDetector.TOO_MANY);
- issues.add(TooManyViewsDetector.TOO_DEEP);
- issues.add(GridLayoutDetector.ISSUE);
- issues.add(OverrideDetector.ISSUE);
- issues.add(OnClickDetector.ISSUE);
- issues.add(ViewTagDetector.ISSUE);
- issues.add(LocaleDetector.STRING_LOCALE);
- issues.add(LocaleDetector.DATE_FORMAT);
- issues.add(RegistrationDetector.ISSUE);
- issues.add(MissingClassDetector.MISSING);
- issues.add(MissingClassDetector.INSTANTIATABLE);
- issues.add(MissingClassDetector.INNERCLASS);
- issues.add(MissingIdDetector.ISSUE);
- issues.add(WrongCaseDetector.WRONGCASE);
- issues.add(HandlerDetector.ISSUE);
- issues.add(FragmentDetector.ISSUE);
- issues.add(TranslationDetector.EXTRA);
- issues.add(TranslationDetector.MISSING);
- issues.add(HardcodedValuesDetector.ISSUE);
- issues.add(Utf8Detector.ISSUE);
- issues.add(DosLineEndingDetector.ISSUE);
- issues.add(CommentDetector.EASTEREGG);
- issues.add(CommentDetector.STOPSHIP);
- issues.add(ProguardDetector.WRONGKEEP);
- issues.add(ProguardDetector.SPLITCONFIG);
- issues.add(PxUsageDetector.PX_ISSUE);
- issues.add(PxUsageDetector.DP_ISSUE);
- issues.add(PxUsageDetector.IN_MM_ISSUE);
- issues.add(PxUsageDetector.SMALL_SP_ISSUE);
- issues.add(TextFieldDetector.ISSUE);
- issues.add(TextViewDetector.ISSUE);
- issues.add(TextViewDetector.SELECTABLE);
- issues.add(UnusedResourceDetector.ISSUE);
- issues.add(UnusedResourceDetector.ISSUE_IDS);
- issues.add(ExtraTextDetector.ISSUE);
- issues.add(PrivateResourceDetector.ISSUE);
- issues.add(ArraySizeDetector.INCONSISTENT);
- issues.add(HardcodedDebugModeDetector.ISSUE);
- issues.add(ManifestOrderDetector.ORDER);
- issues.add(ManifestOrderDetector.USES_SDK);
- issues.add(ManifestOrderDetector.MULTIPLE_USES_SDK);
- issues.add(ManifestOrderDetector.WRONG_PARENT);
- issues.add(ManifestOrderDetector.DUPLICATE_ACTIVITY);
- issues.add(ManifestOrderDetector.TARGET_NEWER);
- issues.add(ManifestOrderDetector.ALLOW_BACKUP);
- issues.add(ManifestOrderDetector.UNIQUE_PERMISSION);
- issues.add(ManifestOrderDetector.SET_VERSION);
- issues.add(ManifestOrderDetector.ILLEGAL_REFERENCE);
- issues.add(SecurityDetector.EXPORTED_PROVIDER);
- issues.add(SecurityDetector.EXPORTED_SERVICE);
- issues.add(SecurityDetector.EXPORTED_RECEIVER);
- issues.add(SecurityDetector.OPEN_PROVIDER);
- issues.add(SecurityDetector.WORLD_READABLE);
- issues.add(SecurityDetector.WORLD_WRITEABLE);
- issues.add(SecureRandomDetector.ISSUE);
- issues.add(IconDetector.GIF_USAGE);
- issues.add(IconDetector.ICON_DENSITIES);
- issues.add(IconDetector.ICON_MISSING_FOLDER);
- issues.add(IconDetector.ICON_DIP_SIZE);
- issues.add(IconDetector.ICON_EXPECTED_SIZE);
- issues.add(IconDetector.ICON_LOCATION);
- issues.add(IconDetector.DUPLICATES_NAMES);
- issues.add(IconDetector.DUPLICATES_CONFIGURATIONS);
- issues.add(IconDetector.ICON_NODPI);
- issues.add(IconDetector.ICON_EXTENSION);
- issues.add(IconDetector.ICON_COLORS);
- issues.add(IconDetector.ICON_XML_AND_PNG);
- issues.add(IconDetector.ICON_LAUNCHER_SHAPE);
- issues.add(TypographyDetector.DASHES);
- issues.add(TypographyDetector.QUOTES);
- issues.add(TypographyDetector.FRACTIONS);
- issues.add(TypographyDetector.ELLIPSIS);
- issues.add(TypographyDetector.OTHER);
- issues.add(ButtonDetector.ORDER);
- issues.add(ButtonDetector.CASE);
- issues.add(ButtonDetector.BACKBUTTON);
- issues.add(ButtonDetector.STYLE);
- issues.add(DetectMissingPrefix.MISSING_NAMESPACE);
- issues.add(OverdrawDetector.ISSUE);
- issues.add(StringFormatDetector.INVALID);
- issues.add(StringFormatDetector.ARG_COUNT);
- issues.add(StringFormatDetector.ARG_TYPES);
- issues.add(TypoDetector.ISSUE);
- issues.add(ViewTypeDetector.ISSUE);
- issues.add(WrongImportDetector.ISSUE);
- issues.add(WrongLocationDetector.ISSUE);
- issues.add(ViewConstructorDetector.ISSUE);
- issues.add(NamespaceDetector.CUSTOMVIEW);
- issues.add(NamespaceDetector.UNUSED);
- issues.add(NamespaceDetector.TYPO);
- issues.add(AlwaysShowActionDetector.ISSUE);
- issues.add(TitleDetector.ISSUE);
- issues.add(ColorUsageDetector.ISSUE);
- issues.add(JavaPerformanceDetector.PAINT_ALLOC);
- issues.add(JavaPerformanceDetector.USE_VALUEOF);
- issues.add(JavaPerformanceDetector.USE_SPARSEARRAY);
- issues.add(WakelockDetector.ISSUE);
- issues.add(CleanupDetector.RECYCLE_RESOURCE);
- issues.add(CleanupDetector.COMMIT_FRAGMENT);
- issues.add(SetJavaScriptEnabledDetector.ISSUE);
- issues.add(ToastDetector.ISSUE);
- issues.add(SharedPrefsDetector.ISSUE);
- issues.add(CutPasteDetector.ISSUE);
- issues.add(NonInternationalizedSmsDetector.ISSUE);
- issues.add(PrivateKeyDetector.ISSUE);
- issues.add(AnnotationDetector.ISSUE);
- issues.add(SystemPermissionsDetector.ISSUE);
- issues.add(RequiredAttributeDetector.ISSUE);
- issues.add(WrongCallDetector.ISSUE);
-
- assert initialCapacity >= issues.size() : issues.size();
-
- addCustomIssues(issues);
-
- sIssues = Collections.unmodifiableList(issues);
-
- // Check that ids are unique
- if (assertionsEnabled()) {
- Set<String> ids = new HashSet<String>();
- for (Issue issue : sIssues) {
- String id = issue.getId();
- assert !ids.contains(id) : "Duplicate id " + id; //$NON-NLS-1$
- ids.add(id);
- }
- }
- }
-
- /**
- * Constructs a new {@link BuiltinIssueRegistry}
- */
- public BuiltinIssueRegistry() {
- }
-
- @NonNull
- @Override
- public List<Issue> getIssues() {
- return sIssues;
- }
-
- /**
- * Add in custom issues registered by the user - via an environment variable
- * or in the .android/lint directory.
- */
- private static void addCustomIssues(List<Issue> issues) {
- // Look for additional detectors registered by the user, via
- // (1) an environment variable (useful for build servers etc), and
- // (2) via jar files in the .android/lint directory
- Set<File> files = null;
- try {
- File lint = new File(AndroidLocation.getFolder() + File.separator + LINT_FOLDER);
- if (lint.exists()) {
- File[] list = lint.listFiles();
- if (list != null) {
- for (File jarFile : list) {
- if (endsWith(jarFile.getName(), ".jar")) { //$NON-NLS-1$
- if (files == null) {
- files = new HashSet<File>();
- }
- files.add(jarFile);
- addIssuesFromJar(jarFile, issues);
- }
- }
- }
- }
- } catch (AndroidLocationException e) {
- // Ignore -- no android dir, so no rules to load.
- }
-
- String lintClassPath = System.getenv("ANDROID_LINT_JARS"); //$NON-NLS-1$
- if (lintClassPath != null && !lintClassPath.isEmpty()) {
- String[] paths = lintClassPath.split(File.pathSeparator);
- for (String path : paths) {
- File jarFile = new File(path);
- if (jarFile.exists() && (files == null || !files.contains(jarFile))) {
- addIssuesFromJar(jarFile, issues);
- }
- }
- }
- }
-
- /** Add the issues found in the given jar file into the given list of issues */
- private static void addIssuesFromJar(File jarFile, List<Issue> issues) {
- JarFile jarfile = null;
- try {
- jarfile = new JarFile(jarFile);
- Manifest manifest = jarfile.getManifest();
- Attributes attrs = manifest.getMainAttributes();
- Object object = attrs.get(new Attributes.Name(MF_LINT_REGISTRY));
- if (object instanceof String) {
- String className = (String) object;
-
- // Make a class loader for this jar
- try {
- URL url = jarFile.toURI().toURL();
- URLClassLoader loader = new URLClassLoader(new URL[] { url },
- BuiltinIssueRegistry.class.getClassLoader());
- try {
- Class<?> registryClass = Class.forName(className, true, loader);
- IssueRegistry registry = (IssueRegistry) registryClass.newInstance();
- for (Issue issue : registry.getIssues()) {
- issues.add(issue);
- }
- } catch (Throwable e) {
- log(e);
- }
- } catch (MalformedURLException e) {
- log(e);
- }
- }
- } catch (IOException e) {
- log(e);
- } finally {
- if (jarfile != null) {
- try {
- jarfile.close();
- } catch (IOException e) {
- // Nothing to be done
- }
- }
- }
- }
-
- private static void log(Throwable e) {
- // TODO: Where do we log this? There's no embedding tool context here. For now,
- // just dump to the console so detector developers get some feedback on what went
- // wrong.
- e.printStackTrace();
- }
-
- private static Set<Issue> sAdtFixes;
-
- /**
- * Returns true if the given issue has an automatic IDE fix.
- *
- * @param tool the name of the tool to be checked
- * @param issue the issue to be checked
- * @return true if the given tool is known to have an automatic fix for the
- * given issue
- */
- @Beta
- public boolean hasAutoFix(String tool, Issue issue) {
- assert tool.equals("adt"); // This is not yet a generic facility;
- // the primary purpose right now is to allow for example the HTML report
- // to give a hint to the user that some fixes don't require manual work
-
- return getIssuesWithFixes().contains(issue);
- }
-
- private static Set<Issue> getIssuesWithFixes() {
- if (sAdtFixes == null) {
- sAdtFixes = new HashSet<Issue>(25);
- sAdtFixes.add(InefficientWeightDetector.INEFFICIENT_WEIGHT);
- sAdtFixes.add(AccessibilityDetector.ISSUE);
- sAdtFixes.add(InefficientWeightDetector.BASELINE_WEIGHTS);
- sAdtFixes.add(HardcodedValuesDetector.ISSUE);
- sAdtFixes.add(UselessViewDetector.USELESS_LEAF);
- sAdtFixes.add(UselessViewDetector.USELESS_PARENT);
- sAdtFixes.add(PxUsageDetector.PX_ISSUE);
- sAdtFixes.add(TextFieldDetector.ISSUE);
- sAdtFixes.add(SecurityDetector.EXPORTED_SERVICE);
- sAdtFixes.add(DetectMissingPrefix.MISSING_NAMESPACE);
- sAdtFixes.add(ScrollViewChildDetector.ISSUE);
- sAdtFixes.add(ObsoleteLayoutParamsDetector.ISSUE);
- sAdtFixes.add(TypographyDetector.DASHES);
- sAdtFixes.add(TypographyDetector.ELLIPSIS);
- sAdtFixes.add(TypographyDetector.FRACTIONS);
- sAdtFixes.add(TypographyDetector.OTHER);
- sAdtFixes.add(TypographyDetector.QUOTES);
- sAdtFixes.add(UseCompoundDrawableDetector.ISSUE);
- sAdtFixes.add(ApiDetector.UNSUPPORTED);
- sAdtFixes.add(TypoDetector.ISSUE);
- sAdtFixes.add(ManifestOrderDetector.ALLOW_BACKUP);
- sAdtFixes.add(MissingIdDetector.ISSUE);
- sAdtFixes.add(TranslationDetector.MISSING);
- sAdtFixes.add(DosLineEndingDetector.ISSUE);
- }
-
- return sAdtFixes;
- }
-
- /**
- * Reset the registry such that it recomputes its available issues.
- * <p>
- * NOTE: This is only intended for testing purposes.
- */
- @VisibleForTesting
- public static void reset() {
- IssueRegistry.reset();
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ButtonDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ButtonDetector.java
deleted file mode 100644
index e756e03..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ButtonDetector.java
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_STRING_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.ATTR_TEXT;
-import static com.android.SdkConstants.BUTTON;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.STRING_PREFIX;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.TAG_STRING;
-import static com.android.SdkConstants.VALUE_SELECTABLE_ITEM_BACKGROUND;
-import static com.android.SdkConstants.VALUE_TRUE;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Check which looks at the order of buttons in dialogs and makes sure that
- * "the dismissive action of a dialog is always on the left whereas the affirmative actions
- * are on the right."
- * <p>
- * This only looks for the affirmative and dismissive actions named "OK" and "Cancel";
- * "Cancel" usually works, but the affirmative action often has many other names -- "Done",
- * "Send", "Go", etc.
- * <p>
- * TODO: Perhaps we should look for Yes/No dialogs and suggested they be rephrased as
- * Cancel/OK dialogs? Similarly, consider "Abort" a synonym for "Cancel" ?
- */
-public class ButtonDetector extends ResourceXmlDetector {
- /** Name of cancel value ("Cancel") */
- private static final String CANCEL_LABEL = "Cancel";
- /** Name of OK value ("Cancel") */
- private static final String OK_LABEL = "OK";
- /** Name of Back value ("Back") */
- private static final String BACK_LABEL = "Back";
-
- /** Layout text attribute reference to {@code @android:string/ok} */
- private static final String ANDROID_OK_RESOURCE =
- ANDROID_STRING_PREFIX + "ok"; //$NON-NLS-1$
- /** Layout text attribute reference to {@code @android:string/cancel} */
- private static final String ANDROID_CANCEL_RESOURCE =
- ANDROID_STRING_PREFIX + "cancel"; //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue ORDER = Issue.create(
- "ButtonOrder", //$NON-NLS-1$
- "Ensures the dismissive action of a dialog is on the left and affirmative on " +
- "the right",
-
- "According to the Android Design Guide,\n" +
- "\n" +
- "\"Action buttons are typically Cancel and/or OK, with OK indicating the preferred " +
- "or most likely action. However, if the options consist of specific actions such " +
- "as Close or Wait rather than a confirmation or cancellation of the action " +
- "described in the content, then all the buttons should be active verbs. As a rule, " +
- "the dismissive action of a dialog is always on the left whereas the affirmative " +
- "actions are on the right.\"\n" +
- "\n" +
- "This check looks for button bars and buttons which look like cancel buttons, " +
- "and makes sure that these are on the left.",
-
- Category.USABILITY,
- 8,
- Severity.WARNING,
- ButtonDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setMoreInfo(
- "http://developer.android.com/design/building-blocks/dialogs.html"); //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue STYLE = Issue.create(
- "ButtonStyle", //$NON-NLS-1$
- "Ensures that buttons in button bars are borderless",
-
- "Button bars typically use a borderless style for the buttons. Set the " +
- "`style=\"?android:attr/buttonBarButtonStyle\"` attribute " +
- "on each of the buttons, and set `style=\"?android:attr/buttonBarStyle\"` on " +
- "the parent layout",
-
- Category.USABILITY,
- 5,
- Severity.WARNING,
- ButtonDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setMoreInfo(
- "http://developer.android.com/design/building-blocks/buttons.html"); //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue BACKBUTTON = Issue.create(
- "BackButton", //$NON-NLS-1$
- "Looks for Back buttons, which are not common on the Android platform.",
- // TODO: Look for ">" as label suffixes as well
-
- "According to the Android Design Guide,\n" +
- "\n" +
- "\"Other platforms use an explicit back button with label to allow the user " +
- "to navigate up the application's hierarchy. Instead, Android uses the main " +
- "action bar's app icon for hierarchical navigation and the navigation bar's " +
- "back button for temporal navigation.\"" +
- "\n" +
- "This check is not very sophisticated (it just looks for buttons with the " +
- "label \"Back\"), so it is disabled by default to not trigger on common " +
- "scenarios like pairs of Back/Next buttons to paginate through screens.",
-
- Category.USABILITY,
- 6,
- Severity.WARNING,
- ButtonDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setEnabledByDefault(false)
- .setMoreInfo(
- "http://developer.android.com/design/patterns/pure-android.html"); //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue CASE = Issue.create(
- "ButtonCase", //$NON-NLS-1$
- "Ensures that Cancel/OK dialog buttons use the canonical capitalization",
-
- "The standard capitalization for OK/Cancel dialogs is \"OK\" and \"Cancel\". " +
- "To ensure that your dialogs use the standard strings, you can use " +
- "the resource strings @android:string/ok and @android:string/cancel.",
-
- Category.USABILITY,
- 2,
- Severity.WARNING,
- ButtonDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Set of resource names whose value was either OK or Cancel */
- private Set<String> mApplicableResources;
-
- /**
- * Map of resource names we'd like resolved into strings in phase 2. The
- * values should be filled in with the actual string contents.
- */
- private Map<String, String> mKeyToLabel;
-
- /**
- * Set of elements we've already warned about. If we've already complained
- * about a cancel button, don't also report the OK button (since it's listed
- * for the warnings on OK buttons).
- */
- private Set<Element> mIgnore;
-
- /** Constructs a new {@link ButtonDetector} */
- public ButtonDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(BUTTON, TAG_STRING);
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- int phase = context.getPhase();
- if (phase == 1 && mApplicableResources != null) {
- // We found resources for the string "Cancel"; perform a second pass
- // where we check layout text attributes against these strings.
- context.getDriver().requestRepeat(this, Scope.RESOURCE_FILE_SCOPE);
- }
- }
-
- private static String stripLabel(String text) {
- text = text.trim();
- if (text.length() > 2
- && (text.charAt(0) == '"' || text.charAt(0) == '\'')
- && (text.charAt(0) == text.charAt(text.length() - 1))) {
- text = text.substring(1, text.length() - 1);
- }
-
- return text;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- // This detector works in two passes.
- // In pass 1, it looks in layout files for hardcoded strings of "Cancel", or
- // references to @string/cancel or @android:string/cancel.
- // It also looks in values/ files for strings whose value is "Cancel",
- // and if found, stores the corresponding keys in a map. (This is necessary
- // since value files are processed after layout files).
- // Then, if at the end of phase 1 any "Cancel" string resources were
- // found in the value files, then it requests a *second* phase,
- // where it looks only for <Button>'s whose text matches one of the
- // cancel string resources.
- int phase = context.getPhase();
- String tagName = element.getTagName();
- if (phase == 1 && tagName.equals(TAG_STRING)) {
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- String text = child.getNodeValue();
- for (int j = 0, len = text.length(); j < len; j++) {
- char c = text.charAt(j);
- if (!Character.isWhitespace(c)) {
- if (c == '"' || c == '\'') {
- continue;
- }
- if (LintUtils.startsWith(text, CANCEL_LABEL, j)) {
- String label = stripLabel(text);
- if (label.equalsIgnoreCase(CANCEL_LABEL)) {
- String name = element.getAttribute(ATTR_NAME);
- foundResource(context, name, element);
-
- if (!label.equals(CANCEL_LABEL)
- && isEnglishResource(context)
- && context.isEnabled(CASE)) {
- assert label.equalsIgnoreCase(CANCEL_LABEL);
- context.report(CASE, child, context.getLocation(child),
- String.format(
- "The standard Android way to capitalize %1$s " +
- "is \"Cancel\" (tip: use @android:string/ok instead)",
- label), null);
- }
- }
- } else if (LintUtils.startsWith(text, OK_LABEL, j)) {
- String label = stripLabel(text);
- if (label.equalsIgnoreCase(OK_LABEL)) {
- String name = element.getAttribute(ATTR_NAME);
- foundResource(context, name, element);
-
- if (!label.equals(OK_LABEL)
- && isEnglishResource(context)
- && context.isEnabled(CASE)) {
- assert text.trim().equalsIgnoreCase(OK_LABEL);
- context.report(CASE, child, context.getLocation(child),
- String.format(
- "The standard Android way to capitalize %1$s " +
- "is \"OK\" (tip: use @android:string/ok instead)",
- label), null);
- }
- }
- } else if (LintUtils.startsWith(text, BACK_LABEL, j) &&
- stripLabel(text).equalsIgnoreCase(BACK_LABEL)) {
- String name = element.getAttribute(ATTR_NAME);
- foundResource(context, name, element);
- }
- break;
- }
- }
- }
- }
- } else if (tagName.equals(BUTTON)) {
- if (phase == 1) {
- if (isInButtonBar(element)
- && !element.hasAttribute(ATTR_STYLE)
- && !VALUE_SELECTABLE_ITEM_BACKGROUND.equals(
- element.getAttributeNS(ANDROID_URI, ATTR_BACKGROUND))
- && (context.getProject().getMinSdk() >= 11
- || context.getFolderVersion() >= 11)
- && context.isEnabled(STYLE)
- && !parentDefinesSelectableItem(element)) {
- context.report(STYLE, element, context.getLocation(element),
- "Buttons in button bars should be borderless; use " +
- "style=\"?android:attr/buttonBarButtonStyle\" (and " +
- "?android:attr/buttonBarStyle on the parent)",
- null);
- }
- }
-
- String text = element.getAttributeNS(ANDROID_URI, ATTR_TEXT);
- if (phase == 2) {
- if (mApplicableResources.contains(text)) {
- String key = text;
- if (key.startsWith(STRING_PREFIX)) {
- key = key.substring(STRING_PREFIX.length());
- }
- String label = mKeyToLabel.get(key);
- boolean isCancel = CANCEL_LABEL.equalsIgnoreCase(label);
- if (isCancel) {
- if (isWrongCancelPosition(element)) {
- reportCancelPosition(context, element);
- }
- } else if (OK_LABEL.equalsIgnoreCase(label)) {
- if (isWrongOkPosition(element)) {
- reportOkPosition(context, element);
- }
- } else {
- assert BACK_LABEL.equalsIgnoreCase(label) : label + ':' + context.file;
- Location location = context.getLocation(element);
- if (context.isEnabled(BACKBUTTON)) {
- context.report(BACKBUTTON, element, location,
- "Back buttons are not standard on Android; see design guide's " +
- "navigation section", null);
- }
- }
- }
- } else if (text.equals(CANCEL_LABEL) || text.equals(ANDROID_CANCEL_RESOURCE)) {
- if (isWrongCancelPosition(element)) {
- reportCancelPosition(context, element);
- }
- } else if (text.equals(OK_LABEL) || text.equals(ANDROID_OK_RESOURCE)) {
- if (isWrongOkPosition(element)) {
- reportOkPosition(context, element);
- }
- }
- }
- }
-
- private static boolean parentDefinesSelectableItem(Element element) {
- String background = element.getAttributeNS(ANDROID_URI, ATTR_BACKGROUND);
- if (VALUE_SELECTABLE_ITEM_BACKGROUND.equals(background)) {
- return true;
- }
-
- Node parent = element.getParentNode();
- if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
- return parentDefinesSelectableItem((Element) parent);
- }
-
- return false;
- }
-
- /** Report the given OK button as being in the wrong position */
- private void reportOkPosition(XmlContext context, Element element) {
- report(context, element, false /*isCancel*/);
- }
-
- /** Report the given Cancel button as being in the wrong position */
- private void reportCancelPosition(XmlContext context, Element element) {
- report(context, element, true /*isCancel*/);
- }
-
-
- /** The Ok/Cancel detector only works with default and English locales currently.
- * TODO: Add in patterns for other languages. We can use the
- * @android:string/ok and @android:string/cancel localizations to look
- * up the canonical ones. */
- private static boolean isEnglishResource(XmlContext context) {
- String folder = context.file.getParentFile().getName();
- if (folder.indexOf('-') != -1) {
- String[] qualifiers = folder.split("-"); //$NON-NLS-1$
- for (String qualifier : qualifiers) {
- if (qualifier.equals("en")) { //$NON-NLS-1$
- return true;
- }
- }
- return false;
- }
-
- // Default folder ("values") - may not be English but we'll consider matches
- // on "OK", "Cancel" and "Back" as matches there
- return true;
- }
-
- /**
- * We've found a resource reference to some label we're interested in ("OK",
- * "Cancel", "Back", ...). Record the corresponding name such that in the
- * next pass through the layouts we can check the context (for OK/Cancel the
- * button order etc).
- */
- private void foundResource(XmlContext context, String name, Element element) {
- if (!isEnglishResource(context)) {
- return;
- }
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- if (mApplicableResources == null) {
- mApplicableResources = new HashSet<String>();
- }
-
- mApplicableResources.add(STRING_PREFIX + name);
-
- // ALSO record all the other string resources in this file to pick up other
- // labels. If you define "OK" in one resource file and "Cancel" in another
- // this won't work, but that's probably not common and has lower overhead.
- Node parentNode = element.getParentNode();
-
- List<Element> items = LintUtils.getChildren(parentNode);
- if (mKeyToLabel == null) {
- mKeyToLabel = new HashMap<String, String>(items.size());
- }
- for (Element item : items) {
- String itemName = item.getAttribute(ATTR_NAME);
- NodeList childNodes = item.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- String text = stripLabel(child.getNodeValue());
- if (!text.isEmpty()) {
- mKeyToLabel.put(itemName, text);
- break;
- }
- }
- }
- }
- }
-
- /** Report the given OK/Cancel button as being in the wrong position */
- private void report(XmlContext context, Element element, boolean isCancel) {
- if (!context.isEnabled(ORDER)) {
- return;
- }
-
- if (mIgnore != null && mIgnore.contains(element)) {
- return;
- }
-
- int target = context.getProject().getTargetSdk();
- if (target < 14) {
- // If you're only targeting pre-ICS UI's, this is not an issue
- return;
- }
-
- boolean mustCreateIcsLayout = false;
- if (context.getProject().getMinSdk() < 14) {
- // If you're *also* targeting pre-ICS UIs, then this reverse button
- // order is correct for layouts intended for pre-ICS and incorrect for
- // ICS layouts.
- //
- // Therefore, we need to know if this layout is an ICS layout or
- // a pre-ICS layout.
- boolean isIcsLayout = context.getFolderVersion() >= 14;
- if (!isIcsLayout) {
- // This layout is not an ICS layout. However, there *must* also be
- // an ICS layout here, or this button order will be wrong:
- File res = context.file.getParentFile().getParentFile();
- File[] resFolders = res.listFiles();
- String fileName = context.file.getName();
- if (resFolders != null) {
- for (File folder : resFolders) {
- String folderName = folder.getName();
- if (folderName.startsWith(SdkConstants.FD_RES_LAYOUT)
- && folderName.contains("-v14")) { //$NON-NLS-1$
- File layout = new File(folder, fileName);
- if (layout.exists()) {
- // Yes, a v14 specific layout is available so this pre-ICS
- // layout order is not a problem
- return;
- }
- }
- }
- }
- mustCreateIcsLayout = true;
- }
- }
-
- List<Element> buttons = LintUtils.getChildren(element.getParentNode());
-
- if (mIgnore == null) {
- mIgnore = new HashSet<Element>();
- }
- for (Element button : buttons) {
- // Mark all the siblings in the ignore list to ensure that we don't
- // report *both* the Cancel and the OK button in "OK | Cancel"
- mIgnore.add(button);
- }
-
- String message;
- if (isCancel) {
- message = "Cancel button should be on the left";
- } else {
- message = "OK button should be on the right";
- }
-
- if (mustCreateIcsLayout) {
- message = String.format(
- "Layout uses the wrong button order for API >= 14: Create a " +
- "layout-v14/%1$s file with opposite order: %2$s",
- context.file.getName(), message);
- }
-
- // Show existing button order? We can only do that for LinearLayouts
- // since in for example a RelativeLayout the order of the elements may
- // not be the same as the visual order
- String layout = element.getParentNode().getNodeName();
- if (layout.equals(LINEAR_LAYOUT) || layout.equals(TABLE_ROW)) {
- List<String> labelList = getLabelList(buttons);
- String wrong = describeButtons(labelList);
- sortButtons(labelList);
- String right = describeButtons(labelList);
- message += String.format(" (was \"%1$s\", should be \"%2$s\")", wrong, right);
- }
-
- Location location = context.getLocation(element);
- context.report(ORDER, element, location, message, null);
- }
-
- /**
- * Sort a list of label buttons into the expected order (Cancel on the left,
- * OK on the right
- */
- private static void sortButtons(List<String> labelList) {
- for (int i = 0, n = labelList.size(); i < n; i++) {
- String label = labelList.get(i);
- if (label.equalsIgnoreCase(CANCEL_LABEL) && i > 0) {
- swap(labelList, 0, i);
- } else if (label.equalsIgnoreCase(OK_LABEL) && i < n - 1) {
- swap(labelList, n - 1, i);
- }
- }
- }
-
- /** Swaps the strings at positions i and j */
- private static void swap(List<String> strings, int i, int j) {
- if (i != j) {
- String temp = strings.get(i);
- strings.set(i, strings.get(j));
- strings.set(j, temp);
- }
- }
-
- /** Creates a display string for a list of button labels, such as "Cancel | OK" */
- private static String describeButtons(List<String> labelList) {
- StringBuilder sb = new StringBuilder(80);
- for (String label : labelList) {
- if (sb.length() > 0) {
- sb.append(" | "); //$NON-NLS-1$
- }
- sb.append(label);
- }
-
- return sb.toString();
- }
-
- /** Returns the ordered list of button labels */
- private List<String> getLabelList(List<Element> views) {
- List<String> labels = new ArrayList<String>();
-
- if (mIgnore == null) {
- mIgnore = new HashSet<Element>();
- }
-
- for (Element view : views) {
- if (view.getTagName().equals(BUTTON)) {
- String text = view.getAttributeNS(ANDROID_URI, ATTR_TEXT);
- String label = getLabel(text);
- labels.add(label);
-
- // Mark all the siblings in the ignore list to ensure that we don't
- // report *both* the Cancel and the OK button in "OK | Cancel"
- mIgnore.add(view);
- }
- }
-
- return labels;
- }
-
- private String getLabel(String key) {
- String label = null;
- if (key.startsWith(ANDROID_STRING_PREFIX)) {
- if (key.equals(ANDROID_OK_RESOURCE)) {
- label = OK_LABEL;
- } else if (key.equals(ANDROID_CANCEL_RESOURCE)) {
- label = CANCEL_LABEL;
- }
- } else if (mKeyToLabel != null) {
- if (key.startsWith(STRING_PREFIX)) {
- label = mKeyToLabel.get(key.substring(STRING_PREFIX.length()));
- }
- }
-
- if (label == null) {
- label = key;
- }
-
- if (label.indexOf(' ') != -1 && label.indexOf('"') == -1) {
- label = '"' + label + '"';
- }
-
- return label;
- }
-
- /** Is the cancel button in the wrong position? It has to be on the left. */
- private boolean isWrongCancelPosition(Element element) {
- return isWrongPosition(element, true /*isCancel*/);
- }
-
- /** Is the OK button in the wrong position? It has to be on the right. */
- private boolean isWrongOkPosition(Element element) {
- return isWrongPosition(element, false /*isCancel*/);
- }
-
- private static boolean isInButtonBar(Element element) {
- assert element.getTagName().equals(BUTTON) : element.getTagName();
- Node parentNode = element.getParentNode();
- if (parentNode.getNodeType() != Node.ELEMENT_NODE) {
- return false;
- }
- Element parent = (Element) parentNode;
-
- String style = parent.getAttribute(ATTR_STYLE);
- if (style != null && style.contains("buttonBarStyle")) { //$NON-NLS-1$
- return true;
- }
-
- // Don't warn about single Cancel / OK buttons
- if (LintUtils.getChildCount(parent) < 2) {
- return false;
- }
-
- String layout = parent.getTagName();
- if (layout.equals(LINEAR_LAYOUT) || layout.equals(TABLE_ROW)) {
- String orientation = parent.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION);
- if (VALUE_VERTICAL.equals(orientation)) {
- return false;
- }
- } else {
- return false;
- }
-
- // Ensure that all the children are buttons
- Node n = parent.getFirstChild();
- while (n != null) {
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- if (!BUTTON.equals(n.getNodeName())) {
- return false;
- }
- }
- n = n.getNextSibling();
- }
-
- return true;
- }
-
- /** Is the given button in the wrong position? */
- private static boolean isWrongPosition(Element element, boolean isCancel) {
- Node parentNode = element.getParentNode();
- if (parentNode.getNodeType() != Node.ELEMENT_NODE) {
- return false;
- }
- Element parent = (Element) parentNode;
-
- // Don't warn about single Cancel / OK buttons
- if (LintUtils.getChildCount(parent) < 2) {
- return false;
- }
-
- String layout = parent.getTagName();
- if (layout.equals(LINEAR_LAYOUT) || layout.equals(TABLE_ROW)) {
- String orientation = parent.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION);
- if (VALUE_VERTICAL.equals(orientation)) {
- return false;
- }
-
- if (isCancel) {
- Node n = element.getPreviousSibling();
- while (n != null) {
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- return true;
- }
- n = n.getPreviousSibling();
- }
- } else {
- Node n = element.getNextSibling();
- while (n != null) {
- if (n.getNodeType() == Node.ELEMENT_NODE) {
- return true;
- }
- n = n.getNextSibling();
- }
- }
-
- return false;
- } else if (layout.equals(RELATIVE_LAYOUT)) {
- // In RelativeLayouts, look for attachments which look like a clear sign
- // that the OK or Cancel buttons are out of order:
- // -- a left attachment on a Cancel button (where the left attachment
- // is a button; we don't want to complain if it's pointing to a spacer
- // or image or progress indicator etc)
- // -- a right-side parent attachment on a Cancel button (unless it's also
- // attached on the left, e.g. a cancel button stretching across the
- // layout)
- // etc.
- if (isCancel) {
- if (element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_TO_RIGHT_OF)
- && isButtonId(parent, element.getAttributeNS(ANDROID_URI,
- ATTR_LAYOUT_TO_RIGHT_OF))) {
- return true;
- }
- if (isTrue(element, ATTR_LAYOUT_ALIGN_PARENT_RIGHT) &&
- !isTrue(element, ATTR_LAYOUT_ALIGN_PARENT_LEFT)) {
- return true;
- }
- } else {
- if (element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_TO_LEFT_OF)
- && isButtonId(parent, element.getAttributeNS(ANDROID_URI,
- ATTR_LAYOUT_TO_RIGHT_OF))) {
- return true;
- }
- if (isTrue(element, ATTR_LAYOUT_ALIGN_PARENT_LEFT) &&
- !isTrue(element, ATTR_LAYOUT_ALIGN_PARENT_RIGHT)) {
- return true;
- }
- }
-
- return false;
- } else {
- // TODO: Consider other button layouts - GridLayouts, custom views extending
- // LinearLayout etc?
- return false;
- }
- }
-
- /**
- * Returns true if the given attribute (in the Android namespace) is set to
- * true on the given element
- */
- private static boolean isTrue(Element element, String attribute) {
- return VALUE_TRUE.equals(element.getAttributeNS(ANDROID_URI, attribute));
- }
-
- /** Is the given target id the id of a {@code <Button>} within this RelativeLayout? */
- private static boolean isButtonId(Element parent, String targetId) {
- for (Element child : LintUtils.getChildren(parent)) {
- String id = child.getAttributeNS(ANDROID_URI, ATTR_ID);
- if (LintUtils.idReferencesMatch(id, targetId)) {
- return child.getTagName().equals(BUTTON);
- }
- }
- return false;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ChildCountDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ChildCountDetector.java
deleted file mode 100644
index bc1e30d..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ChildCountDetector.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.GRID_VIEW;
-import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.LIST_VIEW;
-import static com.android.SdkConstants.REQUEST_FOCUS;
-import static com.android.SdkConstants.SCROLL_VIEW;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Check which makes sure that views have the expected number of declared
- * children (e.g. at most one in ScrollViews and none in AdapterViews)
- */
-public class ChildCountDetector extends LayoutDetector {
-
- /** The main issue discovered by this detector */
- public static final Issue SCROLLVIEW_ISSUE = Issue.create(
- "ScrollViewCount", //$NON-NLS-1$
- "Checks that ScrollViews have exactly one child widget",
- "ScrollViews can only have one child widget. If you want more children, wrap them " +
- "in a container layout.",
- Category.CORRECTNESS,
- 8,
- Severity.WARNING,
- ChildCountDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** The main issue discovered by this detector */
- public static final Issue ADAPTERVIEW_ISSUE = Issue.create(
- "AdapterViewChildren", //$NON-NLS-1$
- "Checks that AdapterViews do not define their children in XML",
- "AdapterViews such as ListViews must be configured with data from Java code, " +
- "such as a ListAdapter.",
- Category.CORRECTNESS,
- 10,
- Severity.WARNING,
- ChildCountDetector.class,
- Scope.RESOURCE_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/android/widget/AdapterView.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link ChildCountDetector} */
- public ChildCountDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- SCROLL_VIEW,
- HORIZONTAL_SCROLL_VIEW,
- LIST_VIEW,
- GRID_VIEW
- // TODO: Shouldn't Spinner be in this list too? (Was not there in layoutopt)
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- int childCount = LintUtils.getChildCount(element);
- String tagName = element.getTagName();
- if (tagName.equals(SCROLL_VIEW) || tagName.equals(HORIZONTAL_SCROLL_VIEW)) {
- if (childCount > 1 && getAccurateChildCount(element) > 1) {
- context.report(SCROLLVIEW_ISSUE, element,
- context.getLocation(element), "A scroll view can have only one child",
- null);
- }
- } else {
- // Adapter view
- if (childCount > 0 && getAccurateChildCount(element) > 0) {
- context.report(ADAPTERVIEW_ISSUE, element,
- context.getLocation(element),
- "A list/grid should have no children declared in XML", null);
- }
- }
- }
-
- /** Counts the number of children, but skips certain tags like {@code <requestFocus>} */
- private static int getAccurateChildCount(Element element) {
- NodeList childNodes = element.getChildNodes();
- int childCount = 0;
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE &&
- !REQUEST_FOCUS.equals(child.getNodeName())) {
- childCount++;
- }
- }
-
- return childCount;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CleanupDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CleanupDetector.java
deleted file mode 100644
index 1541d23..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CleanupDetector.java
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.analysis.Analyzer;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-import org.objectweb.asm.tree.analysis.BasicValue;
-import org.objectweb.asm.tree.analysis.Frame;
-import org.objectweb.asm.tree.analysis.Interpreter;
-import org.objectweb.asm.tree.analysis.Value;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Checks for missing {@code recycle} calls on resources that encourage it, and
- * for missing {@code commit} calls on FragmentTransactions, etc.
- */
-public class CleanupDetector extends Detector implements ClassScanner {
- /** Problems with missing recycle calls */
- public static final Issue RECYCLE_RESOURCE = Issue.create(
- "Recycle", //$NON-NLS-1$
- "Looks for missing recycle() calls on resources",
-
- "Many resources, such as TypedArrays, VelocityTrackers, etc., " +
- "should be recycled (with a `recycle()` call) after use. This lint check looks " +
- "for missing `recycle()` calls.",
-
- Category.PERFORMANCE,
- 7,
- Severity.WARNING,
- CleanupDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- /** Problems with missing commit calls. */
- public static final Issue COMMIT_FRAGMENT = Issue.create(
- "CommitTransaction", //$NON-NLS-1$
- "Looks for missing commit() calls on FragmentTransactions",
-
- "After creating a `FragmentTransaction`, you typically need to commit it as well",
-
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- CleanupDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- // Target method names
- private static final String RECYCLE = "recycle"; //$NON-NLS-1$
- private static final String OBTAIN = "obtain"; //$NON-NLS-1$
- private static final String OBTAIN_NO_HISTORY = "obtainNoHistory"; //$NON-NLS-1$
- private static final String OBTAIN_ATTRIBUTES = "obtainAttributes"; //$NON-NLS-1$
- private static final String OBTAIN_TYPED_ARRAY = "obtainTypedArray"; //$NON-NLS-1$
- private static final String OBTAIN_STYLED_ATTRIBUTES = "obtainStyledAttributes"; //$NON-NLS-1$
- private static final String BEGIN_TRANSACTION = "beginTransaction"; //$NON-NLS-1$
- private static final String COMMIT = "commit"; //$NON-NLS-1$
- private static final String COMMIT_ALLOWING_LOSS = "commitAllowingStateLoss"; //$NON-NLS-1$
-
- // Target owners
- private static final String VELOCITY_TRACKER_CLS = "android/view/VelocityTracker";//$NON-NLS-1$
- private static final String TYPED_ARRAY_CLS = "android/content/res/TypedArray"; //$NON-NLS-1$
- private static final String CONTEXT_CLS = "android/content/Context"; //$NON-NLS-1$
- private static final String MOTION_EVENT_CLS = "android/view/MotionEvent"; //$NON-NLS-1$
- private static final String HANDLER_CLS = "android/os/Handler"; //$NON-NLS-1$
- private static final String RESOURCES_CLS = "android/content/res/Resources"; //$NON-NLS-1$
- private static final String PARCEL_CLS = "android/os/Parcel"; //$NON-NLS-1$
- private static final String FRAGMENT_MANAGER_CLS = "android/app/FragmentManager"; //$NON-NLS-1$
- private static final String FRAGMENT_MANAGER_V4_CLS = "android/support/v4/app/FragmentManager"; //$NON-NLS-1$
- private static final String FRAGMENT_TRANSACTION_CLS = "android/app/FragmentTransaction"; //$NON-NLS-1$
- private static final String FRAGMENT_TRANSACTION_V4_CLS = "android/support/v4/app/FragmentTransaction"; //$NON-NLS-1$
-
- // Target description signatures
- private static final String TYPED_ARRAY_SIG = "Landroid/content/res/TypedArray;"; //$NON-NLS-1$
-
- private boolean mObtainsTypedArray;
- private boolean mRecyclesTypedArray;
- private boolean mObtainsTracker;
- private boolean mRecyclesTracker;
- private boolean mObtainsMotionEvent;
- private boolean mRecyclesMotionEvent;
- private boolean mObtainsParcel;
- private boolean mRecyclesParcel;
- private boolean mObtainsTransaction;
- private boolean mCommitsTransaction;
-
- /** Constructs a new {@link CleanupDetector} */
- public CleanupDetector() {
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- int phase = context.getDriver().getPhase();
- if (phase == 1) {
- if (mObtainsTypedArray && !mRecyclesTypedArray
- || mObtainsTracker && !mRecyclesTracker
- || mObtainsParcel && !mRecyclesParcel
- || mObtainsMotionEvent && !mRecyclesMotionEvent
- || mObtainsTransaction && !mCommitsTransaction) {
- context.getDriver().requestRepeat(this, Scope.CLASS_FILE_SCOPE);
- }
- }
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Arrays.asList(
- RECYCLE,
- OBTAIN_STYLED_ATTRIBUTES,
- OBTAIN,
- OBTAIN_ATTRIBUTES,
- OBTAIN_TYPED_ARRAY,
- OBTAIN_NO_HISTORY,
- BEGIN_TRANSACTION,
- COMMIT,
- COMMIT_ALLOWING_LOSS
- );
- }
-
- @Override
- public void checkCall(
- @NonNull ClassContext context,
- @NonNull ClassNode classNode,
- @NonNull MethodNode method,
- @NonNull MethodInsnNode call) {
- String name = call.name;
- String owner = call.owner;
- String desc = call.desc;
- int phase = context.getDriver().getPhase();
- if (RECYCLE.equals(name) && desc.equals("()V")) { //$NON-NLS-1$
- if (owner.equals(TYPED_ARRAY_CLS)) {
- mRecyclesTypedArray = true;
- } else if (owner.equals(VELOCITY_TRACKER_CLS)) {
- mRecyclesTracker = true;
- } else if (owner.equals(MOTION_EVENT_CLS)) {
- mRecyclesMotionEvent = true;
- } else if (owner.equals(PARCEL_CLS)) {
- mRecyclesParcel = true;
- }
- } else if ((COMMIT.equals(name) || COMMIT_ALLOWING_LOSS.equals(name))
- && desc.equals("()I")) { //$NON-NLS-1$
- if (owner.equals(FRAGMENT_TRANSACTION_CLS)
- || owner.equals(FRAGMENT_TRANSACTION_V4_CLS)) {
- mCommitsTransaction = true;
- }
- } else if (owner.equals(MOTION_EVENT_CLS)) {
- if (OBTAIN.equals(name) || OBTAIN_NO_HISTORY.equals(name)) {
- mObtainsMotionEvent = true;
- if (phase == 2 && !mRecyclesMotionEvent) {
- context.report(RECYCLE_RESOURCE, method, call, context.getLocation(call),
- getErrorMessage(MOTION_EVENT_CLS),
- null);
- } else if (phase == 1
- && checkMethodFlow(context, classNode, method, call, MOTION_EVENT_CLS)) {
- // Already reported error above; don't do global check
- mRecyclesMotionEvent = true;
- }
- }
- } else if (OBTAIN.equals(name)) {
- if (owner.equals(VELOCITY_TRACKER_CLS)) {
- mObtainsTracker = true;
- if (phase == 2 && !mRecyclesTracker) {
- context.report(RECYCLE_RESOURCE, method, call, context.getLocation(call),
- getErrorMessage(VELOCITY_TRACKER_CLS),
- null);
- }
- } else if (owner.equals(PARCEL_CLS)) {
- mObtainsParcel = true;
- if (phase == 2 && !mRecyclesParcel) {
- context.report(RECYCLE_RESOURCE, method, call, context.getLocation(call),
- getErrorMessage(PARCEL_CLS),
- null);
- } else if (phase == 1
- && checkMethodFlow(context, classNode, method, call, PARCEL_CLS)) {
- // Already reported error above; don't do global check
- mRecyclesParcel = true;
- }
- }
- } else if (OBTAIN_STYLED_ATTRIBUTES.equals(name)
- || OBTAIN_ATTRIBUTES.equals(name)
- || OBTAIN_TYPED_ARRAY.equals(name)) {
- if ((owner.equals(CONTEXT_CLS) || owner.equals(RESOURCES_CLS))
- && desc.endsWith(TYPED_ARRAY_SIG)) {
- mObtainsTypedArray = true;
- if (phase == 2 && !mRecyclesTypedArray) {
- context.report(RECYCLE_RESOURCE, method, call, context.getLocation(call),
- getErrorMessage(TYPED_ARRAY_CLS),
- null);
- } else if (phase == 1
- && checkMethodFlow(context, classNode, method, call, TYPED_ARRAY_CLS)) {
- // Already reported error above; don't do global check
- mRecyclesTypedArray = true;
- }
- }
- } else if (BEGIN_TRANSACTION.equals(name)
- && (owner.equals(FRAGMENT_MANAGER_CLS) || owner.equals(FRAGMENT_MANAGER_V4_CLS))) {
- mObtainsTransaction = true;
- if (phase == 2 && !mCommitsTransaction) {
- context.report(COMMIT_FRAGMENT, method, call, context.getLocation(call),
- getErrorMessage(FRAGMENT_MANAGER_CLS), null);
- } else if (phase == 1
- && checkMethodFlow(context, classNode, method, call,
- owner.equals(FRAGMENT_MANAGER_CLS)
- ? FRAGMENT_TRANSACTION_CLS : FRAGMENT_TRANSACTION_V4_CLS)) {
- // Already reported error above; don't do global check
- mCommitsTransaction = true;
- }
- }
- }
-
- /** Computes an error message for a missing recycle of the given type */
- private static String getErrorMessage(String owner) {
- if (FRAGMENT_TRANSACTION_CLS.equals(owner) || FRAGMENT_TRANSACTION_V4_CLS.equals(owner)) {
- return "This transaction should be completed with a commit() call";
- }
- String className = owner.substring(owner.lastIndexOf('/') + 1);
- return String.format("This %1$s should be recycled after use with #recycle()",
- className);
- }
-
- /**
- * Ensures that the given allocate call in the given method has a
- * corresponding recycle method, also within the same method, OR, the
- * allocated resource flows out of the method (either as a return value, or
- * into a field, or into some other method (with some known exceptions; e.g.
- * passing a MotionEvent into another MotionEvent's constructor is fine)
- * <p>
- * Returns true if an error was found
- */
- private static boolean checkMethodFlow(ClassContext context, ClassNode classNode,
- MethodNode method, MethodInsnNode call, String recycleOwner) {
- CleanupTracker interpreter = new CleanupTracker(context, method, call, recycleOwner);
- ResourceAnalyzer analyzer = new ResourceAnalyzer(interpreter);
- interpreter.setAnalyzer(analyzer);
- try {
- analyzer.analyze(classNode.name, method);
- if (!interpreter.isCleanedUp() && !interpreter.isEscaped()) {
- Location location = context.getLocation(call);
- String message = getErrorMessage(recycleOwner);
- Issue issue = call.owner.equals(FRAGMENT_MANAGER_CLS)
- ? COMMIT_FRAGMENT : RECYCLE_RESOURCE;
- context.report(issue, method, call, location, message, null);
- return true;
- }
- } catch (AnalyzerException e) {
- context.log(e, null);
- }
-
- return false;
- }
-
- @VisibleForTesting
- static boolean hasReturnType(String owner, String desc) {
- int descLen = desc.length();
- int ownerLen = owner.length();
- if (descLen < ownerLen + 3) {
- return false;
- }
- if (desc.charAt(descLen - 1) != ';') {
- return false;
- }
- int typeBegin = descLen - 2 - ownerLen;
- if (desc.charAt(typeBegin - 1) != ')' || desc.charAt(typeBegin) != 'L') {
- return false;
- }
- return desc.regionMatches(typeBegin + 1, owner, 0, ownerLen);
- }
-
- /**
- * ASM interpreter which tracks the instances of the allocated resource, and
- * checks whether it is eventually passed to a {@code recycle()} call. If the
- * value flows out of the method (to a field, or a method call), it will
- * also consider the resource recycled.
- */
- private static class CleanupTracker extends Interpreter {
- // Only identity matters, not value
- private static final Value INSTANCE = BasicValue.INT_VALUE;
- private static final Value RECYCLED = BasicValue.FLOAT_VALUE;
- private static final Value UNKNOWN = BasicValue.UNINITIALIZED_VALUE;
-
- private final ClassContext mContext;
- private final MethodNode mMethod;
- private final MethodInsnNode mObtainNode;
- private boolean mIsCleanedUp;
- private boolean mEscapes;
- private final String mRecycleOwner;
- private ResourceAnalyzer mAnalyzer;
-
- public CleanupTracker(
- @NonNull ClassContext context,
- @NonNull MethodNode method,
- @NonNull MethodInsnNode obtainNode,
- @NonNull String recycleOwner) {
- super(Opcodes.ASM4);
- mContext = context;
- mMethod = method;
- mObtainNode = obtainNode;
- mRecycleOwner = recycleOwner;
- }
-
- /**
- * Sets the analyzer associated with the interpreter, such that it can
- * get access to the execution frames
- */
- void setAnalyzer(ResourceAnalyzer analyzer) {
- mAnalyzer = analyzer;
- }
-
- /**
- * Returns whether a recycle call was found for the given method
- *
- * @return true if the resource was recycled
- */
- public boolean isCleanedUp() {
- return mIsCleanedUp;
- }
-
- /**
- * Returns whether the target resource escapes from the method, for
- * example as a return value, or a field assignment, or getting passed
- * to another method
- *
- * @return true if the resource escapes
- */
- public boolean isEscaped() {
- return mEscapes;
- }
-
- @Override
- public Value newOperation(AbstractInsnNode node) throws AnalyzerException {
- return UNKNOWN;
- }
-
- @Override
- public Value newValue(final Type type) {
- if (type != null && type.getSort() == Type.VOID) {
- return null;
- } else {
- return UNKNOWN;
- }
- }
-
- @Override
- public Value copyOperation(AbstractInsnNode node, Value value) throws AnalyzerException {
- return value;
- }
-
- @Override
- public Value binaryOperation(AbstractInsnNode node, Value value1, Value value2)
- throws AnalyzerException {
- if (node.getOpcode() == Opcodes.PUTFIELD) {
- if (value2 == INSTANCE) {
- mEscapes = true;
- }
- }
- return merge(value1, value2);
- }
-
- @Override
- public Value naryOperation(AbstractInsnNode node, List values) throws AnalyzerException {
- if (node == mObtainNode) {
- return INSTANCE;
- }
-
- MethodInsnNode call = null;
- if (node.getType() == AbstractInsnNode.METHOD_INSN) {
- call = (MethodInsnNode) node;
- if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
- if (call.name.equals(RECYCLE) && call.owner.equals(mRecycleOwner)) {
- if (values != null && values.size() == 1 && values.get(0) == INSTANCE) {
- mIsCleanedUp = true;
- Frame frame = mAnalyzer.getCurrentFrame();
- if (frame != null) {
- int localSize = frame.getLocals();
- for (int i = 0; i < localSize; i++) {
- Value local = frame.getLocal(i);
- if (local == INSTANCE) {
- frame.setLocal(i, RECYCLED);
- }
- }
- int stackSize = frame.getStackSize();
- if (stackSize == 1 && frame.getStack(0) == INSTANCE) {
- frame.pop();
- frame.push(RECYCLED);
- }
- }
- return RECYCLED;
- }
- } else if ((call.name.equals(COMMIT) || call.name.equals(COMMIT_ALLOWING_LOSS))
- && call.owner.equals(mRecycleOwner)) {
- if (values != null && values.size() == 1 && values.get(0) == INSTANCE) {
- mIsCleanedUp = true;
- return INSTANCE;
- }
- } else if (call.owner.equals(mRecycleOwner)
- && hasReturnType(mRecycleOwner, call.desc)) {
- // Called method which returns self. This helps handle cases where you call
- // createTransaction().method1().method2().method3().commit() -- if
- // method1, 2 and 3 all return "this" then the commit call is really
- // called on the createTransaction instance
- return INSTANCE;
- }
- }
- }
-
- if (values != null && values.size() >= 1) {
- // Skip the first element: method calls *on* the TypedArray are okay
- int start = node.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1;
- for (int i = 0, n = values.size(); i < n; i++) {
- Object v = values.get(i);
- if (v == INSTANCE && i >= start) {
- // Known special cases
- if (node.getOpcode() == Opcodes.INVOKESTATIC) {
- assert call != null;
- if (call.name.equals(OBTAIN) &&
- call.owner.equals(MOTION_EVENT_CLS)) {
- return UNKNOWN;
- }
- }
-
- // Passing the instance to another method: could leak
- // the instance out of this method (for example calling
- // a method which recycles it on our behalf, or store it
- // in some holder which will recycle it later). In this
- // case, just assume that things are okay.
- mEscapes = true;
- } else if (v == RECYCLED && call != null) {
- Location location = mContext.getLocation(call);
- String message = String.format("This %1$s has already been recycled",
- mRecycleOwner.substring(mRecycleOwner.lastIndexOf('/') + 1));
- mContext.report(RECYCLE_RESOURCE, mMethod, call, location, message, null);
- }
- }
- }
-
- return UNKNOWN;
- }
-
- @Override
- public Value unaryOperation(AbstractInsnNode node, Value value) throws AnalyzerException {
- return value;
- }
-
- @Override
- public Value ternaryOperation(AbstractInsnNode node, Value value1, Value value2,
- Value value3) throws AnalyzerException {
- if (value1 == RECYCLED || value2 == RECYCLED || value3 == RECYCLED) {
- return RECYCLED;
- } else if (value1 == INSTANCE || value2 == INSTANCE || value3 == INSTANCE) {
- return INSTANCE;
- }
- return UNKNOWN;
- }
-
- @Override
- public void returnOperation(AbstractInsnNode node, Value value1, Value value2)
- throws AnalyzerException {
- if (value1 == INSTANCE || value2 == INSTANCE) {
- mEscapes = true;
- }
- }
-
- @Override
- public Value merge(Value value1, Value value2) {
- if (value1 == RECYCLED || value2 == RECYCLED) {
- return RECYCLED;
- } else if (value1 == INSTANCE || value2 == INSTANCE) {
- return INSTANCE;
- }
- return UNKNOWN;
- }
- }
-
- private static class ResourceAnalyzer extends Analyzer {
- private Frame mCurrent;
- private Frame mFrame1;
- private Frame mFrame2;
-
- public ResourceAnalyzer(Interpreter interpreter) {
- super(interpreter);
- }
-
- Frame getCurrentFrame() {
- return mCurrent;
- }
-
- @Override
- protected void init(String owner, MethodNode m) throws AnalyzerException {
- mCurrent = mFrame2;
- super.init(owner, m);
- }
-
- @Override
- protected Frame newFrame(int nLocals, int nStack) {
- // Stash the two most recent frame allocations. When init is called the second
- // most recently seen frame is the current frame used during execution, which
- // is where we need to replace INSTANCE with RECYCLED when the void
- // recycle method is called.
- Frame newFrame = super.newFrame(nLocals, nStack);
- mFrame2 = mFrame1;
- mFrame1 = newFrame;
- return newFrame;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java
deleted file mode 100644
index e7ffcb6..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ColorUsageDetector.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.RESOURCE_CLZ_COLOR;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.io.File;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.Select;
-
-/**
- * Looks for cases where the code attempts to set a resource id, rather than
- * a resolved color, as the RGB int.
- */
-public class ColorUsageDetector extends Detector implements Detector.JavaScanner {
- /** Attempting to set a resource id as a color */
- public static final Issue ISSUE = Issue.create(
- "ResourceAsColor", //$NON-NLS-1$
- "Looks for calls to setColor where a resource id is passed instead of a " +
- "resolved color",
-
- "Methods that take a color in the form of an integer should be passed " +
- "an RGB triple, not the actual color resource id. You must call " +
- "`getResources().getColor(resource)` to resolve the actual color value first.",
-
- Category.CORRECTNESS,
- 7,
- Severity.ERROR,
- ColorUsageDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Constructs a new {@link ColorUsageDetector} check */
- public ColorUsageDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public boolean appliesToResourceRefs() {
- return true;
- }
-
- @Override
- public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull Node select, @NonNull String type, @NonNull String name, boolean isFramework) {
- if (type.equals(RESOURCE_CLZ_COLOR)) {
- while (select.getParent() instanceof Select) {
- select = select.getParent();
- }
-
- // See if this method is being called on a setter
- if (select.getParent() instanceof MethodInvocation) {
- MethodInvocation call = (MethodInvocation) select.getParent();
- String methodName = call.astName().astValue();
- if (methodName.endsWith("Color") //$NON-NLS-1$
- && methodName.startsWith("set")) { //$NON-NLS-1$
- context.report(
- ISSUE, select, context.getLocation(select), String.format(
- "Should pass resolved color instead of resource id here: " +
- "getResources().getColor(%1$s)", select.toString()),
- null);
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CommentDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CommentDetector.java
deleted file mode 100644
index 6f07e77..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CommentDetector.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Comment;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Node;
-
-/**
- * Looks for issues in Java comments
- */
-public class CommentDetector extends Detector implements Detector.JavaScanner {
- private static final String STOPSHIP_COMMENT = "STOPSHIP"; //$NON-NLS-1$
-
- /** Looks for hidden code */
- public static final Issue EASTEREGG = Issue.create(
- "EasterEgg", //$NON-NLS-1$
- "Looks for hidden easter eggs",
- "An \"easter egg\" is code deliberately hidden in the code, both from potential " +
- "users and even from other developers. This lint check looks for code which " +
- "looks like it may be hidden from sight.",
- Category.SECURITY,
- 6,
- Severity.WARNING,
- CommentDetector.class,
- Scope.JAVA_FILE_SCOPE).setEnabledByDefault(false);
-
- /** Looks for special comment markers intended to stop shipping the code */
- public static final Issue STOPSHIP = Issue.create(
- "StopShip", //$NON-NLS-1$
- "Looks for comment markers of the form \"STOPSHIP\" which indicates that code " +
- "should not be released yet",
-
- "Using the comment `// STOPSHIP` can be used to flag code that is incomplete but " +
- "checked in. This comment marker can be used to indicate that the code should not " +
- "be shipped until the issue is addressed, and lint will look for these.",
- Category.CORRECTNESS,
- 10,
- Severity.WARNING,
- CommentDetector.class,
- Scope.JAVA_FILE_SCOPE).setEnabledByDefault(false);
-
- private static final String ESCAPE_STRING = "\\u002a\\u002f"; //$NON-NLS-1$
-
- /** Lombok's AST only passes comment nodes for Javadoc so I need to do manual token scanning
- instead */
- private static final boolean USE_AST = false;
-
-
- /** Constructs a new {@link CommentDetector} check */
- public CommentDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- @Override
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- if (USE_AST) {
- return Collections.<Class<? extends Node>>singletonList(Comment.class);
- } else {
- return null;
- }
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- // Lombok does not generate comment nodes for block and line comments, only for
- // javadoc comments!
- if (USE_AST) {
- return new CommentChecker(context);
- } else {
- String source = context.getContents();
- if (source == null) {
- return null;
- }
- // Process the Java source such that we pass tokens to it
-
- for (int i = 0, n = source.length() - 1; i < n; i++) {
- char c = source.charAt(i);
- if (c == '\\') {
- i += 1;
- } else if (c == '/') {
- char next = source.charAt(i + 1);
- if (next == '/') {
- // Line comment
- int start = i + 2;
- int end = source.indexOf('\n', start);
- if (end == -1) {
- end = n;
- }
- checkComment(context, source, 0, start, end);
- } else if (next == '*') {
- // Block comment
- int start = i + 2;
- int end = source.indexOf("*/", start);
- if (end == -1) {
- end = n;
- }
- checkComment(context, source, 0, start, end);
- }
- }
- }
- return null;
- }
- }
-
- private static class CommentChecker extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public CommentChecker(JavaContext context) {
- mContext = context;
- }
-
- @Override
- public boolean visitComment(Comment node) {
- String contents = node.astContent();
- checkComment(mContext, contents, node.getPosition().getStart(), 0, contents.length());
- return super.visitComment(node);
- }
- }
-
- private static void checkComment(
- @NonNull Context context,
- @NonNull String source,
- int offset,
- int start,
- int end) {
- char prev = 0;
- char c;
- for (int i = start; i < end - 2; i++, prev = c) {
- c = source.charAt(i);
- if (prev == '\\') {
- if (c == 'u' || c == 'U') {
- if (source.regionMatches(true, i - 1, ESCAPE_STRING,
- 0, ESCAPE_STRING.length())) {
- Location location = Location.create(context.file, source,
- offset + i - 1, offset + i - 1 + ESCAPE_STRING.length());
- context.report(EASTEREGG, location,
- "Code might be hidden here; found unicode escape sequence " +
- "which is interpreted as comment end, compiled code follows",
- null);
- }
- } else {
- i++;
- }
- } else if (prev == 'S' && c == 'T' &&
- source.regionMatches(i - 1, STOPSHIP_COMMENT, 0, STOPSHIP_COMMENT.length())) {
- // TODO: Only flag this issue in release mode??
- Location location = Location.create(context.file, source,
- offset + i - 1, offset + i - 1 + STOPSHIP_COMMENT.length());
- context.report(STOPSHIP, location,
- "STOPSHIP comment found; points to code which must be fixed prior " +
- "to release",
- null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ControlFlowGraph.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ControlFlowGraph.java
deleted file mode 100644
index cbafe28..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ControlFlowGraph.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.collect.Maps;
-
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FrameNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.LabelNode;
-import org.objectweb.asm.tree.LineNumberNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.TryCatchBlockNode;
-import org.objectweb.asm.tree.analysis.Analyzer;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-import org.objectweb.asm.tree.analysis.BasicInterpreter;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A {@linkplain ControlFlowGraph} is a graph containing a node for each
- * instruction in a method, and an edge for each possible control flow; usually
- * just "next" for the instruction following the current instruction, but in the
- * case of a branch such as an "if", multiple edges to each successive location,
- * or with a "goto", a single edge to the jumped-to instruction.
- * <p>
- * It also adds edges for abnormal control flow, such as the possibility of a
- * method call throwing a runtime exception.
- */
-public class ControlFlowGraph {
- /** Map from instructions to nodes */
- private Map<AbstractInsnNode, Node> mNodeMap;
-
- /**
- * Creates a new {@link ControlFlowGraph} and populates it with the flow
- * control for the given method. If the optional {@code initial} parameter is
- * provided with an existing graph, then the graph is simply populated, not
- * created. This allows subclassing of the graph instance, if necessary.
- *
- * @param initial usually null, but can point to an existing instance of a
- * {@link ControlFlowGraph} in which that graph is reused (but
- * populated with new edges)
- * @param classNode the class containing the method to be analyzed
- * @param method the method to be analyzed
- * @return a {@link ControlFlowGraph} with nodes for the control flow in the
- * given method
- * @throws AnalyzerException if the underlying bytecode library is unable to
- * analyze the method bytecode
- */
- @NonNull
- public static ControlFlowGraph create(
- @Nullable ControlFlowGraph initial,
- @NonNull ClassNode classNode,
- @NonNull MethodNode method) throws AnalyzerException {
- final ControlFlowGraph graph = initial != null ? initial : new ControlFlowGraph();
- final InsnList instructions = method.instructions;
- graph.mNodeMap = Maps.newHashMapWithExpectedSize(instructions.size());
-
- // Create a flow control graph using ASM4's analyzer. According to the ASM 4 guide
- // (download.forge.objectweb.org/asm/asm4-guide.pdf) there are faster ways to construct
- // it, but those require a lot more code.
- Analyzer analyzer = new Analyzer(new BasicInterpreter()) {
- @Override
- protected void newControlFlowEdge(int insn, int successor) {
- // Update the information as of whether the this object has been
- // initialized at the given instruction.
- AbstractInsnNode from = instructions.get(insn);
- AbstractInsnNode to = instructions.get(successor);
- graph.add(from, to);
- }
-
- @Override
- protected boolean newControlFlowExceptionEdge(int insn, TryCatchBlockNode tcb) {
- AbstractInsnNode from = instructions.get(insn);
- graph.exception(from, tcb);
- return super.newControlFlowExceptionEdge(insn, tcb);
- }
-
- @Override
- protected boolean newControlFlowExceptionEdge(int insn, int successor) {
- AbstractInsnNode from = instructions.get(insn);
- AbstractInsnNode to = instructions.get(successor);
- graph.exception(from, to);
- return super.newControlFlowExceptionEdge(insn, successor);
- }
- };
-
- analyzer.analyze(classNode.name, method);
- return graph;
- }
-
- /** A {@link Node} is a node in the control flow graph for a method, pointing to
- * the instruction and its possible successors */
- public static class Node {
- /** The instruction */
- public final AbstractInsnNode instruction;
- /** Any normal successors (e.g. following instruction, or goto or conditional flow) */
- public final List<Node> successors = new ArrayList<Node>(2);
- /** Any abnormal successors (e.g. the handler to go to following an exception) */
- public final List<Node> exceptions = new ArrayList<Node>(1);
-
- /** A tag for use during depth-first-search iteration of the graph etc */
- public int visit;
-
- /**
- * Constructs a new control graph node
- *
- * @param instruction the instruction to associate with this node
- */
- public Node(@NonNull AbstractInsnNode instruction) {
- this.instruction = instruction;
- }
-
- void addSuccessor(@NonNull Node node) {
- if (!successors.contains(node)) {
- successors.add(node);
- }
- }
-
- void addExceptionPath(@NonNull Node node) {
- if (!exceptions.contains(node)) {
- exceptions.add(node);
- }
- }
-
- /**
- * Represents this instruction as a string, for debugging purposes
- *
- * @param includeAdjacent whether it should include a display of
- * adjacent nodes as well
- * @return a string representation
- */
- @NonNull
- public String toString(boolean includeAdjacent) {
- StringBuilder sb = new StringBuilder(100);
-
- sb.append(getId(instruction));
- sb.append(':');
-
- if (instruction instanceof LabelNode) {
- //LabelNode l = (LabelNode) instruction;
- //sb.append('L' + l.getLabel().getOffset() + ":");
- //sb.append('L' + l.getLabel().info + ":");
- sb.append("LABEL");
- } else if (instruction instanceof LineNumberNode) {
- sb.append("LINENUMBER ").append(((LineNumberNode)instruction).line);
- } else if (instruction instanceof FrameNode) {
- sb.append("FRAME");
- } else {
- int opcode = instruction.getOpcode();
- // AbstractVisitor isn't available unless debug/util is included,
- boolean printed = false;
- try {
- Class<?> cls = Class.forName("org.objectweb.asm.util"); //$NON-NLS-1$
- Field field = cls.getField("OPCODES");
- String[] OPCODES = (String[]) field.get(null);
- printed = true;
- if (opcode > 0 && opcode <= OPCODES.length) {
- sb.append(OPCODES[opcode]);
- if (instruction.getType() == AbstractInsnNode.METHOD_INSN) {
- sb.append('(').append(((MethodInsnNode)instruction).name).append(')');
- }
- }
- } catch (Throwable t) {
- // debug not installed: just do toString() on the instructions
- }
- if (!printed) {
- if (instruction.getType() == AbstractInsnNode.METHOD_INSN) {
- sb.append('(').append(((MethodInsnNode)instruction).name).append(')');
- } else {
- sb.append(instruction.toString());
- }
- }
- }
-
- if (includeAdjacent) {
- if (successors != null && !successors.isEmpty()) {
- sb.append(" Next:");
- for (Node successor : successors) {
- sb.append(' ');
- sb.append(successor.toString(false));
- }
- }
-
- if (exceptions != null && !exceptions.isEmpty()) {
- sb.append(" Exceptions:");
- for (Node exception : exceptions) {
- sb.append(' ');
- sb.append(exception.toString(false));
- }
- }
- sb.append('\n');
- }
-
- return sb.toString();
- }
- }
-
- /** Adds an exception flow to this graph */
- protected void add(@NonNull AbstractInsnNode from, @NonNull AbstractInsnNode to) {
- getNode(from).addSuccessor(getNode(to));
- }
-
- /** Adds an exception flow to this graph */
- protected void exception(@NonNull AbstractInsnNode from, @NonNull AbstractInsnNode to) {
- // For now, these edges appear useless; we also get more specific
- // information via the TryCatchBlockNode which we use instead.
- //getNode(from).addExceptionPath(getNode(to));
- }
-
- /** Adds an exception try block node to this graph */
- protected void exception(@NonNull AbstractInsnNode from, @NonNull TryCatchBlockNode tcb) {
- // Add tcb's to all instructions in the range
- LabelNode start = tcb.start;
- LabelNode end = tcb.end; // exclusive
-
- // Add exception edges for all method calls in the range
- AbstractInsnNode curr = start;
- Node handlerNode = getNode(tcb.handler);
- while (curr != end && curr != null) {
- if (curr.getType() == AbstractInsnNode.METHOD_INSN) {
- // Method call; add exception edge to handler
- if (tcb.type == null) {
- // finally block: not an exception path
- getNode(curr).addSuccessor(handlerNode);
- }
- getNode(curr).addExceptionPath(handlerNode);
- }
- curr = curr.getNext();
- }
- }
-
- /**
- * Looks up (and if necessary) creates a graph node for the given instruction
- *
- * @param instruction the instruction
- * @return the control flow graph node corresponding to the given
- * instruction
- */
- @NonNull
- public Node getNode(@NonNull AbstractInsnNode instruction) {
- Node node = mNodeMap.get(instruction);
- if (node == null) {
- node = new Node(instruction);
- mNodeMap.put(instruction, node);
- }
-
- return node;
- }
-
- /**
- * Creates a human readable version of the graph
- *
- * @param start the starting instruction, or null if not known or to use the
- * first instruction
- * @return a string version of the graph
- */
- @NonNull
- public String toString(@Nullable Node start) {
- StringBuilder sb = new StringBuilder(400);
-
- AbstractInsnNode curr;
- if (start != null) {
- curr = start.instruction;
- } else {
- if (mNodeMap.isEmpty()) {
- return "<empty>";
- } else {
- curr = mNodeMap.keySet().iterator().next();
- while (curr.getPrevious() != null) {
- curr = curr.getPrevious();
- }
- }
- }
-
- while (curr != null) {
- Node node = mNodeMap.get(curr);
- if (node != null) {
- sb.append(node.toString(true));
- }
- curr = curr.getNext();
- }
-
- return sb.toString();
- }
-
- @Override
- public String toString() {
- return toString(null);
- }
-
- // ---- For debugging only ----
-
- private static Map<Object, String> sIds = null;
- private static int sNextId = 1;
- private static String getId(Object object) {
- if (sIds == null) {
- sIds = Maps.newHashMap();
- }
- String id = sIds.get(object);
- if (id == null) {
- id = Integer.toString(sNextId++);
- sIds.put(object, id);
- }
- return id;
- }
-}
-
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CutPasteDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CutPasteDetector.java
deleted file mode 100644
index 84fb6b6..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/CutPasteDetector.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.RESOURCE_CLZ_ID;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.collect.Maps;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import lombok.ast.ArrayAccess;
-import lombok.ast.AstVisitor;
-import lombok.ast.BinaryExpression;
-import lombok.ast.Cast;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.If;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.Select;
-import lombok.ast.Statement;
-import lombok.ast.VariableDefinitionEntry;
-import lombok.ast.VariableReference;
-
-/**
- * Detector looking for cut & paste issues
- */
-public class CutPasteDetector extends Detector implements Detector.JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "CutPasteId", //$NON-NLS-1$
- "Looks for code cut & paste mistakes in findViewById() calls",
-
- "This lint check looks for cases where you have cut & pasted calls to " +
- "`findViewById` but have forgotten to update the R.id field. It's possible " +
- "that your code is simply (redundantly) looking up the field repeatedly, " +
- "but lint cannot distinguish that from a case where you for example want to " +
- "initialize fields `prev` and `next` and you cut & pasted `findViewById(R.id.prev)` " +
- "and forgot to update the second initialization to `R.id.next`.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- CutPasteDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- private Node mLastMethod;
- private Map<String, MethodInvocation> mIds;
- private Map<String, String> mLhs;
- private Map<String, String> mCallOperands;
-
- /** Constructs a new {@link CutPasteDetector} check */
- public CutPasteDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("findViewById"); //$NON-NLS-1$
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation call) {
- String lhs = getLhs(call);
- if (lhs == null) {
- return;
- }
-
- Node method = JavaContext.findSurroundingMethod(call);
- if (method == null) {
- return;
- } else if (method != mLastMethod) {
- mIds = Maps.newHashMap();
- mLhs = Maps.newHashMap();
- mCallOperands = Maps.newHashMap();
- mLastMethod = method;
- }
-
- String callOperand = call.astOperand() != null ? call.astOperand().toString() : "";
-
- Expression first = call.astArguments().first();
- if (first instanceof Select) {
- Select select = (Select) first;
- String id = select.astIdentifier().astValue();
- Expression operand = select.astOperand();
- if (operand instanceof Select) {
- Select type = (Select) operand;
- if (type.astIdentifier().astValue().equals(RESOURCE_CLZ_ID)) {
- if (mIds.containsKey(id)) {
- if (lhs.equals(mLhs.get(id))) {
- return;
- }
- if (!callOperand.equals(mCallOperands.get(id))) {
- return;
- }
- MethodInvocation earlierCall = mIds.get(id);
- if (!isReachableFrom(method, earlierCall, call)) {
- return;
- }
- Location location = context.getLocation(call);
- Location secondary = context.getLocation(earlierCall);
- secondary.setMessage("First usage here");
- location.setSecondary(secondary);
- context.report(ISSUE, call, location, String.format(
- "The id %1$s has already been looked up in this method; possible " +
- "cut & paste error?", first.toString()), null);
- } else {
- mIds.put(id, call);
- mLhs.put(id, lhs);
- mCallOperands.put(id, callOperand);
- }
- }
- }
- }
- }
-
- @Nullable
- private static String getLhs(@NonNull MethodInvocation call) {
- Node parent = call.getParent();
- if (parent instanceof Cast) {
- parent = parent.getParent();
- }
-
- if (parent instanceof VariableDefinitionEntry) {
- VariableDefinitionEntry vde = (VariableDefinitionEntry) parent;
- return vde.astName().astValue();
- } else if (parent instanceof BinaryExpression) {
- BinaryExpression be = (BinaryExpression) parent;
- Expression left = be.astLeft();
- if (left instanceof VariableReference || left instanceof Select) {
- return be.astLeft().toString();
- } else if (left instanceof ArrayAccess) {
- ArrayAccess aa = (ArrayAccess) left;
- return aa.astOperand().toString();
- }
- }
-
- return null;
- }
-
- private static boolean isReachableFrom(
- @NonNull Node method,
- @NonNull MethodInvocation from,
- @NonNull MethodInvocation to) {
- ReachableVisitor visitor = new ReachableVisitor(from, to);
- method.accept(visitor);
-
- return visitor.isReachable();
- }
-
- private static class ReachableVisitor extends ForwardingAstVisitor {
- @NonNull private final MethodInvocation mFrom;
- @NonNull private final MethodInvocation mTo;
- private boolean mReachable;
- private boolean mSeenEnd;
-
- public ReachableVisitor(@NonNull MethodInvocation from, @NonNull MethodInvocation to) {
- mFrom = from;
- mTo = to;
- }
-
- boolean isReachable() {
- return mReachable;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (node == mFrom) {
- mReachable = true;
- } else if (node == mTo) {
- mSeenEnd = true;
-
- }
- return super.visitMethodInvocation(node);
- }
-
- @Override
- public boolean visitIf(If node) {
- Expression condition = node.astCondition();
- Statement body = node.astStatement();
- Statement elseBody = node.astElseStatement();
- if (condition != null) {
- condition.accept(this);
- }
- if (body != null) {
- boolean wasReachable = mReachable;
- body.accept(this);
- mReachable = wasReachable;
- }
- if (elseBody != null) {
- boolean wasReachable = mReachable;
- elseBody.accept(this);
- mReachable = wasReachable;
- }
-
- endVisit(node);
-
- return false;
- }
-
- @Override
- public boolean visitNode(Node node) {
- return mSeenEnd;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.java
deleted file mode 100644
index 6475a7a..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DeprecationDetector.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_AUTO_TEXT;
-import static com.android.SdkConstants.ATTR_CAPITALIZE;
-import static com.android.SdkConstants.ATTR_EDITABLE;
-import static com.android.SdkConstants.ATTR_ENABLED;
-import static com.android.SdkConstants.ATTR_INPUT_METHOD;
-import static com.android.SdkConstants.ATTR_NUMERIC;
-import static com.android.SdkConstants.ATTR_PASSWORD;
-import static com.android.SdkConstants.ATTR_PHONE_NUMBER;
-import static com.android.SdkConstants.ATTR_SINGLE_LINE;
-import static com.android.SdkConstants.EDIT_TEXT;
-import static com.android.SdkConstants.VALUE_TRUE;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check which looks for usage of deprecated tags, attributes, etc.
- */
-public class DeprecationDetector extends LayoutDetector {
- /** Usage of deprecated views or attributes */
- public static final Issue ISSUE = Issue.create(
- "Deprecated", //$NON-NLS-1$
- "Looks for usages of deprecated layouts, attributes, and so on.",
- "Deprecated views, attributes and so on are deprecated because there " +
- "is a better way to do something. Do it that new way. You've been warned.",
- Category.CORRECTNESS,
- 2,
- Severity.WARNING,
- DeprecationDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link DeprecationDetector} */
- public DeprecationDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(
- ABSOLUTE_LAYOUT
- );
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Arrays.asList(
- // TODO: fill_parent is deprecated as of API 8.
- // We could warn about it, but it will probably be very noisy
- // and make people disable the deprecation check; let's focus on
- // some older flags for now
- //"fill_parent",
-
- ATTR_EDITABLE,
- ATTR_INPUT_METHOD,
- ATTR_AUTO_TEXT,
- ATTR_CAPITALIZE,
-
- // This flag is still used a lot and is still properly handled by TextView
- // so in the interest of not being too noisy and make people ignore all the
- // output, keep quiet about this one -for now-.
- //ATTR_SINGLE_LINE,
-
- // This attribute is marked deprecated in android.R.attr but apparently
- // using the suggested replacement of state_enabled doesn't work, see issue 27613
- //ATTR_ENABLED,
-
- ATTR_NUMERIC,
- ATTR_PHONE_NUMBER,
- ATTR_PASSWORD
-
- // These attributes are also deprecated; not yet enabled until we
- // know the API level to apply the deprecation for:
-
- // "ignored as of ICS (but deprecated earlier)"
- //"fadingEdge",
-
- // "This attribute is not used by the Android operating system."
- //"restoreNeedsApplication",
-
- // "This will create a non-standard UI appearance, because the search bar UI is
- // changing to use only icons for its buttons."
- //"searchButtonText",
-
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- context.report(ISSUE, element, context.getLocation(element),
- String.format("%1$s is deprecated", element.getTagName()), null);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (!ANDROID_URI.equals(attribute.getNamespaceURI())) {
- return;
- }
-
- String name = attribute.getLocalName();
- String fix;
- int minSdk = 1;
- if (name.equals(ATTR_EDITABLE)) {
- if (!EDIT_TEXT.equals(attribute.getOwnerElement().getTagName())) {
- fix = "Use an <EditText> to make it editable";
- } else {
- if (VALUE_TRUE.equals(attribute.getValue())) {
- fix = "<EditText> is already editable";
- } else {
- fix = "Use inputType instead";
- }
- }
- } else if (name.equals(ATTR_ENABLED)) {
- fix = "Use state_enabled instead";
- } else if (name.equals(ATTR_SINGLE_LINE)) {
- fix = "Use maxLines=\"1\" instead";
- } else {
- assert name.equals(ATTR_INPUT_METHOD)
- || name.equals(ATTR_CAPITALIZE)
- || name.equals(ATTR_NUMERIC)
- || name.equals(ATTR_PHONE_NUMBER)
- || name.equals(ATTR_PASSWORD)
- || name.equals(ATTR_AUTO_TEXT);
- fix = "Use inputType instead";
- // The inputType attribute was introduced in API 3 so don't warn about
- // deprecation if targeting older platforms
- minSdk = 3;
- }
-
- if (context.getProject().getMinSdk() < minSdk) {
- return;
- }
-
- context.report(ISSUE, attribute, context.getLocation(attribute),
- String.format("%1$s is deprecated: %2$s",
- attribute.getName(), fix), null);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DetectMissingPrefix.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DetectMissingPrefix.java
deleted file mode 100644
index 2b24732..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DetectMissingPrefix.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_PKG_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_CLASS;
-import static com.android.SdkConstants.ATTR_CORE_APP;
-import static com.android.SdkConstants.ATTR_LAYOUT;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.TOOLS_URI;
-import static com.android.SdkConstants.VIEW_TAG;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-import static com.android.resources.ResourceFolderType.ANIM;
-import static com.android.resources.ResourceFolderType.ANIMATOR;
-import static com.android.resources.ResourceFolderType.COLOR;
-import static com.android.resources.ResourceFolderType.DRAWABLE;
-import static com.android.resources.ResourceFolderType.INTERPOLATOR;
-import static com.android.resources.ResourceFolderType.LAYOUT;
-import static com.android.resources.ResourceFolderType.MENU;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Detects layout attributes on builtin Android widgets that do not specify
- * a prefix but probably should.
- */
-public class DetectMissingPrefix extends LayoutDetector {
-
- /** Attributes missing the android: prefix */
- public static final Issue MISSING_NAMESPACE = Issue.create(
- "MissingPrefix", //$NON-NLS-1$
- "Detect XML attributes not using the Android namespace",
- "Most Android views have attributes in the Android namespace. When referencing " +
- "these attributes you *must* include the namespace prefix, or your attribute will " +
- "be interpreted by `aapt` as just a custom attribute.\n" +
- "\n" +
- "Similarly, in manifest files, nearly all attributes should be in the `android:` " +
- "namespace.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- DetectMissingPrefix.class,
- EnumSet.of(Scope.MANIFEST, Scope.RESOURCE_FILE))
- .addAnalysisScope(Scope.MANIFEST_SCOPE)
- .addAnalysisScope(Scope.RESOURCE_FILE_SCOPE);
-
- private static final Set<String> NO_PREFIX_ATTRS = new HashSet<String>();
- static {
- NO_PREFIX_ATTRS.add(ATTR_CLASS);
- NO_PREFIX_ATTRS.add(ATTR_STYLE);
- NO_PREFIX_ATTRS.add(ATTR_LAYOUT);
- NO_PREFIX_ATTRS.add(ATTR_PACKAGE);
- NO_PREFIX_ATTRS.add(ATTR_CORE_APP);
- }
-
- /** Constructs a new {@link DetectMissingPrefix} */
- public DetectMissingPrefix() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == LAYOUT
- || folderType == MENU
- || folderType == DRAWABLE
- || folderType == ANIM
- || folderType == ANIMATOR
- || folderType == COLOR
- || folderType == INTERPOLATOR;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String uri = attribute.getNamespaceURI();
- if (uri == null || uri.isEmpty()) {
- String name = attribute.getName();
- if (name == null) {
- return;
- }
- if (NO_PREFIX_ATTRS.contains(name)) {
- return;
- }
-
- Element element = attribute.getOwnerElement();
- if (isCustomView(element) && context.getResourceFolderType() != null) {
- return;
- }
-
- if (name.startsWith(XMLNS_PREFIX)) {
- return;
- }
-
- context.report(MISSING_NAMESPACE, attribute,
- context.getLocation(attribute),
- "Attribute is missing the Android namespace prefix",
- null);
- } else if (!ANDROID_URI.equals(uri)
- && !TOOLS_URI.equals(uri)
- && context.getResourceFolderType() == ResourceFolderType.LAYOUT
- && !isCustomView(attribute.getOwnerElement())
- && !attribute.getLocalName().startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- // TODO: Consider not enforcing that the parent is a custom view
- // too, though in that case we should filter out views that are
- // layout params for the custom view parent:
- // ....&& !attribute.getLocalName().startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && attribute.getOwnerElement().getParentNode().getNodeType() == Node.ELEMENT_NODE
- && !isCustomView((Element) attribute.getOwnerElement().getParentNode())) {
- context.report(MISSING_NAMESPACE, attribute,
- context.getLocation(attribute),
- String.format("Unexpected namespace prefix \"%1$s\" found for tag %2$s",
- attribute.getPrefix(), attribute.getOwnerElement().getTagName()),
- null);
- }
- }
-
- private static boolean isCustomView(Element element) {
- // If this is a custom view, the usage of custom attributes can be legitimate
- String tag = element.getTagName();
- if (tag.equals(VIEW_TAG)) {
- // <view class="my.custom.view" ...>
- return true;
- }
-
- return tag.indexOf('.') != -1 && !tag.startsWith(ANDROID_PKG_PREFIX);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DosLineEndingDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DosLineEndingDetector.java
deleted file mode 100644
index 1a2a720..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DosLineEndingDetector.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Document;
-
-/**
- * Checks that the line endings in DOS files are consistent
- */
-public class DosLineEndingDetector extends LayoutDetector {
- /** Detects mangled DOS line ending documents */
- public static final Issue ISSUE = Issue.create(
- "MangledCRLF", //$NON-NLS-1$
- "Checks that files with DOS line endings are consistent",
-
- "On Windows, line endings are typically recorded as carriage return plus " +
- "newline: \\r\\n.\n" +
- "\n" +
- "This detector looks for invalid line endings with repeated carriage return " +
- "characters (without newlines). Previous versions of the ADT plugin could " +
- "accidentally introduce these into the file, and when editing the file, the " +
- "editor could produce confusing visual artifacts.",
-
- Category.CORRECTNESS,
- 2,
- Severity.ERROR,
- DosLineEndingDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setMoreInfo("https://bugs.eclipse.org/bugs/show_bug.cgi?id=375421"); //$NON-NLS-1$
-
- /** Constructs a new {@link DosLineEndingDetector} */
- public DosLineEndingDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- String contents = context.getContents();
- if (contents == null) {
- return;
- }
-
- // We could look for *consistency* and complain if you mix \n and \r\n too,
- // but that isn't really a problem (most editors handle it) so let's
- // not complain needlessly.
-
- char prev = 0;
- for (int i = 0, n = contents.length(); i < n; i++) {
- char c = contents.charAt(i);
- if (c == '\r' && prev == '\r') {
- String message = "Incorrect line ending: found carriage return (\\r) without " +
- "corresponding newline (\\n)";
-
- // Mark the whole line as the error range, since pointing just to the
- // line ending makes the error invisible in IDEs and error reports etc
- // Find the most recent non-blank line
- boolean blankLine = true;
- for (int index = i - 2; index < i; index++) {
- char d = contents.charAt(index);
- if (!Character.isWhitespace(d)) {
- blankLine = false;
- }
- }
-
- int lineBegin = i;
- for (int index = i - 2; index >= 0; index--) {
- char d = contents.charAt(index);
- if (d == '\n') {
- lineBegin = index + 1;
- if (!blankLine) {
- break;
- }
- } else if (!Character.isWhitespace(d)) {
- blankLine = false;
- }
- }
-
- int lineEnd = Math.min(contents.length(), i + 1);
- Location location = Location.create(context.file, contents, lineBegin, lineEnd);
- context.report(ISSUE, document.getDocumentElement(), location, message, null);
- return;
- }
- prev = c;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateIdDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateIdDetector.java
deleted file mode 100644
index de3e4d2..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateIdDetector.java
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Checks for duplicate ids within a layout and within an included layout
- */
-public class DuplicateIdDetector extends LayoutDetector {
- private Set<String> mIds;
- private Map<File, Set<String>> mFileToIds;
- private Map<File, List<String>> mIncludes;
-
- // Data structures used for location collection in phase 2
-
- // Map from include files to include names to pairs of message and location
- // Map from file defining id, to the id to be defined, to a pair of location and message
- private Multimap<File, Multimap<String, Occurrence>> mLocations;
- private List<Occurrence> mErrors;
-
- /** The main issue discovered by this detector */
- public static final Issue WITHIN_LAYOUT = Issue.create(
- "DuplicateIds", //$NON-NLS-1$
- "Checks for duplicate ids within a single layout",
- "Within a layout, id's should be unique since otherwise `findViewById()` can " +
- "return an unexpected view.",
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- DuplicateIdDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** The main issue discovered by this detector */
- public static final Issue CROSS_LAYOUT = Issue.create(
- "DuplicateIncludedIds", //$NON-NLS-1$
- "Checks for duplicate ids across layouts that are combined with include tags",
- "It's okay for two independent layouts to use the same ids. However, if " +
- "layouts are combined with include tags, then the id's need to be unique " +
- "within any chain of included layouts, or `Activity#findViewById()` can " +
- "return an unexpected view.",
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- DuplicateIdDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Constructs a duplicate id check */
- public DuplicateIdDetector() {
- }
-
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.MENU;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_ID);
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(VIEW_INCLUDE);
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mIds = new HashSet<String>();
- }
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- if (context.getPhase() == 1) {
- // Store this layout's set of ids for full project analysis in afterCheckProject
- mFileToIds.put(context.file, mIds);
-
- mIds = null;
- }
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mFileToIds = new HashMap<File, Set<String>>();
- mIncludes = new HashMap<File, List<String>>();
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- // Look for duplicates
- if (!mIncludes.isEmpty()) {
- // Traverse all the include chains and ensure that there are no duplicates
- // across.
- if (context.isEnabled(CROSS_LAYOUT)
- && context.getScope().contains(Scope.ALL_RESOURCE_FILES)) {
- IncludeGraph graph = new IncludeGraph(context);
- graph.check();
- }
- }
- } else {
- assert context.getPhase() == 2;
-
- if (mErrors != null) {
- for (Occurrence occurrence : mErrors) {
- //assert location != null : occurrence;
- Location location = occurrence.location;
- if (location == null) {
- location = Location.create(occurrence.file);
- } else {
- Object clientData = location.getClientData();
- if (clientData instanceof Node) {
- Node node = (Node) clientData;
- if (context.getDriver().isSuppressed(CROSS_LAYOUT, node)) {
- continue;
- }
- }
- }
-
- List<Occurrence> sorted = new ArrayList<Occurrence>();
- Occurrence curr = occurrence.next;
- while (curr != null) {
- sorted.add(curr);
- curr = curr.next;
- }
- Collections.sort(sorted);
- Location prev = location;
- for (Occurrence o : sorted) {
- if (o.location != null) {
- prev.setSecondary(o.location);
- prev = o.location;
- }
- }
-
- context.report(CROSS_LAYOUT, location, occurrence.message, null);
- }
- }
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- // Record include graph such that we can look for inter-layout duplicates after the
- // project has been fully checked
-
- String layout = element.getAttribute(ATTR_LAYOUT); // NOTE: Not in android: namespace
- if (layout.startsWith(LAYOUT_RESOURCE_PREFIX)) { // Ignore @android:layout/ layouts
- layout = layout.substring(LAYOUT_RESOURCE_PREFIX.length());
-
- if (context.getPhase() == 1) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- List<String> to = mIncludes.get(context.file);
- if (to == null) {
- to = new ArrayList<String>();
- mIncludes.put(context.file, to);
- }
- to.add(layout);
- } else {
- assert context.getPhase() == 2;
-
- Collection<Multimap<String, Occurrence>> maps = mLocations.get(context.file);
- if (maps != null && !maps.isEmpty()) {
- for (Multimap<String, Occurrence> map : maps) {
- if (!maps.isEmpty()) {
- Collection<Occurrence> occurrences = map.get(layout);
- if (occurrences != null && !occurrences.isEmpty()) {
- for (Occurrence occurrence : occurrences) {
- Location location = context.getLocation(element);
- location.setClientData(element);
- location.setMessage(occurrence.message);
- location.setSecondary(occurrence.location);
- occurrence.location = location;
- }
- }
- }
- }
- }
- }
- }
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- assert attribute.getName().equals(ATTR_ID) || attribute.getLocalName().equals(ATTR_ID);
- String id = attribute.getValue();
- if (context.getPhase() == 1) {
- if (mIds.contains(id)) {
- Location location = context.getLocation(attribute);
-
- Attr first = findIdAttribute(attribute.getOwnerDocument(), id);
- if (first != null && first != attribute) {
- Location secondLocation = context.getLocation(first);
- secondLocation.setMessage(String.format("%1$s originally defined here", id));
- location.setSecondary(secondLocation);
- }
-
- context.report(WITHIN_LAYOUT, attribute, location,
- String.format("Duplicate id %1$s, already defined earlier in this layout",
- id), null);
- } else if (id.startsWith(NEW_ID_PREFIX)) {
- // Skip id's on include tags
- if (attribute.getOwnerElement().getTagName().equals(VIEW_INCLUDE)) {
- return;
- }
-
- mIds.add(id);
- }
- } else {
- Collection<Multimap<String, Occurrence>> maps = mLocations.get(context.file);
- if (maps != null && !maps.isEmpty()) {
- for (Multimap<String, Occurrence> map : maps) {
- if (!maps.isEmpty()) {
- Collection<Occurrence> occurrences = map.get(id);
- if (occurrences != null && !occurrences.isEmpty()) {
- for (Occurrence occurrence : occurrences) {
- if (context.getDriver().isSuppressed(CROSS_LAYOUT, attribute)) {
- return;
- }
- Location location = context.getLocation(attribute);
- location.setClientData(attribute);
- location.setMessage(occurrence.message);
- location.setSecondary(occurrence.location);
- occurrence.location = location;
- }
- }
- }
- }
- }
- }
- }
-
- /** Find the first id attribute with the given value below the given node */
- private static Attr findIdAttribute(Node node, String targetValue) {
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- Attr attribute = ((Element) node).getAttributeNodeNS(ANDROID_URI, ATTR_ID);
- if (attribute != null && attribute.getValue().equals(targetValue)) {
- return attribute;
- }
- }
-
- NodeList children = node.getChildNodes();
- for (int i = 0, n = children.getLength(); i < n; i++) {
- Node child = children.item(i);
- Attr result = findIdAttribute(child, targetValue);
- if (result != null) {
- return result;
- }
- }
-
- return null;
- }
-
- /** Include Graph Node */
- private static class Layout {
- private final File mFile;
- private final Set<String> mIds;
- private List<Layout> mIncludes;
- private List<Layout> mIncludedBy;
-
- Layout(File file, Set<String> ids) {
- mFile = file;
- mIds = ids;
- }
-
- Set<String> getIds() {
- return mIds;
- }
-
- String getLayoutName() {
- return LintUtils.getLayoutName(mFile);
- }
-
- String getDisplayName() {
- return mFile.getParentFile().getName() + File.separator + mFile.getName();
- }
-
- void include(Layout target) {
- if (mIncludes == null) {
- mIncludes = new ArrayList<Layout>();
- }
- mIncludes.add(target);
-
- if (target.mIncludedBy == null) {
- target.mIncludedBy = new ArrayList<Layout>();
- }
- target.mIncludedBy.add(this);
- }
-
- boolean isIncluded() {
- return mIncludedBy != null && !mIncludedBy.isEmpty();
- }
-
- File getFile() {
- return mFile;
- }
-
- List<Layout> getIncludes() {
- return mIncludes;
- }
-
- @Override
- public String toString() {
- return getDisplayName();
- }
- }
-
- private class IncludeGraph {
- private final Context mContext;
- private final Map<File, Layout> mFileToLayout;
-
- public IncludeGraph(Context context) {
- mContext = context;
-
- // Produce a DAG of the files to be included, and compute edges to all eligible
- // includes.
- // Then visit the DAG and whenever you find a duplicate emit a warning about the
- // include path which reached it.
- mFileToLayout = new HashMap<File, Layout>(2 * mIncludes.size());
- for (File file : mIncludes.keySet()) {
- if (!mFileToLayout.containsKey(file)) {
- mFileToLayout.put(file, new Layout(file, mFileToIds.get(file)));
- }
- }
- for (File file : mFileToIds.keySet()) {
- Set<String> ids = mFileToIds.get(file);
- if (ids != null && !ids.isEmpty()) {
- if (!mFileToLayout.containsKey(file)) {
- mFileToLayout.put(file, new Layout(file, ids));
- }
- }
- }
- Multimap<String, Layout> nameToLayout =
- ArrayListMultimap.create(mFileToLayout.size(), 4);
- for (File file : mFileToLayout.keySet()) {
- String name = LintUtils.getLayoutName(file);
- nameToLayout.put(name, mFileToLayout.get(file));
- }
-
- // Build up the DAG
- for (File file : mIncludes.keySet()) {
- Layout from = mFileToLayout.get(file);
- assert from != null : file;
-
- List<String> includedLayouts = mIncludes.get(file);
- for (String name : includedLayouts) {
- Collection<Layout> layouts = nameToLayout.get(name);
- if (layouts != null && !layouts.isEmpty()) {
- if (layouts.size() == 1) {
- from.include(layouts.iterator().next());
- } else {
- // See if we have an obvious match
- File folder = from.getFile().getParentFile();
- File candidate = new File(folder, name + DOT_XML);
- Layout candidateLayout = mFileToLayout.get(candidate);
- if (candidateLayout != null) {
- from.include(candidateLayout);
- } else if (mFileToIds.containsKey(candidate)) {
- // We had an entry in mFileToIds, but not a layout: this
- // means that the file exists, but had no includes or ids.
- // This can't be a valid match: there is a layout that we know
- // the include will pick, but it has no includes (to other layouts)
- // and no ids, so no need to look at it
- continue;
- } else {
- for (Layout to : layouts) {
- // Decide if the two targets are compatible
- if (isCompatible(from, to)) {
- from.include(to);
- }
- }
- }
- }
- } else {
- // The layout is including some layout which has no ids or other includes
- // so it's not relevant for a duplicate id search
- continue;
- }
- }
- }
- }
-
- /** Determine whether two layouts are compatible. They are not if they (for example)
- * specify conflicting qualifiers such as {@code -land} and {@code -port}.
- * @param from the include from
- * @param to the include to
- * @return true if the two are compatible */
- boolean isCompatible(Layout from, Layout to) {
- File fromFolder = from.mFile.getParentFile();
- File toFolder = to.mFile.getParentFile();
- if (fromFolder.equals(toFolder)) {
- return true;
- }
-
- String[] fromQualifiers = fromFolder.getName().split("-"); //$NON-NLS-1$
- String[] toQualifiers = toFolder.getName().split("-"); //$NON-NLS-1$
-
- if (isPortrait(fromQualifiers) != isPortrait(toQualifiers)) {
- return false;
- }
-
- return true;
- }
-
- private boolean isPortrait(String[] qualifiers) {
- for (String qualifier : qualifiers) {
- if (qualifier.equals("port")) { //$NON-NLS-1$
- return true;
- } else if (qualifier.equals("land")) { //$NON-NLS-1$
- return false;
- }
- }
-
- return true; // it's the default
- }
-
- public void check() {
- // Visit the DAG, looking for conflicts
- for (Layout layout : mFileToLayout.values()) {
- if (!layout.isIncluded()) { // Only check from "root" nodes
- Deque<Layout> stack = new ArrayDeque<Layout>();
- getIds(layout, stack, new HashSet<Layout>());
- }
- }
- }
-
- /**
- * Computes the cumulative set of ids used in a given layout. We can't
- * just depth-first-search the graph and check the set of ids
- * encountered along the way, because we need to detect when multiple
- * includes contribute the same ids. For example, if a file is included
- * more than once, that would result in duplicates.
- */
- private Set<String> getIds(Layout layout, Deque<Layout> stack, Set<Layout> seen) {
- seen.add(layout);
-
- Set<String> layoutIds = layout.getIds();
- List<Layout> includes = layout.getIncludes();
- if (includes != null) {
- Set<String> ids = new HashSet<String>();
- if (layoutIds != null) {
- ids.addAll(layoutIds);
- }
-
- stack.push(layout);
-
- Multimap<String, Set<String>> nameToIds =
- ArrayListMultimap.create(includes.size(), 4);
-
- for (Layout included : includes) {
- if (seen.contains(included)) {
- continue;
- }
- Set<String> includedIds = getIds(included, stack, seen);
- if (includedIds != null) {
- String layoutName = included.getLayoutName();
-
- idCheck:
- for (String id : includedIds) {
- if (ids.contains(id)) {
- Collection<Set<String>> idSets = nameToIds.get(layoutName);
- if (idSets != null) {
- for (Set<String> siblingIds : idSets) {
- if (siblingIds.contains(id)) {
- // The id reference was added by a sibling,
- // so no need to complain (again)
- continue idCheck;
- }
- }
- }
-
- // Duplicate! Record location request for new phase.
- if (mLocations == null) {
- mErrors = new ArrayList<Occurrence>();
- mLocations = ArrayListMultimap.create();
- mContext.getDriver().requestRepeat(DuplicateIdDetector.this,
- Scope.ALL_RESOURCES_SCOPE);
- }
-
- Map<Layout, Occurrence> occurrences =
- new HashMap<Layout, Occurrence>();
- findId(layout, id, new ArrayDeque<Layout>(), occurrences,
- new HashSet<Layout>());
- assert occurrences.size() >= 2;
-
- // Stash a request to find the given include
- Collection<Occurrence> values = occurrences.values();
- List<Occurrence> sorted = new ArrayList<Occurrence>(values);
- Collections.sort(sorted);
- String msg = String.format(
- "Duplicate id %1$s, defined or included multiple " +
- "times in %2$s: %3$s",
- id, layout.getDisplayName(),
- sorted.toString());
-
- // Store location request for the <include> tag
- Occurrence primary = new Occurrence(layout.getFile(), msg, null);
- Multimap<String, Occurrence> m = ArrayListMultimap.create();
- m.put(layoutName, primary);
- mLocations.put(layout.getFile(), m);
- mErrors.add(primary);
-
- Occurrence prev = primary;
-
- // Now store all the included occurrences of the id
- for (Occurrence occurrence : values) {
- if (occurrence.file.equals(layout.getFile())) {
- occurrence.message = "Defined here";
- } else {
- occurrence.message = String.format(
- "Defined here, included via %1$s",
- occurrence.includePath);
- }
-
- m = ArrayListMultimap.create();
- m.put(id, occurrence);
- mLocations.put(occurrence.file, m);
-
- // Link locations together
- prev.next = occurrence;
- prev = occurrence;
- }
- }
- ids.add(id);
- }
-
- // Store these ids such that on a conflict, we can tell when
- // an id was added by a single variation of this file
- nameToIds.put(layoutName, includedIds);
- }
- }
- Layout visited = stack.pop();
- assert visited == layout;
- return ids;
- } else {
- return layoutIds;
- }
- }
-
- private void findId(Layout layout, String id, Deque<Layout> stack,
- Map<Layout, Occurrence> occurrences, Set<Layout> seen) {
- seen.add(layout);
-
- Set<String> layoutIds = layout.getIds();
- if (layoutIds != null && layoutIds.contains(id)) {
- StringBuilder path = new StringBuilder(80);
-
- if (!stack.isEmpty()) {
- Iterator<Layout> iterator = stack.descendingIterator();
- while (iterator.hasNext()) {
- path.append(iterator.next().getDisplayName());
- path.append(" => ");
- }
- }
- path.append(layout.getDisplayName());
- path.append(" defines ");
- path.append(id);
-
- assert occurrences.get(layout) == null : id + ',' + layout;
- occurrences.put(layout, new Occurrence(layout.getFile(), null, path.toString()));
- }
-
- List<Layout> includes = layout.getIncludes();
- if (includes != null) {
- stack.push(layout);
- for (Layout included : includes) {
- if (!seen.contains(included)) {
- findId(included, id, stack, occurrences, seen);
- }
- }
- Layout visited = stack.pop();
- assert visited == layout;
- }
- }
- }
-
- private static class Occurrence implements Comparable<Occurrence> {
- public final File file;
- public final String includePath;
- public Occurrence next;
- public Location location;
- public String message;
-
- public Occurrence(File file, String message, String includePath) {
- this.file = file;
- this.message = message;
- this.includePath = includePath;
- }
-
- @Override
- public String toString() {
- return includePath != null ? includePath : message;
- }
-
- @Override
- public int compareTo(Occurrence other) {
- // First sort by length, then sort by name
- int delta = toString().length() - other.toString().length();
- if (delta != 0) {
- return delta;
- }
-
- return toString().compareTo(other.toString());
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateResourceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateResourceDetector.java
deleted file mode 100644
index 004303c..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/DuplicateResourceDetector.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TYPE;
-import static com.android.SdkConstants.TAG_ITEM;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * This detector identifies cases where a resource is defined multiple times in the
- * same resource folder
- */
-public class DuplicateResourceDetector extends ResourceXmlDetector {
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "DuplicateDefinition", //$NON-NLS-1$
- "Discovers duplicate definitions of resources",
-
- "You can define a resource multiple times in different resource folders; that's how " +
- "string translations are done, for example. However, defining the same resource " +
- "more than once in the same resource folder is likely an error, for example " +
- "attempting to add a new resource without realizing that the name is already used, " +
- "and so on.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- DuplicateResourceDetector.class,
- Scope.ALL_RESOURCES_SCOPE).addAnalysisScope(Scope.RESOURCE_FILE_SCOPE);
-
- private static final String PRODUCT = "product"; //$NON-NLS-1$
- private Map<ResourceType, Set<String>> mTypeMap;
- private Map<ResourceType, List<Pair<String, Location.Handle>>> mLocations;
- private File mParent;
-
- /** Constructs a new {@link DuplicateResourceDetector} */
- public DuplicateResourceDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- @Override
- @Nullable
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_NAME);
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- File parent = context.file.getParentFile();
- if (!parent.equals(mParent)) {
- mParent = parent;
- mTypeMap = Maps.newEnumMap(ResourceType.class);
- mLocations = Maps.newEnumMap(ResourceType.class);
- }
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- Element element = attribute.getOwnerElement();
-
- if (element.hasAttribute(PRODUCT)) {
- return;
- }
-
- String tag = element.getTagName();
- String typeString = tag;
- if (tag.equals(TAG_ITEM)) {
- typeString = element.getAttribute(ATTR_TYPE);
- }
- ResourceType type = ResourceType.getEnum(typeString);
- if (type == null) {
- return;
- }
-
- if (type == ResourceType.ATTR
- && element.getParentNode().getNodeName().equals(
- ResourceType.DECLARE_STYLEABLE.getName())) {
- return;
- }
-
- Set<String> names = mTypeMap.get(type);
- if (names == null) {
- names = Sets.newHashSetWithExpectedSize(40);
- mTypeMap.put(type, names);
- }
-
- String name = attribute.getValue();
- if (names.contains(name)) {
- String message = String.format("%1$s has already been defined in this folder",
- name);
- Location location = context.getLocation(attribute);
- List<Pair<String, Handle>> list = mLocations.get(type);
- for (Pair<String, Handle> pair : list) {
- if (name.equals(pair.getFirst())) {
- Location secondary = pair.getSecond().resolve();
- secondary.setMessage("Previously defined here");
- location.setSecondary(secondary);
- }
- }
- context.report(ISSUE, attribute, location, message, null);
- } else {
- names.add(name);
- List<Pair<String, Handle>> list = mLocations.get(type);
- if (list == null) {
- list = Lists.newArrayList();
- mLocations.put(type, list);
- }
- Location.Handle handle = context.parser.createLocationHandle(context, attribute);
- list.add(Pair.of(name, handle));
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ExtraTextDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ExtraTextDetector.java
deleted file mode 100644
index e0781db..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ExtraTextDetector.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.DefaultPosition;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Position;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * Check which looks for invalid resources. Aapt already performs some validation,
- * such as making sure that resource references point to resources that exist, but this
- * detector looks for additional issues.
- */
-public class ExtraTextDetector extends ResourceXmlDetector {
- private boolean mFoundText;
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ExtraText", //$NON-NLS-1$
- "Looks for extraneous text in layout files",
- "Layout resource files should only contain elements and attributes. Any XML " +
- "text content found in the file is likely accidental (and potentially " +
- "dangerous if the text resembles XML and the developer believes the text " +
- "to be functional)",
- Category.CORRECTNESS,
- 3,
- Severity.WARNING,
- ExtraTextDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new detector */
- public ExtraTextDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT
- || folderType == ResourceFolderType.MENU
- || folderType == ResourceFolderType.ANIM
- || folderType == ResourceFolderType.ANIMATOR
- || folderType == ResourceFolderType.DRAWABLE
- || folderType == ResourceFolderType.COLOR;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- mFoundText = false;
- visitNode(context, document);
- }
-
- private void visitNode(XmlContext context, Node node) {
- short nodeType = node.getNodeType();
- if (nodeType == Node.TEXT_NODE && !mFoundText) {
- String text = node.getNodeValue();
- for (int i = 0, n = text.length(); i < n; i++) {
- char c = text.charAt(i);
- if (!Character.isWhitespace(c)) {
- String snippet = text.trim();
- int maxLength = 100;
- if (snippet.length() > maxLength) {
- snippet = snippet.substring(0, maxLength) + "...";
- }
- Location location = context.getLocation(node);
- if (i > 0) {
- // Adjust the error position to point to the beginning of
- // the text rather than the beginning of the text node
- // (which is often the newline at the end of the previous
- // line and the indentation)
- Position start = location.getStart();
- if (start != null) {
- int line = start.getLine();
- int column = start.getColumn();
- int offset = start.getOffset();
-
- for (int j = 0; j < i; j++) {
- offset++;
-
- if (text.charAt(j) == '\n') {
- if (line != -1) {
- line++;
- }
- if (column != -1) {
- column = 0;
- }
- } else if (column != -1) {
- column++;
- }
- }
-
- start = new DefaultPosition(line, column, offset);
- location = Location.create(context.file, start, location.getEnd());
- }
- }
- context.report(ISSUE, node, location,
- String.format("Unexpected text found in layout file: \"%1$s\"",
- snippet), null);
- mFoundText = true;
- break;
- }
- }
- }
-
- // Visit children
- NodeList childNodes = node.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- visitNode(context, child);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FieldGetterDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FieldGetterDetector.java
deleted file mode 100644
index 04841ab..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FieldGetterDetector.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.google.common.collect.Maps;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.VarInsnNode;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Looks for getter calls within the same class that could be replaced by
- * direct field references instead.
- */
-public class FieldGetterDetector extends Detector implements Detector.ClassScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "FieldGetter", //$NON-NLS-1$
- "Suggests replacing uses of getters with direct field access within a class",
-
- "Accessing a field within the class that defines a getter for that field is " +
- "at least 3 times faster than calling the getter. For simple getters that do " +
- "nothing other than return the field, you might want to just reference the " +
- "local field directly instead.\n" +
- "\n" +
- "NOTE: As of Android 2.3 (Gingerbread), this optimization is performed " +
- "automatically by Dalvik, so there is no need to change your code; this is " +
- "only relevant if you are targeting older versions of Android.",
-
- Category.PERFORMANCE,
- 4,
- Severity.WARNING,
- FieldGetterDetector.class,
- Scope.CLASS_FILE_SCOPE).
- // This is a micro-optimization: not enabled by default
- setEnabledByDefault(false).setMoreInfo(
- "http://developer.android.com/guide/practices/design/performance.html#internal_get_set"); //$NON-NLS-1$
- private ArrayList<Entry> mPendingCalls;
-
- /** Constructs a new {@link FieldGetterDetector} check */
- public FieldGetterDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public int[] getApplicableAsmNodeTypes() {
- return new int[] { AbstractInsnNode.METHOD_INSN };
- }
-
- @Override
- public void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull AbstractInsnNode instruction) {
- // As of Gingerbread/API 9, Dalvik performs this optimization automatically
- if (context.getProject().getMinSdk() >= 9) {
- return;
- }
-
- if ((method.access & Opcodes.ACC_STATIC) != 0) {
- // Not an instance method
- return;
- }
-
- if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) {
- return;
- }
-
- MethodInsnNode node = (MethodInsnNode) instruction;
- String name = node.name;
- String owner = node.owner;
-
- AbstractInsnNode prev = LintUtils.getPrevInstruction(instruction);
- if (prev == null || prev.getOpcode() != Opcodes.ALOAD) {
- return;
- }
- VarInsnNode prevVar = (VarInsnNode) prev;
- if (prevVar.var != 0) { // Not on "this", variable 0 in instance methods?
- return;
- }
-
- if (((name.startsWith("get") && name.length() > 3 //$NON-NLS-1$
- && Character.isUpperCase(name.charAt(3)))
- || (name.startsWith("is") && name.length() > 2 //$NON-NLS-1$
- && Character.isUpperCase(name.charAt(2))))
- && owner.equals(classNode.name)) {
- // Calling a potential getter method on self. We now need to
- // investigate the method body of the getter call and make sure
- // it's really a plain getter, not just a method which happens
- // to have a method name like a getter, or a method which not
- // only returns a field but possibly computes it or performs
- // other initialization or side effects. This is done in a
- // second pass over the bytecode, initiated by the finish()
- // method.
- if (mPendingCalls == null) {
- mPendingCalls = new ArrayList<Entry>();
- }
-
- mPendingCalls.add(new Entry(name, node, method));
- }
-
- super.checkInstruction(context, classNode, method, instruction);
- }
-
- @Override
- public void afterCheckFile(@NonNull Context c) {
- ClassContext context = (ClassContext) c;
-
- if (mPendingCalls != null) {
- Set<String> names = new HashSet<String>(mPendingCalls.size());
- for (Entry entry : mPendingCalls) {
- names.add(entry.name);
- }
-
- Map<String, String> getters = checkMethods(context.getClassNode(), names);
- if (!getters.isEmpty()) {
- for (String getter : getters.keySet()) {
- for (Entry entry : mPendingCalls) {
- String name = entry.name;
- // There can be more than one reference to the same name:
- // one for each call site
- if (name.equals(getter)) {
- Location location = context.getLocation(entry.call);
- String fieldName = getters.get(getter);
- if (fieldName == null) {
- fieldName = "";
- }
- context.report(ISSUE, entry.method, entry.call, location,
- String.format(
- "Calling getter method %1$s() on self is " +
- "slower than field access (%2$s)", getter, fieldName), fieldName);
- }
- }
- }
- }
- }
-
- mPendingCalls = null;
- }
-
- // Holder class for getters to be checked
- private static class Entry {
- public final String name;
- public final MethodNode method;
- public final MethodInsnNode call;
-
- public Entry(String name, MethodInsnNode call, MethodNode method) {
- super();
- this.name = name;
- this.call = call;
- this.method = method;
- }
- }
-
- // Validate that these getter methods are really just simple field getters
- // like these int and String getters:
- // public int getFoo();
- // Code:
- // 0: aload_0
- // 1: getfield #21; //Field mFoo:I
- // 4: ireturn
- //
- // public java.lang.String getBar();
- // Code:
- // 0: aload_0
- // 1: getfield #25; //Field mBar:Ljava/lang/String;
- // 4: areturn
- //
- // Returns a map of valid getters as keys, and if the field name is found, the field name
- // for each getter as its value.
- private static Map<String, String> checkMethods(ClassNode classNode, Set<String> names) {
- Map<String, String> validGetters = Maps.newHashMap();
- @SuppressWarnings("rawtypes")
- List methods = classNode.methods;
- String fieldName = null;
- checkMethod:
- for (Object methodObject : methods) {
- MethodNode method = (MethodNode) methodObject;
- if (names.contains(method.name)
- && method.desc.startsWith("()")) { //$NON-NLS-1$ // (): No arguments
- InsnList instructions = method.instructions;
- int mState = 1;
- for (AbstractInsnNode curr = instructions.getFirst();
- curr != null;
- curr = curr.getNext()) {
- switch (curr.getOpcode()) {
- case -1:
- // Skip label and line number nodes
- continue;
- case Opcodes.ALOAD:
- if (mState == 1) {
- fieldName = null;
- mState = 2;
- } else {
- continue checkMethod;
- }
- break;
- case Opcodes.GETFIELD:
- if (mState == 2) {
- FieldInsnNode field = (FieldInsnNode) curr;
- fieldName = field.name;
- mState = 3;
- } else {
- continue checkMethod;
- }
- break;
- case Opcodes.ARETURN:
- case Opcodes.FRETURN:
- case Opcodes.IRETURN:
- case Opcodes.DRETURN:
- case Opcodes.LRETURN:
- case Opcodes.RETURN:
- if (mState == 3) {
- validGetters.put(method.name, fieldName);
- }
- continue checkMethod;
- default:
- continue checkMethod;
- }
- }
- }
- }
-
- return validGetters;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FragmentDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FragmentDetector.java
deleted file mode 100644
index f6ebcd6..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/FragmentDetector.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.FRAGMENT;
-import static com.android.SdkConstants.FRAGMENT_V4;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.List;
-
-/**
- * Checks that Fragment subclasses can be instantiated via
- * {link {@link Class#newInstance()}}: the class is public, static, and has
- * a public null constructor.
- * <p>
- * This helps track down issues like
- * http://stackoverflow.com/questions/8058809/fragment-activity-crashes-on-screen-rotate
- * (and countless duplicates)
- */
-public class FragmentDetector extends Detector implements ClassScanner {
- private static final String FRAGMENT_NAME_SUFFIX = "Fragment"; //$NON-NLS-1$
-
- /** Are fragment subclasses instantiatable? */
- public static final Issue ISSUE = Issue.create(
- "ValidFragment", //$NON-NLS-1$
- "Ensures that Fragment subclasses can be instantiated",
-
- "From the Fragment documentation:\n" +
- "*Every* fragment must have an empty constructor, so it can be instantiated when " +
- "restoring its activity's state. It is strongly recommended that subclasses do not " +
- "have other constructors with parameters, since these constructors will not be " +
- "called when the fragment is re-instantiated; instead, arguments can be supplied " +
- "by the caller with `setArguments(Bundle)` and later retrieved by the Fragment " +
- "with `getArguments()`.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- FragmentDetector.class,
- Scope.CLASS_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/android/app/Fragment.html#Fragment()"); //$NON-NLS-1$
-
-
- /** Constructs a new {@link FragmentDetector} */
- public FragmentDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
- // Ignore abstract classes since they are clearly (and by definition) not intended to
- // be instantiated. We're looking for accidental non-static or missing constructor
- // scenarios here.
- return;
- }
-
- LintDriver driver = context.getDriver();
-
- if (!(driver.isSubclassOf(classNode, FRAGMENT)
- || driver.isSubclassOf(classNode, FRAGMENT_V4))) {
- if (!context.getScope().contains(Scope.ALL_JAVA_FILES)) {
- // Single file checking: Just check that it looks like a fragment class
- // (since we don't have a full superclass map)
- if (!classNode.name.endsWith(FRAGMENT_NAME_SUFFIX) ||
- classNode.superName == null) {
- return;
- }
- } else {
- return;
- }
- }
-
- if ((classNode.access & Opcodes.ACC_PUBLIC) == 0) {
- context.report(ISSUE, context.getLocation(classNode), String.format(
- "This fragment class should be public (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- return;
- }
-
- if (classNode.name.indexOf('$') != -1 && !LintUtils.isStaticInnerClass(classNode)) {
- context.report(ISSUE, context.getLocation(classNode), String.format(
- "This fragment inner class should be static (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- return;
- }
-
- boolean hasDefaultConstructor = false;
- @SuppressWarnings("rawtypes") // ASM API
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- if (method.name.equals(CONSTRUCTOR_NAME)) {
- if (method.desc.equals("()V")) { //$NON-NLS-1$
- // The constructor must be public
- if ((method.access & Opcodes.ACC_PUBLIC) != 0) {
- hasDefaultConstructor = true;
- } else {
- context.report(ISSUE, context.getLocation(method, classNode),
- "The default constructor must be public",
- null);
- // Also mark that we have a constructor so we don't complain again
- // below since we've already emitted a more specific error related
- // to the default constructor
- hasDefaultConstructor = true;
- }
- } else if (!method.desc.contains("()")) { //$NON-NLS-1$
- context.report(ISSUE, context.getLocation(method, classNode),
- // TODO: Use separate issue for this which isn't an error
- "Avoid non-default constructors in fragments: use a default constructor " +
- "plus Fragment#setArguments(Bundle) instead",
- null);
- }
- }
- }
-
- if (!hasDefaultConstructor) {
- context.report(ISSUE, context.getLocation(classNode), String.format(
- "This fragment should provide a default constructor (a public " +
- "constructor with no arguments) (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/GridLayoutDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/GridLayoutDetector.java
deleted file mode 100644
index c348502..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/GridLayoutDetector.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_COLUMN_COUNT;
-import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN;
-import static com.android.SdkConstants.ATTR_LAYOUT_ROW;
-import static com.android.SdkConstants.ATTR_ROW_COUNT;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check which looks for potential errors in declarations of GridLayouts, such as specifying
- * row/column numbers outside the declared dimensions of the grid.
- */
-public class GridLayoutDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "GridLayout", //$NON-NLS-1$
- "Checks for potential GridLayout errors like declaring rows and columns outside " +
- "the declared grid dimensions",
- "Declaring a layout_row or layout_column that falls outside the declared size " +
- "of a GridLayout's `rowCount` or `columnCount` is usually an unintentional error.",
- Category.CORRECTNESS,
- 4,
- Severity.FATAL,
- GridLayoutDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link GridLayoutDetector} check */
- public GridLayoutDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(
- "GridLayout" //$NON-NLS-1$
- );
- }
-
- private static int getInt(Element element, String attribute, int defaultValue) {
- String valueString = element.getAttributeNS(ANDROID_URI, attribute);
- if (valueString != null && !valueString.isEmpty()) {
- try {
- return Integer.decode(valueString);
- } catch (NumberFormatException nufe) {
- // Ignore - error in user's XML
- }
- }
-
- return defaultValue;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- int declaredRowCount = getInt(element, ATTR_ROW_COUNT, -1);
- int declaredColumnCount = getInt(element, ATTR_COLUMN_COUNT, -1);
-
- if (declaredColumnCount != -1 || declaredRowCount != -1) {
- for (Element child : LintUtils.getChildren(element)) {
- if (declaredColumnCount != -1) {
- int column = getInt(child, ATTR_LAYOUT_COLUMN, -1);
- if (column >= declaredColumnCount) {
- Attr node = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_COLUMN);
- context.report(ISSUE, node, context.getLocation(node),
- String.format("Column attribute (%1$d) exceeds declared grid column count (%2$d)",
- column, declaredColumnCount), null);
- }
- }
- if (declaredRowCount != -1) {
- int row = getInt(child, ATTR_LAYOUT_ROW, -1);
- if (row > declaredRowCount) {
- Attr node = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_ROW);
- context.report(ISSUE, node, context.getLocation(node),
- String.format("Row attribute (%1$d) exceeds declared grid row count (%2$d)",
- row, declaredRowCount), null);
- }
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HandlerDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HandlerDetector.java
deleted file mode 100644
index cfe8f0b..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HandlerDetector.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.tree.ClassNode;
-
-/**
- * Checks that Handler implementations are top level classes or static.
- * See the corresponding check in the android.os.Handler source code.
- */
-public class HandlerDetector extends Detector implements ClassScanner {
-
- /** Potentially leaking handlers */
- public static final Issue ISSUE = Issue.create(
- "HandlerLeak", //$NON-NLS-1$
- "Ensures that Handler classes do not hold on to a reference to an outer class",
-
- "In Android, Handler classes should be static or leaks might occur. " +
- "Messages enqueued on the application thread's MessageQueue also retain their " +
- "target Handler. If the Handler is an inner class, its outer class will be " +
- "retained as well. To avoid leaking the outer class, declare the Handler as a " +
- "static nested class with a WeakReference to its outer class.",
-
- Category.PERFORMANCE,
- 4,
- Severity.WARNING,
- HandlerDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- /** Constructs a new {@link HandlerDetector} */
- public HandlerDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if (classNode.name.indexOf('$') == -1) {
- return;
- }
-
- if (context.getDriver().isSubclassOf(classNode, "android/os/Handler") //$NON-NLS-1$
- && !LintUtils.isStaticInnerClass(classNode)) {
- Location location = context.getLocation(classNode);
- context.report(ISSUE, location, String.format(
- "This Handler class should be static or leaks might occur (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedDebugModeDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedDebugModeDetector.java
deleted file mode 100644
index fd678ca..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedDebugModeDetector.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_DEBUGGABLE;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Checks for hardcoded debug mode in manifest files
- */
-public class HardcodedDebugModeDetector extends Detector implements Detector.XmlScanner {
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "HardcodedDebugMode", //$NON-NLS-1$
- "Checks for hardcoded values of android:debuggable in the manifest",
-
- "It's best to leave out the `android:debuggable` attribute from the manifest. " +
- "If you do, then the tools will automatically insert `android:debuggable=true` when " +
- "building an APK to debug on an emulator or device. And when you perform a " +
- "release build, such as Exporting APK, it will automatically set it to `false`.\n" +
- "\n" +
- "If on the other hand you specify a specific value in the manifest file, then " +
- "the tools will always use it. This can lead to accidentally publishing " +
- "your app with debug information.",
-
- Category.SECURITY,
- 5,
- Severity.WARNING,
- HardcodedDebugModeDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Constructs a new {@link HardcodedDebugModeDetector} check */
- public HardcodedDebugModeDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return file.getName().equals(ANDROID_MANIFEST_XML);
- }
-
- // ---- Implements Detector.XmlScanner ----
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singleton(ATTR_DEBUGGABLE);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (attribute.getNamespaceURI().equals(ANDROID_URI)) {
- //if (attribute.getOwnerElement().getTagName().equals(TAG_APPLICATION)) {
- context.report(ISSUE, attribute, context.getLocation(attribute),
- "Avoid hardcoding the debug mode; leaving it out allows debug and " +
- "release builds to automatically assign one", null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedValuesDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedValuesDetector.java
deleted file mode 100644
index 11cc19d..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/HardcodedValuesDetector.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION;
-import static com.android.SdkConstants.ATTR_HINT;
-import static com.android.SdkConstants.ATTR_LABEL;
-import static com.android.SdkConstants.ATTR_PROMPT;
-import static com.android.SdkConstants.ATTR_TEXT;
-import static com.android.SdkConstants.ATTR_TITLE;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Check which looks at the children of ScrollViews and ensures that they fill/match
- * the parent width instead of setting wrap_content.
- */
-public class HardcodedValuesDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "HardcodedText", //$NON-NLS-1$
- "Looks for hardcoded text attributes which should be converted to resource lookup",
- "Hardcoding text attributes directly in layout files is bad for several reasons:\n" +
- "\n" +
- "* When creating configuration variations (for example for landscape or portrait)" +
- "you have to repeat the actual text (and keep it up to date when making changes)\n" +
- "\n" +
- "* The application cannot be translated to other languages by just adding new " +
- "translations for existing string resources.\n" +
- "\n" +
- "In Eclipse there is a quickfix to automatically extract this hardcoded string into " +
- "a resource lookup.",
-
- Category.I18N,
- 5,
- Severity.WARNING,
- HardcodedValuesDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- // TODO: Add additional issues here, such as hardcoded colors, hardcoded sizes, etc
-
- /** Constructs a new {@link HardcodedValuesDetector} */
- public HardcodedValuesDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Arrays.asList(
- // Layouts
- ATTR_TEXT,
- ATTR_CONTENT_DESCRIPTION,
- ATTR_HINT,
- ATTR_LABEL,
- ATTR_PROMPT,
-
- // Menus
- ATTR_TITLE
- );
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.MENU;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String value = attribute.getValue();
- if (!value.isEmpty() && (value.charAt(0) != '@' && value.charAt(0) != '?')) {
- // Make sure this is really one of the android: attributes
- if (!ANDROID_URI.equals(attribute.getNamespaceURI())) {
- return;
- }
-
- context.report(ISSUE, attribute, context.getLocation(attribute),
- String.format("[I18N] Hardcoded string \"%1$s\", should use @string resource",
- value), null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java
deleted file mode 100644
index 7f26c96..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/IconDetector.java
+++ /dev/null
@@ -1,1906 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_ICON;
-import static com.android.SdkConstants.DOT_9PNG;
-import static com.android.SdkConstants.DOT_GIF;
-import static com.android.SdkConstants.DOT_JPEG;
-import static com.android.SdkConstants.DOT_JPG;
-import static com.android.SdkConstants.DOT_PNG;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.DRAWABLE_FOLDER;
-import static com.android.SdkConstants.DRAWABLE_HDPI;
-import static com.android.SdkConstants.DRAWABLE_LDPI;
-import static com.android.SdkConstants.DRAWABLE_MDPI;
-import static com.android.SdkConstants.DRAWABLE_PREFIX;
-import static com.android.SdkConstants.DRAWABLE_XHDPI;
-import static com.android.SdkConstants.MENU_TYPE;
-import static com.android.SdkConstants.R_CLASS;
-import static com.android.SdkConstants.R_DRAWABLE_PREFIX;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_APPLICATION;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_PROVIDER;
-import static com.android.SdkConstants.TAG_RECEIVER;
-import static com.android.SdkConstants.TAG_SERVICE;
-import static com.android.tools.lint.detector.api.LintUtils.endsWith;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Element;
-
-import java.awt.Dimension;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.TypeReference;
-import lombok.ast.TypeReferencePart;
-import lombok.ast.VariableReference;
-
-/**
- * Checks for common icon problems, such as wrong icon sizes, placing icons in the
- * density independent drawable folder, etc.
- */
-public class IconDetector extends ResourceXmlDetector implements Detector.JavaScanner {
-
- private static final boolean INCLUDE_LDPI;
- static {
- boolean includeLdpi = false;
-
- String value = System.getenv("ANDROID_LINT_INCLUDE_LDPI"); //$NON-NLS-1$
- if (value != null) {
- includeLdpi = Boolean.valueOf(value);
- }
- INCLUDE_LDPI = includeLdpi;
- }
-
- /** Pattern for the expected density folders to be found in the project */
- private static final Pattern DENSITY_PATTERN = Pattern.compile(
- "^drawable-(nodpi|xhdpi|hdpi|mdpi" //$NON-NLS-1$
- + (INCLUDE_LDPI ? "|ldpi" : "") + ")$"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-
- private static final String[] REQUIRED_DENSITIES = INCLUDE_LDPI
- ? new String[] { DRAWABLE_LDPI, DRAWABLE_MDPI, DRAWABLE_HDPI, DRAWABLE_XHDPI }
- : new String[] { DRAWABLE_MDPI, DRAWABLE_HDPI, DRAWABLE_XHDPI };
-
- private static final String[] DENSITY_QUALIFIERS =
- new String[] {
- "-ldpi", //$NON-NLS-1$
- "-mdpi", //$NON-NLS-1$
- "-hdpi", //$NON-NLS-1$
- "-xhdpi" //$NON-NLS-1$
- };
-
- /** Scope needed to detect the types of icons (which involves scanning .java files,
- * the manifest, menu files etc to see how icons are used
- */
- private static final EnumSet<Scope> ICON_TYPE_SCOPE = EnumSet.of(Scope.ALL_RESOURCE_FILES,
- Scope.JAVA_FILE, Scope.MANIFEST);
-
- /** Wrong icon size according to published conventions */
- public static final Issue ICON_EXPECTED_SIZE = Issue.create(
- "IconExpectedSize", //$NON-NLS-1$
- "Ensures that launcher icons, notification icons etc have the correct size",
- "There are predefined sizes (for each density) for launcher icons. You " +
- "should follow these conventions to make sure your icons fit in with the " +
- "overall look of the platform.",
- Category.ICONS,
- 5,
- Severity.WARNING,
- IconDetector.class,
- ICON_TYPE_SCOPE)
- // Still some potential false positives:
- .setEnabledByDefault(false)
- .setMoreInfo(
- "http://developer.android.com/design/style/iconography.html"); //$NON-NLS-1$
-
- /** Inconsistent dip size across densities */
- public static final Issue ICON_DIP_SIZE = Issue.create(
- "IconDipSize", //$NON-NLS-1$
- "Ensures that icons across densities provide roughly the same density-independent size",
- "Checks the all icons which are provided in multiple densities, all compute to " +
- "roughly the same density-independent pixel (`dip`) size. This catches errors where " +
- "images are either placed in the wrong folder, or icons are changed to new sizes " +
- "but some folders are forgotten.",
- Category.ICONS,
- 5,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Images in res/drawable folder */
- public static final Issue ICON_LOCATION = Issue.create(
- "IconLocation", //$NON-NLS-1$
- "Ensures that images are not defined in the density-independent drawable folder",
- "The res/drawable folder is intended for density-independent graphics such as " +
- "shapes defined in XML. For bitmaps, move it to `drawable-mdpi` and consider " +
- "providing higher and lower resolution versions in `drawable-ldpi`, `drawable-hdpi` " +
- "and `drawable-xhdpi`. If the icon *really* is density independent (for example " +
- "a solid color) you can place it in `drawable-nodpi`.",
- Category.ICONS,
- 5,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/screens_support.html"); //$NON-NLS-1$
-
- /** Missing density versions of image */
- public static final Issue ICON_DENSITIES = Issue.create(
- "IconDensities", //$NON-NLS-1$
- "Ensures that icons provide custom versions for all supported densities",
- "Icons will look best if a custom version is provided for each of the " +
- "major screen density classes (low, medium, high, extra high). " +
- "This lint check identifies icons which do not have complete coverage " +
- "across the densities.\n" +
- "\n" +
- "Low density is not really used much anymore, so this check ignores " +
- "the ldpi density. To force lint to include it, set the environment " +
- "variable `ANDROID_LINT_INCLUDE_LDPI=true`. For more information on " +
- "current density usage, see " +
- "http://developer.android.com/resources/dashboard/screens.html",
- Category.ICONS,
- 4,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/screens_support.html"); //$NON-NLS-1$
-
- /** Missing density folders */
- public static final Issue ICON_MISSING_FOLDER = Issue.create(
- "IconMissingDensityFolder", //$NON-NLS-1$
- "Ensures that all the density folders are present",
- "Icons will look best if a custom version is provided for each of the " +
- "major screen density classes (low, medium, high, extra high). " +
- "This lint check identifies folders which are missing, such as `drawable-hdpi`." +
- "\n" +
- "Low density is not really used much anymore, so this check ignores " +
- "the ldpi density. To force lint to include it, set the environment " +
- "variable `ANDROID_LINT_INCLUDE_LDPI=true`. For more information on " +
- "current density usage, see " +
- "http://developer.android.com/resources/dashboard/screens.html",
- Category.ICONS,
- 3,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/screens_support.html"); //$NON-NLS-1$
-
- /** Using .gif bitmaps */
- public static final Issue GIF_USAGE = Issue.create(
- "GifUsage", //$NON-NLS-1$
- "Checks for images using the GIF file format which is discouraged",
- "The `.gif` file format is discouraged. Consider using `.png` (preferred) " +
- "or `.jpg` (acceptable) instead.",
- Category.ICONS,
- 5,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap"); //$NON-NLS-1$
-
- /** Duplicated icons across different names */
- public static final Issue DUPLICATES_NAMES = Issue.create(
- "IconDuplicates", //$NON-NLS-1$
- "Finds duplicated icons under different names",
- "If an icon is repeated under different names, you can consolidate and just " +
- "use one of the icons and delete the others to make your application smaller. " +
- "However, duplicated icons usually are not intentional and can sometimes point " +
- "to icons that were accidentally overwritten or accidentally not updated.",
- Category.ICONS,
- 3,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Duplicated contents across configurations for a given name */
- public static final Issue DUPLICATES_CONFIGURATIONS = Issue.create(
- "IconDuplicatesConfig", //$NON-NLS-1$
- "Finds icons that have identical bitmaps across various configuration parameters",
- "If an icon is provided under different configuration parameters such as " +
- "`drawable-hdpi` or `-v11`, they should typically be different. This detector " +
- "catches cases where the same icon is provided in different configuration folder " +
- "which is usually not intentional.",
- Category.ICONS,
- 5,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Icons appearing in both -nodpi and a -Ndpi folder */
- public static final Issue ICON_NODPI = Issue.create(
- "IconNoDpi", //$NON-NLS-1$
- "Finds icons that appear in both a -nodpi folder and a dpi folder",
- "Bitmaps that appear in `drawable-nodpi` folders will not be scaled by the " +
- "Android framework. If a drawable resource of the same name appears *both* in " +
- "a `-nodpi` folder as well as a dpi folder such as `drawable-hdpi`, then " +
- "the behavior is ambiguous and probably not intentional. Delete one or the " +
- "other, or use different names for the icons.",
- Category.ICONS,
- 7,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Icons appearing as both drawable xml files and bitmaps */
- public static final Issue ICON_XML_AND_PNG = Issue.create(
- "IconXmlAndPng", //$NON-NLS-1$
- "Finds icons that appear both as a drawable .xml file and as bitmaps",
- "If a drawable resource appears as an .xml file in the drawable/ folder, " +
- "it's usually not intentional for it to also appear as a bitmap using the " +
- "same name; generally you expect the drawable XML file to define states " +
- "and each state has a corresponding drawable bitmap.",
- Category.ICONS,
- 7,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Wrong filename according to the format */
- public static final Issue ICON_EXTENSION = Issue.create(
- "IconExtension", //$NON-NLS-1$
- "Checks that the icon file extension matches the actual image format in the file",
-
- "Ensures that icons have the correct file extension (e.g. a .png file is " +
- "really in the PNG format and not for example a GIF file named .png.)",
- Category.ICONS,
- 3,
- Severity.WARNING,
- IconDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Wrong filename according to the format */
- public static final Issue ICON_COLORS = Issue.create(
- "IconColors", //$NON-NLS-1$
- "Checks that icons follow the recommended visual style",
-
- "Notification icons and Action Bar icons should only white and shades of gray. " +
- "See the Android Design Guide for more details. " +
- "Note that the way Lint decides whether an icon is an action bar icon or " +
- "a notification icon is based on the filename prefix: `ic_menu_` for " +
- "action bar icons, `ic_stat_` for notification icons etc. These correspond " +
- "to the naming conventions documented in " +
- "http://developer.android.com/guide/practices/ui_guidelines/icon_design.html",
- Category.ICONS,
- 6,
- Severity.WARNING,
- IconDetector.class,
- ICON_TYPE_SCOPE).setMoreInfo(
- "http://developer.android.com/design/style/iconography.html"); //$NON-NLS-1$
-
- /** Wrong launcher icon shape */
- public static final Issue ICON_LAUNCHER_SHAPE = Issue.create(
- "IconLauncherShape", //$NON-NLS-1$
- "Checks that launcher icons follow the recommended visual style",
-
- "According to the Android Design Guide " +
- "(http://developer.android.com/design/style/iconography.html) " +
- "your launcher icons should \"use a distinct silhouette\", " +
- "a \"three-dimensional, front view, with a slight perspective as if viewed " +
- "from above, so that users perceive some depth.\"\n" +
- "\n" +
- "The unique silhouette implies that your launcher icon should not be a filled " +
- "square.",
- Category.ICONS,
- 6,
- Severity.WARNING,
- IconDetector.class,
- ICON_TYPE_SCOPE).setMoreInfo(
- "http://developer.android.com/design/style/iconography.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link IconDetector} check */
- public IconDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.SLOW;
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- mLauncherIcons = null;
- mActionBarIcons = null;
- mNotificationIcons = null;
- }
-
- @Override
- public void afterCheckLibraryProject(@NonNull Context context) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- checkResourceFolder(context, context.getProject());
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- checkResourceFolder(context, context.getProject());
- }
-
- private void checkResourceFolder(Context context, @NonNull Project project) {
- List<File> resourceFolders = project.getResourceFolders();
- for (File res : resourceFolders) {
- File[] folders = res.listFiles();
- if (folders != null) {
- boolean checkFolders = context.isEnabled(ICON_DENSITIES)
- || context.isEnabled(ICON_MISSING_FOLDER)
- || context.isEnabled(ICON_NODPI)
- || context.isEnabled(ICON_XML_AND_PNG);
- boolean checkDipSizes = context.isEnabled(ICON_DIP_SIZE);
- boolean checkDuplicates = context.isEnabled(DUPLICATES_NAMES)
- || context.isEnabled(DUPLICATES_CONFIGURATIONS);
-
- Map<File, Dimension> pixelSizes = null;
- Map<File, Long> fileSizes = null;
- if (checkDipSizes || checkDuplicates) {
- pixelSizes = new HashMap<File, Dimension>();
- fileSizes = new HashMap<File, Long>();
- }
- Map<File, Set<String>> folderToNames = new HashMap<File, Set<String>>();
- Map<File, Set<String>> nonDpiFolderNames = new HashMap<File, Set<String>>();
- for (File folder : folders) {
- String folderName = folder.getName();
- if (folderName.startsWith(DRAWABLE_FOLDER)) {
- File[] files = folder.listFiles();
- if (files != null) {
- checkDrawableDir(context, folder, files, pixelSizes, fileSizes);
-
- if (checkFolders && DENSITY_PATTERN.matcher(folderName).matches()) {
- Set<String> names = new HashSet<String>(files.length);
- for (File f : files) {
- String name = f.getName();
- if (isDrawableFile(name)) {
- names.add(name);
- }
- }
- folderToNames.put(folder, names);
- } else if (checkFolders) {
- Set<String> names = new HashSet<String>(files.length);
- for (File f : files) {
- String name = f.getName();
- if (isDrawableFile(name)) {
- names.add(name);
- }
- }
- nonDpiFolderNames.put(folder, names);
- }
- }
- }
- }
-
- if (checkDipSizes) {
- checkDipSizes(context, pixelSizes);
- }
-
- if (checkDuplicates) {
- checkDuplicates(context, pixelSizes, fileSizes);
- }
-
- if (checkFolders && !folderToNames.isEmpty()) {
- checkDensities(context, res, folderToNames, nonDpiFolderNames);
- }
- }
- }
- }
-
- private static boolean isDrawableFile(String name) {
- // endsWith(name, DOT_PNG) is also true for endsWith(name, DOT_9PNG)
- return endsWith(name, DOT_PNG)|| endsWith(name, DOT_JPG) || endsWith(name, DOT_GIF)
- || endsWith(name, DOT_XML) || endsWith(name, DOT_JPEG);
- }
-
- // This method looks for duplicates in the assets. This uses two pieces of information
- // (file sizes and image dimensions) to quickly reject candidates, such that it only
- // needs to check actual file contents on a small subset of the available files.
- private static void checkDuplicates(Context context, Map<File, Dimension> pixelSizes,
- Map<File, Long> fileSizes) {
- Map<Long, Set<File>> sameSizes = new HashMap<Long, Set<File>>();
- Map<Long, File> seenSizes = new HashMap<Long, File>(fileSizes.size());
- for (Map.Entry<File, Long> entry : fileSizes.entrySet()) {
- File file = entry.getKey();
- Long size = entry.getValue();
- if (seenSizes.containsKey(size)) {
- Set<File> set = sameSizes.get(size);
- if (set == null) {
- set = new HashSet<File>();
- set.add(seenSizes.get(size));
- sameSizes.put(size, set);
- }
- set.add(file);
- } else {
- seenSizes.put(size, file);
- }
- }
-
- if (sameSizes.isEmpty()) {
- return;
- }
-
- // Now go through the files that have the same size and check to see if we can
- // split them apart based on image dimensions
- // Note: we may not have file sizes on all the icons; in particular,
- // we don't have file sizes for ninepatch files.
- Collection<Set<File>> candidateLists = sameSizes.values();
- for (Set<File> candidates : candidateLists) {
- Map<Dimension, Set<File>> sameDimensions = new HashMap<Dimension, Set<File>>(
- candidates.size());
- List<File> noSize = new ArrayList<File>();
- for (File file : candidates) {
- Dimension dimension = pixelSizes.get(file);
- if (dimension != null) {
- Set<File> set = sameDimensions.get(dimension);
- if (set == null) {
- set = new HashSet<File>();
- sameDimensions.put(dimension, set);
- }
- set.add(file);
- } else {
- noSize.add(file);
- }
- }
-
-
- // Files that we have no dimensions for must be compared against everything
- Collection<Set<File>> sets = sameDimensions.values();
- if (!noSize.isEmpty()) {
- if (!sets.isEmpty()) {
- for (Set<File> set : sets) {
- set.addAll(noSize);
- }
- } else {
- // Must just test the noSize elements against themselves
- HashSet<File> noSizeSet = new HashSet<File>(noSize);
- sets = Collections.<Set<File>>singletonList(noSizeSet);
- }
- }
-
- // Map from file to actual byte contents of the file.
- // We store this in a map such that for repeated files, such as noSize files
- // which can appear in multiple buckets, we only need to read them once
- Map<File, byte[]> fileContents = new HashMap<File, byte[]>();
-
- // Now we're ready for the final check where we actually check the
- // bits. We have to partition the files into buckets of files that
- // are identical.
- for (Set<File> set : sets) {
- if (set.size() < 2) {
- continue;
- }
-
- // Read all files in this set and store in map
- for (File file : set) {
- byte[] bits = fileContents.get(file);
- if (bits == null) {
- try {
- bits = context.getClient().readBytes(file);
- fileContents.put(file, bits);
- } catch (IOException e) {
- context.log(e, null);
- }
- }
- }
-
- // Map where the key file is known to be equal to the value file.
- // After we check individual files for equality this will be used
- // to look for transitive equality.
- Map<File, File> equal = new HashMap<File, File>();
-
- // Now go and compare all the files. This isn't an efficient algorithm
- // but the number of candidates should be very small
-
- List<File> files = new ArrayList<File>(set);
- Collections.sort(files);
- for (int i = 0; i < files.size() - 1; i++) {
- for (int j = i + 1; j < files.size(); j++) {
- File file1 = files.get(i);
- File file2 = files.get(j);
- byte[] contents1 = fileContents.get(file1);
- byte[] contents2 = fileContents.get(file2);
- if (contents1 == null || contents2 == null) {
- // File couldn't be read: ignore
- continue;
- }
- if (contents1.length != contents2.length) {
- // Sizes differ: not identical.
- // This shouldn't happen since we've already partitioned based
- // on File.length(), but just make sure here since the file
- // system could have lied, or cached a value that has changed
- // if the file was just overwritten
- continue;
- }
- boolean same = true;
- for (int k = 0; k < contents1.length; k++) {
- if (contents1[k] != contents2[k]) {
- same = false;
- break;
- }
- }
- if (same) {
- equal.put(file1, file2);
- }
- }
- }
-
- if (!equal.isEmpty()) {
- Map<File, Set<File>> partitions = new HashMap<File, Set<File>>();
- List<Set<File>> sameSets = new ArrayList<Set<File>>();
- for (Map.Entry<File, File> entry : equal.entrySet()) {
- File file1 = entry.getKey();
- File file2 = entry.getValue();
- Set<File> set1 = partitions.get(file1);
- Set<File> set2 = partitions.get(file2);
- if (set1 != null) {
- set1.add(file2);
- } else if (set2 != null) {
- set2.add(file1);
- } else {
- set = new HashSet<File>();
- sameSets.add(set);
- set.add(file1);
- set.add(file2);
- partitions.put(file1, set);
- partitions.put(file2, set);
- }
- }
-
- // We've computed the partitions of equal files. Now sort them
- // for stable output.
- List<List<File>> lists = new ArrayList<List<File>>();
- for (Set<File> same : sameSets) {
- assert !same.isEmpty();
- ArrayList<File> sorted = new ArrayList<File>(same);
- Collections.sort(sorted);
- lists.add(sorted);
- }
- // Sort overall partitions by the first item in each list
- Collections.sort(lists, new Comparator<List<File>>() {
- @Override
- public int compare(List<File> list1, List<File> list2) {
- return list1.get(0).compareTo(list2.get(0));
- }
- });
-
- for (List<File> sameFiles : lists) {
- Location location = null;
- boolean sameNames = true;
- String lastName = null;
- for (File file : sameFiles) {
- if (lastName != null && !lastName.equals(file.getName())) {
- sameNames = false;
- }
- lastName = file.getName();
- // Chain locations together
- Location linkedLocation = location;
- location = Location.create(file);
- location.setSecondary(linkedLocation);
- }
-
- if (sameNames) {
- StringBuilder sb = new StringBuilder(sameFiles.size() * 16);
- for (File file : sameFiles) {
- if (sb.length() > 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(file.getParentFile().getName());
- }
- String message = String.format(
- "The %1$s icon has identical contents in the following configuration folders: %2$s",
- lastName, sb.toString());
- context.report(DUPLICATES_CONFIGURATIONS, location, message, null);
- } else {
- StringBuilder sb = new StringBuilder(sameFiles.size() * 16);
- for (File file : sameFiles) {
- if (sb.length() > 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(file.getName());
- }
- String message = String.format(
- "The following unrelated icon files have identical contents: %1$s",
- sb.toString());
- context.report(DUPLICATES_NAMES, location, message, null);
- }
- }
- }
- }
- }
-
- }
-
- // This method checks the given map from resource file to pixel dimensions for each
- // such image and makes sure that the normalized dip sizes across all the densities
- // are mostly the same.
- private static void checkDipSizes(Context context, Map<File, Dimension> pixelSizes) {
- // Partition up the files such that I can look at a series by name. This
- // creates a map from filename (such as foo.png) to a list of files
- // providing that icon in various folders: drawable-mdpi/foo.png, drawable-hdpi/foo.png
- // etc.
- Map<String, List<File>> nameToFiles = new HashMap<String, List<File>>();
- for (File file : pixelSizes.keySet()) {
- String name = file.getName();
- List<File> list = nameToFiles.get(name);
- if (list == null) {
- list = new ArrayList<File>();
- nameToFiles.put(name, list);
- }
- list.add(file);
- }
-
- ArrayList<String> names = new ArrayList<String>(nameToFiles.keySet());
- Collections.sort(names);
-
- // We have to partition the files further because it's possible for the project
- // to have different configurations for an icon, such as this:
- // drawable-large-hdpi/foo.png, drawable-large-mdpi/foo.png,
- // drawable-hdpi/foo.png, drawable-mdpi/foo.png,
- // drawable-hdpi-v11/foo.png and drawable-mdpi-v11/foo.png.
- // In this case we don't want to compare across categories; we want to
- // ensure that the drawable-large-{density} icons are consistent,
- // that the drawable-{density}-v11 icons are consistent, and that
- // the drawable-{density} icons are consistent.
-
- // Map from name to list of map from parent folder to list of files
- Map<String, Map<String, List<File>>> configMap =
- new HashMap<String, Map<String,List<File>>>();
- for (Map.Entry<String, List<File>> entry : nameToFiles.entrySet()) {
- String name = entry.getKey();
- List<File> files = entry.getValue();
- for (File file : files) {
- String parentName = file.getParentFile().getName();
- // Strip out the density part
- int index = -1;
- for (String qualifier : DENSITY_QUALIFIERS) {
- index = parentName.indexOf(qualifier);
- if (index != -1) {
- parentName = parentName.substring(0, index)
- + parentName.substring(index + qualifier.length());
- break;
- }
- }
- if (index == -1) {
- // No relevant qualifier found in the parent directory name,
- // e.g. it's just "drawable" or something like "drawable-nodpi".
- continue;
- }
-
- Map<String, List<File>> folderMap = configMap.get(name);
- if (folderMap == null) {
- folderMap = new HashMap<String,List<File>>();
- configMap.put(name, folderMap);
- }
- // Map from name to a map from parent folder to files
- List<File> list = folderMap.get(parentName);
- if (list == null) {
- list = new ArrayList<File>();
- folderMap.put(parentName, list);
- }
- list.add(file);
- }
- }
-
- for (String name : names) {
- //List<File> files = nameToFiles.get(name);
- Map<String, List<File>> configurations = configMap.get(name);
- if (configurations == null) {
- // Nothing in this configuration: probably only found in drawable/ or
- // drawable-nodpi etc directories.
- continue;
- }
-
- for (Map.Entry<String, List<File>> entry : configurations.entrySet()) {
- List<File> files = entry.getValue();
-
- // Ensure that all the dip sizes are *roughly* the same
- Map<File, Dimension> dipSizes = new HashMap<File, Dimension>();
- int dipWidthSum = 0; // Incremental computation of average
- int dipHeightSum = 0; // Incremental computation of average
- int count = 0;
- for (File file : files) {
- float factor = getMdpiScalingFactor(file.getParentFile().getName());
- if (factor > 0) {
- Dimension size = pixelSizes.get(file);
- if (size == null) {
- continue;
- }
- Dimension dip = new Dimension(
- Math.round(size.width / factor),
- Math.round(size.height / factor));
- dipWidthSum += dip.width;
- dipHeightSum += dip.height;
- dipSizes.put(file, dip);
- count++;
- }
- }
- if (count == 0) {
- // Icons in drawable/ and drawable-nodpi/
- continue;
- }
- int meanWidth = dipWidthSum / count;
- int meanHeight = dipHeightSum / count;
-
- // Compute standard deviation?
- int squareWidthSum = 0;
- int squareHeightSum = 0;
- for (Dimension size : dipSizes.values()) {
- squareWidthSum += (size.width - meanWidth) * (size.width - meanWidth);
- squareHeightSum += (size.height - meanHeight) * (size.height - meanHeight);
- }
- double widthStdDev = Math.sqrt(squareWidthSum / count);
- double heightStdDev = Math.sqrt(squareHeightSum / count);
-
- if (widthStdDev > meanWidth / 10 || heightStdDev > meanHeight) {
- Location location = null;
- StringBuilder sb = new StringBuilder(100);
-
- // Sort entries by decreasing dip size
- List<Map.Entry<File, Dimension>> entries =
- new ArrayList<Map.Entry<File,Dimension>>();
- for (Map.Entry<File, Dimension> entry2 : dipSizes.entrySet()) {
- entries.add(entry2);
- }
- Collections.sort(entries,
- new Comparator<Map.Entry<File, Dimension>>() {
- @Override
- public int compare(Entry<File, Dimension> e1,
- Entry<File, Dimension> e2) {
- Dimension d1 = e1.getValue();
- Dimension d2 = e2.getValue();
- if (d1.width != d2.width) {
- return d2.width - d1.width;
- }
-
- return d2.height - d1.height;
- }
- });
- for (Map.Entry<File, Dimension> entry2 : entries) {
- if (sb.length() > 0) {
- sb.append(", ");
- }
- File file = entry2.getKey();
-
- // Chain locations together
- Location linkedLocation = location;
- location = Location.create(file);
- location.setSecondary(linkedLocation);
- Dimension dip = entry2.getValue();
- Dimension px = pixelSizes.get(file);
- String fileName = file.getParentFile().getName() + File.separator
- + file.getName();
- sb.append(String.format("%1$s: %2$dx%3$d dp (%4$dx%5$d px)",
- fileName, dip.width, dip.height, px.width, px.height));
- }
- String message = String.format(
- "The image %1$s varies significantly in its density-independent (dip) " +
- "size across the various density versions: %2$s",
- name, sb.toString());
- context.report(ICON_DIP_SIZE, location, message, null);
- }
- }
- }
- }
-
- private static void checkDensities(Context context, File res,
- Map<File, Set<String>> folderToNames,
- Map<File, Set<String>> nonDpiFolderNames) {
- // TODO: Is there a way to look at the manifest and figure out whether
- // all densities are expected to be needed?
- // Note: ldpi is probably not needed; it has very little usage
- // (about 2%; http://developer.android.com/resources/dashboard/screens.html)
- // TODO: Use the matrix to check out if we can eliminate densities based
- // on the target screens?
-
- Set<String> definedDensities = new HashSet<String>();
- for (File f : folderToNames.keySet()) {
- definedDensities.add(f.getName());
- }
-
- // Look for missing folders -- if you define say drawable-mdpi then you
- // should also define -hdpi and -xhdpi.
- if (context.isEnabled(ICON_MISSING_FOLDER)) {
- List<String> missing = new ArrayList<String>();
- for (String density : REQUIRED_DENSITIES) {
- if (!definedDensities.contains(density)) {
- missing.add(density);
- }
- }
- if (!missing.isEmpty()) {
- context.report(
- ICON_MISSING_FOLDER,
- Location.create(res),
- String.format("Missing density variation folders in %1$s: %2$s",
- context.getProject().getDisplayPath(res),
- LintUtils.formatList(missing, -1)),
- null);
- }
- }
-
- if (context.isEnabled(ICON_NODPI)) {
- Set<String> noDpiNames = new HashSet<String>();
- for (Map.Entry<File, Set<String>> entry : folderToNames.entrySet()) {
- if (isNoDpiFolder(entry.getKey())) {
- noDpiNames.addAll(entry.getValue());
- }
- }
- if (!noDpiNames.isEmpty()) {
- // Make sure that none of the nodpi names appear in a non-nodpi folder
- Set<String> inBoth = new HashSet<String>();
- List<File> files = new ArrayList<File>();
- for (Map.Entry<File, Set<String>> entry : folderToNames.entrySet()) {
- File folder = entry.getKey();
- String folderName = folder.getName();
- if (!isNoDpiFolder(folder)) {
- assert DENSITY_PATTERN.matcher(folderName).matches();
- Set<String> overlap = nameIntersection(noDpiNames, entry.getValue());
- inBoth.addAll(overlap);
- for (String name : overlap) {
- files.add(new File(folder, name));
- }
- }
- }
-
- if (!inBoth.isEmpty()) {
- List<String> list = new ArrayList<String>(inBoth);
- Collections.sort(list);
-
- // Chain locations together
- Collections.sort(files);
- Location location = null;
- for (File file : files) {
- Location linkedLocation = location;
- location = Location.create(file);
- location.setSecondary(linkedLocation);
- }
-
- context.report(ICON_NODPI, location,
- String.format(
- "The following images appear in both -nodpi and in a density folder: %1$s",
- LintUtils.formatList(list,
- context.getDriver().isAbbreviating() ? 10 : -1)),
- null);
- }
- }
- }
-
- if (context.isEnabled(ICON_XML_AND_PNG)) {
- Map<File, Set<String>> folderMap = Maps.newHashMap(folderToNames);
- folderMap.putAll(nonDpiFolderNames);
- Set<String> xmlNames = Sets.newHashSetWithExpectedSize(100);
- Set<String> bitmapNames = Sets.newHashSetWithExpectedSize(100);
-
- for (Map.Entry<File, Set<String>> entry : folderMap.entrySet()) {
- Set<String> names = entry.getValue();
- for (String name : names) {
- if (endsWith(name, DOT_XML)) {
- xmlNames.add(name);
- } else if (isDrawableFile(name)) {
- bitmapNames.add(name);
- }
- }
- }
- if (!xmlNames.isEmpty() && !bitmapNames.isEmpty()) {
- // Make sure that none of the nodpi names appear in a non-nodpi folder
- Set<String> overlap = nameIntersection(xmlNames, bitmapNames);
- if (!overlap.isEmpty()) {
- Multimap<String, File> map = ArrayListMultimap.create();
- Set<String> bases = Sets.newHashSetWithExpectedSize(overlap.size());
- for (String name : overlap) {
- bases.add(LintUtils.getBaseName(name));
- }
-
- for (String base : bases) {
- for (Map.Entry<File, Set<String>> entry : folderMap.entrySet()) {
- File folder = entry.getKey();
- for (String n : entry.getValue()) {
- if (base.equals(LintUtils.getBaseName(n))) {
- map.put(base, new File(folder, n));
- }
- }
- }
- }
- List<String> sorted = new ArrayList<String>(map.keySet());
- Collections.sort(sorted);
- for (String name : sorted) {
- List<File> lists = Lists.newArrayList(map.get(name));
- Collections.sort(lists);
-
- // Chain locations together
- Location location = null;
- for (File file : lists) {
- Location linkedLocation = location;
- location = Location.create(file);
- location.setSecondary(linkedLocation);
- }
-
- List<String> fileNames = Lists.newArrayList();
- boolean seenXml = false;
- boolean seenNonXml = false;
- for (File f : lists) {
- boolean isXml = endsWith(f.getPath(), DOT_XML);
- if (isXml && !seenXml) {
- fileNames.add(context.getProject().getDisplayPath(f));
- seenXml = true;
- } else if (!isXml && !seenNonXml) {
- fileNames.add(context.getProject().getDisplayPath(f));
- seenNonXml = true;
- }
- }
-
- context.report(ICON_XML_AND_PNG, location,
- String.format(
- "The following images appear both as density independent .xml files and as bitmap files: %1$s",
- LintUtils.formatList(fileNames,
- context.getDriver().isAbbreviating() ? 10 : -1)),
- null);
- }
- }
- }
- }
-
- if (context.isEnabled(ICON_DENSITIES)) {
- // Look for folders missing some of the specific assets
- Set<String> allNames = new HashSet<String>();
- for (Entry<File,Set<String>> entry : folderToNames.entrySet()) {
- if (!isNoDpiFolder(entry.getKey())) {
- Set<String> names = entry.getValue();
- allNames.addAll(names);
- }
- }
-
- for (Map.Entry<File, Set<String>> entry : folderToNames.entrySet()) {
- File file = entry.getKey();
- if (isNoDpiFolder(file)) {
- continue;
- }
- Set<String> names = entry.getValue();
- if (names.size() != allNames.size()) {
- List<String> delta = new ArrayList<String>(nameDifferences(allNames, names));
- if (delta.isEmpty()) {
- continue;
- }
- Collections.sort(delta);
- String foundIn = "";
- if (delta.size() == 1) {
- // Produce list of where the icon is actually defined
- List<String> defined = new ArrayList<String>();
- String name = delta.get(0);
- for (Map.Entry<File, Set<String>> e : folderToNames.entrySet()) {
- if (e.getValue().contains(name)) {
- defined.add(e.getKey().getName());
- }
- }
- if (!defined.isEmpty()) {
- foundIn = String.format(" (found in %1$s)",
- LintUtils.formatList(defined,
- context.getDriver().isAbbreviating() ? 5 : -1));
- }
- }
-
- context.report(ICON_DENSITIES, Location.create(file),
- String.format(
- "Missing the following drawables in %1$s: %2$s%3$s",
- file.getName(),
- LintUtils.formatList(delta,
- context.getDriver().isAbbreviating() ? 5 : -1),
- foundIn),
- null);
- }
- }
- }
- }
-
- /**
- * Compute the difference in names between a and b. This is not just
- * Sets.difference(a, b) because we want to make the comparisons <b>without
- * file extensions</b> and return the result <b>with</b>..
- */
- private static Set<String> nameDifferences(Set<String> a, Set<String> b) {
- Set<String> names1 = new HashSet<String>(a.size());
- for (String s : a) {
- names1.add(LintUtils.getBaseName(s));
- }
- Set<String> names2 = new HashSet<String>(b.size());
- for (String s : b) {
- names2.add(LintUtils.getBaseName(s));
- }
-
- names1.removeAll(names2);
-
- if (!names1.isEmpty()) {
- // Map filenames back to original filenames with extensions
- Set<String> result = new HashSet<String>(names1.size());
- for (String s : a) {
- if (names1.contains(LintUtils.getBaseName(s))) {
- result.add(s);
- }
- }
- for (String s : b) {
- if (names1.contains(LintUtils.getBaseName(s))) {
- result.add(s);
- }
- }
-
- return result;
- }
-
- return Collections.emptySet();
- }
-
- /**
- * Compute the intersection in names between a and b. This is not just
- * Sets.intersection(a, b) because we want to make the comparisons <b>without
- * file extensions</b> and return the result <b>with</b>.
- */
- private static Set<String> nameIntersection(Set<String> a, Set<String> b) {
- Set<String> names1 = new HashSet<String>(a.size());
- for (String s : a) {
- names1.add(LintUtils.getBaseName(s));
- }
- Set<String> names2 = new HashSet<String>(b.size());
- for (String s : b) {
- names2.add(LintUtils.getBaseName(s));
- }
-
- names1.retainAll(names2);
-
- if (!names1.isEmpty()) {
- // Map filenames back to original filenames with extensions
- Set<String> result = new HashSet<String>(names1.size());
- for (String s : a) {
- if (names1.contains(LintUtils.getBaseName(s))) {
- result.add(s);
- }
- }
- for (String s : b) {
- if (names1.contains(LintUtils.getBaseName(s))) {
- result.add(s);
- }
- }
-
- return result;
- }
-
- return Collections.emptySet();
- }
-
- private static boolean isNoDpiFolder(File file) {
- return file.getName().contains("-nodpi");
- }
-
- private Map<File, BufferedImage> mImageCache;
-
- @Nullable
- private BufferedImage getImage(@Nullable File file) throws IOException {
- if (mImageCache == null) {
- mImageCache = Maps.newHashMap();
- } else {
- BufferedImage image = mImageCache.get(file);
- if (image != null) {
- return image;
- }
- }
-
- BufferedImage image = ImageIO.read(file);
- mImageCache.put(file, image);
-
- return image;
- }
-
- private void checkDrawableDir(Context context, File folder, File[] files,
- Map<File, Dimension> pixelSizes, Map<File, Long> fileSizes) {
- if (folder.getName().equals(DRAWABLE_FOLDER)
- && context.isEnabled(ICON_LOCATION) &&
- // If supporting older versions than Android 1.6, it's not an error
- // to include bitmaps in drawable/
- context.getProject().getMinSdk() >= 4) {
- for (File file : files) {
- String name = file.getName();
- if (name.endsWith(DOT_XML)) {
- // pass - most common case, avoids checking other extensions
- } else if (endsWith(name, DOT_PNG)
- || endsWith(name, DOT_JPG)
- || endsWith(name, DOT_JPEG)
- || endsWith(name, DOT_GIF)) {
- context.report(ICON_LOCATION,
- Location.create(file),
- String.format("Found bitmap drawable res/drawable/%1$s in " +
- "densityless folder",
- file.getName()),
- null);
- }
- }
- }
-
- if (context.isEnabled(GIF_USAGE)) {
- for (File file : files) {
- String name = file.getName();
- if (endsWith(name, DOT_GIF)) {
- context.report(GIF_USAGE, Location.create(file),
- "Using the .gif format for bitmaps is discouraged",
- null);
- }
- }
- }
-
- if (context.isEnabled(ICON_EXTENSION)) {
- for (File file : files) {
- String path = file.getPath();
- if (isDrawableFile(path) && !endsWith(path, DOT_XML)) {
- checkExtension(context, file);
- }
- }
- }
-
- if (context.isEnabled(ICON_COLORS)) {
- for (File file : files) {
- String name = file.getName();
-
- if (isDrawableFile(name)
- && !endsWith(name, DOT_XML)
- && !endsWith(name, DOT_9PNG)) {
- String baseName = getBaseName(name);
- boolean isActionBarIcon = isActionBarIcon(context, baseName, file);
- if (isActionBarIcon || isNotificationIcon(baseName)) {
- Dimension size = checkColor(context, file, isActionBarIcon);
-
- // Store dimension for size check if we went to the trouble of reading image
- if (size != null && pixelSizes != null) {
- pixelSizes.put(file, size);
- }
- }
- }
- }
- }
-
- if (context.isEnabled(ICON_LAUNCHER_SHAPE)) {
- // Look up launcher icon name
- for (File file : files) {
- String name = file.getName();
- if (isLauncherIcon(getBaseName(name))
- && !endsWith(name, DOT_XML)
- && !endsWith(name, DOT_9PNG)) {
- checkLauncherShape(context, file);
- }
- }
- }
-
- // Check icon sizes
- if (context.isEnabled(ICON_EXPECTED_SIZE)) {
- checkExpectedSizes(context, folder, files);
- }
-
- if (pixelSizes != null || fileSizes != null) {
- for (File file : files) {
- // TODO: Combine this check with the check for expected sizes such that
- // I don't check file sizes twice!
- String fileName = file.getName();
-
- if (endsWith(fileName, DOT_PNG) || endsWith(fileName, DOT_JPG)
- || endsWith(fileName, DOT_JPEG)) {
- // Only scan .png files (except 9-patch png's) and jpg files for
- // dip sizes. Duplicate checks can also be performed on ninepatch files.
- if (pixelSizes != null && !endsWith(fileName, DOT_9PNG)
- && !pixelSizes.containsKey(file)) { // already read by checkColor?
- Dimension size = getSize(file);
- pixelSizes.put(file, size);
- }
- if (fileSizes != null) {
- fileSizes.put(file, file.length());
- }
- }
- }
- }
-
- mImageCache = null;
- }
-
- /**
- * Check that launcher icons do not fill every pixel in the image
- */
- private void checkLauncherShape(Context context, File file) {
- try {
- BufferedImage image = getImage(file);
- if (image != null) {
- // TODO: see if the shape is rectangular but inset from outer rectangle; if so
- // that's probably not right either!
- for (int y = 0, height = image.getHeight(); y < height; y++) {
- for (int x = 0, width = image.getWidth(); x < width; x++) {
- int rgb = image.getRGB(x, y);
- if ((rgb & 0xFF000000) == 0) {
- return;
- }
- }
- }
-
- String message = "Launcher icons should not fill every pixel of their square " +
- "region; see the design guide for details";
- context.report(ICON_LAUNCHER_SHAPE, Location.create(file),
- message, null);
- }
- } catch (IOException e) {
- // Pass: ignore files we can't read
- }
- }
-
- /**
- * Check whether the icons in the file are okay. Also return the image size
- * if known (for use by other checks)
- */
- private Dimension checkColor(Context context, File file, boolean isActionBarIcon) {
- int folderVersion = Context.getFolderVersion(file);
- if (isActionBarIcon) {
- if (folderVersion != -1 && folderVersion < 11
- || !isAndroid30(context, folderVersion)) {
- return null;
- }
- } else {
- if (folderVersion != -1 && folderVersion < 9
- || !isAndroid23(context, folderVersion)
- && !isAndroid30(context, folderVersion)) {
- return null;
- }
- }
-
- // TODO: This only checks icons that are known to be using the Holo style.
- // However, if the user has minSdk < 11 as well as targetSdk > 11, we should
- // also check that they actually include a -v11 or -v14 folder with proper
- // icons, since the below won't flag the older icons.
- try {
- BufferedImage image = getImage(file);
- if (image != null) {
- if (isActionBarIcon) {
- checkPixels:
- for (int y = 0, height = image.getHeight(); y < height; y++) {
- for (int x = 0, width = image.getWidth(); x < width; x++) {
- int rgb = image.getRGB(x, y);
- if ((rgb & 0xFF000000) != 0) { // else: transparent
- int r = (rgb & 0xFF0000) >>> 16;
- int g = (rgb & 0x00FF00) >>> 8;
- int b = (rgb & 0x0000FF);
- if (r != g || r != b) {
- String message = "Action Bar icons should use a single gray "
- + "color (#333333 for light themes (with 60%/30% "
- + "opacity for enabled/disabled), and #FFFFFF with "
- + "opacity 80%/30% for dark themes";
- context.report(ICON_COLORS, Location.create(file),
- message, null);
- break checkPixels;
- }
- }
- }
- }
- } else {
- if (folderVersion >= 11 || isAndroid30(context, folderVersion)) {
- // Notification icons. Should be white as of API 14
- checkPixels:
- for (int y = 0, height = image.getHeight(); y < height; y++) {
- for (int x = 0, width = image.getWidth(); x < width; x++) {
- int rgb = image.getRGB(x, y);
- if ((rgb & 0xFF000000) != 0
- && rgb != 0xFFFFFFFF) {
- int r = (rgb & 0xFF0000) >>> 16;
- int g = (rgb & 0x00FF00) >>> 8;
- int b = (rgb & 0x0000FF);
- if (r == g && r == b) {
- // If the pixel is not white, it might be because of
- // anti-aliasing. In that case, at least one neighbor
- // should be of a different color
- if (x < width - 1 && rgb != image.getRGB(x + 1, y)) {
- continue;
- }
- if (x > 0 && rgb != image.getRGB(x - 1, y)) {
- continue;
- }
- if (y < height - 1 && rgb != image.getRGB(x, y + 1)) {
- continue;
- }
- if (y > 0 && rgb != image.getRGB(x, y - 1)) {
- continue;
- }
- }
-
- String message = "Notification icons must be entirely white";
- context.report(ICON_COLORS, Location.create(file),
- message, null);
- break checkPixels;
- }
- }
- }
- } else {
- // As of API 9, should be gray.
- checkPixels:
- for (int y = 0, height = image.getHeight(); y < height; y++) {
- for (int x = 0, width = image.getWidth(); x < width; x++) {
- int rgb = image.getRGB(x, y);
- if ((rgb & 0xFF000000) != 0) { // else: transparent
- int r = (rgb & 0xFF0000) >>> 16;
- int g = (rgb & 0x00FF00) >>> 8;
- int b = (rgb & 0x0000FF);
- if (r != g || r != b) {
- String message = "Notification icons should not use "
- + "colors";
- context.report(ICON_COLORS, Location.create(file),
- message, null);
- break checkPixels;
- }
- }
- }
- }
- }
- }
-
- return new Dimension(image.getWidth(), image.getHeight());
- }
- } catch (IOException e) {
- // Pass: ignore files we can't read
- }
-
- return null;
- }
-
- private static void checkExtension(Context context, File file) {
- try {
- ImageInputStream input = ImageIO.createImageInputStream(file);
- if (input != null) {
- try {
- Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
- while (readers.hasNext()) {
- ImageReader reader = readers.next();
- try {
- reader.setInput(input);
-
- // Check file extension
- String formatName = reader.getFormatName();
- if (formatName != null && !formatName.isEmpty()) {
- String path = file.getPath();
- int index = path.lastIndexOf('.');
- String extension = path.substring(index+1).toLowerCase(Locale.US);
-
- if (!formatName.equalsIgnoreCase(extension)) {
- if (endsWith(path, DOT_JPG)
- && formatName.equals("JPEG")) { //$NON-NLS-1$
- return;
- }
- String message = String.format(
- "Misleading file extension; named .%1$s but the " +
- "file format is %2$s", extension, formatName);
- Location location = Location.create(file);
- context.report(ICON_EXTENSION, location, message, null);
- }
- break;
- }
- } finally {
- reader.dispose();
- }
- }
- } finally {
- if (input != null) {
- input.close();
- }
- }
- }
- } catch (IOException e) {
- // Pass -- we can't handle all image types, warn about those we can
- }
- }
-
- private static String getBaseName(String name) {
- String baseName = name;
- int index = baseName.indexOf('.');
- if (index != -1) {
- baseName = baseName.substring(0, index);
- }
-
- return baseName;
- }
-
- private void checkExpectedSizes(Context context, File folder, File[] files) {
- if (files == null || files.length == 0) {
- return;
- }
-
- String folderName = folder.getName();
- int folderVersion = Context.getFolderVersion(files[0]);
-
- for (File file : files) {
- String name = file.getName();
-
- // TODO: Look up exact app icon from the manifest rather than simply relying on
- // the naming conventions described here:
- // http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#design-tips
- // See if we can figure out other types of icons from usage too.
-
- String baseName = getBaseName(name);
-
- if (isLauncherIcon(baseName)) {
- // Launcher icons
- checkSize(context, folderName, file, 48, 48, true /*exact*/);
- } else if (isActionBarIcon(baseName)) {
- checkSize(context, folderName, file, 32, 32, true /*exact*/);
- } else if (name.startsWith("ic_dialog_")) { //$NON-NLS-1$
- // Dialog
- checkSize(context, folderName, file, 32, 32, true /*exact*/);
- } else if (name.startsWith("ic_tab_")) { //$NON-NLS-1$
- // Tab icons
- checkSize(context, folderName, file, 32, 32, true /*exact*/);
- } else if (isNotificationIcon(baseName)) {
- // Notification icons
- if (isAndroid30(context, folderVersion)) {
- checkSize(context, folderName, file, 24, 24, true /*exact*/);
- } else if (isAndroid23(context, folderVersion)) {
- checkSize(context, folderName, file, 16, 25, false /*exact*/);
- } else {
- // Android 2.2 or earlier
- // TODO: Should this be done for each folder size?
- checkSize(context, folderName, file, 25, 25, true /*exact*/);
- }
- } else if (name.startsWith("ic_menu_")) { //$NON-NLS-1$
- if (isAndroid30(context, folderVersion)) {
- // Menu icons (<=2.3 only: Replaced by action bar icons (ic_action_ in 3.0).
- // However the table halfway down the page on
- // http://developer.android.com/guide/practices/ui_guidelines/icon_design.html
- // and the README in the icon template download says that convention is ic_menu
- checkSize(context, folderName, file, 32, 32, true);
- } else if (isAndroid23(context, folderVersion)) {
- // The icon should be 32x32 inside the transparent image; should
- // we check that this is mostly the case (a few pixels are allowed to
- // overlap for anti-aliasing etc)
- checkSize(context, folderName, file, 48, 48, true /*exact*/);
- } else {
- // Android 2.2 or earlier
- // TODO: Should this be done for each folder size?
- checkSize(context, folderName, file, 48, 48, true /*exact*/);
- }
- }
- // TODO: ListView icons?
- }
- }
-
- /**
- * Is this drawable folder for an Android 3.0 drawable? This will be the
- * case if it specifies -v11+, or if the minimum SDK version declared in the
- * manifest is at least 11.
- */
- private static boolean isAndroid30(Context context, int folderVersion) {
- return folderVersion >= 11 || context.getMainProject().getMinSdk() >= 11;
- }
-
- /**
- * Is this drawable folder for an Android 2.3 drawable? This will be the
- * case if it specifies -v9 or -v10, or if the minimum SDK version declared in the
- * manifest is 9 or 10 (and it does not specify some higher version like -v11
- */
- private static boolean isAndroid23(Context context, int folderVersion) {
- if (isAndroid30(context, folderVersion)) {
- return false;
- }
-
- if (folderVersion == 9 || folderVersion == 10) {
- return true;
- }
-
- int minSdk = context.getMainProject().getMinSdk();
-
- return minSdk == 9 || minSdk == 10;
- }
-
- private static float getMdpiScalingFactor(String folderName) {
- // Can't do startsWith(DRAWABLE_MDPI) because the folder could
- // be something like "drawable-sw600dp-mdpi".
- if (folderName.contains("-mdpi")) { //$NON-NLS-1$
- return 1.0f;
- } else if (folderName.contains("-hdpi")) { //$NON-NLS-1$
- return 1.5f;
- } else if (folderName.contains("-xhdpi")) { //$NON-NLS-1$
- return 2.0f;
- } else if (folderName.contains("-ldpi")) { //$NON-NLS-1$
- return 0.75f;
- } else {
- return 0f;
- }
- }
-
- private static void checkSize(Context context, String folderName, File file,
- int mdpiWidth, int mdpiHeight, boolean exactMatch) {
- String fileName = file.getName();
- // Only scan .png files (except 9-patch png's) and jpg files
- if (!((endsWith(fileName, DOT_PNG) && !endsWith(fileName, DOT_9PNG)) ||
- endsWith(fileName, DOT_JPG) || endsWith(fileName, DOT_JPEG))) {
- return;
- }
-
- int width;
- int height;
- // Use 3:4:6:8 scaling ratio to look up the other expected sizes
- if (folderName.startsWith(DRAWABLE_MDPI)) {
- width = mdpiWidth;
- height = mdpiHeight;
- } else if (folderName.startsWith(DRAWABLE_HDPI)) {
- // Perform math using floating point; if we just do
- // width = mdpiWidth * 3 / 2;
- // then for mdpiWidth = 25 (as in notification icons on pre-GB) we end up
- // with width = 37, instead of 38 (with floating point rounding we get 37.5 = 38)
- width = Math.round(mdpiWidth * 3.f / 2);
- height = Math.round(mdpiHeight * 3f / 2);
- } else if (folderName.startsWith(DRAWABLE_XHDPI)) {
- width = mdpiWidth * 2;
- height = mdpiHeight * 2;
- } else if (folderName.startsWith(DRAWABLE_LDPI)) {
- width = Math.round(mdpiWidth * 3f / 4);
- height = Math.round(mdpiHeight * 3f / 4);
- } else {
- return;
- }
-
- Dimension size = getSize(file);
- if (size != null) {
- if (exactMatch && size.width != width || size.height != height) {
- context.report(
- ICON_EXPECTED_SIZE,
- Location.create(file),
- String.format(
- "Incorrect icon size for %1$s: expected %2$dx%3$d, but was %4$dx%5$d",
- folderName + File.separator + file.getName(),
- width, height, size.width, size.height),
- null);
- } else if (!exactMatch && size.width > width || size.height > height) {
- context.report(
- ICON_EXPECTED_SIZE,
- Location.create(file),
- String.format(
- "Incorrect icon size for %1$s: icon size should be at most %2$dx%3$d, but was %4$dx%5$d",
- folderName + File.separator + file.getName(),
- width, height, size.width, size.height),
- null);
- }
- }
- }
-
- private static Dimension getSize(File file) {
- try {
- ImageInputStream input = ImageIO.createImageInputStream(file);
- if (input != null) {
- try {
- Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
- if (readers.hasNext()) {
- ImageReader reader = readers.next();
- try {
- reader.setInput(input);
- return new Dimension(reader.getWidth(0), reader.getHeight(0));
- } finally {
- reader.dispose();
- }
- }
- } finally {
- if (input != null) {
- input.close();
- }
- }
- }
-
- // Fallback: read the image using the normal means
- BufferedImage image = ImageIO.read(file);
- if (image != null) {
- return new Dimension(image.getWidth(), image.getHeight());
- } else {
- return null;
- }
- } catch (IOException e) {
- // Pass -- we can't handle all image types, warn about those we can
- return null;
- }
- }
-
-
- private Set<String> mActionBarIcons;
- private Set<String> mNotificationIcons;
- private Set<String> mLauncherIcons;
- private Multimap<String, String> mMenuToIcons;
-
- private boolean isLauncherIcon(String name) {
- assert name.indexOf('.') == -1; // Should supply base name
-
- // Naming convention
- if (name.startsWith("ic_launcher")) { //$NON-NLS-1$
- return true;
- }
- return mLauncherIcons != null && mLauncherIcons.contains(name);
- }
-
- private boolean isNotificationIcon(String name) {
- assert name.indexOf('.') == -1; // Should supply base name
-
- // Naming convention
- if (name.startsWith("ic_stat_")) { //$NON-NLS-1$
- return true;
- }
-
- return mNotificationIcons != null && mNotificationIcons.contains(name);
- }
-
- private boolean isActionBarIcon(String name) {
- assert name.indexOf('.') == -1; // Should supply base name
-
- // Naming convention
- if (name.startsWith("ic_action_")) { //$NON-NLS-1$
- return true;
- }
-
- // Naming convention
-
- return mActionBarIcons != null && mActionBarIcons.contains(name);
- }
-
- private boolean isActionBarIcon(Context context, String name, File file) {
- if (isActionBarIcon(name)) {
- return true;
- }
-
- // As of Android 3.0 ic_menu_ are action icons
- if (file != null && name.startsWith("ic_menu_") //$NON-NLS-1$
- && isAndroid30(context, Context.getFolderVersion(file))) {
- // Naming convention
- return true;
- }
-
- return false;
- }
-
- // XML detector: Skim manifest and menu files
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return file.getName().equals(ANDROID_MANIFEST_XML);
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.MENU;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- // Manifest
- TAG_APPLICATION,
- TAG_ACTIVITY,
- TAG_SERVICE,
- TAG_PROVIDER,
- TAG_RECEIVER,
-
- // Menu
- TAG_ITEM
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String icon = element.getAttributeNS(ANDROID_URI, ATTR_ICON);
- if (icon != null && icon.startsWith(DRAWABLE_PREFIX)) {
- icon = icon.substring(DRAWABLE_PREFIX.length());
-
- String tagName = element.getTagName();
- if (tagName.equals(TAG_ITEM)) {
- if (mMenuToIcons == null) {
- mMenuToIcons = ArrayListMultimap.create();
- }
- String menu = getBaseName(context.file.getName());
- mMenuToIcons.put(menu, icon);
- } else {
- // Manifest tags: launcher icons
- if (mLauncherIcons == null) {
- mLauncherIcons = Sets.newHashSet();
- }
- mLauncherIcons.add(icon);
- }
- }
- }
-
-
- // ---- Implements JavaScanner ----
-
- private static final String NOTIFICATION_CLASS = "Notification"; //$NON-NLS-1$
- private static final String NOTIFICATION_COMPAT_CLASS = "NotificationCompat"; //$NON-NLS-1$
- private static final String BUILDER_CLASS = "Builder"; //$NON-NLS-1$
- private static final String SET_SMALL_ICON = "setSmallIcon"; //$NON-NLS-1$
- private static final String ON_CREATE_OPTIONS_MENU = "onCreateOptionsMenu"; //$NON-NLS-1$
-
- @Override
- @Nullable
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new NotificationFinder();
- }
-
- @Override
- @Nullable
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- List<Class<? extends Node>> types = new ArrayList<Class<? extends Node>>(3);
- types.add(MethodDeclaration.class);
- types.add(ConstructorInvocation.class);
- return types;
- }
-
- private final class NotificationFinder extends ForwardingAstVisitor {
- @Override
- public boolean visitMethodDeclaration(MethodDeclaration node) {
- if (ON_CREATE_OPTIONS_MENU.equals(node.astMethodName().astValue())) {
- // Gather any R.menu references found in this method
- node.accept(new MenuFinder());
- }
-
- return super.visitMethodDeclaration(node);
- }
-
- @Override
- public boolean visitConstructorInvocation(ConstructorInvocation node) {
- TypeReference reference = node.astTypeReference();
- StrictListAccessor<TypeReferencePart, TypeReference> parts = reference.astParts();
- String typeName = parts.last().astIdentifier().astValue();
- if (NOTIFICATION_CLASS.equals(typeName)) {
- StrictListAccessor<Expression, ConstructorInvocation> args = node.astArguments();
- if (args.size() == 3) {
- if (args.first() instanceof Select && handleSelect((Select) args.first())) {
- return super.visitConstructorInvocation(node);
- }
-
- Node method = StringFormatDetector.getParentMethod(node);
- if (method != null) {
- // Must track local types
- String name = StringFormatDetector.getResourceForFirstArg(method, node);
- if (name != null) {
- if (mNotificationIcons == null) {
- mNotificationIcons = Sets.newHashSet();
- }
- mNotificationIcons.add(name);
- }
- }
- }
- } else if (BUILDER_CLASS.equals(typeName)) {
- boolean isBuilder = false;
- if (parts.size() == 1) {
- isBuilder = true;
- } else if (parts.size() == 2) {
- String clz = parts.first().astIdentifier().astValue();
- if (NOTIFICATION_CLASS.equals(clz) || NOTIFICATION_COMPAT_CLASS.equals(clz)) {
- isBuilder = true;
- }
- }
- if (isBuilder) {
- Node method = StringFormatDetector.getParentMethod(node);
- if (method != null) {
- SetIconFinder finder = new SetIconFinder();
- method.accept(finder);
- }
- }
- }
-
- return super.visitConstructorInvocation(node);
- }
- }
-
- private boolean handleSelect(Select select) {
- if (select.toString().startsWith(R_DRAWABLE_PREFIX)) {
- String name = select.astIdentifier().astValue();
- if (mNotificationIcons == null) {
- mNotificationIcons = Sets.newHashSet();
- }
- mNotificationIcons.add(name);
-
- return true;
- }
-
- return false;
- }
-
- private final class SetIconFinder extends ForwardingAstVisitor {
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (SET_SMALL_ICON.equals(node.astName().astValue())) {
- StrictListAccessor<Expression,MethodInvocation> arguments = node.astArguments();
- if (arguments.size() == 1 && arguments.first() instanceof Select) {
- handleSelect((Select) arguments.first());
- }
- }
- return super.visitMethodInvocation(node);
- }
- }
-
- private final class MenuFinder extends ForwardingAstVisitor {
- @Override
- public boolean visitSelect(Select node) {
- // R.type.name
- if (node.astOperand() instanceof Select) {
- Select select = (Select) node.astOperand();
- if (select.astOperand() instanceof VariableReference) {
- VariableReference reference = (VariableReference) select.astOperand();
- if (reference.astIdentifier().astValue().equals(R_CLASS)) {
- String type = select.astIdentifier().astValue();
-
- if (type.equals(MENU_TYPE)) {
- String name = node.astIdentifier().astValue();
- // Reclassify icons in the given menu as action bar icons
- if (mMenuToIcons != null) {
- Collection<String> icons = mMenuToIcons.get(name);
- if (icons != null) {
- if (mActionBarIcons == null) {
- mActionBarIcons = Sets.newHashSet();
- }
- mActionBarIcons.addAll(icons);
- }
- }
- }
- }
- }
- }
-
- return super.visitSelect(node);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InefficientWeightDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InefficientWeightDetector.java
deleted file mode 100644
index 0608de1..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InefficientWeightDetector.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BASELINE_ALIGNED;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-import static com.android.SdkConstants.VIEW;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-import static com.android.SdkConstants.VIEW_TAG;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Checks whether a layout_weight is declared inefficiently.
- */
-public class InefficientWeightDetector extends LayoutDetector {
-
- /** Can a weight be replaced with 0dp instead for better performance? */
- public static final Issue INEFFICIENT_WEIGHT = Issue.create(
- "InefficientWeight", //$NON-NLS-1$
- "Looks for inefficient weight declarations in LinearLayouts",
- "When only a single widget in a LinearLayout defines a weight, it is more " +
- "efficient to assign a width/height of `0dp` to it since it will absorb all " +
- "the remaining space anyway. With a declared width/height of `0dp` it " +
- "does not have to measure its own size first.",
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- InefficientWeightDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Are weights nested? */
- public static final Issue NESTED_WEIGHTS = Issue.create(
- "NestedWeights", //$NON-NLS-1$
- "Looks for nested layout weights, which are costly",
- "Layout weights require a widget to be measured twice. When a LinearLayout with " +
- "non-zero weights is nested inside another LinearLayout with non-zero weights, " +
- "then the number of measurements increase exponentially.",
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- InefficientWeightDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Should a LinearLayout set android:baselineAligned? */
- public static final Issue BASELINE_WEIGHTS = Issue.create(
- "DisableBaselineAlignment", //$NON-NLS-1$
- "Looks for LinearLayouts which should set android:baselineAligned=false",
- "When a LinearLayout is used to distribute the space proportionally between " +
- "nested layouts, the baseline alignment property should be turned off to " +
- "make the layout computation faster.",
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- InefficientWeightDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Using 0dp on the wrong dimension */
- public static final Issue WRONG_0DP = Issue.create(
- "Suspicious0dp", //$NON-NLS-1$
- "Looks for 0dp as the width in a vertical LinearLayout or as the height in a " +
- "horizontal",
-
- "Using 0dp as the width in a horizontal LinearLayout with weights is a useful " +
- "trick to ensure that only the weights (and not the intrinsic sizes) are used " +
- "when sizing the children.\n" +
- "\n" +
- "However, if you use 0dp for the opposite dimension, the view will be invisible. " +
- "This can happen if you change the orientation of a layout without also flipping " +
- "the 0dp dimension in all the children.",
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- InefficientWeightDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Missing explicit orientation */
- public static final Issue ORIENTATION = Issue.create(
- "Orientation", //$NON-NLS-1$
- "Checks that LinearLayouts with multiple children set the orientation",
-
- "The default orientation of a LinearLayout is horizontal. It's pretty easy to "
- + "believe that the layout is vertical, add multiple children to it, and wonder "
- + "why only the first child is visible (when the subsequent children are "
- + "off screen to the right). This lint rule helps pinpoint this issue by "
- + "warning whenever a LinearLayout is used with an implicit orientation "
- + "and multiple children.",
-
- Category.CORRECTNESS,
- 2,
- Severity.ERROR,
- InefficientWeightDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Map from element to whether that element has a non-zero linear layout
- * weight or has an ancestor which does
- */
- private final Map<Node, Boolean> mInsideWeight = new IdentityHashMap<Node, Boolean>();
-
- /** Constructs a new {@link InefficientWeightDetector} */
- public InefficientWeightDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(LINEAR_LAYOUT);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- List<Element> children = LintUtils.getChildren(element);
- // See if there is exactly one child with a weight
- boolean multipleWeights = false;
- Element weightChild = null;
- boolean checkNesting = context.isEnabled(NESTED_WEIGHTS);
- for (Element child : children) {
- if (child.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT)) {
- if (weightChild != null) {
- // More than one child defining a weight!
- multipleWeights = true;
- } else if (!multipleWeights) {
- weightChild = child;
- }
-
- if (checkNesting) {
- mInsideWeight.put(child, Boolean.TRUE);
-
- Boolean inside = mInsideWeight.get(element);
- if (inside == null) {
- mInsideWeight.put(element, Boolean.FALSE);
- } else if (inside) {
- Attr sizeNode = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT);
- context.report(NESTED_WEIGHTS, sizeNode,
- context.getLocation(sizeNode),
- "Nested weights are bad for performance", null);
- // Don't warn again
- checkNesting = false;
- }
- }
- }
- }
-
- String orientation = element.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION);
- if (children.size() >= 2 && (orientation == null || orientation.isEmpty())
- && context.isEnabled(ORIENTATION)) {
- // See if at least one of the children, except the last one, sets layout_width
- // to match_parent (or fill_parent), in an implicitly horizontal layout, since
- // that might mean the last child won't be visible. This is a source of confusion
- // for new Android developers.
- boolean maxWidthSet = false;
- Iterator<Element> iterator = children.iterator();
- while (iterator.hasNext()) {
- Element child = iterator.next();
- if (!iterator.hasNext()) { // Don't check the last one
- break;
- }
- String width = child.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- if (VALUE_MATCH_PARENT.equals(width) || VALUE_FILL_PARENT.equals(width)) {
- // Also check that weights are not set here; this affects the computation
- // a bit and the child may not fill up the whole linear layout
- if (!child.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT)) {
- maxWidthSet = true;
- break;
- }
- }
- }
- if (maxWidthSet && !element.hasAttribute(ATTR_STYLE)) {
- String message = "Wrong orientation? No orientation specified, and the default "
- + "is horizontal, yet this layout has multiple children where at "
- + "least one has layout_width=\"match_parent\"";
- context.report(ORIENTATION, element, context.getLocation(element), message, null);
- }
- }
-
- if (context.isEnabled(BASELINE_WEIGHTS) && weightChild != null
- && !VALUE_VERTICAL.equals(orientation)
- && !element.hasAttributeNS(ANDROID_URI, ATTR_BASELINE_ALIGNED)) {
- // See if all the children are layouts
- boolean allChildrenAreLayouts = !children.isEmpty();
- SdkInfo sdkInfo = context.getClient().getSdkInfo(context.getProject());
- for (Element child : children) {
- String tagName = child.getTagName();
- if (!(sdkInfo.isLayout(tagName)
- // RadioGroup is a layout, but one which possibly should be base aligned
- && !tagName.equals(RADIO_GROUP)
- // Consider <fragment> tags as layouts for the purposes of this check
- || VIEW_FRAGMENT.equals(tagName)
- // Ditto for <include> tags
- || VIEW_INCLUDE.equals(tagName))) {
- allChildrenAreLayouts = false;
- }
- }
- if (allChildrenAreLayouts) {
- context.report(BASELINE_WEIGHTS,
- element,
- context.getLocation(element),
- "Set android:baselineAligned=\"false\" on this element for better performance",
- null);
- }
- }
-
- if (context.isEnabled(INEFFICIENT_WEIGHT)
- && weightChild != null && !multipleWeights) {
- String dimension;
- if (VALUE_VERTICAL.equals(orientation)) {
- dimension = ATTR_LAYOUT_HEIGHT;
- } else {
- dimension = ATTR_LAYOUT_WIDTH;
- }
- Attr sizeNode = weightChild.getAttributeNodeNS(ANDROID_URI, dimension);
- String size = sizeNode != null ? sizeNode.getValue() : "(undefined)";
- if (!size.startsWith("0")) { //$NON-NLS-1$
- String msg = String.format(
- "Use a %1$s of 0dip instead of %2$s for better performance",
- dimension, size);
- context.report(INEFFICIENT_WEIGHT,
- weightChild,
- context.getLocation(sizeNode != null ? sizeNode : weightChild), msg, null);
-
- }
- }
-
- if (context.isEnabled(WRONG_0DP)) {
- checkWrong0Dp(context, element, children);
- }
- }
-
- private static void checkWrong0Dp(XmlContext context, Element element,
- List<Element> children) {
- boolean isVertical = false;
- String orientation = element.getAttributeNS(ANDROID_URI, ATTR_ORIENTATION);
- if (VALUE_VERTICAL.equals(orientation)) {
- isVertical = true;
- }
-
- for (Element child : children) {
- String tagName = child.getTagName();
- if (tagName.equals(VIEW)) {
- // Might just used for spacing
- return;
- }
- if (tagName.indexOf('.') != -1 || tagName.equals(VIEW_TAG)) {
- // Custom views might perform their own dynamic sizing or ignore the layout
- // attributes all together
- return;
- }
-
- boolean hasWeight = child.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT);
-
- Attr widthNode = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- Attr heightNode = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
-
- boolean noWidth = false;
- boolean noHeight = false;
- if (widthNode != null && widthNode.getValue().startsWith("0")) { //$NON-NLS-1$
- noWidth = true;
- }
- if (heightNode != null && heightNode.getValue().startsWith("0")) { //$NON-NLS-1$
- noHeight = true;
- } else if (!noWidth) {
- return;
- }
-
- // If you're specifying 0dp for both the width and height you are probably
- // trying to hide it deliberately
- if (noWidth && noHeight) {
- return;
- }
- assert noWidth || noHeight;
-
- if (noWidth) {
- assert widthNode != null;
- if (!hasWeight) {
- context.report(WRONG_0DP, widthNode, context.getLocation(widthNode),
- "Suspicious size: this will make the view invisible, should be " +
- "used with layout_weight", null);
- } else if (isVertical) {
- context.report(WRONG_0DP, widthNode, context.getLocation(widthNode),
- "Suspicious size: this will make the view invisible, probably " +
- "intended for layout_height", null);
- }
- } else {
- assert noHeight;
- assert heightNode != null;
- if (!hasWeight) {
- context.report(WRONG_0DP, widthNode, context.getLocation(heightNode),
- "Suspicious size: this will make the view invisible, should be " +
- "used with layout_weight", null);
- } else if (!isVertical) {
- context.report(WRONG_0DP, widthNode, context.getLocation(heightNode),
- "Suspicious size: this will make the view invisible, probably " +
- "intended for layout_width", null);
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InvalidPackageDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InvalidPackageDetector.java
deleted file mode 100644
index 048f6ae..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/InvalidPackageDetector.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.google.common.collect.Sets;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldInsnNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.LdcInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.io.File;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-import lombok.ast.libs.org.parboiled.google.collect.Lists;
-
-/**
- * Looks for usages of Java packages that are not included in Android.
- */
-public class InvalidPackageDetector extends Detector implements Detector.ClassScanner {
- /** Accessing an invalid package */
- public static final Issue ISSUE = Issue.create("InvalidPackage", //$NON-NLS-1$
- "Finds API accesses to APIs that are not supported in Android",
-
- "This check scans through libraries looking for calls to APIs that are not included " +
- "in Android.\n" +
- "\n" +
- "When you create Android projects, the classpath is set up such that you can only " +
- "access classes in the API packages that are included in Android. However, if you " +
- "add other projects to your libs/ folder, there is no guarantee that those .jar " +
- "files were built with an Android specific classpath, and in particular, they " +
- "could be accessing unsupported APIs such as java.applet.\n" +
- "\n" +
- "This check scans through library jars and looks for references to API packages " +
- "that are not included in Android and flags these. This is only an error if your " +
- "code calls one of the library classes which wind up referencing the unsupported " +
- "package.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- InvalidPackageDetector.class,
- EnumSet.of(Scope.JAVA_LIBRARIES));
-
- private static final String JAVA_PKG_PREFIX = "java/"; //$NON-NLS-1$
- private static final String JAVAX_PKG_PREFIX = "javax/"; //$NON-NLS-1$
-
- private ApiLookup mApiDatabase;
-
- /**
- * List of candidates that are potential package violations. These are
- * recorded as candidates rather than flagged immediately such that we can
- * filter out hits for classes that are also defined as libraries (possibly
- * encountered later in the library traversal).
- */
- private List<Candidate> mCandidates;
- /**
- * Set of Java packages defined in the libraries; this means that if the
- * user has added libraries in this package namespace (such as the
- * null annotations jars) we don't flag these.
- */
- private final Set<String> mJavaxLibraryClasses = Sets.newHashSetWithExpectedSize(64);
-
- /** Constructs a new package check */
- public InvalidPackageDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.SLOW;
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- mApiDatabase = ApiLookup.get(context.getClient());
- }
-
- // ---- Implements ClassScanner ----
-
- @SuppressWarnings("rawtypes") // ASM API
- @Override
- public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
- if (!context.isFromClassLibrary() || shouldSkip(context.file)) {
- return;
- }
-
- if (mApiDatabase == null) {
- return;
- }
-
- if (classNode.name.startsWith(JAVAX_PKG_PREFIX)) {
- mJavaxLibraryClasses.add(classNode.name);
- }
-
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
-
- InsnList nodes = method.instructions;
-
- // Check return type
- // The parameter types are already handled as local variables so we can skip
- // right to the return type.
- // Check types in parameter list
- String signature = method.desc;
- if (signature != null) {
- int args = signature.indexOf(')');
- if (args != -1 && signature.charAt(args + 1) == 'L') {
- String type = signature.substring(args + 2, signature.length() - 1);
- if (isInvalidPackage(type)) {
- AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
- record(context, method, first, type);
- }
- }
- }
-
- for (int i = 0, n = nodes.size(); i < n; i++) {
- AbstractInsnNode instruction = nodes.get(i);
- int type = instruction.getType();
- if (type == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode node = (MethodInsnNode) instruction;
- String owner = node.owner;
-
- // No need to check methods in this local class; we know they
- // won't be an API match
- if (node.getOpcode() == Opcodes.INVOKEVIRTUAL
- && owner.equals(classNode.name)) {
- owner = classNode.superName;
- }
-
- while (owner != null) {
- if (isInvalidPackage(owner)) {
- record(context, method, instruction, owner);
- }
-
- // For virtual dispatch, walk up the inheritance chain checking
- // each inherited method
- if (owner.startsWith("android/") //$NON-NLS-1$
- || owner.startsWith(JAVA_PKG_PREFIX)
- || owner.startsWith(JAVAX_PKG_PREFIX)) {
- owner = null;
- } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
- owner = context.getDriver().getSuperClass(owner);
- } else if (node.getOpcode() == Opcodes.INVOKESTATIC) {
- // Inherit through static classes as well
- owner = context.getDriver().getSuperClass(owner);
- } else {
- owner = null;
- }
- }
- } else if (type == AbstractInsnNode.FIELD_INSN) {
- FieldInsnNode node = (FieldInsnNode) instruction;
- String owner = node.owner;
- if (isInvalidPackage(owner)) {
- record(context, method, instruction, owner);
- }
- } else if (type == AbstractInsnNode.LDC_INSN) {
- LdcInsnNode node = (LdcInsnNode) instruction;
- if (node.cst instanceof Type) {
- Type t = (Type) node.cst;
- String className = t.getInternalName();
- if (isInvalidPackage(className)) {
- record(context, method, instruction, className);
- }
- }
- }
- }
- }
- }
-
- private boolean isInvalidPackage(String owner) {
- if (owner.startsWith(JAVA_PKG_PREFIX)
- || owner.startsWith(JAVAX_PKG_PREFIX)) {
- return !mApiDatabase.isValidJavaPackage(owner);
- }
-
- return false;
- }
-
- private void record(ClassContext context, MethodNode method,
- AbstractInsnNode instruction, String owner) {
- if (owner.indexOf('$') != -1) {
- // Don't report inner classes too; there will pretty much always be an outer class
- // reference as well
- return;
- }
-
- if (mCandidates == null) {
- mCandidates = Lists.newArrayList();
- }
- mCandidates.add(new Candidate(owner, context.getClassNode().name, context.getJarFile()));
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mCandidates == null) {
- return;
- }
-
- for (Candidate candidate : mCandidates) {
- String type = candidate.mClass;
- if (mJavaxLibraryClasses.contains(type)) {
- continue;
- }
- File jarFile = candidate.mJarFile;
- String referencedIn = candidate.mReferencedIn;
-
- Location location = Location.create(jarFile);
- Object pkg = getPackageName(type);
- String message = String.format(
- "Invalid package reference in library; not included in Android: %1$s. " +
- "Referenced from %2$s.", pkg, ClassContext.getFqcn(referencedIn));
- context.report(ISSUE, location, message, null);
- }
- }
-
- private static Object getPackageName(String owner) {
- String pkg = owner;
- int index = pkg.lastIndexOf('/');
- if (index != -1) {
- pkg = pkg.substring(0, index);
- }
-
- return ClassContext.getFqcn(pkg);
- }
-
- private static boolean shouldSkip(File file) {
- // No need to do work on this library, which is included in pretty much all new ADT
- // projects
- if (file.getPath().endsWith("android-support-v4.jar")) { //$NON-NLS-1$
- return true;
- }
-
- return false;
- }
-
- private static class Candidate {
- private final String mReferencedIn;
- private final File mJarFile;
- private final String mClass;
-
- public Candidate(String className, String referencedIn, File jarFile) {
- mClass = className;
- mReferencedIn = referencedIn;
- mJarFile = jarFile;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/JavaPerformanceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/JavaPerformanceDetector.java
deleted file mode 100644
index b161699..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/JavaPerformanceDetector.java
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.BinaryExpression;
-import lombok.ast.BinaryOperator;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.If;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.This;
-import lombok.ast.Throw;
-import lombok.ast.TypeReference;
-import lombok.ast.TypeReferencePart;
-import lombok.ast.UnaryExpression;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableReference;
-
-/**
- * Looks for performance issues in Java files, such as memory allocations during
- * drawing operations and using HashMap instead of SparseArray.
- */
-public class JavaPerformanceDetector extends Detector implements Detector.JavaScanner {
- /** Allocating objects during a paint method */
- public static final Issue PAINT_ALLOC = Issue.create(
- "DrawAllocation", //$NON-NLS-1$
- "Looks for memory allocations within drawing code",
-
- "You should avoid allocating objects during a drawing or layout operation. These " +
- "are called frequently, so a smooth UI can be interrupted by garbage collection " +
- "pauses caused by the object allocations.\n" +
- "\n" +
- "The way this is generally handled is to allocate the needed objects up front " +
- "and to reuse them for each drawing operation.\n" +
- "\n" +
- "Some methods allocate memory on your behalf (such as `Bitmap.create`), and these " +
- "should be handled in the same way.",
-
- Category.PERFORMANCE,
- 9,
- Severity.WARNING,
- JavaPerformanceDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Using HashMaps where SparseArray would be better */
- public static final Issue USE_SPARSEARRAY = Issue.create(
- "UseSparseArrays", //$NON-NLS-1$
- "Looks for opportunities to replace HashMaps with the more efficient SparseArray",
-
- "For maps where the keys are of type integer, it's typically more efficient to " +
- "use the Android `SparseArray` API. This check identifies scenarios where you might " +
- "want to consider using `SparseArray` instead of `HashMap` for better performance.\n" +
- "\n" +
- "This is *particularly* useful when the value types are primitives like ints, " +
- "where you can use `SparseIntArray` and avoid auto-boxing the values from `int` to " +
- "`Integer`.\n" +
- "\n" +
- "If you need to construct a `HashMap` because you need to call an API outside of " +
- "your control which requires a `Map`, you can suppress this warning using for " +
- "example the `@SuppressLint` annotation.",
-
- Category.PERFORMANCE,
- 4,
- Severity.WARNING,
- JavaPerformanceDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Using {@code new Integer()} instead of the more efficient {@code Integer.valueOf} */
- public static final Issue USE_VALUEOF = Issue.create(
- "UseValueOf", //$NON-NLS-1$
- "Looks for usages of \"new\" for wrapper classes which should use \"valueOf\" instead",
-
- "You should not call the constructor for wrapper classes directly, such as" +
- "`new Integer(42)`. Instead, call the `valueOf` factory method, such as " +
- "`Integer.valueOf(42)`. This will typically use less memory because common integers " +
- "such as 0 and 1 will share a single instance.",
-
- Category.PERFORMANCE,
- 4,
- Severity.WARNING,
- JavaPerformanceDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- static final String ON_MEASURE = "onMeasure"; //$NON-NLS-1$
- static final String ON_DRAW = "onDraw"; //$NON-NLS-1$
- static final String ON_LAYOUT = "onLayout"; //$NON-NLS-1$
- private static final String INT = "int"; //$NON-NLS-1$
- private static final String INTEGER = "Integer"; //$NON-NLS-1$
- private static final String BOOL = "boolean"; //$NON-NLS-1$
- private static final String BOOLEAN = "Boolean"; //$NON-NLS-1$
- private static final String LONG = "Long"; //$NON-NLS-1$
- private static final String CHARACTER = "Character"; //$NON-NLS-1$
- private static final String DOUBLE = "Double"; //$NON-NLS-1$
- private static final String FLOAT = "Float"; //$NON-NLS-1$
- private static final String HASH_MAP = "HashMap"; //$NON-NLS-1$
- private static final String SPARSE_ARRAY = "SparseArray"; //$NON-NLS-1$
- private static final String CANVAS = "Canvas"; //$NON-NLS-1$
- private static final String LAYOUT = "layout"; //$NON-NLS-1$
-
- /** Constructs a new {@link JavaPerformanceDetector} check */
- public JavaPerformanceDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- List<Class<? extends Node>> types = new ArrayList<Class<? extends Node>>(3);
- types.add(ConstructorInvocation.class);
- types.add(MethodDeclaration.class);
- types.add(MethodInvocation.class);
- return types;
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new PerformanceVisitor(context);
- }
-
- private static class PerformanceVisitor extends ForwardingAstVisitor {
- private final JavaContext mContext;
- private final boolean mCheckMaps;
- private final boolean mCheckAllocations;
- private final boolean mCheckValueOf;
- /** Whether allocations should be "flagged" in the current method */
- private boolean mFlagAllocations;
-
- public PerformanceVisitor(JavaContext context) {
- mContext = context;
-
- mCheckAllocations = context.isEnabled(PAINT_ALLOC);
- mCheckMaps = context.isEnabled(USE_SPARSEARRAY);
- mCheckValueOf = context.isEnabled(USE_VALUEOF);
- }
-
- @Override
- public boolean visitMethodDeclaration(MethodDeclaration node) {
- mFlagAllocations = isBlockedAllocationMethod(node);
-
- return super.visitMethodDeclaration(node);
- }
-
- @Override
- public boolean visitConstructorInvocation(ConstructorInvocation node) {
- String typeName = null;
- if (mCheckMaps) {
- TypeReference reference = node.astTypeReference();
- typeName = reference.astParts().last().astIdentifier().astValue();
- // TODO: Should we handle factory method constructions of HashMaps as well,
- // e.g. via Guava? This is a bit trickier since we need to infer the type
- // arguments from the calling context.
- if (typeName.equals(HASH_MAP)) {
- checkHashMap(node, reference);
- } else if (typeName.equals(SPARSE_ARRAY)) {
- checkSparseArray(node, reference);
- }
- }
-
- if (mCheckValueOf) {
- if (typeName == null) {
- TypeReference reference = node.astTypeReference();
- typeName = reference.astParts().last().astIdentifier().astValue();
- }
- if ((typeName.equals(INTEGER)
- || typeName.equals(BOOLEAN)
- || typeName.equals(FLOAT)
- || typeName.equals(CHARACTER)
- || typeName.equals(LONG)
- || typeName.equals(DOUBLE))
- && node.astTypeReference().astParts().size() == 1
- && node.astArguments().size() == 1) {
- String argument = node.astArguments().first().toString();
- mContext.report(USE_VALUEOF, node, mContext.getLocation(node),
- String.format("Use %1$s.valueOf(%2$s) instead", typeName, argument),
- null);
- }
- }
-
- if (mFlagAllocations && !(node.getParent() instanceof Throw) && mCheckAllocations) {
- // Make sure we're still inside the method declaration that marked
- // mInDraw as true, in case we've left it and we're in a static
- // block or something:
- Node method = node;
- while (method != null) {
- if (method instanceof MethodDeclaration) {
- break;
- }
- method = method.getParent();
- }
- if (method != null && isBlockedAllocationMethod(((MethodDeclaration) method))
- && !isLazilyInitialized(node)) {
- reportAllocation(node);
- }
- }
-
- return super.visitConstructorInvocation(node);
- }
-
- private void reportAllocation(Node node) {
- mContext.report(PAINT_ALLOC, node, mContext.getLocation(node),
- "Avoid object allocations during draw/layout operations (preallocate and " +
- "reuse instead)", null);
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (mFlagAllocations && node.astOperand() != null) {
- // Look for forbidden methods
- String methodName = node.astName().astValue();
- if (methodName.equals("createBitmap") //$NON-NLS-1$
- || methodName.equals("createScaledBitmap")) { //$NON-NLS-1$
- String operand = node.astOperand().toString();
- if (operand.equals("Bitmap") //$NON-NLS-1$
- || operand.equals("android.graphics.Bitmap")) { //$NON-NLS-1$
- if (!isLazilyInitialized(node)) {
- reportAllocation(node);
- }
- }
- } else if (methodName.startsWith("decode")) { //$NON-NLS-1$
- // decodeFile, decodeByteArray, ...
- String operand = node.astOperand().toString();
- if (operand.equals("BitmapFactory") //$NON-NLS-1$
- || operand.equals("android.graphics.BitmapFactory")) { //$NON-NLS-1$
- if (!isLazilyInitialized(node)) {
- reportAllocation(node);
- }
- }
- } else if (methodName.equals("getClipBounds")) { //$NON-NLS-1$
- if (node.astArguments().isEmpty()) {
- mContext.report(PAINT_ALLOC, node, mContext.getLocation(node),
- "Avoid object allocations during draw operations: Use " +
- "Canvas.getClipBounds(Rect) instead of Canvas.getClipBounds() " +
- "which allocates a temporary Rect", null);
- }
- }
- }
-
- return super.visitMethodInvocation(node);
- }
-
- /**
- * Check whether the given invocation is done as a lazy initialization,
- * e.g. {@code if (foo == null) foo = new Foo();}.
- * <p>
- * This tries to also handle the scenario where the check is on some
- * <b>other</b> variable - e.g.
- * <pre>
- * if (foo == null) {
- * foo == init1();
- * bar = new Bar();
- * }
- * </pre>
- * or
- * <pre>
- * if (!initialized) {
- * initialized = true;
- * bar = new Bar();
- * }
- * </pre>
- */
- private static boolean isLazilyInitialized(Node node) {
- Node curr = node.getParent();
- while (curr != null) {
- if (curr instanceof MethodDeclaration) {
- return false;
- } else if (curr instanceof If) {
- If ifNode = (If) curr;
- // See if the if block represents a lazy initialization:
- // compute all variable names seen in the condition
- // (e.g. for "if (foo == null || bar != foo)" the result is "foo,bar"),
- // and then compute all variables assigned to in the if body,
- // and if there is an overlap, we'll consider the whole if block
- // guarded (so lazily initialized and an allocation we won't complain
- // about.)
- List<String> assignments = new ArrayList<String>();
- AssignmentTracker visitor = new AssignmentTracker(assignments);
- ifNode.astStatement().accept(visitor);
- if (!assignments.isEmpty()) {
- List<String> references = new ArrayList<String>();
- addReferencedVariables(references, ifNode.astCondition());
- if (!references.isEmpty()) {
- SetView<String> intersection = Sets.intersection(
- new HashSet<String>(assignments),
- new HashSet<String>(references));
- return !intersection.isEmpty();
- }
- }
- return false;
-
- }
- curr = curr.getParent();
- }
-
- return false;
- }
-
- /** Adds any variables referenced in the given expression into the given list */
- private static void addReferencedVariables(Collection<String> variables,
- Expression expression) {
- if (expression instanceof BinaryExpression) {
- BinaryExpression binary = (BinaryExpression) expression;
- addReferencedVariables(variables, binary.astLeft());
- addReferencedVariables(variables, binary.astRight());
- } else if (expression instanceof UnaryExpression) {
- UnaryExpression unary = (UnaryExpression) expression;
- addReferencedVariables(variables, unary.astOperand());
- } else if (expression instanceof VariableReference) {
- VariableReference reference = (VariableReference) expression;
- variables.add(reference.astIdentifier().astValue());
- } else if (expression instanceof Select) {
- Select select = (Select) expression;
- if (select.astOperand() instanceof This) {
- variables.add(select.astIdentifier().astValue());
- }
- }
- }
-
- /**
- * Returns whether the given method declaration represents a method
- * where allocating objects is not allowed for performance reasons
- */
- private static boolean isBlockedAllocationMethod(MethodDeclaration node) {
- return isOnDrawMethod(node) || isOnMeasureMethod(node) || isOnLayoutMethod(node)
- || isLayoutMethod(node);
- }
-
- /**
- * Returns true if this method looks like it's overriding android.view.View's
- * {@code protected void onDraw(Canvas canvas)}
- */
- private static boolean isOnDrawMethod(MethodDeclaration node) {
- if (ON_DRAW.equals(node.astMethodName().astValue())) {
- StrictListAccessor<VariableDefinition, MethodDeclaration> parameters =
- node.astParameters();
- if (parameters != null && parameters.size() == 1) {
- VariableDefinition arg0 = parameters.first();
- TypeReferencePart type = arg0.astTypeReference().astParts().last();
- String typeName = type.getTypeName();
- if (typeName.equals(CANVAS)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if this method looks like it's overriding
- * android.view.View's
- * {@code protected void onLayout(boolean changed, int left, int top,
- * int right, int bottom)}
- */
- private static boolean isOnLayoutMethod(MethodDeclaration node) {
- if (ON_LAYOUT.equals(node.astMethodName().astValue())) {
- StrictListAccessor<VariableDefinition, MethodDeclaration> parameters =
- node.astParameters();
- if (parameters != null && parameters.size() == 5) {
- Iterator<VariableDefinition> iterator = parameters.iterator();
- if (!iterator.hasNext()) {
- return false;
- }
-
- // Ensure that the argument list matches boolean, int, int, int, int
- TypeReferencePart type = iterator.next().astTypeReference().astParts().last();
- if (!type.getTypeName().equals(BOOL) || !iterator.hasNext()) {
- return false;
- }
- for (int i = 0; i < 4; i++) {
- type = iterator.next().astTypeReference().astParts().last();
- if (!type.getTypeName().equals(INT)) {
- return false;
- }
- if (!iterator.hasNext()) {
- return i == 3;
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if this method looks like it's overriding android.view.View's
- * {@code protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)}
- */
- private static boolean isOnMeasureMethod(MethodDeclaration node) {
- if (ON_MEASURE.equals(node.astMethodName().astValue())) {
- StrictListAccessor<VariableDefinition, MethodDeclaration> parameters =
- node.astParameters();
- if (parameters != null && parameters.size() == 2) {
- VariableDefinition arg0 = parameters.first();
- VariableDefinition arg1 = parameters.last();
- TypeReferencePart type1 = arg0.astTypeReference().astParts().last();
- TypeReferencePart type2 = arg1.astTypeReference().astParts().last();
- return INT.equals(type1.getTypeName()) && INT.equals(type2.getTypeName());
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if this method looks like it's overriding android.view.View's
- * {@code public void layout(int l, int t, int r, int b)}
- */
- private static boolean isLayoutMethod(MethodDeclaration node) {
- if (LAYOUT.equals(node.astMethodName().astValue())) {
- StrictListAccessor<VariableDefinition, MethodDeclaration> parameters =
- node.astParameters();
- if (parameters != null && parameters.size() == 4) {
- Iterator<VariableDefinition> iterator = parameters.iterator();
- for (int i = 0; i < 4; i++) {
- if (!iterator.hasNext()) {
- return false;
- }
- VariableDefinition next = iterator.next();
- TypeReferencePart type = next.astTypeReference().astParts().last();
- if (!INT.equals(type.getTypeName())) {
- return false;
- }
- }
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Checks whether the given constructor call and type reference refers
- * to a HashMap constructor call that is eligible for replacement by a
- * SparseArray call instead
- */
- private void checkHashMap(ConstructorInvocation node, TypeReference reference) {
- // reference.hasTypeArguments returns false where it should not
- StrictListAccessor<TypeReference, TypeReference> types = reference.getTypeArguments();
- if (types != null && types.size() == 2) {
- TypeReference first = types.first();
- if (first.getTypeName().equals(INTEGER)) {
- String valueType = types.last().getTypeName();
- if (valueType.equals(INTEGER)) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseIntArray(...) instead for better performance",
- null);
- } else if (valueType.equals(BOOLEAN)) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseBooleanArray(...) instead for better performance",
- null);
- } else if (valueType.equals(LONG) && mContext.getProject().getMinSdk() >= 17) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseLongArray(...) instead for better performance",
- null);
- } else {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- String.format(
- "Use new SparseArray<%1$s>(...) instead for better performance",
- valueType),
- null);
- }
- }
- }
- }
-
- private void checkSparseArray(ConstructorInvocation node, TypeReference reference) {
- // reference.hasTypeArguments returns false where it should not
- StrictListAccessor<TypeReference, TypeReference> types = reference.getTypeArguments();
- if (types != null && types.size() == 1) {
- TypeReference first = types.first();
- String valueType = first.getTypeName();
- if (valueType.equals(INTEGER)) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseIntArray(...) instead for better performance",
- null);
- } else if (valueType.equals(BOOLEAN)) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseBooleanArray(...) instead for better performance",
- null);
- } else if (valueType.equals(LONG) && mContext.getProject().getMinSdk() >= 17) {
- mContext.report(USE_SPARSEARRAY, node, mContext.getLocation(node),
- "Use new SparseLongArray(...) instead for better performance",
- null);
- }
- }
- }
- }
-
- /** Visitor which records variable names assigned into */
- private static class AssignmentTracker extends ForwardingAstVisitor {
- private final Collection<String> mVariables;
-
- public AssignmentTracker(Collection<String> variables) {
- mVariables = variables;
- }
-
- @Override
- public boolean visitBinaryExpression(BinaryExpression node) {
- BinaryOperator operator = node.astOperator();
- if (operator == BinaryOperator.ASSIGN || operator == BinaryOperator.OR_ASSIGN) {
- Expression left = node.astLeft();
- String variable;
- if (left instanceof Select && ((Select) left).astOperand() instanceof This) {
- variable = ((Select) left).astIdentifier().astValue();
- } else {
- variable = left.toString();
- }
- mVariables.add(variable);
- }
-
- return super.visitBinaryExpression(node);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LabelForDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LabelForDetector.java
deleted file mode 100644
index 283e244..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LabelForDetector.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_HINT;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LABEL_FOR;
-import static com.android.SdkConstants.AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.EDIT_TEXT;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.MULTI_AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.tools.lint.detector.api.LintUtils.stripIdPrefix;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Detector which finds unlabeled text fields
- */
-public class LabelForDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "LabelFor", //$NON-NLS-1$
- "Ensures that text fields are marked with a labelFor attribute",
- "Text fields should be labelled with a `labelFor` attribute, " +
- "provided your `minSdkVersion` is at least 17.\n" +
- "\n" +
- "If your view is labeled but by a label in a different layout which " +
- "includes this one, just suppress this warning from lint.",
- Category.A11Y,
- 2,
- Severity.WARNING,
- LabelForDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- private Set<String> mLabels;
- private List<Element> mTextFields;
-
- /** Constructs a new {@link LabelForDetector} */
- public LabelForDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- @Nullable
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_LABEL_FOR);
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- EDIT_TEXT,
- AUTO_COMPLETE_TEXT_VIEW,
- MULTI_AUTO_COMPLETE_TEXT_VIEW
- );
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- if (mTextFields != null) {
- if (mLabels == null) {
- mLabels = Collections.emptySet();
- }
-
- for (Element element : mTextFields) {
- if (element.hasAttributeNS(ANDROID_URI, ATTR_HINT)) {
- continue;
- }
- String id = element.getAttributeNS(ANDROID_URI, ATTR_ID);
- boolean missing = true;
- if (mLabels.contains(id)) {
- missing = false;
- } else if (id.startsWith(NEW_ID_PREFIX)) {
- missing = !mLabels.contains(ID_PREFIX + stripIdPrefix(id));
- } else if (id.startsWith(ID_PREFIX)) {
- missing = !mLabels.contains(NEW_ID_PREFIX + stripIdPrefix(id));
- }
-
- if (missing) {
- XmlContext xmlContext = (XmlContext) context;
- Location location = xmlContext.getLocation(element);
- String message;
- if (id == null || id.isEmpty()) {
- message = "No label views point to this text field with a " +
- "labelFor attribute";
- } else {
- message = String.format("No label views point to this text field with " +
- "an android:labelFor=\"@+id/%1$s\" attribute", id);
- }
- xmlContext.report(ISSUE, element, location, message, null);
- }
-
- }
- }
-
- mLabels = null;
- mTextFields = null;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (mLabels == null) {
- mLabels = Sets.newHashSet();
- }
- mLabels.add(attribute.getValue());
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- // NOTE: This should NOT be checking *minSdkVersion*, but *targetSdkVersion*
- // or even buildTarget instead. However, there's a risk that this will flag
- // way too much and make the rule annoying until API 17 support becomes
- // more widespread, so for now limit the check to those projects *really*
- // working with 17. When API 17 reaches a certain amount of adoption, change
- // this to flag all apps supporting 17, including those supporting earlier
- // versions as well.
- if (context.getMainProject().getMinSdk() < 17) {
- return;
- }
-
- if (mTextFields == null) {
- mTextFields = new ArrayList<Element>();
- }
- mTextFields.add(element);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LocaleDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LocaleDetector.java
deleted file mode 100644
index 3bde211..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/LocaleDetector.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.FORMAT_METHOD;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.LdcInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.analysis.Analyzer;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-import org.objectweb.asm.tree.analysis.Frame;
-import org.objectweb.asm.tree.analysis.SourceInterpreter;
-import org.objectweb.asm.tree.analysis.SourceValue;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-
-/**
- * Checks for errors related to locale handling
- */
-public class LocaleDetector extends Detector implements ClassScanner {
- /** Calling risky convenience methods */
- public static final Issue STRING_LOCALE = Issue.create(
- "DefaultLocale", //$NON-NLS-1$
- "Finds calls to locale-ambiguous String manipulation methods",
-
- "Calling `String#toLowerCase()` or `#toUpperCase()` *without specifying an " +
- "explicit locale* is a common source of bugs. The reason for that is that those " +
- "methods will use the current locale on the user's device, and even though the " +
- "code appears to work correctly when you are developing the app, it will fail " +
- "in some locales. For example, in the Turkish locale, the uppercase replacement " +
- "for `i` is *not* `I`.\n" +
- "\n" +
- "If you want the methods to just perform ASCII replacement, for example to convert " +
- "an enum name, call `String#toUpperCase(Locale.US)` instead. If you really want to " +
- "use the current locale, call `String#toUpperCase(Locale.getDefault())` instead.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- LocaleDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.CLASS_FILE)).setMoreInfo(
- "http://developer.android.com/reference/java/util/Locale.html#default_locale"); //$NON-NLS-1$
-
- /** Constructing SimpleDateFormat without an explicit locale */
- public static final Issue DATE_FORMAT = Issue.create(
- "SimpleDateFormat", //$NON-NLS-1$
- "Using SimpleDateFormat directly without an explicit locale",
-
- "Almost all callers should use `getDateInstance()`, `getDateTimeInstance()`, or " +
- "`getTimeInstance()` to get a ready-made instance of SimpleDateFormat suitable " +
- "for the user's locale. The main reason you'd create an instance this class " +
- "directly is because you need to format/parse a specific machine-readable format, " +
- "in which case you almost certainly want to explicitly ask for US to ensure that " +
- "you get ASCII digits (rather than, say, Arabic digits).\n" +
- "\n" +
- "Therefore, you should either use the form of the SimpleDateFormat constructor " +
- "where you pass in an explicit locale, such as Locale.US, or use one of the " +
- "get instance methods, or suppress this error if really know what you are doing.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- LocaleDetector.class,
- Scope.CLASS_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/java/text/SimpleDateFormat.html"); //$NON-NLS-1$
-
- static final String DATE_FORMAT_OWNER = "java/text/SimpleDateFormat"; //$NON-NLS-1$
- private static final String STRING_OWNER = "java/lang/String"; //$NON-NLS-1$
-
- /** Constructs a new {@link LocaleDetector} */
- public LocaleDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Arrays.asList(
- "toLowerCase", //$NON-NLS-1$
- "toUpperCase", //$NON-NLS-1$
- FORMAT_METHOD
- );
- }
-
- @Override
- @Nullable
- public List<String> getApplicableCallOwners() {
- return Collections.singletonList(DATE_FORMAT_OWNER);
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- String owner = call.owner;
- String desc = call.desc;
- String name = call.name;
- if (owner.equals(DATE_FORMAT_OWNER)) {
- if (!name.equals(CONSTRUCTOR_NAME)) {
- return;
- }
- if (desc.equals("(Ljava/lang/String;Ljava/text/DateFormatSymbols;)V") //$NON-NLS-1$
- || desc.equals("()V") //$NON-NLS-1$
- || desc.equals("(Ljava/lang/String;)V")) { //$NON-NLS-1$
- Location location = context.getLocation(call);
- String message =
- "To get local formatting use getDateInstance(), getDateTimeInstance(), " +
- "or getTimeInstance(), or use new SimpleDateFormat(String template, " +
- "Locale locale) with for example Locale.US for ASCII dates.";
- context.report(DATE_FORMAT, method, call, location, message, null);
- }
- return;
- } else if (!owner.equals(STRING_OWNER)) {
- return;
- }
-
- if (name.equals(FORMAT_METHOD)) {
- // Only check the non-locale version of String.format
- if (!desc.equals("(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;")) { //$NON-NLS-1$
- return;
- }
- // Find the formatting string
- Analyzer analyzer = new Analyzer(new SourceInterpreter() {
- @Override
- public SourceValue newOperation(AbstractInsnNode insn) {
- if (insn.getOpcode() == Opcodes.LDC) {
- Object cst = ((LdcInsnNode) insn).cst;
- if (cst instanceof String) {
- return new StringValue(1, (String) cst);
- }
- }
- return super.newOperation(insn);
- }
- });
- try {
- Frame[] frames = analyzer.analyze(classNode.name, method);
- InsnList instructions = method.instructions;
- Frame frame = frames[instructions.indexOf(call)];
- if (frame.getStackSize() == 0) {
- return;
- }
- SourceValue stackValue = (SourceValue) frame.getStack(0);
- if (stackValue instanceof StringValue) {
- String format = ((StringValue) stackValue).getString();
- if (format != null && StringFormatDetector.isLocaleSpecific(format)) {
- Location location = context.getLocation(call);
- String message =
- "Implicitly using the default locale is a common source of bugs: " +
- "Use String.format(Locale, ...) instead";
- context.report(STRING_LOCALE, method, call, location, message, null);
- }
- }
- } catch (AnalyzerException e) {
- context.log(e, null);
- }
- } else {
- if (desc.equals("()Ljava/lang/String;")) { //$NON-NLS-1$
- Location location = context.getLocation(call);
- String message = String.format(
- "Implicitly using the default locale is a common source of bugs: " +
- "Use %1$s(Locale) instead", name);
- context.report(STRING_LOCALE, method, call, location, message, null);
- }
- }
- }
-
- private static class StringValue extends SourceValue {
- private final String mString;
-
- StringValue(int size, String string) {
- super(size);
- mString = string;
- }
-
- String getString() {
- return mString;
- }
-
- @Override
- public int getSize() {
- return 1;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java
deleted file mode 100644
index 83fac97..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_MIN_SDK_VERSION;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.ATTR_TARGET_SDK_VERSION;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_APPLICATION;
-import static com.android.SdkConstants.TAG_PERMISSION;
-import static com.android.SdkConstants.TAG_PROVIDER;
-import static com.android.SdkConstants.TAG_RECEIVER;
-import static com.android.SdkConstants.TAG_SERVICE;
-import static com.android.SdkConstants.TAG_USES_LIBRARY;
-import static com.android.SdkConstants.TAG_USES_PERMISSION;
-import static com.android.SdkConstants.TAG_USES_SDK;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.Maps;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Checks for issues in AndroidManifest files such as declaring elements in the
- * wrong order.
- */
-public class ManifestOrderDetector extends Detector implements Detector.XmlScanner {
-
- /** Wrong order of elements in the manifest */
- public static final Issue ORDER = Issue.create(
- "ManifestOrder", //$NON-NLS-1$
- "Checks for manifest problems like <uses-sdk> after the <application> tag",
- "The <application> tag should appear after the elements which declare " +
- "which version you need, which features you need, which libraries you " +
- "need, and so on. In the past there have been subtle bugs (such as " +
- "themes not getting applied correctly) when the `<application>` tag appears " +
- "before some of these other elements, so it's best to order your " +
- "manifest in the logical dependency order.",
- Category.CORRECTNESS,
- 5,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Missing a {@code <uses-sdk>} element */
- public static final Issue USES_SDK = Issue.create(
- "UsesMinSdkAttributes", //$NON-NLS-1$
- "Checks that the minimum SDK and target SDK attributes are defined",
-
- "The manifest should contain a `<uses-sdk>` element which defines the " +
- "minimum API Level required for the application to run, " +
- "as well as the target version (the highest API level you have tested " +
- "the version for.)",
-
- Category.CORRECTNESS,
- 9,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"); //$NON-NLS-1$
-
- /** Using a targetSdkVersion that isn't recent */
- public static final Issue TARGET_NEWER = Issue.create(
- "OldTargetApi", //$NON-NLS-1$
- "Checks that the manifest specifies a targetSdkVersion that is recent",
-
- "When your application runs on a version of Android that is more recent than your " +
- "`targetSdkVersion` specifies that it has been tested with, various compatibility " +
- "modes kick in. This ensures that your application continues to work, but it may " +
- "look out of place. For example, if the `targetSdkVersion` is less than 14, your " +
- "app may get an option button in the UI.\n" +
- "\n" +
- "To fix this issue, set the `targetSdkVersion` to the highest available value. Then " +
- "test your app to make sure everything works correctly. You may want to consult " +
- "the compatibility notes to see what changes apply to each version you are adding " +
- "support for: " +
- "http://developer.android.com/reference/android/os/Build.VERSION_CODES.html",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/android/os/Build.VERSION_CODES.html"); //$NON-NLS-1$
-
- /** Using multiple {@code <uses-sdk>} elements */
- public static final Issue MULTIPLE_USES_SDK = Issue.create(
- "MultipleUsesSdk", //$NON-NLS-1$
- "Checks that the <uses-sdk> element appears at most once",
-
- "The `<uses-sdk>` element should appear just once; the tools will *not* merge the " +
- "contents of all the elements so if you split up the attributes across multiple " +
- "elements, only one of them will take effect. To fix this, just merge all the " +
- "attributes from the various elements into a single <uses-sdk> element.",
-
- Category.CORRECTNESS,
- 6,
- Severity.FATAL,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"); //$NON-NLS-1$
-
- /** Missing a {@code <uses-sdk>} element */
- public static final Issue WRONG_PARENT = Issue.create(
- "WrongManifestParent", //$NON-NLS-1$
- "Checks that various manifest elements are declared in the right place",
-
- "The `<uses-library>` element should be defined as a direct child of the " +
- "`<application>` tag, not the `<manifest>` tag or an `<activity>` tag. Similarly, " +
- "a `<uses-sdk>` tag much be declared at the root level, and so on. This check " +
- "looks for incorrect declaration locations in the manifest, and complains " +
- "if an element is found in the wrong place.",
-
- Category.CORRECTNESS,
- 6,
- Severity.FATAL,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
-
- /** Missing a {@code <uses-sdk>} element */
- public static final Issue DUPLICATE_ACTIVITY = Issue.create(
- "DuplicateActivity", //$NON-NLS-1$
- "Checks that an activity is registered only once in the manifest",
-
- "An activity should only be registered once in the manifest. If it is " +
- "accidentally registered more than once, then subtle errors can occur, " +
- "since attribute declarations from the two elements are not merged, so " +
- "you may accidentally remove previous declarations.",
-
- Category.CORRECTNESS,
- 5,
- Severity.ERROR,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Not explicitly defining allowBackup */
- public static final Issue ALLOW_BACKUP = Issue.create(
- "AllowBackup", //$NON-NLS-1$
- "Ensure that allowBackup is explicitly set in the application's manifest",
-
- "The allowBackup attribute determines if an application's data can be backed up " +
- "and restored. It is documented at " +
- "http://developer.android.com/reference/android/R.attr.html#allowBackup\n" +
- "\n" +
- "By default, this flag is set to `true`. When this flag is set to `true`, " +
- "application data can be backed up and restored by the user using `adb backup` " +
- "and `adb restore`.\n" +
- "\n" +
- "This may have security consequences for an application. `adb backup` allows " +
- "users who have enabled USB debugging to copy application data off of the " +
- "device. Once backed up, all application data can be read by the user. " +
- "`adb restore` allows creation of application data from a source specified " +
- "by the user. Following a restore, applications should not assume that the " +
- "data, file permissions, and directory permissions were created by the " +
- "application itself.\n" +
- "\n" +
- "Setting `allowBackup=\"false\"` opts an application out of both backup and " +
- "restore.\n" +
- "\n" +
- "To fix this warning, decide whether your application should support backup, " +
- "and explicitly set `android:allowBackup=(true|false)\"`",
-
- Category.SECURITY,
- 3,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/android/R.attr.html#allowBackup");
-
- /** Conflicting permission names */
- public static final Issue UNIQUE_PERMISSION = Issue.create(
- "UniquePermission", //$NON-NLS-1$
- "Checks that permission names are unique",
-
- "The unqualified names or your permissions must be unique. The reason for this " +
- "is that at build time, the `aapt` tool will generate a class named `Manifest` " +
- "which contains a field for each of your permissions. These fields are named " +
- "using your permission unqualified names (i.e. the name portion after the last " +
- "dot).\n" +
- "\n" +
- "If more than one permission maps to the same field name, that field will " +
- "arbitrarily name just one of them.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Using a resource for attributes that do not allow it */
- public static final Issue SET_VERSION = Issue.create(
- "MissingVersion", //$NON-NLS-1$
- "Checks that the application name and version are set",
-
- "You should define the version information for your application.\n" +
- "`android:versionCode`: An integer value that represents the version of the " +
- "application code, relative to other versions.\n" +
- "\n" +
- "`android:versionName`: A string value that represents the release version of " +
- "the application code, as it should be shown to users.",
-
- Category.CORRECTNESS,
- 2,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/tools/publishing/versioning.html#appversioning");
-
- /** Using a resource for attributes that do not allow it */
- public static final Issue ILLEGAL_REFERENCE = Issue.create(
- "IllegalResourceRef", //$NON-NLS-1$
- "Checks for resource references where only literals are allowed",
-
- "For the `versionCode` attribute, you have to specify an actual integer " +
- "literal; you cannot use an indirection with a `@dimen/name` resource. " +
- "Similarly, the `versionName` attribute should be an actual string, not " +
- "a string resource url.",
-
- Category.CORRECTNESS,
- 8,
- Severity.WARNING,
- ManifestOrderDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Constructs a new {@link ManifestOrderDetector} check */
- public ManifestOrderDetector() {
- }
-
- private boolean mSeenApplication;
-
- /** Number of times we've seen the <uses-sdk> element */
- private int mSeenUsesSdk;
-
- /** Activities we've encountered */
- private final Set<String> mActivities = new HashSet<String>();
-
- /** Permission basenames */
- private Map<String, String> mPermissionNames;
-
- /** Package declared in the manifest */
- private String mPackage;
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return file.getName().equals(ANDROID_MANIFEST_XML);
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- mSeenApplication = false;
- mSeenUsesSdk = 0;
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- XmlContext xmlContext = (XmlContext) context;
- Element element = xmlContext.document.getDocumentElement();
- if (element != null) {
- checkDocumentElement(xmlContext, element);
- }
-
- if (mSeenUsesSdk == 0 && context.isEnabled(USES_SDK)) {
- context.report(USES_SDK, Location.create(context.file),
- "Manifest should specify a minimum API level with " +
- "<uses-sdk android:minSdkVersion=\"?\" />; if it really supports " +
- "all versions of Android set it to 1.", null);
- }
- }
-
- private void checkDocumentElement(XmlContext context, Element element) {
- Attr codeNode = element.getAttributeNodeNS(ANDROID_URI, "versionCode");//$NON-NLS-1$
- if (codeNode != null && codeNode.getValue().startsWith(PREFIX_RESOURCE_REF)
- && context.isEnabled(ILLEGAL_REFERENCE)) {
- context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
- "The android:versionCode cannot be a resource url, it must be "
- + "a literal integer", null);
- } else if (codeNode == null && context.isEnabled(SET_VERSION)) {
- context.report(SET_VERSION, element, context.getLocation(element),
- "Should set android:versionCode to specify the application version", null);
- }
- Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, "versionName");//$NON-NLS-1$
- if (nameNode != null && nameNode.getValue().startsWith(PREFIX_RESOURCE_REF)
- && context.isEnabled(ILLEGAL_REFERENCE)) {
- context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
- "The android:versionName cannot be a resource url, it must be "
- + "a literal string", null);
- } else if (nameNode == null && context.isEnabled(SET_VERSION)) {
- context.report(SET_VERSION, element, context.getLocation(element),
- "Should set android:versionName to specify the application version", null);
- }
- }
-
- // ---- Implements Detector.XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_APPLICATION,
- TAG_USES_PERMISSION,
- TAG_PERMISSION,
- "permission-tree", //$NON-NLS-1$
- "permission-group", //$NON-NLS-1$
- TAG_USES_SDK,
- "uses-configuration", //$NON-NLS-1$
- "uses-feature", //$NON-NLS-1$
- "supports-screens", //$NON-NLS-1$
- "compatible-screens", //$NON-NLS-1$
- "supports-gl-texture", //$NON-NLS-1$
- TAG_USES_LIBRARY,
- TAG_ACTIVITY,
- TAG_SERVICE,
- TAG_PROVIDER,
- TAG_RECEIVER
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String tag = element.getTagName();
- Node parentNode = element.getParentNode();
-
- if (tag.equals(TAG_USES_LIBRARY) || tag.equals(TAG_ACTIVITY) || tag.equals(TAG_SERVICE)
- || tag.equals(TAG_PROVIDER) || tag.equals(TAG_RECEIVER)) {
- if (!TAG_APPLICATION.equals(parentNode.getNodeName())
- && context.isEnabled(WRONG_PARENT)) {
- context.report(WRONG_PARENT, element, context.getLocation(element),
- String.format(
- "The <%1$s> element must be a direct child of the <application> element",
- tag), null);
- }
-
- if (tag.equals(TAG_ACTIVITY)) {
- Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- if (nameNode != null) {
- String name = nameNode.getValue();
- if (!name.isEmpty()) {
- if (name.charAt(0) == '.') {
- name = getPackage(element) + name;
- } else if (name.indexOf('.') == -1) {
- name = getPackage(element) + '.' + name;
- }
- if (mActivities.contains(name)) {
- String message = String.format(
- "Duplicate registration for activity %1$s", name);
- context.report(DUPLICATE_ACTIVITY, element,
- context.getLocation(nameNode), message, null);
- } else {
- mActivities.add(name);
- }
- }
- }
- }
-
- return;
- }
-
- if (parentNode != element.getOwnerDocument().getDocumentElement()
- && context.isEnabled(WRONG_PARENT)) {
- context.report(WRONG_PARENT, element, context.getLocation(element),
- String.format(
- "The <%1$s> element must be a direct child of the " +
- "<manifest> root element", tag), null);
- }
-
- if (tag.equals(TAG_USES_SDK)) {
- mSeenUsesSdk++;
-
- if (mSeenUsesSdk == 2) { // Only warn when we encounter the first one
- Location location = context.getLocation(element);
-
- // Link up *all* encountered locations in the document
- NodeList elements = element.getOwnerDocument().getElementsByTagName(TAG_USES_SDK);
- Location secondary = null;
- for (int i = elements.getLength() - 1; i >= 0; i--) {
- Element e = (Element) elements.item(i);
- if (e != element) {
- Location l = context.getLocation(e);
- l.setSecondary(secondary);
- l.setMessage("Also appears here");
- secondary = l;
- }
- }
- location.setSecondary(secondary);
-
- if (context.isEnabled(MULTIPLE_USES_SDK)) {
- context.report(MULTIPLE_USES_SDK, element, location,
- "There should only be a single <uses-sdk> element in the manifest:" +
- " merge these together", null);
- }
- return;
- }
-
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION)) {
- if (context.isEnabled(USES_SDK)) {
- context.report(USES_SDK, element, context.getLocation(element),
- "<uses-sdk> tag should specify a minimum API level with " +
- "android:minSdkVersion=\"?\"", null);
- }
- } else {
- Attr codeNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION);
- if (codeNode != null && codeNode.getValue().startsWith(PREFIX_RESOURCE_REF)
- && context.isEnabled(ILLEGAL_REFERENCE)) {
- context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
- "The android:minSdkVersion cannot be a resource url, it must be "
- + "a literal integer (or string if a preview codename)", null);
- }
- }
-
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION)) {
- // Warn if not setting target SDK -- but only if the min SDK is somewhat
- // old so there's some compatibility stuff kicking in (such as the menu
- // button etc)
- if (context.isEnabled(USES_SDK)) {
- context.report(USES_SDK, element, context.getLocation(element),
- "<uses-sdk> tag should specify a target API level (the " +
- "highest verified version; when running on later versions, " +
- "compatibility behaviors may be enabled) with " +
- "android:targetSdkVersion=\"?\"", null);
- }
- } else if (context.isEnabled(TARGET_NEWER)){
- String target = element.getAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION);
- try {
- int api = Integer.parseInt(target);
- if (api < context.getClient().getHighestKnownApiLevel()) {
- context.report(TARGET_NEWER, element, context.getLocation(element),
- "Not targeting the latest versions of Android; compatibility " +
- "modes apply. Consider testing and updating this version. " +
- "Consult the android.os.Build.VERSION_CODES javadoc for details.",
- null);
- }
- } catch (NumberFormatException nufe) {
- // Ignore: AAPT will enforce this.
- }
- }
-
- Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION);
- if (nameNode != null && nameNode.getValue().startsWith(PREFIX_RESOURCE_REF)
- && context.isEnabled(ILLEGAL_REFERENCE)) {
- context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
- "The android:targetSdkVersion cannot be a resource url, it must be "
- + "a literal integer (or string if a preview codename)", null);
- }
- }
- if (tag.equals(TAG_PERMISSION)) {
- Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- if (nameNode != null) {
- String name = nameNode.getValue();
- String base = name.substring(name.lastIndexOf('.') + 1);
- if (mPermissionNames == null) {
- mPermissionNames = Maps.newHashMap();
- } else if (mPermissionNames.containsKey(base)) {
- String prevName = mPermissionNames.get(base);
- Location location = context.getLocation(nameNode);
- NodeList siblings = element.getParentNode().getChildNodes();
- for (int i = 0, n = siblings.getLength(); i < n; i++) {
- Node node = siblings.item(i);
- if (node == element) {
- break;
- } else if (node.getNodeType() == Node.ELEMENT_NODE) {
- Element sibling = (Element) node;
- String suffix = '.' + base;
- if (sibling.getTagName().equals(TAG_PERMISSION)) {
- String b = element.getAttributeNS(ANDROID_URI, ATTR_NAME);
- if (b.endsWith(suffix)) {
- Location prevLocation = context.getLocation(node);
- prevLocation.setMessage("Previous permission here");
- location.setSecondary(prevLocation);
- break;
- }
-
- }
- }
- }
-
- String message = String.format("Permission name %1$s is not unique " +
- "(appears in both %2$s and %3$s)", base, prevName, name);
- context.report(UNIQUE_PERMISSION, element, location, message, null);
- }
-
- mPermissionNames.put(base, name);
- }
- }
-
- if (tag.equals(TAG_APPLICATION)) {
- mSeenApplication = true;
- if (!element.hasAttributeNS(ANDROID_URI, SdkConstants.ATTR_ALLOW_BACKUP)
- && context.isEnabled(ALLOW_BACKUP)
- && context.getMainProject().getMinSdk() >= 4) {
- context.report(ALLOW_BACKUP, element, context.getLocation(element),
- "Should explicitly set android:allowBackup to true or " +
- "false (it's true by default, and that can have some security " +
- "implications for the application's data)", null);
- }
- } else if (mSeenApplication) {
- if (context.isEnabled(ORDER)) {
- context.report(ORDER, element, context.getLocation(element),
- String.format("<%1$s> tag appears after <application> tag", tag), null);
- }
-
- // Don't complain for *every* element following the <application> tag
- mSeenApplication = false;
- }
- }
-
- private String getPackage(Element element) {
- if (mPackage == null) {
- mPackage = element.getOwnerDocument().getDocumentElement().getAttribute(ATTR_PACKAGE);
- }
-
- return mPackage;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MathDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MathDetector.java
deleted file mode 100644
index 8709852..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MathDetector.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Looks for usages of {@link java.lang.Math} methods which can be replaced with
- * {@code android.util.FloatMath} methods to avoid casting.
- */
-public class MathDetector extends Detector implements Detector.ClassScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "FloatMath", //$NON-NLS-1$
- "Suggests replacing android.util.FloatMath calls with java.lang.Math",
-
- "In older versions of Android, using android.util.FloatMath was recommended " +
- "for performance reasons when operating on floats. However, on modern hardware " +
- "doubles are just as fast as float (though they take more memory), and in " +
- "recent versions of Android, FloatMath is actually slower than using java.lang.Math " +
- "due to the way the JIT optimizes java.lang.Math. Therefore, you should use " +
- "Math instead of FloatMath if you are only targeting Froyo and above.",
-
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- MathDetector.class,
- Scope.CLASS_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/design/performance.html#avoidfloat"); //$NON-NLS-1$
-
- /** Constructs a new {@link MathDetector} check */
- public MathDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Arrays.asList(
- "sin", //$NON-NLS-1$
- "cos", //$NON-NLS-1$
- "ceil", //$NON-NLS-1$
- "sqrt", //$NON-NLS-1$
- "floor" //$NON-NLS-1$
- );
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- String owner = call.owner;
-
- if (owner.equals("android/util/FloatMath") //$NON-NLS-1$
- && context.getProject().getMinSdk() >= 8) {
- String message = String.format(
- "Use java.lang.Math#%1$s instead of android.util.FloatMath#%1$s() " +
- "since it is faster as of API 8", call.name);
- context.report(ISSUE, method, call, context.getLocation(call), message, null /*data*/);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java
deleted file mode 100644
index 1b76c03..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_FOREGROUND;
-import static com.android.SdkConstants.ATTR_LAYOUT;
-import static com.android.SdkConstants.ATTR_LAYOUT_GRAVITY;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.FRAME_LAYOUT;
-import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.R_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Expression;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-
-/**
- * Checks whether a root FrameLayout can be replaced with a {@code <merge>} tag.
- */
-public class MergeRootFrameLayoutDetector extends LayoutDetector implements Detector.JavaScanner {
- /**
- * Set of layouts that we want to enable the warning for. We only warn for
- * {@code <FrameLayout>}'s that are the root of a layout included from
- * another layout, or directly referenced via a {@code setContentView} call.
- */
- private Set<String> mWhitelistedLayouts;
-
- /**
- * Set of pending [layout, location] pairs where the given layout is a
- * FrameLayout that perhaps should be replaced by a {@code <merge>} tag (if
- * the layout is included or set as the content view. This must be processed
- * after the whole project has been scanned since the set of includes etc
- * can be encountered after the included layout.
- */
- private List<Pair<String, Location.Handle>> mPending;
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "MergeRootFrame", //$NON-NLS-1$
- "Checks whether a root <FrameLayout> can be replaced with a <merge> tag",
- "If a `<FrameLayout>` is the root of a layout and does not provide background " +
- "or padding etc, it can often be replaced with a `<merge>` tag which is slightly " +
- "more efficient. Note that this depends on context, so make sure you understand " +
- "how the `<merge>` tag works before proceeding.",
- Category.PERFORMANCE,
- 4,
- Severity.WARNING,
- MergeRootFrameLayoutDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.JAVA_FILE)).setMoreInfo(
- "http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link MergeRootFrameLayoutDetector} */
- public MergeRootFrameLayoutDetector() {
- }
-
- @Override
- @NonNull
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return LintUtils.isXmlFile(file) || LintUtils.endsWith(file.getName(), DOT_JAVA);
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mPending != null && mWhitelistedLayouts != null) {
- // Process all the root FrameLayouts that are eligible, and generate
- // suggestions for <merge> replacements for any layouts that are included
- // from other layouts
- for (Pair<String, Handle> pair : mPending) {
- String layout = pair.getFirst();
- if (mWhitelistedLayouts.contains(layout)) {
- Handle handle = pair.getSecond();
-
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ISSUE, (Node) clientData)) {
- return;
- }
- }
-
- Location location = handle.resolve();
- context.report(ISSUE, location,
- "This <FrameLayout> can be replaced with a <merge> tag", null);
- }
- }
- }
- }
-
- // Implements XmlScanner
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(VIEW_INCLUDE, FRAME_LAYOUT);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String tag = element.getTagName();
- if (tag.equals(VIEW_INCLUDE)) {
- String layout = element.getAttribute(ATTR_LAYOUT); // NOTE: Not in android: namespace
- if (layout.startsWith(LAYOUT_RESOURCE_PREFIX)) { // Ignore @android:layout/ layouts
- layout = layout.substring(LAYOUT_RESOURCE_PREFIX.length());
- whiteListLayout(layout);
- }
- } else {
- assert tag.equals(FRAME_LAYOUT);
- if (LintUtils.isRootElement(element) &&
- ((isWidthFillParent(element) && isHeightFillParent(element)) ||
- !element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_GRAVITY))
- && !element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND)
- && !element.hasAttributeNS(ANDROID_URI, ATTR_FOREGROUND)
- && !hasPadding(element)) {
- String layout = LintUtils.getLayoutName(context.file);
- Handle handle = context.parser.createLocationHandle(context, element);
- handle.setClientData(element);
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- if (mPending == null) {
- mPending = new ArrayList<Pair<String,Handle>>();
- }
- mPending.add(Pair.of(layout, handle));
- }
- }
- }
-
- private void whiteListLayout(String layout) {
- if (mWhitelistedLayouts == null) {
- mWhitelistedLayouts = new HashSet<String>();
- }
- mWhitelistedLayouts.add(layout);
- }
-
- // Implements JavaScanner
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("setContentView"); //$NON-NLS-1$
- }
-
- @Override
- public void visitMethod(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- StrictListAccessor<Expression, MethodInvocation> argumentList = node.astArguments();
- if (argumentList != null && argumentList.size() == 1) {
- Expression argument = argumentList.first();
- if (argument instanceof Select) {
- String expression = argument.toString();
- if (expression.startsWith(R_LAYOUT_RESOURCE_PREFIX)) {
- whiteListLayout(expression.substring(R_LAYOUT_RESOURCE_PREFIX.length()));
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingClassDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingClassDetector.java
deleted file mode 100644
index 8002c40..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingClassDetector.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_PKG_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_CLASS;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_APPLICATION;
-import static com.android.SdkConstants.TAG_PROVIDER;
-import static com.android.SdkConstants.TAG_RECEIVER;
-import static com.android.SdkConstants.TAG_SERVICE;
-import static com.android.SdkConstants.TAG_STRING;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-import static com.android.SdkConstants.VIEW_TAG;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.SdkUtils;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Checks to ensure that classes referenced in the manifest actually exist and are included
- *
- */
-public class MissingClassDetector extends LayoutDetector implements ClassScanner {
- /** Manifest-referenced classes missing from the project or libraries */
- public static final Issue MISSING = Issue.create(
- "MissingRegistered", //$NON-NLS-1$
- "Ensures that classes referenced in the manifest are present in the project or libraries",
-
- "If a class is referenced in the manifest, it must also exist in the project (or in one " +
- "of the libraries included by the project. This check helps uncover typos in " +
- "registration names, or attempts to rename or move classes without updating the " +
- "manifest file properly.",
-
- Category.CORRECTNESS,
- 8,
- Severity.ERROR,
- MissingClassDetector.class,
- EnumSet.of(Scope.MANIFEST, Scope.CLASS_FILE, Scope.JAVA_LIBRARIES, Scope.RESOURCE_FILE))
- .setMoreInfo("http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
-
- /** Are activity, service, receiver etc subclasses instantiatable? */
- public static final Issue INSTANTIATABLE = Issue.create(
- "Instantiatable", //$NON-NLS-1$
- "Ensures that classes registered in the manifest file are instantiatable",
-
- "Activities, services, broadcast receivers etc. registered in the manifest file " +
- "must be \"instantiatable\" by the system, which means that the class must be " +
- "public, it must have an empty public constructor, and if it's an inner class, " +
- "it must be a static inner class.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- MissingClassDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- /** Is the right character used for inner class separators? */
- public static final Issue INNERCLASS = Issue.create(
- "InnerclassSeparator", //$NON-NLS-1$
- "Ensures that inner classes are referenced using '$' instead of '.' in class names",
-
- "When you reference an inner class in a manifest file, you must use '$' instead of '.' " +
- "as the separator character, i.e. Outer$Inner instead of Outer.Inner.\n" +
- "\n" +
- "(If you get this warning for a class which is not actually an inner class, it's " +
- "because you are using uppercase characters in your package name, which is not " +
- "conventional.)",
-
- Category.CORRECTNESS,
- 3,
- Severity.WARNING,
- MissingClassDetector.class,
- Scope.MANIFEST_SCOPE);
-
- private Map<String, Location.Handle> mReferencedClasses;
- private Set<String> mCustomViews;
- private boolean mHaveClasses;
-
- /** Constructs a new {@link MissingClassDetector} */
- public MissingClassDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return ALL;
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES || folderType == ResourceFolderType.LAYOUT;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String pkg = null;
- Node classNameNode;
- String className;
- String tag = element.getTagName();
- ResourceFolderType folderType = context.getResourceFolderType();
- if (folderType == ResourceFolderType.VALUES) {
- if (!tag.equals(TAG_STRING)) {
- return;
- }
- Attr attr = element.getAttributeNode(ATTR_NAME);
- if (attr == null) {
- return;
- }
- className = attr.getValue();
- classNameNode = attr;
- } else if (folderType == ResourceFolderType.LAYOUT) {
- if (tag.indexOf('.') > 0) {
- className = tag;
- classNameNode = element;
- } else if (tag.equals(VIEW_FRAGMENT) || tag.equals(VIEW_TAG)) {
- Attr attr = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- if (attr == null) {
- attr = element.getAttributeNode(ATTR_CLASS);
- }
- if (attr == null) {
- return;
- }
- className = attr.getValue();
- classNameNode = attr;
- } else {
- return;
- }
- } else {
- // Manifest file
- if (TAG_APPLICATION.equals(tag)
- || TAG_ACTIVITY.equals(tag)
- || TAG_SERVICE.equals(tag)
- || TAG_RECEIVER.equals(tag)
- || TAG_PROVIDER.equals(tag)) {
- Element root = element.getOwnerDocument().getDocumentElement();
- pkg = root.getAttribute(ATTR_PACKAGE);
- Attr attr = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- if (attr == null) {
- return;
- }
- className = attr.getValue();
- classNameNode = attr;
- } else {
- return;
- }
- }
- if (className.isEmpty()) {
- return;
- }
-
- String fqcn;
- int dotIndex = className.indexOf('.');
- if (dotIndex <= 0) {
- if (pkg == null) {
- return; // value file
- }
- if (dotIndex == 0) {
- fqcn = pkg + className;
- } else {
- // According to the <activity> manifest element documentation, this is not
- // valid ( http://developer.android.com/guide/topics/manifest/activity-element.html )
- // but it appears in manifest files and appears to be supported by the runtime
- // so handle this in code as well:
- fqcn = pkg + '.' + className;
- }
- } else { // else: the class name is already a fully qualified class name
- fqcn = className;
- // Only look for fully qualified tracker names in analytics files
- if (folderType == ResourceFolderType.VALUES
- && !SdkUtils.endsWith(context.file.getPath(), "analytics.xml")) { //$NON-NLS-1$
- return;
- }
- }
-
- String signature = ClassContext.getInternalName(fqcn);
- if (signature.isEmpty() || signature.startsWith(ANDROID_PKG_PREFIX)) {
- return;
- }
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- Handle handle = null;
- if (!context.getDriver().isSuppressed(MISSING, element)) {
- if (mReferencedClasses == null) {
- mReferencedClasses = Maps.newHashMapWithExpectedSize(16);
- mCustomViews = Sets.newHashSetWithExpectedSize(8);
- }
-
- handle = context.parser.createLocationHandle(context, element);
- mReferencedClasses.put(signature, handle);
- if (folderType == ResourceFolderType.LAYOUT && !tag.equals(VIEW_FRAGMENT)) {
- mCustomViews.add(ClassContext.getInternalName(className));
- }
- }
-
- if (signature.indexOf('$') != -1 && pkg != null) {
- if (className.indexOf('$') == -1 && className.indexOf('.', 1) > 0) {
- boolean haveUpperCase = false;
- for (int i = 0, n = pkg.length(); i < n; i++) {
- if (Character.isUpperCase(pkg.charAt(i))) {
- haveUpperCase = true;
- break;
- }
- }
- if (!haveUpperCase) {
- String message = "Use '$' instead of '.' for inner classes " +
- "(or use only lowercase letters in package names)";
- Location location = context.getLocation(classNameNode);
- context.report(INNERCLASS, element, location, message, null);
- }
- }
-
- // The internal name contains a $ which means it's an inner class.
- // The conversion from fqcn to internal name is a bit ambiguous:
- // "a.b.C.D" usually means "inner class D in class C in package a.b".
- // However, it can (see issue 31592) also mean class D in package "a.b.C".
- // To make sure we don't falsely complain that foo/Bar$Baz doesn't exist,
- // in case the user has actually created a package named foo/Bar and a proper
- // class named Baz, we register *both* into the reference map.
- // When generating errors we'll look for these an rip them back out if
- // it looks like one of the two variations have been seen.
- if (handle != null) {
- signature = signature.replace('$', '/');
- mReferencedClasses.put(signature, handle);
- }
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (!context.getProject().isLibrary() && mHaveClasses
- && mReferencedClasses != null && !mReferencedClasses.isEmpty()
- && context.getDriver().getScope().contains(Scope.CLASS_FILE)) {
- List<String> classes = new ArrayList<String>(mReferencedClasses.keySet());
- Collections.sort(classes);
- for (String owner : classes) {
- Location.Handle handle = mReferencedClasses.get(owner);
- String fqcn = ClassContext.getFqcn(owner);
-
- String signature = ClassContext.getInternalName(fqcn);
- if (!signature.equals(owner)) {
- if (!mReferencedClasses.containsKey(signature)) {
- continue;
- }
- } else {
- signature = signature.replace('$', '/');
- if (!mReferencedClasses.containsKey(signature)) {
- continue;
- }
- }
- mReferencedClasses.remove(owner);
-
- // Ignore usages of platform libraries
- if (owner.startsWith("android/")) { //$NON-NLS-1$
- continue;
- }
-
- String message = String.format(
- "Class referenced in the manifest, %1$s, was not found in the " +
- "project or the libraries", fqcn);
- Location location = handle.resolve();
- File parentFile = location.getFile().getParentFile();
- if (parentFile != null) {
- String parent = parentFile.getName();
- ResourceFolderType type = ResourceFolderType.getFolderType(parent);
- if (type == ResourceFolderType.LAYOUT) {
- message = String.format(
- "Class referenced in the layout file, %1$s, was not found in "
- + "the project or the libraries", fqcn);
- } else if (type == ResourceFolderType.VALUES) {
- message = String.format(
- "Class referenced in the analytics file, %1$s, was not "
- + "found in the project or the libraries", fqcn);
- }
- }
-
- context.report(MISSING, location, message, null);
- }
- }
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if (!mHaveClasses && !context.isFromClassLibrary()
- && context.getProject() == context.getMainProject()) {
- mHaveClasses = true;
- }
- String curr = classNode.name;
- if (mReferencedClasses != null && mReferencedClasses.containsKey(curr)) {
- boolean isCustomView = mCustomViews.contains(curr);
- mReferencedClasses.remove(curr);
-
- // Ensure that the class is public, non static and has a null constructor!
-
- if ((classNode.access & Opcodes.ACC_PUBLIC) == 0) {
- context.report(INSTANTIATABLE, context.getLocation(classNode), String.format(
- "This class should be public (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- return;
- }
-
- if (classNode.name.indexOf('$') != -1 && !LintUtils.isStaticInnerClass(classNode)) {
- context.report(INSTANTIATABLE, context.getLocation(classNode), String.format(
- "This inner class should be static (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- return;
- }
-
- boolean hasDefaultConstructor = false;
- @SuppressWarnings("rawtypes") // ASM API
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- if (method.name.equals(CONSTRUCTOR_NAME)) {
- if (method.desc.equals("()V")) { //$NON-NLS-1$
- // The constructor must be public
- if ((method.access & Opcodes.ACC_PUBLIC) != 0) {
- hasDefaultConstructor = true;
- } else {
- context.report(INSTANTIATABLE, context.getLocation(method, classNode),
- "The default constructor must be public",
- null);
- // Also mark that we have a constructor so we don't complain again
- // below since we've already emitted a more specific error related
- // to the default constructor
- hasDefaultConstructor = true;
- }
- }
- }
- }
-
- if (!hasDefaultConstructor && !isCustomView && !context.isFromClassLibrary()
- && context.getProject().getReportIssues()) {
- context.report(INSTANTIATABLE, context.getLocation(classNode), String.format(
- "This class should provide a default constructor (a public " +
- "constructor with no arguments) (%1$s)",
- ClassContext.createSignature(classNode.name, null, null)),
- null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingIdDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingIdDetector.java
deleted file mode 100644
index 1b79600..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/MissingIdDetector.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_TAG;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check which looks for missing id's in views where they are probably needed
- */
-public class MissingIdDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "MissingId", //$NON-NLS-1$
- "Ensures that XML tags like <fragment> specify an id or tag attribute",
-
- "If you do not specify an android:id or an android:tag attribute on a " +
- "<fragment> element, then if the activity is restarted (for example for " +
- "an orientation rotation) you may lose state. From the fragment " +
- "documentation:\n" +
- "\n" +
- "\"Each fragment requires a unique identifier that the system can use " +
- "to restore the fragment if the activity is restarted (and which you can " +
- "use to capture the fragment to perform transactions, such as remove it). " +
- "* Supply the android:id attribute with a unique ID.\n" +
- "* Supply the android:tag attribute with a unique string.\n" +
- "If you provide neither of the previous two, the system uses the ID of the " +
- "container view.",
-
- Category.CORRECTNESS,
- 5,
- Severity.WARNING,
- MissingIdDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setMoreInfo("http://developer.android.com/guide/components/fragments.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link MissingIdDetector} */
- public MissingIdDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(VIEW_FRAGMENT);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_ID) &&
- !element.hasAttributeNS(ANDROID_URI, ATTR_TAG)) {
- context.report(ISSUE, element, context.getLocation(element),
- "This <fragment> tag should specify an id or a tag to preserve state " +
- "across activity restarts", null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NamespaceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NamespaceDetector.java
deleted file mode 100644
index 0b6ab02..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NamespaceDetector.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.AUTO_URI;
-import static com.android.SdkConstants.URI_PREFIX;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-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;
-import org.w3c.dom.NodeList;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Checks for various issues related to XML namespaces
- */
-public class NamespaceDetector extends LayoutDetector {
- /** Typos in the namespace */
- public static final Issue TYPO = Issue.create(
- "NamespaceTypo", //$NON-NLS-1$
- "Looks for misspellings in namespace declarations",
-
- "Accidental misspellings in namespace declarations can lead to some very " +
- "obscure error messages. This check looks for potential misspellings to " +
- "help track these down.",
- Category.CORRECTNESS,
- 8,
- Severity.WARNING,
- NamespaceDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Unused namespace declarations */
- public static final Issue UNUSED = Issue.create(
- "UnusedNamespace", //$NON-NLS-1$
- "Finds unused namespaces in XML documents",
-
- "Unused namespace declarations take up space and require processing that is not " +
- "necessary",
-
- Category.PERFORMANCE,
- 1,
- Severity.WARNING,
- NamespaceDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Using custom namespace attributes in a library project */
- public static final Issue CUSTOMVIEW = Issue.create(
- "LibraryCustomView", //$NON-NLS-1$
- "Flags custom attributes in libraries, which must use the res-auto-namespace instead",
-
- "When using a custom view with custom attributes in a library project, the layout " +
- "must use the special namespace " + AUTO_URI + " instead of a URI which includes " +
- "the library project's own package. This will be used to automatically adjust the " +
- "namespace of the attributes when the library resources are merged into the " +
- "application project.",
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- NamespaceDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Prefix relevant for custom namespaces */
- private static final String XMLNS_ANDROID = "xmlns:android"; //$NON-NLS-1$
- private static final String XMLNS_A = "xmlns:a"; //$NON-NLS-1$
-
- private Map<String, Attr> mUnusedNamespaces;
- private boolean mCheckUnused;
-
- /** Constructs a new {@link NamespaceDetector} */
- public NamespaceDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- boolean haveCustomNamespace = false;
- Element root = document.getDocumentElement();
- NamedNodeMap attributes = root.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Node item = attributes.item(i);
- if (item.getNodeName().startsWith(XMLNS_PREFIX)) {
- String value = item.getNodeValue();
-
- if (!value.equals(ANDROID_URI)) {
- Attr attribute = (Attr) item;
-
- if (value.startsWith(URI_PREFIX)) {
- haveCustomNamespace = true;
- if (mUnusedNamespaces == null) {
- mUnusedNamespaces = new HashMap<String, Attr>();
- }
- mUnusedNamespaces.put(item.getNodeName().substring(XMLNS_PREFIX.length()),
- attribute);
- } else if (!value.startsWith("http://")) { //$NON-NLS-1$
- context.report(TYPO, attribute, context.getLocation(attribute),
- "Suspicious namespace: should start with http://", null);
-
- continue;
- }
-
- String name = attribute.getName();
- if (!name.equals(XMLNS_ANDROID) && !name.equals(XMLNS_A)) {
- // See if it looks like a typo
- int resIndex = value.indexOf("/res/"); //$NON-NLS-1$
- if (resIndex != -1 && value.length() + 5 > URI_PREFIX.length()) {
- String urlPrefix = value.substring(0, resIndex + 5);
- if (!urlPrefix.equals(URI_PREFIX) &&
- LintUtils.editDistance(URI_PREFIX, urlPrefix) <= 3) {
- String correctUri = URI_PREFIX + value.substring(resIndex + 5);
- context.report(TYPO, attribute, context.getLocation(attribute),
- String.format(
- "Possible typo in URL: was \"%1$s\", should " +
- "probably be \"%2$s\"",
- value, correctUri),
- null);
- }
- }
- continue;
- }
-
- if (!context.isEnabled(TYPO)) {
- continue;
- }
-
- if (name.equals(XMLNS_A)) {
- // For the "android" prefix we always assume that the namespace prefix
- // should be our expected prefix, but for the "a" prefix we make sure
- // that it's at least "close"; if you're bound it to something completely
- // different, don't complain.
- if (LintUtils.editDistance(ANDROID_URI, value) > 4) {
- continue;
- }
- }
-
- if (value.equalsIgnoreCase(ANDROID_URI)) {
- context.report(TYPO, attribute, context.getLocation(attribute),
- String.format(
- "URI is case sensitive: was \"%1$s\", expected \"%2$s\"",
- value, ANDROID_URI), null);
- } else {
- context.report(TYPO, attribute, context.getLocation(attribute),
- String.format(
- "Unexpected namespace URI bound to the \"android\" " +
- "prefix, was %1$s, expected %2$s", value, ANDROID_URI),
- null);
- }
- }
- }
- }
-
- if (haveCustomNamespace) {
- boolean checkCustomAttrs = context.isEnabled(CUSTOMVIEW) && context.getProject().isLibrary();
- mCheckUnused = context.isEnabled(UNUSED);
-
- if (checkCustomAttrs) {
- checkCustomNamespace(context, root);
- }
- checkElement(context, root);
-
- if (mCheckUnused && !mUnusedNamespaces.isEmpty()) {
- for (Map.Entry<String, Attr> entry : mUnusedNamespaces.entrySet()) {
- String prefix = entry.getKey();
- Attr attribute = entry.getValue();
- context.report(UNUSED, attribute, context.getLocation(attribute),
- String.format("Unused namespace %1$s", prefix), null);
- }
- }
- }
- }
-
- private static void checkCustomNamespace(XmlContext context, Element element) {
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- if (attribute.getName().startsWith(XMLNS_PREFIX)) {
- String uri = attribute.getValue();
- if (uri != null && !uri.isEmpty() && uri.startsWith(URI_PREFIX)
- && !uri.equals(ANDROID_URI)) {
- context.report(CUSTOMVIEW, attribute, context.getLocation(attribute),
- "When using a custom namespace attribute in a library project, " +
- "use the namespace \"" + AUTO_URI + "\" instead.", null);
- }
- }
- }
- }
-
- private void checkElement(XmlContext context, Node node) {
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- if (mCheckUnused) {
- NamedNodeMap attributes = node.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- String prefix = attribute.getPrefix();
- if (prefix != null) {
- mUnusedNamespaces.remove(prefix);
- }
- }
- }
-
- NodeList childNodes = node.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- checkElement(context, childNodes.item(i));
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java
deleted file mode 100644
index 4650a8f..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.GALLERY;
-import static com.android.SdkConstants.GRID_VIEW;
-import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.LIST_VIEW;
-import static com.android.SdkConstants.SCROLL_VIEW;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Checks whether a root FrameLayout can be replaced with a {@code <merge>} tag.
- */
-public class NestedScrollingWidgetDetector extends LayoutDetector {
- private int mVisitingHorizontalScroll;
- private int mVisitingVerticalScroll;
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "NestedScrolling", //$NON-NLS-1$
- "Checks whether a scrolling widget has any nested scrolling widgets within",
- // TODO: Better description!
- "A scrolling widget such as a `ScrollView` should not contain any nested " +
- "scrolling widgets since this has various usability issues",
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- NestedScrollingWidgetDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link NestedScrollingWidgetDetector} */
- public NestedScrollingWidgetDetector() {
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- mVisitingHorizontalScroll = 0;
- mVisitingVerticalScroll = 0;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- SCROLL_VIEW,
- LIST_VIEW,
- GRID_VIEW,
- // Horizontal
- GALLERY,
- HORIZONTAL_SCROLL_VIEW
- );
- }
-
- private Element findOuterScrollingWidget(Node node, boolean vertical) {
- Collection<String> applicableElements = getApplicableElements();
- while (node != null) {
- if (node instanceof Element) {
- Element element = (Element) node;
- String tagName = element.getTagName();
- if (applicableElements.contains(tagName)
- && vertical == isVerticalScroll(element)) {
- return element;
- }
- }
-
- node = node.getParentNode();
- }
-
- return null;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- boolean vertical = isVerticalScroll(element);
- if (vertical) {
- mVisitingVerticalScroll++;
- } else {
- mVisitingHorizontalScroll++;
- }
-
- if (mVisitingHorizontalScroll > 1 || mVisitingVerticalScroll > 1) {
- Element parent = findOuterScrollingWidget(element.getParentNode(), vertical);
- if (parent != null) {
- String format;
- if (mVisitingVerticalScroll > 1) {
- format = "The vertically scrolling %1$s should not contain another " +
- "vertically scrolling widget (%2$s)";
- } else {
- format = "The horizontally scrolling %1$s should not contain another " +
- "horizontally scrolling widget (%2$s)";
- }
- String msg = String.format(format, parent.getTagName(), element.getTagName());
- context.report(ISSUE, element, context.getLocation(element), msg, null);
- }
- }
- }
-
- @Override
- public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) {
- if (isVerticalScroll(element)) {
- mVisitingVerticalScroll--;
- assert mVisitingVerticalScroll >= 0;
- } else {
- mVisitingHorizontalScroll--;
- assert mVisitingHorizontalScroll >= 0;
- }
- }
-
- private static boolean isVerticalScroll(Element element) {
- String view = element.getTagName();
- if (view.equals(GALLERY) || view.equals(HORIZONTAL_SCROLL_VIEW)) {
- return false;
- } else {
- // This method should only be called with one of the 5 widget types
- // listed in getApplicableElements
- assert view.equals(SCROLL_VIEW) || view.equals(LIST_VIEW) || view.equals(GRID_VIEW);
- return true;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java
deleted file mode 100644
index e970572..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/NonInternationalizedSmsDetector.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Expression;
-import lombok.ast.MethodInvocation;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-
-/** Detector looking for text messages sent to an unlocalized phone number. */
-public class NonInternationalizedSmsDetector extends Detector implements Detector.JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "UnlocalizedSms", //$NON-NLS-1$
- "Looks for code sending text messages to unlocalized phone numbers",
-
- "SMS destination numbers must start with a country code or the application code " +
- "must ensure that the SMS is only sent when the user is in the same country as " +
- "the receiver.",
-
- Category.CORRECTNESS,
- 5,
- Severity.WARNING,
- NonInternationalizedSmsDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
-
- /** Constructs a new {@link NonInternationalizedSmsDetector} check */
- public NonInternationalizedSmsDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- List<String> methodNames = new ArrayList<String>(2);
- methodNames.add("sendTextMessage"); //$NON-NLS-1$
- methodNames.add("sendMultipartTextMessage"); //$NON-NLS-1$
- return methodNames;
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- assert node.astName().astValue().equals("sendTextMessage") || //$NON-NLS-1$
- node.astName().astValue().equals("sendMultipartTextMessage"); //$NON-NLS-1$
- if (node.astOperand() == null) {
- // "sendTextMessage"/"sendMultipartTextMessage" in the code with no operand
- return;
- }
-
- StrictListAccessor<Expression, MethodInvocation> args = node.astArguments();
- if (args.size() == 5) {
- Expression destinationAddress = args.first();
- if (destinationAddress instanceof StringLiteral) {
- String number = ((StringLiteral) destinationAddress).astValue();
-
- if (!number.startsWith("+")) { //$NON-NLS-1$
- context.report(ISSUE, node, context.getLocation(destinationAddress),
- "To make sure the SMS can be sent by all users, please start the SMS number " +
- "with a + and a country code or restrict the code invocation to people in the country " +
- "you are targeting.",
- null);
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java
deleted file mode 100644
index 559a7ad..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_LAYOUT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ABOVE;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING;
-import static com.android.SdkConstants.ATTR_LAYOUT_BELOW;
-import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_HORIZONTAL;
-import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_IN_PARENT;
-import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_VERTICAL;
-import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN;
-import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN_SPAN;
-import static com.android.SdkConstants.ATTR_LAYOUT_GRAVITY;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_ROW;
-import static com.android.SdkConstants.ATTR_LAYOUT_ROW_SPAN;
-import static com.android.SdkConstants.ATTR_LAYOUT_SPAN;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_WEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_LAYOUT_X;
-import static com.android.SdkConstants.ATTR_LAYOUT_Y;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.GRID_LAYOUT;
-import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-import static com.android.SdkConstants.VIEW_MERGE;
-import static com.android.SdkConstants.VIEW_TAG;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.IDomParser;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Looks for layout params on views that are "obsolete" - may have made sense
- * when the view was added but there is a different layout parent now which does
- * not use the given layout params.
- */
-public class ObsoleteLayoutParamsDetector extends LayoutDetector {
- /** Usage of deprecated views or attributes */
- public static final Issue ISSUE = Issue.create(
- "ObsoleteLayoutParam", //$NON-NLS-1$
- "Looks for layout params that are not valid for the given parent layout",
- "The given layout_param is not defined for the given layout, meaning it has no " +
- "effect. This usually happens when you change the parent layout or move view " +
- "code around without updating the layout params. This will cause useless " +
- "attribute processing at runtime, and is misleading for others reading the " +
- "layout so the parameter should be removed.",
- Category.PERFORMANCE,
- 6,
- Severity.WARNING,
- ObsoleteLayoutParamsDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Set of layout parameter names that are considered valid no matter what so
- * no other checking is necessary - such as layout_width and layout_height.
- */
- private static final Set<String> VALID = new HashSet<String>(10);
-
- /**
- * Mapping from a layout parameter name (local name only) to the defining
- * ViewGroup. Note that it's possible for the same name to be defined by
- * multiple ViewGroups - but it turns out this is extremely rare (the only
- * examples are layout_column defined by both TableRow and GridLayout, and
- * layout_gravity defined by many layouts) so rather than handle this with
- * every single layout attribute pointing to a list, this is just special
- * cased instead.
- */
- private static final Map<String, String> PARAM_TO_VIEW = new HashMap<String, String>(28);
-
- static {
- // Available (mostly) everywhere: No check
- VALID.add(ATTR_LAYOUT_WIDTH);
- VALID.add(ATTR_LAYOUT_HEIGHT);
-
- // The layout_gravity isn't "global" but it's defined on many of the most
- // common layouts (FrameLayout, LinearLayout and GridLayout) so we don't
- // currently check for it. In order to do this we'd need to make the map point
- // to lists rather than individual layouts or we'd need a bunch of special cases
- // like the one done for layout_column below.
- VALID.add(ATTR_LAYOUT_GRAVITY);
-
- // From ViewGroup.MarginLayoutParams
- VALID.add(ATTR_LAYOUT_MARGIN_LEFT);
- VALID.add(ATTR_LAYOUT_MARGIN_RIGHT);
- VALID.add(ATTR_LAYOUT_MARGIN_TOP);
- VALID.add(ATTR_LAYOUT_MARGIN_BOTTOM);
- VALID.add(ATTR_LAYOUT_MARGIN);
-
- // Absolute Layout
- PARAM_TO_VIEW.put(ATTR_LAYOUT_X, ABSOLUTE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_Y, ABSOLUTE_LAYOUT);
-
- // Linear Layout
- PARAM_TO_VIEW.put(ATTR_LAYOUT_WEIGHT, LINEAR_LAYOUT);
-
- // Grid Layout
- PARAM_TO_VIEW.put(ATTR_LAYOUT_COLUMN, GRID_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_COLUMN_SPAN, GRID_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ROW, GRID_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ROW_SPAN, GRID_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ROW_SPAN, GRID_LAYOUT);
-
- // Table Layout
- // ATTR_LAYOUT_COLUMN is defined for both GridLayout and TableLayout,
- // so we don't want to do
- // PARAM_TO_VIEW.put(ATTR_LAYOUT_COLUMN, TABLE_ROW);
- // here since it would wipe out the above GridLayout registration.
- // Since this is the only case where there is a conflict (in addition to layout_gravity
- // which is defined in many places), rather than making the map point to lists
- // this specific case is just special cased below, look for ATTR_LAYOUT_COLUMN.
- PARAM_TO_VIEW.put(ATTR_LAYOUT_SPAN, TABLE_ROW);
-
- // Relative Layout
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_LEFT, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_RIGHT, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_TOP, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_BOTTOM, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_PARENT_TOP, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_PARENT_LEFT, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_PARENT_RIGHT, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ALIGN_BASELINE, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_CENTER_IN_PARENT, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_CENTER_VERTICAL, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_CENTER_HORIZONTAL, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_TO_RIGHT_OF, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_TO_LEFT_OF, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_BELOW, RELATIVE_LAYOUT);
- PARAM_TO_VIEW.put(ATTR_LAYOUT_ABOVE, RELATIVE_LAYOUT);
- }
-
- /**
- * Map from an included layout to all the including contexts (each including
- * context is a pair of a file containing the include to the parent tag at
- * the included location)
- */
- private Map<String, List<Pair<File, String>>> mIncludes;
-
- /**
- * List of pending include checks. When a layout parameter attribute is
- * found on a root element, or on a child of a {@code merge} root tag, then
- * we want to check across layouts whether the including context (the parent
- * of the include tag) is valid for this attribute. We cannot check this
- * immediately because we are processing the layouts in an arbitrary order
- * so the included layout may be seen before the including layout and so on.
- * Therefore, we stash these attributes to be checked after we're done. Each
- * pair is a pair of an attribute name to be checked, and the file that
- * attribute is referenced in.
- */
- private final List<Pair<String, Location.Handle>> mPending =
- new ArrayList<Pair<String,Location.Handle>>();
-
- /** Constructs a new {@link ObsoleteLayoutParamsDetector} */
- public ObsoleteLayoutParamsDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(VIEW_INCLUDE);
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String name = attribute.getLocalName();
- if (name != null && name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- if (VALID.contains(name)) {
- return;
- }
-
- String parent = PARAM_TO_VIEW.get(name);
- if (parent != null) {
- Element viewElement = attribute.getOwnerElement();
- Node layoutNode = viewElement.getParentNode();
- if (layoutNode == null || layoutNode.getNodeType() != Node.ELEMENT_NODE) {
- // This is a layout attribute on a root element; this presumably means
- // that this layout is included so check the included layouts to make
- // sure at least one included context is valid for this layout_param.
- // We can't do that yet since we may be processing the include tag to
- // this layout after the layout itself. Instead, stash a work order...
- if (context.getScope().contains(Scope.ALL_RESOURCE_FILES)) {
- IDomParser parser = context.parser;
- Location.Handle handle = parser.createLocationHandle(context, attribute);
- handle.setClientData(attribute);
- mPending.add(Pair.of(name, handle));
- }
-
- return;
- }
-
- String parentTag = ((Element) layoutNode).getTagName();
- if (parentTag.equals(VIEW_MERGE)) {
- // This is a merge which means we need to check the including contexts,
- // wherever they are. This has to be done after all the files have been
- // scanned since we are not processing the files in any particular order.
- if (context.getScope().contains(Scope.ALL_RESOURCE_FILES)) {
- IDomParser parser = context.parser;
- Location.Handle handle = parser.createLocationHandle(context, attribute);
- handle.setClientData(attribute);
- mPending.add(Pair.of(name, handle));
- }
-
- return;
- }
-
- if (!isValidParamForParent(context, name, parent, parentTag)) {
- if (name.equals(ATTR_LAYOUT_COLUMN)
- && isValidParamForParent(context, name, TABLE_ROW, parentTag)) {
- return;
- }
- context.report(ISSUE, attribute, context.getLocation(attribute),
- String.format("Invalid layout param in a %1$s: %2$s", parentTag, name),
- null);
- }
- } else {
- // We could warn about unknown layout params but this might be brittle if
- // new params are added or if people write custom ones; this is just a log
- // for us to track these and update the check as necessary:
- //context.client.log(null,
- // String.format("Unrecognized layout param '%1$s'", name));
- }
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String layout = element.getAttribute(ATTR_LAYOUT);
- if (layout.startsWith(LAYOUT_RESOURCE_PREFIX)) { // Ignore @android:layout/ layouts
- layout = layout.substring(LAYOUT_RESOURCE_PREFIX.length());
-
- Node parent = element.getParentNode();
- if (parent.getNodeType() == Node.ELEMENT_NODE) {
- String tag = parent.getNodeName();
- if (tag.indexOf('.') == -1 && !tag.equals(VIEW_MERGE)) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- if (mIncludes == null) {
- mIncludes = new HashMap<String, List<Pair<File, String>>>();
- }
- List<Pair<File, String>> includes = mIncludes.get(layout);
- if (includes == null) {
- includes = new ArrayList<Pair<File, String>>();
- mIncludes.put(layout, includes);
- }
- includes.add(Pair.of(context.file, tag));
- }
- }
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mIncludes == null) {
- return;
- }
-
- for (Pair<String, Location.Handle> pending : mPending) {
- Handle handle = pending.getSecond();
- Location location = handle.resolve();
- File file = location.getFile();
- String layout = file.getName();
- if (layout.endsWith(DOT_XML)) {
- layout = layout.substring(0, layout.length() - DOT_XML.length());
- }
-
- List<Pair<File, String>> includes = mIncludes.get(layout);
- if (includes == null) {
- // Nobody included this file
- continue;
- }
-
- String name = pending.getFirst();
- String parent = PARAM_TO_VIEW.get(name);
- if (parent == null) {
- continue;
- }
-
- boolean isValid = false;
- for (Pair<File, String> include : includes) {
- String parentTag = include.getSecond();
- if (isValidParamForParent(context, name, parent, parentTag)) {
- isValid = true;
- break;
- } else if (!isValid && name.equals(ATTR_LAYOUT_COLUMN)
- && isValidParamForParent(context, name, TABLE_ROW, parentTag)) {
- isValid = true;
- break;
- }
- }
-
- if (!isValid) {
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ISSUE, (Node) clientData)) {
- return;
- }
- }
-
- StringBuilder sb = new StringBuilder(40);
- for (Pair<File, String> include : includes) {
- if (sb.length() > 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- File from = include.getFirst();
- String parentTag = include.getSecond();
- sb.append(String.format("included from within a %1$s in %2$s",
- parentTag,
- from.getParentFile().getName() + File.separator + from.getName()));
- }
- String message = String.format("Invalid layout param '%1$s' (%2$s)",
- name, sb.toString());
- // TODO: Compute applicable scope node
- context.report(ISSUE, location, message, null);
- }
- }
- }
-
- /**
- * Checks whether the given layout parameter name is valid for the given
- * parent tag assuming it has the given current parent tag
- */
- private static boolean isValidParamForParent(Context context, String name, String parent,
- String parentTag) {
- if (parentTag.indexOf('.') != -1 || parentTag.equals(VIEW_TAG)) {
- // Custom tag: We don't know whether it extends one of the builtin
- // types where the layout param is valid, so don't complain
- return true;
- }
-
- SdkInfo sdk = context.getSdkInfo();
-
- if (!parentTag.equals(parent)) {
- String tag = sdk.getParentViewName(parentTag);
- while (tag != null) {
- if (tag.equals(parent)) {
- return true;
- }
- tag = sdk.getParentViewName(tag);
- }
-
- return false;
- }
-
- return true;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OnClickDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OnClickDetector.java
deleted file mode 100644
index 2a07a86..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OnClickDetector.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_ON_CLICK;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.base.Joiner;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Node;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks for missing onClick handlers
- */
-public class OnClickDetector extends LayoutDetector implements ClassScanner {
- /** Missing onClick handlers */
- public static final Issue ISSUE = Issue.create(
- "OnClick", //$NON-NLS-1$
- "Ensures that onClick attribute values refer to real methods",
-
- "The `onClick` attribute value should be the name of a method in this View's context " +
- "to invoke when the view is clicked. This name must correspond to a public method " +
- "that takes exactly one parameter of type `View`.\n" +
- "\n" +
- "Must be a string value, using '\\;' to escape characters such as '\\n' or " +
- "'\\uxxxx' for a unicode character.",
- Category.CORRECTNESS,
- 10,
- Severity.ERROR,
- OnClickDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.CLASS_FILE));
-
- private Map<String, Location.Handle> mNames;
- private Map<String, List<String>> mSimilar;
- private boolean mHaveBytecode;
-
- /** Constructs a new {@link OnClickDetector} */
- public OnClickDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mNames != null && !mNames.isEmpty() && mHaveBytecode) {
- List<String> names = new ArrayList<String>(mNames.keySet());
- Collections.sort(names);
- LintDriver driver = context.getDriver();
- for (String name : names) {
- Handle handle = mNames.get(name);
-
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (driver.isSuppressed(ISSUE, (Node) clientData)) {
- continue;
- }
- }
-
- Location location = handle.resolve();
- String message = String.format(
- "Corresponding method handler 'public void %1$s(android.view.View)' not found",
- name);
- List<String> similar = mSimilar != null ? mSimilar.get(name) : null;
- if (similar != null) {
- Collections.sort(similar);
- message += String.format(" (did you mean %1$s ?)", Joiner.on(", ").join(similar));
- }
- context.report(ISSUE, location, message, null);
- }
- }
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_ON_CLICK);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String value = attribute.getValue();
- if (value.isEmpty() || value.trim().isEmpty()) {
- context.report(ISSUE, attribute, context.getLocation(attribute),
- "onClick attribute value cannot be empty", null);
- } else if (!value.equals(value.trim())) {
- context.report(ISSUE, attribute, context.getLocation(attribute),
- "There should be no whitespace around attribute values", null);
- } else if (!value.startsWith(PREFIX_RESOURCE_REF)) { // Not resolved
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- if (mNames == null) {
- mNames = new HashMap<String, Location.Handle>();
- }
- Handle handle = context.parser.createLocationHandle(context, attribute);
- handle.setClientData(attribute);
-
- // Replace unicode characters with the actual value since that's how they
- // appear in the ASM signatures
- if (value.contains("\\u")) { //$NON-NLS-1$
- Pattern pattern = Pattern.compile("\\\\u(\\d\\d\\d\\d)"); //$NON-NLS-1$
- Matcher matcher = pattern.matcher(value);
- StringBuilder sb = new StringBuilder(value.length());
- int remainder = 0;
- while (matcher.find()) {
- sb.append(value.substring(0, matcher.start()));
- String unicode = matcher.group(1);
- int hex = Integer.parseInt(unicode, 16);
- sb.append((char) hex);
- remainder = matcher.end();
- }
- sb.append(value.substring(remainder));
- value = sb.toString();
- }
-
- mNames.put(value, handle);
- }
- }
-
- // ---- Implements ClassScanner ----
-
- @SuppressWarnings("rawtypes")
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if (mNames == null) {
- // No onClick attributes in the XML files
- return;
- }
-
- mHaveBytecode = true;
-
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- boolean rightArguments = method.desc.equals("(Landroid/view/View;)V"); //$NON-NLS-1$
- if (!mNames.containsKey(method.name)) {
- if (rightArguments) {
- // See if there's a possible typo instead
- for (String n : mNames.keySet()) {
- if (LintUtils.editDistance(n, method.name) <= 2) {
- recordSimilar(n, classNode, method);
- break;
- }
- }
- }
- continue;
- }
-
- // TODO: Validate class hierarchy: should extend a context method
- // Longer term, also validate that it's in a layout that corresponds to
- // the given activity
-
- if (rightArguments){
- // Found: remove from list to be checked
- mNames.remove(method.name);
-
- // Make sure the method is public
- if ((method.access & Opcodes.ACC_PUBLIC) == 0) {
- Location location = context.getLocation(method, classNode);
- String message = String.format(
- "On click handler %1$s(View) must be public",
- method.name);
- context.report(ISSUE, location, message, null);
- } else if ((method.access & Opcodes.ACC_STATIC) != 0) {
- Location location = context.getLocation(method, classNode);
- String message = String.format(
- "On click handler %1$s(View) should not be static",
- method.name);
- context.report(ISSUE, location, message, null);
- }
-
- if (mNames.isEmpty()) {
- mNames = null;
- return;
- }
- }
- }
- }
-
- private void recordSimilar(String name, ClassNode classNode, MethodNode method) {
- if (mSimilar == null) {
- mSimilar = new HashMap<String, List<String>>();
- }
- List<String> list = mSimilar.get(name);
- if (list == null) {
- list = new ArrayList<String>();
- mSimilar.put(name, list);
- }
-
- String signature = ClassContext.createSignature(classNode.name, method.name, method.desc);
- list.add(signature);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverdrawDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverdrawDetector.java
deleted file mode 100644
index 6627411..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverdrawDetector.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PARENT;
-import static com.android.SdkConstants.ATTR_THEME;
-import static com.android.SdkConstants.ATTR_TILE_MODE;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.DRAWABLE_PREFIX;
-import static com.android.SdkConstants.NULL_RESOURCE;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_APPLICATION;
-import static com.android.SdkConstants.TAG_BITMAP;
-import static com.android.SdkConstants.TAG_STYLE;
-import static com.android.SdkConstants.TRANSPARENT_COLOR;
-import static com.android.SdkConstants.VALUE_DISABLED;
-import static com.android.tools.lint.detector.api.LintUtils.endsWith;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.CompilationUnit;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.MethodInvocation;
-import lombok.ast.PackageDeclaration;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.VariableReference;
-
-/**
- * Check which looks for overdraw problems where view areas are painted and then
- * painted over, meaning that the bottom paint operation is a waste of time.
- */
-public class OverdrawDetector extends LayoutDetector implements Detector.JavaScanner {
- private static final String R_STYLE_PREFIX = "R.style."; //$NON-NLS-1$
- private static final String SET_THEME = "setTheme"; //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "Overdraw", //$NON-NLS-1$
- "Looks for overdraw issues (where a view is painted only to be fully painted over)",
- "If you set a background drawable on a root view, then you should use a " +
- "custom theme where the theme background is null. Otherwise, the theme background " +
- "will be painted first, only to have your custom background completely cover it; " +
- "this is called \"overdraw\".\n" +
- "\n" +
- "NOTE: This detector relies on figuring out which layouts are associated with " +
- "which activities based on scanning the Java code, and it's currently doing that " +
- "using an inexact pattern matching algorithm. Therefore, it can incorrectly " +
- "conclude which activity the layout is associated with and then wrongly complain " +
- "that a background-theme is hidden.\n" +
- "\n" +
- "If you want your custom background on multiple pages, then you should consider " +
- "making a custom theme with your custom background and just using that theme " +
- "instead of a root element background.\n" +
- "\n" +
- "Of course it's possible that your custom drawable is translucent and you want " +
- "it to be mixed with the background. However, you will get better performance " +
- "if you pre-mix the background with your drawable and use that resulting image or " +
- "color as a custom theme background instead.\n",
-
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- OverdrawDetector.class,
- EnumSet.of(Scope.MANIFEST, Scope.JAVA_FILE, Scope.ALL_RESOURCE_FILES));
-
- /** Mapping from FQN activity names to theme names registered in the manifest */
- private Map<String, String> mActivityToTheme;
-
- /** The default theme declared in the manifest, or null */
- private String mManifestTheme;
-
- /** Mapping from layout name (not including {@code @layout/} prefix) to activity FQN */
- private Map<String, List<String>> mLayoutToActivity;
-
- /** List of theme names registered in the project which have blank backgrounds */
- private List<String> mBlankThemes;
-
- /** Set of activities registered in the manifest. We will limit the Java analysis to
- * these. */
- private Set<String> mActivities;
-
- /** List of drawable resources that are not flagged for overdraw (XML drawables
- * except for {@code <bitmap>} drawables without tiling) */
- private List<String> mValidDrawables;
-
- /**
- * List of pairs of (location, background drawable) corresponding to root elements
- * in layouts that define a given background drawable. These should be checked to
- * see if they are painting on top of a non-transparent theme.
- */
- private List<Pair<Location, String>> mRootAttributes;
-
- /** Constructs a new {@link OverdrawDetector} */
- public OverdrawDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- // Look in layouts for drawable resources
- return super.appliesTo(folderType)
- // and in resource files for theme definitions
- || folderType == ResourceFolderType.VALUES
- // and in drawable files for bitmap tiling modes
- || folderType == ResourceFolderType.DRAWABLE;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return LintUtils.isXmlFile(file) || LintUtils.endsWith(file.getName(), DOT_JAVA);
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- /** Is the given theme a "blank" theme (one not painting its background) */
- private boolean isBlankTheme(String name) {
- if (name.startsWith("@android:style/Theme_")) { //$NON-NLS-1$
- if (name.contains("NoFrame") //$NON-NLS-1$
- || name.contains("Theme_Wallpaper") //$NON-NLS-1$
- || name.contains("Theme_Holo_Wallpaper") //$NON-NLS-1$
- || name.contains("Theme_Translucent") //$NON-NLS-1$
- || name.contains("Theme_Dialog_NoFrame") //$NON-NLS-1$
- || name.contains("Theme_Holo_Dialog_Alert") //$NON-NLS-1$
- || name.contains("Theme_Holo_Light_Dialog_Alert") //$NON-NLS-1$
- || name.contains("Theme_Dialog_Alert") //$NON-NLS-1$
- || name.contains("Theme_Panel") //$NON-NLS-1$
- || name.contains("Theme_Light_Panel") //$NON-NLS-1$
- || name.contains("Theme_Holo_Panel") //$NON-NLS-1$
- || name.contains("Theme_Holo_Light_Panel")) { //$NON-NLS-1$
- return true;
- }
- }
-
- if (mBlankThemes != null && mBlankThemes.contains(name)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mRootAttributes != null) {
- for (Pair<Location, String> pair : mRootAttributes) {
- Location location = pair.getFirst();
-
- Object clientData = location.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ISSUE, (Node) clientData)) {
- return;
- }
- }
-
- String layoutName = location.getFile().getName();
- if (endsWith(layoutName, DOT_XML)) {
- layoutName = layoutName.substring(0, layoutName.length() - DOT_XML.length());
- }
-
- String theme = getTheme(context, layoutName);
- if (theme == null || !isBlankTheme(theme)) {
- String drawable = pair.getSecond();
- String message = String.format(
- "Possible overdraw: Root element paints background %1$s with " +
- "a theme that also paints a background (inferred theme is %2$s)",
- drawable, theme);
- // TODO: Compute applicable scope node
- context.report(ISSUE, location, message, null);
- }
-
- }
- }
- }
-
- /** Return the theme to be used for the given layout */
- private String getTheme(Context context, String layoutName) {
- if (mActivityToTheme != null && mLayoutToActivity != null) {
- List<String> activities = mLayoutToActivity.get(layoutName);
- if (activities != null) {
- for (String activity : activities) {
- String theme = mActivityToTheme.get(activity);
- if (theme != null) {
- return theme;
- }
- }
- }
- }
-
- if (mManifestTheme != null) {
- return mManifestTheme;
- }
-
- Project project = context.getMainProject();
- int apiLevel = project.getTargetSdk();
- if (apiLevel == -1) {
- apiLevel = project.getMinSdk();
- }
-
- if (apiLevel >= 11) {
- return "@android:style/Theme.Holo"; //$NON-NLS-1$
- } else {
- return "@android:style/Theme"; //$NON-NLS-1$
- }
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- // Only consider the root element's background
- if (attribute.getOwnerDocument().getDocumentElement() == attribute.getOwnerElement()) {
- // If the drawable is a non-repeated pattern then the overdraw might be
- // intentional since the image isn't covering the whole screen
- String background = attribute.getValue();
- if (mValidDrawables != null && mValidDrawables.contains(background)) {
- return;
- }
-
- if (background.equals(TRANSPARENT_COLOR)) {
- return;
- }
-
- if (background.startsWith("@android:drawable/")) { //$NON-NLS-1$
- // We haven't had a chance to study the builtin drawables the way we
- // check the project local ones in scanBitmap() and beforeCheckFile(),
- // but many of these are not bitmaps, so ignore these
- return;
- }
-
- String name = context.file.getName();
- if (name.contains("list_") || name.contains("_item")) { //$NON-NLS-1$ //$NON-NLS-2$
- // Canonical list_item layout name: don't warn about these, it's
- // pretty common to want to paint custom list item backgrounds
- return;
- }
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- Location location = context.getLocation(attribute);
- location.setClientData(attribute);
- if (mRootAttributes == null) {
- mRootAttributes = new ArrayList<Pair<Location,String>>();
- }
- mRootAttributes.add(Pair.of(location, attribute.getValue()));
- }
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(
- // Layouts: Look for background attributes on root elements for possible overdraw
- ATTR_BACKGROUND
- );
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- // Manifest: Look at theme registrations
- TAG_ACTIVITY,
- TAG_APPLICATION,
-
- // Resource files: Look at theme definitions
- TAG_STYLE,
-
- // Bitmaps
- TAG_BITMAP
- );
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- if (endsWith(context.file.getName(), DOT_XML)) {
- // Drawable XML files should not be considered for overdraw, except for <bitmap>'s.
- // The bitmap elements are handled in the scanBitmap() method; it will clear
- // out anything added by this method.
- File parent = context.file.getParentFile();
- ResourceFolderType type = ResourceFolderType.getFolderType(parent.getName());
- if (type == ResourceFolderType.DRAWABLE) {
- if (mValidDrawables == null) {
- mValidDrawables = new ArrayList<String>();
- }
- String resource = getDrawableResource(context.file);
- mValidDrawables.add(resource);
- }
- }
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String tag = element.getTagName();
- if (tag.equals(TAG_STYLE)) {
- scanTheme(element);
- } else if (tag.equals(TAG_ACTIVITY)) {
- scanActivity(context, element);
- } else if (tag.equals(TAG_APPLICATION)) {
- if (element.hasAttributeNS(ANDROID_URI, ATTR_THEME)) {
- mManifestTheme = element.getAttributeNS(ANDROID_URI, ATTR_THEME);
- }
- } else if (tag.equals(TAG_BITMAP)) {
- scanBitmap(context, element);
- }
- }
-
- private static String getDrawableResource(File drawableFile) {
- String resource = drawableFile.getName();
- if (endsWith(resource, DOT_XML)) {
- resource = resource.substring(0, resource.length() - DOT_XML.length());
- }
- return DRAWABLE_PREFIX + resource;
- }
-
- private void scanBitmap(Context context, Element element) {
- String tileMode = element.getAttributeNS(ANDROID_URI, ATTR_TILE_MODE);
- if (!(tileMode.equals(VALUE_DISABLED) || tileMode.isEmpty())) {
- if (mValidDrawables != null) {
- String resource = getDrawableResource(context.file);
- mValidDrawables.remove(resource);
- }
- }
- }
-
- private void scanActivity(Context context, Element element) {
- String name = element.getAttributeNS(ANDROID_URI, ATTR_NAME);
- if (name.indexOf('$') != -1) {
- name = name.replace('$', '.');
- }
- if (name.startsWith(".")) { //$NON-NLS-1$
- String pkg = context.getProject().getPackage();
- if (pkg != null && !pkg.isEmpty()) {
- name = pkg + name;
- }
- }
-
- if (mActivities == null) {
- mActivities = new HashSet<String>();
- }
- mActivities.add(name);
-
- String theme = element.getAttributeNS(ANDROID_URI, ATTR_THEME);
- if (theme != null && !theme.isEmpty()) {
- if (mActivityToTheme == null) {
- mActivityToTheme = new HashMap<String, String>();
- }
- mActivityToTheme.put(name, theme.replace('.', '_'));
- }
- }
-
- private void scanTheme(Element element) {
- // Look for theme definitions, and record themes that provide a null background.
- String styleName = element.getAttribute(ATTR_NAME);
- String parent = element.getAttribute(ATTR_PARENT);
- if (parent == null) {
- // Eclipse DOM workaround
- parent = "";
- }
-
- if (parent.isEmpty()) {
- int index = styleName.lastIndexOf('.');
- if (index != -1) {
- parent = styleName.substring(0, index);
- }
- }
- parent = parent.replace('.', '_');
-
- String resource = STYLE_RESOURCE_PREFIX + styleName.replace('.', '_');
-
- NodeList items = element.getChildNodes();
- for (int i = 0, n = items.getLength(); i < n; i++) {
- if (items.item(i).getNodeType() == Node.ELEMENT_NODE) {
- Element item = (Element) items.item(i);
- String name = item.getAttribute(ATTR_NAME);
- if (name.equals("android:windowBackground")) { //$NON-NLS-1$
- NodeList textNodes = item.getChildNodes();
- for (int j = 0, m = textNodes.getLength(); j < m; j++) {
- Node textNode = textNodes.item(j);
- if (textNode.getNodeType() == Node.TEXT_NODE) {
- String text = textNode.getNodeValue();
- String trim = text.trim();
- if (!trim.isEmpty()) {
- if (trim.equals(NULL_RESOURCE)
- || trim.equals(TRANSPARENT_COLOR)
- || mValidDrawables != null
- && mValidDrawables.contains(trim)) {
- if (mBlankThemes == null) {
- mBlankThemes = new ArrayList<String>();
- }
- mBlankThemes.add(resource);
- }
- }
- }
- }
-
- return;
- }
- }
- }
-
- if (isBlankTheme(parent)) {
- if (mBlankThemes == null) {
- mBlankThemes = new ArrayList<String>();
- }
- mBlankThemes.add(resource);
- }
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes() {
- // This detector does not specify specific node types; this means
- // that the infrastructure will run the full visitor on the compilation
- // unit rather than on individual nodes. This is important since this
- // detector relies on pruning (if it gets to a class declaration that is
- // not an activity, it skips everything inside).
- return null;
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- if (!context.getProject().getReportIssues()) {
- return null;
- }
- return new OverdrawVisitor();
- }
-
- private class OverdrawVisitor extends ForwardingAstVisitor {
- private static final String ACTIVITY = "Activity"; //$NON-NLS-1$
- private String mClassFqn;
-
- @Override
- public boolean visitClassDeclaration(ClassDeclaration node) {
- String name = node.getDescription();
-
- if (mActivities != null && mActivities.contains(mClassFqn) || name.endsWith(ACTIVITY)
- || node.astExtending() != null &&
- node.astExtending().getDescription().endsWith(ACTIVITY)) {
- String packageName = "";
- if (node.getParent() instanceof CompilationUnit) {
- CompilationUnit compilationUnit = (CompilationUnit) node.getParent();
- PackageDeclaration packageDeclaration = compilationUnit.astPackageDeclaration();
- if (packageDeclaration == null) {
- // No package declaration: ignore this one
- return true;
- }
- packageName = packageDeclaration.getPackageName();
- }
- mClassFqn = (!packageName.isEmpty() ? (packageName + '.') : "") + name;
-
- return false;
- }
-
- return true; // Done: No need to look inside this class
- }
-
- // Store R.layout references in activity classes in a map mapping back layouts
- // to activities
- @Override
- public boolean visitSelect(Select node) {
- if (node.astIdentifier().astValue().equals("layout") //$NON-NLS-1$
- && node.astOperand() instanceof VariableReference
- && ((VariableReference) node.astOperand()).astIdentifier().astValue()
- .equals("R") //$NON-NLS-1$
- && node.getParent() instanceof Select) {
- String layout = ((Select) node.getParent()).astIdentifier().astValue();
- if (mLayoutToActivity == null) {
- mLayoutToActivity = new HashMap<String, List<String>>();
- }
- List<String> list = mLayoutToActivity.get(layout);
- if (list == null) {
- list = new ArrayList<String>();
- mLayoutToActivity.put(layout, list);
- }
- list.add(mClassFqn);
- }
-
- return false;
- }
-
-
- // Look for setTheme(R.style.whatever) and register as a theme registration
- // for the current activity
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (node.astName().astValue().equals(SET_THEME)) {
- // Look at argument
- StrictListAccessor<Expression, MethodInvocation> args = node.astArguments();
- if (args.size() == 1) {
- Expression arg = args.first();
- if (arg instanceof Select) {
- String resource = arg.toString();
- if (resource.startsWith(R_STYLE_PREFIX)) {
- if (mActivityToTheme == null) {
- mActivityToTheme = new HashMap<String, String>();
- }
- String name = ((Select) arg).astIdentifier().astValue();
- mActivityToTheme.put(mClassFqn, STYLE_RESOURCE_PREFIX + name);
- }
- }
- }
- }
-
- return false;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverrideDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverrideDetector.java
deleted file mode 100644
index 15e2245..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/OverrideDetector.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
-import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ACC_STATIC;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
-
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * Checks for accidental overrides
- */
-public class OverrideDetector extends Detector implements ClassScanner {
- /** Accidental overrides */
- public static final Issue ISSUE = Issue.create(
- "DalvikOverride", //$NON-NLS-1$
- "Looks for methods treated as overrides by Dalvik",
-
- "The Android virtual machine will treat a package private method in one " +
- "class as overriding a package private method in its super class, even if " +
- "they are in separate packages. This may be surprising, but for compatibility " +
- "reasons the behavior has not been changed (yet).\n" +
- "\n" +
- "If you really did intend for this method to override the other, make the " +
- "method `protected` instead.\n" +
- "\n" +
- "If you did *not* intend the override, consider making the method private, or " +
- "changing its name or signature.",
-
- Category.CORRECTNESS,
- 7,
- Severity.ERROR,
- OverrideDetector.class,
- EnumSet.of(Scope.ALL_CLASS_FILES));
-
- /** map from owner class name to JVM signatures for its package private methods */
- private final Map<String, Set<String>> mPackagePrivateMethods = Maps.newHashMap();
-
- /** Map from owner to signature to super class being overridden */
- private Map<String, Map<String, String>> mErrors;
-
- /**
- * Map from owner to signature to corresponding location. When there are
- * errors a single error can have locations for both the overriding and
- * overridden methods.
- */
- private Map<String, Map<String, Location>> mLocations;
-
- /** Constructs a new {@link OverrideDetector} */
- public OverrideDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- // Process the check in two passes:
- //
- // In the first pass, gather the full set of package private methods for
- // each class.
- // When all classes have been processed at the end of the first pass,
- // find out whether any of the methods are potentially overriding those
- // in its super classes.
- //
- // If so, request a second pass. In the second pass, we gather full locations
- // for both the base and overridden method calls, and store these.
- // If the location is found to be in a suppressed context, remove that error
- // entry.
- //
- // At the end of the second pass, we generate the errors, combining locations
- // from both the overridden and overriding methods.
- if (context.getPhase() == 1) {
- Set<String> classes = mPackagePrivateMethods.keySet();
- LintDriver driver = context.getDriver();
- for (String owner : classes) {
- Set<String> methods = mPackagePrivateMethods.get(owner);
- String superClass = driver.getSuperClass(owner);
- int packageIndex = owner.lastIndexOf('/');
- while (superClass != null) {
- int superPackageIndex = superClass.lastIndexOf('/');
-
- // Only compare methods that differ in packages
- if (packageIndex == -1 || superPackageIndex != packageIndex ||
- !owner.regionMatches(0, superClass, 0, packageIndex)) {
- Set<String> superMethods = mPackagePrivateMethods.get(superClass);
- if (superMethods != null) {
- SetView<String> intersection = Sets.intersection(methods,
- superMethods);
- if (!intersection.isEmpty()) {
- if (mLocations == null) {
- mLocations = Maps.newHashMap();
- }
- // We need a separate data structure to keep track of which
- // signatures are in error,
- if (mErrors == null) {
- mErrors = Maps.newHashMap();
- }
-
- for (String signature : intersection) {
- Map<String, Location> locations = mLocations.get(owner);
- if (locations == null) {
- locations = Maps.newHashMap();
- mLocations.put(owner, locations);
- }
- locations.put(signature, null);
-
- locations = mLocations.get(superClass);
- if (locations == null) {
- locations = Maps.newHashMap();
- mLocations.put(superClass, locations);
- }
- locations.put(signature, null);
-
-
- Map<String, String> errors = mErrors.get(owner);
- if (errors == null) {
- errors = Maps.newHashMap();
- mErrors.put(owner, errors);
- }
- errors.put(signature, superClass);
- }
- }
- }
- }
- superClass = driver.getSuperClass(superClass);
- }
- }
-
- if (mErrors != null) {
- context.requestRepeat(this, ISSUE.getScope());
- }
- } else {
- assert context.getPhase() == 2;
-
- for (Entry<String, Map<String, String>> ownerEntry : mErrors.entrySet()) {
- String owner = ownerEntry.getKey();
- Map<String, String> methodToSuper = ownerEntry.getValue();
- for (Entry<String, String> entry : methodToSuper.entrySet()) {
- String signature = entry.getKey();
- String superClass = entry.getValue();
-
- Map<String, Location> ownerLocations = mLocations.get(owner);
- if (ownerLocations != null) {
- Location location = ownerLocations.get(signature);
- if (location != null) {
- Map<String, Location> superLocations = mLocations.get(superClass);
- if (superLocations != null) {
- Location superLocation = superLocations.get(signature);
- if (superLocation != null) {
- location.setSecondary(superLocation);
- superLocation.setMessage(
- "This method is treated as overridden");
- }
- }
- String methodName = signature;
- int index = methodName.indexOf('(');
- if (index != -1) {
- methodName = methodName.substring(0, index);
- }
- String message = String.format(
- "This package private method may be unintentionally " +
- "overriding %1$s in %2$s", methodName,
- ClassContext.getFqcn(superClass));
- context.report(ISSUE, location, message, null);
- }
- }
- }
- }
- }
- }
-
- @SuppressWarnings("rawtypes") // ASM4 API
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- List methodList = classNode.methods;
- if (context.getPhase() == 1) {
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- int access = method.access;
- // Only record non-static package private methods
- if ((access & (ACC_STATIC|ACC_PRIVATE|ACC_PROTECTED|ACC_PUBLIC)) != 0) {
- continue;
- }
-
- // Ignore constructors too
- if (CONSTRUCTOR_NAME.equals(method.name)) {
- continue;
- }
-
- String owner = classNode.name;
- Set<String> methods = mPackagePrivateMethods.get(owner);
- if (methods == null) {
- methods = Sets.newHashSetWithExpectedSize(methodList.size());
- mPackagePrivateMethods.put(owner, methods);
- }
- methods.add(method.name + method.desc);
- }
- } else {
- assert context.getPhase() == 2;
- Map<String, Location> methods = mLocations.get(classNode.name);
- if (methods == null) {
- // No locations needed from this class
- return;
- }
-
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
-
- String signature = method.name + method.desc;
- if (methods.containsKey(signature)){
- if (context.getDriver().isSuppressed(ISSUE, classNode,
- method, null)) {
- Map<String, String> errors = mErrors.get(classNode.name);
- if (errors != null) {
- errors.remove(signature);
- }
- continue;
- }
-
- Location location = context.getLocation(method, classNode);
- methods.put(signature, location);
- String description = ClassContext.createSignature(classNode.name,
- method.name, method.desc);
- location.setClientData(description);
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java
deleted file mode 100644
index e8887a5..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateKeyDetector.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.google.common.base.Charsets;
-import com.google.common.io.Files;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.EnumSet;
-
-/**
- * Looks for packaged private key files.
- */
-public class PrivateKeyDetector extends Detector implements Detector.OtherFileScanner {
- /** Packaged private key files */
- public static final Issue ISSUE = Issue.create(
- "PackagedPrivateKey", //$NON-NLS-1$
- "Looks for packaged private key files",
-
- "In general, you should not package private key files inside your app.",
-
- Category.SECURITY,
- 8,
- Severity.WARNING,
- PrivateKeyDetector.class,
- Scope.OTHER_SCOPE);
-
- /** Constructs a new {@link PrivateKeyDetector} check */
- public PrivateKeyDetector() {
- }
-
- private static boolean isPrivateKeyFile(File file) {
- if (!file.isFile() ||
- (!LintUtils.endsWith(file.getPath(), "pem") && //NON-NLS-1$
- !LintUtils.endsWith(file.getPath(), "key"))) { //NON-NLS-1$
- return false;
- }
-
- try {
- String firstLine = Files.readFirstLine(file, Charsets.US_ASCII);
- return firstLine != null &&
- firstLine.startsWith("---") && //NON-NLS-1$
- firstLine.contains("PRIVATE KEY"); //NON-NLS-1$
- } catch (IOException ex) {
- // Don't care
- }
-
- return false;
- }
-
- // ---- Implements OtherFileScanner ----
-
- @NonNull
- @Override
- public EnumSet<Scope> getApplicableFiles() {
- return Scope.OTHER_SCOPE;
- }
-
- @Override
- public void run(@NonNull Context context) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- File file = context.file;
- if (isPrivateKeyFile(file)) {
- String fileName = file.getParentFile().getName() + File.separator
- + file.getName();
- String message = String.format(
- "The %1$s file seems to be a private key file. " +
- "Please make sure not to embed this in your APK file.", fileName);
- context.report(ISSUE, Location.create(file), message, null);
- }
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateResourceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateResourceDetector.java
deleted file mode 100644
index d8a4ce0..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PrivateResourceDetector.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-
-import java.util.Collection;
-
-/**
- * Check which looks for access of private resources.
- */
-public class PrivateResourceDetector extends ResourceXmlDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "PrivateResource", //$NON-NLS-1$
- "Looks for references to private resources",
- "Private resources should not be referenced; the may not be present everywhere, and " +
- "even where they are they may disappear without notice.\n" +
- "\n" +
- "To fix this, copy the resource into your own project. You can find the platform " +
- "resources under `$ANDROID_SK/platforms/android-$VERSION/data/res/.`",
- Category.CORRECTNESS,
- 3,
- Severity.FATAL,
- PrivateResourceDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new detector */
- public PrivateResourceDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String value = attribute.getNodeValue();
- if (value.startsWith("@*android:")) { //$NON-NLS-1$
- context.report(ISSUE, attribute, context.getLocation(attribute),
- "Illegal resource reference: @*android resources are private and " +
- "not always present", null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ProguardDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ProguardDetector.java
deleted file mode 100644
index 7762659..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ProguardDetector.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.PROGUARD_CONFIG;
-import static com.android.SdkConstants.PROJECT_PROPERTIES;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.io.File;
-import java.util.EnumSet;
-
-/**
- * Check which looks for errors in Proguard files.
- */
-public class ProguardDetector extends Detector {
-
- /** The main issue discovered by this detector */
- public static final Issue WRONGKEEP = Issue.create(
- "Proguard", //$NON-NLS-1$
- "Looks for problems in proguard config files",
- "Using `-keepclasseswithmembernames` in a proguard config file is not " +
- "correct; it can cause some symbols to be renamed which should not be.\n" +
- "Earlier versions of ADT used to create proguard.cfg files with the " +
- "wrong format. Instead of `-keepclasseswithmembernames` use " +
- "`-keepclasseswithmembers`, since the old flags also implies " +
- "\"allow shrinking\" which means symbols only referred to from XML and " +
- "not Java (such as possibly CustomViews) can get deleted.",
- Category.CORRECTNESS,
- 8,
- Severity.FATAL,
- ProguardDetector.class,
- EnumSet.of(Scope.PROGUARD_FILE)).setMoreInfo(
- "http://http://code.google.com/p/android/issues/detail?id=16384"); //$NON-NLS-1$
-
- /** Finds ProGuard files that contain non-project specific configuration
- * locally and suggests replacing it with an include path */
- public static final Issue SPLITCONFIG = Issue.create(
- "ProguardSplit", //$NON-NLS-1$
- "Checks for old proguard.cfg files that contain generic Android rules",
-
- "Earlier versions of the Android tools bundled a single `proguard.cfg` file " +
- "containing a ProGuard configuration file suitable for Android shrinking and " +
- "obfuscation. However, that version was copied into new projects, which " +
- "means that it does not continue to get updated as we improve the default " +
- "ProGuard rules for Android.\n" +
- "\n" +
- "In the new version of the tools, we have split the ProGuard configuration " +
- "into two halves:\n" +
- "* A simple configuration file containing only project-specific flags, in " +
- "your project\n" +
- "* A generic configuration file containing the recommended set of ProGuard " +
- "options for Android projects. This generic file lives in the SDK install " +
- "directory which means that it gets updated along with the tools.\n" +
- "\n" +
- "In order for this to work, the proguard.config property in the " +
- "`project.properties` file now refers to a path, so you can reference both " +
- "the generic file as well as your own (and any additional files too).\n" +
- "\n" +
- "To migrate your project to the new setup, create a new `proguard-project.txt` file " +
- "in your project containing any project specific ProGuard flags as well as " +
- "any customizations you have made, then update your project.properties file " +
- "to contain:\n" +
- "`proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt`",
-
- Category.CORRECTNESS,
- 3,
- Severity.WARNING,
- ProguardDetector.class,
- EnumSet.of(Scope.PROGUARD_FILE));
-
- @Override
- public void run(@NonNull Context context) {
- String contents = context.getContents();
- if (contents != null) {
- if (context.isEnabled(WRONGKEEP)) {
- int index = contents.indexOf(
- // Old pattern:
- "-keepclasseswithmembernames class * {\n" + //$NON-NLS-1$
- " public <init>(android."); //$NON-NLS-1$
- if (index != -1) {
- context.report(WRONGKEEP,
- Location.create(context.file, contents, index, index),
- "Obsolete ProGuard file; use -keepclasseswithmembers instead of " +
- "-keepclasseswithmembernames", null);
- }
- }
- if (context.isEnabled(SPLITCONFIG)) {
- int index = contents.indexOf("-keep public class * extends android.app.Activity");
- if (index != -1) {
- // Only complain if project.properties actually references this file;
- // no need to bother the users who got a default proguard.cfg file
- // when they created their projects but haven't actually hooked it up
- // to shrinking & obfuscation.
- File propertyFile = new File(context.file.getParentFile(), PROJECT_PROPERTIES);
- if (!propertyFile.exists()) {
- return;
- }
- String properties = context.getClient().readFile(propertyFile);
- int i = properties.indexOf(PROGUARD_CONFIG);
- if (i == -1) {
- return;
- }
- // Make sure the entry isn't just commented out, such as
- // # To enable ProGuard to shrink and obfuscate your code, uncomment this:
- // #proguard.config=proguard.cfg
- for (; i >= 0; i--) {
- char c = properties.charAt(i);
- if (c == '#') {
- return;
- }
- if (c == '\n') {
- break;
- }
- }
- if (properties.contains(PROGUARD_CONFIG)) {
- context.report(SPLITCONFIG,
- Location.create(context.file, contents, index, index),
- String.format(
- "Local ProGuard configuration contains general Android " +
- "configuration: Inherit these settings instead? " +
- "Modify project.properties to define " +
- "proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:%1$s" +
- " and then keep only project-specific configuration here",
- context.file.getName()), null);
- }
- }
- }
- }
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PxUsageDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PxUsageDetector.java
deleted file mode 100644
index ed9447e..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/PxUsageDetector.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TEXT_SIZE;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_STYLE;
-import static com.android.SdkConstants.UNIT_DIP;
-import static com.android.SdkConstants.UNIT_DP;
-import static com.android.SdkConstants.UNIT_IN;
-import static com.android.SdkConstants.UNIT_MM;
-import static com.android.SdkConstants.UNIT_PX;
-import static com.android.SdkConstants.UNIT_SP;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check for px dimensions instead of dp dimensions.
- * Also look for non-"sp" text sizes.
- */
-public class PxUsageDetector extends LayoutDetector {
- /** Using px instead of dp */
- public static final Issue PX_ISSUE = Issue.create(
- "PxUsage", //$NON-NLS-1$
- "Looks for use of the \"px\" dimension",
- // This description is from the below screen support document
- "For performance reasons and to keep the code simpler, the Android system uses pixels " +
- "as the standard unit for expressing dimension or coordinate values. That means that " +
- "the dimensions of a view are always expressed in the code using pixels, but " +
- "always based on the current screen density. For instance, if `myView.getWidth()` " +
- "returns 10, the view is 10 pixels wide on the current screen, but on a device with " +
- "a higher density screen, the value returned might be 15. If you use pixel values " +
- "in your application code to work with bitmaps that are not pre-scaled for the " +
- "current screen density, you might need to scale the pixel values that you use in " +
- "your code to match the un-scaled bitmap source.",
- Category.CORRECTNESS,
- 2,
- Severity.WARNING,
- PxUsageDetector.class,
- Scope.RESOURCE_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/screens_support.html#screen-independence"); //$NON-NLS-1$
-
- /** Using mm/in instead of dp */
- public static final Issue IN_MM_ISSUE = Issue.create(
- "InOrMmUsage", //$NON-NLS-1$
- "Looks for use of the \"mm\" or \"in\" dimensions",
-
- "Avoid using `mm` (millimeters) or `in` (inches) as the unit for dimensions.\n" +
- "\n" +
- "While it should work in principle, unfortunately many devices do not report " +
- "the correct true physical density, which means that the dimension calculations " +
- "won't work correctly. You are better off using `dp` (and for font sizes, `sp`.)",
-
- Category.CORRECTNESS,
- 4,
- Severity.WARNING,
- PxUsageDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Using sp instead of dp */
- public static final Issue DP_ISSUE = Issue.create(
- "SpUsage", //$NON-NLS-1$
- "Looks for uses of \"dp\" instead of \"sp\" dimensions for text sizes",
-
- "When setting text sizes, you should normally use `sp`, or \"scale-independent " +
- "pixels\". This is like the `dp` unit, but it is also scaled " +
- "by the user's font size preference. It is recommend you use this unit when " +
- "specifying font sizes, so they will be adjusted for both the screen density " +
- "and the user's preference.\n" +
- "\n" +
- "There *are* cases where you might need to use `dp`; typically this happens when " +
- "the text is in a container with a specific dp-size. This will prevent the text " +
- "from spilling outside the container. Note however that this means that the user's " +
- "font size settings are not respected, so consider adjusting the layout itself " +
- "to be more flexible.",
- Category.CORRECTNESS,
- 3,
- Severity.WARNING,
- PxUsageDetector.class,
- Scope.RESOURCE_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/training/multiscreen/screendensities.html"); //$NON-NLS-1$
-
- /** Using text sizes that are too small */
- public static final Issue SMALL_SP_ISSUE = Issue.create(
- "SmallSp", //$NON-NLS-1$
- "Looks for text sizes that are too small",
-
- "Avoid using sizes smaller than 12sp.",
-
- Category.USABILITY,
- 4,
- Severity.WARNING,
- PxUsageDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
-
- /** Constructs a new {@link PxUsageDetector} */
- public PxUsageDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- // Look in both layouts (at attribute values) and in value files (at style definitions)
- return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- @Nullable
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(TAG_STYLE);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- if (context.getResourceFolderType() != ResourceFolderType.LAYOUT) {
- return;
- }
-
- String value = attribute.getValue();
- if (value.endsWith(UNIT_PX) && value.matches("\\d+px")) { //$NON-NLS-1$
- if (value.charAt(0) == '0') {
- // 0px is fine. 0px is 0dp regardless of density...
- return;
- }
- if (context.isEnabled(PX_ISSUE)) {
- context.report(PX_ISSUE, attribute, context.getLocation(attribute),
- "Avoid using \"px\" as units; use \"dp\" instead", null);
- }
- } else if (value.endsWith(UNIT_MM) && value.matches("\\d+mm") //$NON-NLS-1$
- || value.endsWith(UNIT_IN) && value.matches("\\d+in")) { //$NON-NLS-1$
- if (value.charAt(0) == '0') {
- // 0mm == 0in == 0dp
- return;
- }
- if (context.isEnabled(IN_MM_ISSUE)) {
- String unit = value.substring(value.length() - 2);
- context.report(IN_MM_ISSUE, attribute, context.getLocation(attribute),
- String.format("Avoid using \"%1$s\" as units " +
- "(it does not work accurately on all devices); use \"dp\" instead",
- unit),
- null);
- }
- } else if (value.endsWith(UNIT_SP)
- && (ATTR_TEXT_SIZE.equals(attribute.getLocalName())
- || ATTR_LAYOUT_HEIGHT.equals(attribute.getLocalName()))
- && value.matches("\\d+sp")) { //$NON-NLS-1$
- int size = getSize(value);
- if (size > 0 && size < 12) {
- context.report(SMALL_SP_ISSUE, attribute, context.getLocation(attribute),
- String.format("Avoid using sizes smaller than 12sp: %1$s", value),
- null);
- }
- } else if (ATTR_TEXT_SIZE.equals(attribute.getLocalName())
- && (value.endsWith(UNIT_DP) || value.endsWith(UNIT_DIP))
- && (value.matches("\\d+di?p"))) { //$NON-NLS-1$
- if (context.isEnabled(DP_ISSUE)) {
- context.report(DP_ISSUE, attribute, context.getLocation(attribute),
- "Should use \"sp\" instead of \"dp\" for text sizes", null);
- }
- }
- }
-
- private static int getSize(String text) {
- assert text.matches("\\d+sp") : text; //$NON-NLS-1$
- return Integer.parseInt(text.substring(0, text.length() - 2));
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (context.getResourceFolderType() != ResourceFolderType.VALUES) {
- return;
- }
-
- assert element.getTagName().equals(TAG_STYLE);
- NodeList itemNodes = element.getChildNodes();
- for (int j = 0, nodeCount = itemNodes.getLength(); j < nodeCount; j++) {
- Node item = itemNodes.item(j);
- if (item.getNodeType() == Node.ELEMENT_NODE &&
- TAG_ITEM.equals(item.getNodeName())) {
- Element itemElement = (Element) item;
- NodeList childNodes = item.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() != Node.TEXT_NODE) {
- return;
- }
-
- checkStyleItem(context, itemElement, child);
- }
- }
- }
- }
-
- private static void checkStyleItem(XmlContext context, Element item, Node textNode) {
- String text = textNode.getNodeValue();
- for (int j = text.length() - 1; j > 0; j--) {
- char c = text.charAt(j);
- if (!Character.isWhitespace(c)) {
- if (c == 'x' && text.charAt(j - 1) == 'p') { // ends with px
- text = text.trim();
- if (text.matches("\\d+px") && text.charAt(0) != '0') { //$NON-NLS-1$
- if (context.isEnabled(PX_ISSUE)) {
- context.report(PX_ISSUE, item, context.getLocation(textNode),
- "Avoid using \"px\" as units; use \"dp\" instead", null);
- }
- }
- } else if (c == 'm' && text.charAt(j - 1) == 'm' ||
- c == 'n' && text.charAt(j - 1) == 'i') {
- text = text.trim();
- String unit = text.substring(text.length() - 2);
- if (text.matches("\\d+" + unit) && text.charAt(0) != '0') { //$NON-NLS-1$
- if (context.isEnabled(IN_MM_ISSUE)) {
- context.report(IN_MM_ISSUE, item, context.getLocation(textNode),
- String.format("Avoid using \"%1$s\" as units "
- + "(it does not work accurately on all devices); "
- + "use \"dp\" instead", unit), null);
- }
- }
- } else if (c == 'p' && (text.charAt(j - 1) == 'd'
- || text.charAt(j - 1) == 'i')) { // ends with dp or di
- text = text.trim();
- String name = item.getAttribute(ATTR_NAME);
- if ((name.equals(ATTR_TEXT_SIZE)
- || name.equals("android:textSize")) //$NON-NLS-1$
- && text.matches("\\d+di?p")) { //$NON-NLS-1$
- if (context.isEnabled(DP_ISSUE)) {
- context.report(DP_ISSUE, item, context.getLocation(textNode),
- "Should use \"sp\" instead of \"dp\" for text sizes", null);
- }
- }
- } else if (c == 'p' && text.charAt(j - 1) == 's') {
- String name = item.getAttribute(ATTR_NAME);
- if (ATTR_TEXT_SIZE.equals(name) || ATTR_LAYOUT_HEIGHT.equals(name)) {
- text = text.trim();
- String unit = text.substring(text.length() - 2);
- if (text.matches("\\d+" + unit)) { //$NON-NLS-1$
- if (context.isEnabled(SMALL_SP_ISSUE)) {
- int size = getSize(text);
- if (size > 0 && size < 12) {
- context.report(SMALL_SP_ISSUE, item,
- context.getLocation(textNode), String.format(
- "Avoid using sizes smaller than 12sp: %1$s",
- text), null);
- }
- }
- }
- }
- }
- break;
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RegistrationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RegistrationDetector.java
deleted file mode 100644
index c4fd0a7..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RegistrationDetector.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_APP_ACTIVITY;
-import static com.android.SdkConstants.ANDROID_APP_SERVICE;
-import static com.android.SdkConstants.ANDROID_CONTENT_BROADCAST_RECEIVER;
-import static com.android.SdkConstants.ANDROID_CONTENT_CONTENT_PROVIDER;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_PROVIDER;
-import static com.android.SdkConstants.TAG_RECEIVER;
-import static com.android.SdkConstants.TAG_SERVICE;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.w3c.dom.Element;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Map.Entry;
-
-/**
- * Checks for missing manifest registrations for activities, services etc
- * and also makes sure that they are registered with the correct tag
- */
-public class RegistrationDetector extends LayoutDetector implements ClassScanner {
- /** Unregistered activities and services */
- public static final Issue ISSUE = Issue.create(
- "Registered", //$NON-NLS-1$
- "Ensures that Activities, Services and Content Providers are registered in the manifest",
-
- "Activities, services and content providers should be registered in the " +
- "`AndroidManifest.xml` file using `<activity>`, `<service>` and `<provider>` tags.\n" +
- "\n" +
- "If your activity is simply a parent class intended to be subclassed by other " +
- "\"real\" activities, make it an abstract class.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- RegistrationDetector.class,
- EnumSet.of(Scope.MANIFEST, Scope.CLASS_FILE)).setMoreInfo(
- "http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
-
- private Multimap<String, String> mManifestRegistrations;
-
- /** Constructs a new {@link RegistrationDetector} */
- public RegistrationDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(sTags);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String fqcn = getFqcn(element);
- String tag = element.getTagName();
- String frameworkClass = tagToClass(tag);
- if (frameworkClass != null) {
- String signature = ClassContext.getInternalName(fqcn);
- if (mManifestRegistrations == null) {
- mManifestRegistrations = ArrayListMultimap.create(4, 8);
- }
- mManifestRegistrations.put(frameworkClass, signature);
- if (signature.indexOf('$') != -1) {
- // The internal name contains a $ which means it's an inner class.
- // The conversion from fqcn to internal name is a bit ambiguous:
- // "a.b.C.D" usually means "inner class D in class C in package a.b".
- // However, it can (see issue 31592) also mean class D in package "a.b.C".
- // Place *both* of these possibilities in the registered map, since this
- // is only used to check that an activity is registered, not the other way
- // (so it's okay to have entries there that do not correspond to real classes).
- signature = signature.replace('$', '/');
- mManifestRegistrations.put(frameworkClass, signature);
- }
- }
- }
-
- /**
- * Returns the fully qualified class name for a manifest entry element that
- * specifies a name attribute
- *
- * @param element the element
- * @return the fully qualified class name
- */
- @NonNull
- private static String getFqcn(@NonNull Element element) {
- Element root = element.getOwnerDocument().getDocumentElement();
- String pkg = root.getAttribute(ATTR_PACKAGE);
- String className = element.getAttributeNS(ANDROID_URI, ATTR_NAME);
- if (className.startsWith(".")) { //$NON-NLS-1$
- return pkg + className;
- } else if (className.indexOf('.') == -1) {
- // According to the <activity> manifest element documentation, this is not
- // valid ( http://developer.android.com/guide/topics/manifest/activity-element.html )
- // but it appears in manifest files and appears to be supported by the runtime
- // so handle this in code as well:
- return pkg + '.' + className;
- } // else: the class name is already a fully qualified class name
-
- return className;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- // Abstract classes do not need to be registered
- if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
- return;
- }
- String curr = classNode.name;
-
- int lastIndex = curr.lastIndexOf('$');
- if (lastIndex != -1 && lastIndex < curr.length() - 1) {
- if (Character.isDigit(curr.charAt(lastIndex+1))) {
- // Anonymous inner class, doesn't need to be registered
- return;
- }
- }
-
- while (curr != null) {
- for (String s : sClasses) {
- if (curr.equals(s)) {
- Collection<String> registered = mManifestRegistrations != null ?
- mManifestRegistrations.get(curr) : null;
- if (registered == null || !registered.contains(classNode.name)) {
- report(context, classNode, curr);
- }
-
- }
- }
-
- curr = context.getDriver().getSuperClass(curr);
- }
- }
-
- private void report(ClassContext context, ClassNode classNode, String curr) {
- String tag = classToTag(curr);
- String className = ClassContext.createSignature(classNode.name, null, null);
-
- String wrongClass = null; // The framework class this class actually extends
- if (mManifestRegistrations != null) {
- Collection<Entry<String,String>> entries =
- mManifestRegistrations.entries();
- for (Entry<String,String> entry : entries) {
- if (entry.getValue().equals(classNode.name)) {
- wrongClass = entry.getKey();
- break;
- }
- }
- }
- if (wrongClass != null) {
- Location location = context.getLocation(classNode);
- context.report(
- ISSUE,
- location,
- String.format(
- "%1$s is a <%2$s> but is registered in the manifest as a <%3$s>",
- className, tag, classToTag(wrongClass)),
- null);
- } else if (!tag.equals(TAG_RECEIVER)) { // don't need to be registered
- Location location = context.getLocation(classNode);
- context.report(
- ISSUE,
- location,
- String.format(
- "The <%1$s> %2$s is not registered in the manifest",
- tag, className),
- null);
- }
- }
-
- /** The manifest tags we care about */
- private static final String[] sTags = new String[] {
- TAG_ACTIVITY,
- TAG_SERVICE,
- TAG_RECEIVER,
- TAG_PROVIDER,
- // Keep synchronized with {@link #sClasses}
- };
-
- /** The corresponding framework classes that the tags in {@link #sTags} should extend */
- private static final String[] sClasses = new String[] {
- ANDROID_APP_ACTIVITY,
- ANDROID_APP_SERVICE,
- ANDROID_CONTENT_BROADCAST_RECEIVER,
- ANDROID_CONTENT_CONTENT_PROVIDER,
- // Keep synchronized with {@link #sTags}
- };
-
- /** Looks up the corresponding framework class a given manifest tag's class should extend */
- private static String tagToClass(String tag) {
- for (int i = 0, n = sTags.length; i < n; i++) {
- if (sTags[i].equals(tag)) {
- return sClasses[i];
- }
- }
-
- return null;
- }
-
- /** Looks up the tag a given framework class should be registered with */
- private static String classToTag(String className) {
- for (int i = 0, n = sClasses.length; i < n; i++) {
- if (sClasses[i].equals(className)) {
- return sTags[i];
- }
- }
-
- return null;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RequiredAttributeDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RequiredAttributeDetector.java
deleted file mode 100644
index 861c1be..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/RequiredAttributeDetector.java
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
-import static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_LAYOUT;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PARENT;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.FD_RES_LAYOUT;
-import static com.android.SdkConstants.FN_RESOURCE_BASE;
-import static com.android.SdkConstants.FQCN_GRID_LAYOUT_V7;
-import static com.android.SdkConstants.GRID_LAYOUT;
-import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.REQUEST_FOCUS;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.TABLE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_STYLE;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-import static com.android.SdkConstants.VIEW_MERGE;
-import static com.android.resources.ResourceFolderType.LAYOUT;
-import static com.android.resources.ResourceFolderType.VALUES;
-import static com.android.tools.lint.detector.api.LintUtils.getLayoutName;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Expression;
-import lombok.ast.MethodInvocation;
-import lombok.ast.NullLiteral;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.VariableReference;
-
-/**
- * Ensures that layout width and height attributes are specified
- */
-public class RequiredAttributeDetector extends LayoutDetector implements Detector.JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "RequiredSize", //$NON-NLS-1$
- "Ensures that the layout_width and layout_height are specified for all views",
-
- "All views must specify an explicit layout_width and layout_height attribute. " +
- "There is a runtime check for this, so if you fail to specify a size, an exception " +
- "is thrown at runtime.\n" +
- "\n" +
- "It's possible to specify these widths via styles as well. GridLayout, as a special " +
- "case, does not require you to specify a size.",
- Category.CORRECTNESS,
- 4,
- Severity.ERROR,
- RequiredAttributeDetector.class,
- EnumSet.of(Scope.JAVA_FILE, Scope.ALL_RESOURCE_FILES));
-
- /** Map from each style name to parent style */
- @Nullable private Map<String, String> mStyleParents;
-
- /** Set of style names where the style sets the layout width */
- @Nullable private Set<String> mWidthStyles;
-
- /** Set of style names where the style sets the layout height */
- @Nullable private Set<String> mHeightStyles;
-
- /** Set of layout names for layouts that are included by an {@code <include>} tag
- * where the width is set on the include */
- @Nullable private Set<String> mIncludedWidths;
-
- /** Set of layout names for layouts that are included by an {@code <include>} tag
- * where the height is set on the include */
- @Nullable private Set<String> mIncludedHeights;
-
- /** Set of layout names for layouts that are included by an {@code <include>} tag
- * where the width is <b>not</b> set on the include */
- @Nullable private Set<String> mNotIncludedWidths;
-
- /** Set of layout names for layouts that are included by an {@code <include>} tag
- * where the height is <b>not</b> set on the include */
- @Nullable private Set<String> mNotIncludedHeights;
-
- /** Whether the width was set in a theme definition */
- private boolean mSetWidthInTheme;
-
- /** Whether the height was set in a theme definition */
- private boolean mSetHeightInTheme;
-
- /** Constructs a new {@link RequiredAttributeDetector} */
- public RequiredAttributeDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == LAYOUT || folderType == VALUES;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- // Process checks in two phases:
- // Phase 1: Gather styles and includes (styles are encountered after the layouts
- // so we can't do it in a single phase, and includes can be affected by includes from
- // layouts we haven't seen yet)
- // Phase 2: Process layouts, using gathered style and include data, and mark layouts
- // not known.
- //
- if (context.getPhase() == 1) {
- checkSizeSetInTheme();
-
- context.requestRepeat(this, Scope.RESOURCE_FILE_SCOPE);
- }
- }
-
- private boolean isWidthStyle(String style) {
- return isSizeStyle(style, mWidthStyles);
- }
-
- private boolean isHeightStyle(String style) {
- return isSizeStyle(style, mHeightStyles);
- }
-
- private boolean isSizeStyle(String style, Set<String> sizeStyles) {
- if (isFrameworkSizeStyle(style)) {
- return true;
- }
- if (sizeStyles == null) {
- return false;
- }
- return isSizeStyle(stripStylePrefix(style), sizeStyles, 0);
- }
-
- private static boolean isFrameworkSizeStyle(String style) {
- // The styles Widget.TextView.ListSeparator (and several theme variations, such as
- // Widget.Holo.TextView.ListSeparator, Widget.Holo.Light.TextView.ListSeparator, etc)
- // define layout_width and layout_height.
- // These are exposed through the listSeparatorTextViewStyle style.
- if (style.equals("?android:attr/listSeparatorTextViewStyle") //$NON-NLS-1$
- || style.equals("?android/listSeparatorTextViewStyle")) { //$NON-NLS-1$
- return true;
- }
-
- // It's also set on Widget.QuickContactBadge and Widget.QuickContactBadgeSmall
- // These are exposed via a handful of attributes with a common prefix
- if (style.startsWith("?android:attr/quickContactBadgeStyle")) { //$NON-NLS-1$
- return true;
- }
-
- // Finally, the styles are set on MediaButton and Widget.Holo.Tab (and
- // Widget.Holo.Light.Tab) but these are not exposed via attributes.
-
- return false;
- }
-
- private boolean isSizeStyle(
- @NonNull String style,
- @NonNull Set<String> sizeStyles, int depth) {
- if (depth == 30) {
- // Cycle between local and framework attribute style missed
- // by the fact that we're stripping the distinction between framework
- // and local styles here
- return false;
- }
-
- assert !style.startsWith(STYLE_RESOURCE_PREFIX)
- && !style.startsWith(ANDROID_STYLE_RESOURCE_PREFIX);
-
- if (sizeStyles.contains(style)) {
- return true;
- }
-
- if (mStyleParents != null) {
- String parentStyle = mStyleParents.get(style);
- if (parentStyle != null) {
- parentStyle = stripStylePrefix(parentStyle);
- if (isSizeStyle(parentStyle, sizeStyles, depth + 1)) {
- return true;
- }
- }
- }
-
- int index = style.lastIndexOf('.');
- if (index > 0) {
- return isSizeStyle(style.substring(0, index), sizeStyles, depth + 1);
- }
-
- return false;
- }
-
- private void checkSizeSetInTheme() {
- // Look through the styles and determine whether each style is a theme
- if (mStyleParents == null) {
- return;
- }
-
- Map<String, Boolean> isTheme = Maps.newHashMap();
- for (String style : mStyleParents.keySet()) {
- if (isTheme(stripStylePrefix(style), isTheme, 0)) {
- mSetWidthInTheme = true;
- mSetHeightInTheme = true;
- break;
- }
- }
- }
-
- private boolean isTheme(String style, Map<String, Boolean> isTheme, int depth) {
- if (depth == 30) {
- // Cycle between local and framework attribute style missed
- // by the fact that we're stripping the distinction between framework
- // and local styles here
- return false;
- }
-
- assert !style.startsWith(STYLE_RESOURCE_PREFIX)
- && !style.startsWith(ANDROID_STYLE_RESOURCE_PREFIX);
-
- Boolean known = isTheme.get(style);
- if (known != null) {
- return known;
- }
-
- if (style.contains("Theme")) { //$NON-NLS-1$
- isTheme.put(style, true);
- return true;
- }
-
- if (mStyleParents != null) {
- String parentStyle = mStyleParents.get(style);
- if (parentStyle != null) {
- parentStyle = stripStylePrefix(parentStyle);
- if (isTheme(parentStyle, isTheme, depth + 1)) {
- isTheme.put(style, true);
- return true;
- }
- }
- }
-
- int index = style.lastIndexOf('.');
- if (index > 0) {
- String parentStyle = style.substring(0, index);
- boolean result = isTheme(parentStyle, isTheme, depth + 1);
- isTheme.put(style, result);
- return result;
- }
-
- return false;
- }
-
- private static boolean hasLayoutVariations(File file) {
- File parent = file.getParentFile();
- if (parent == null) {
- return false;
- }
- File res = file.getParentFile();
- if (res == null) {
- return false;
- }
- String name = file.getName();
- File[] folders = res.listFiles();
- if (folders == null) {
- return false;
- }
- for (File folder : folders) {
- if (!folder.getName().startsWith(FD_RES_LAYOUT)) {
- continue;
- }
- if (folder.equals(parent)) {
- continue;
- }
- File other = new File(folder, name);
- if (other.exists()) {
- return true;
- }
- }
-
- return false;
- }
-
- private static String stripStylePrefix(@NonNull String style) {
- if (style.startsWith(STYLE_RESOURCE_PREFIX)) {
- style = style.substring(STYLE_RESOURCE_PREFIX.length());
- } else if (style.startsWith(ANDROID_STYLE_RESOURCE_PREFIX)) {
- style = style.substring(ANDROID_STYLE_RESOURCE_PREFIX.length());
- }
-
- return style;
- }
-
- private static boolean isRootElement(@NonNull Node node) {
- return node == node.getOwnerDocument().getDocumentElement();
- }
-
- // ---- Implements XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return ALL;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- ResourceFolderType folderType = context.getResourceFolderType();
- int phase = context.getPhase();
- if (phase == 1 && folderType == VALUES) {
- String tag = element.getTagName();
- if (TAG_STYLE.equals(tag)) {
- String parent = element.getAttribute(ATTR_PARENT);
- if (parent != null && !parent.isEmpty()) {
- String name = element.getAttribute(ATTR_NAME);
- if (name != null && !name.isEmpty()) {
- if (mStyleParents == null) {
- mStyleParents = Maps.newHashMap();
- }
- mStyleParents.put(name, parent);
- }
- }
- } else if (TAG_ITEM.equals(tag)
- && TAG_STYLE.equals(element.getParentNode().getNodeName())) {
- String name = element.getAttribute(ATTR_NAME);
- if (name.endsWith(ATTR_LAYOUT_WIDTH) &&
- name.equals(ANDROID_NS_NAME_PREFIX + ATTR_LAYOUT_WIDTH)) {
- if (mWidthStyles == null) {
- mWidthStyles = Sets.newHashSet();
- }
- String styleName = ((Element) element.getParentNode()).getAttribute(ATTR_NAME);
- mWidthStyles.add(styleName);
- }
- if (name.endsWith(ATTR_LAYOUT_HEIGHT) &&
- name.equals(ANDROID_NS_NAME_PREFIX + ATTR_LAYOUT_HEIGHT)) {
- if (mHeightStyles == null) {
- mHeightStyles = Sets.newHashSet();
- }
- String styleName = ((Element) element.getParentNode()).getAttribute(ATTR_NAME);
- mHeightStyles.add(styleName);
- }
- }
- } else if (folderType == LAYOUT) {
- if (phase == 1) {
- // Gather includes
- if (element.getTagName().equals(VIEW_INCLUDE)) {
- String layout = element.getAttribute(ATTR_LAYOUT);
- if (layout != null && !layout.isEmpty()) {
- recordIncludeWidth(layout,
- element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH));
- recordIncludeHeight(layout,
- element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT));
- }
- }
- } else {
- assert phase == 2; // Check everything using style data and include data
- boolean hasWidth = element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- boolean hasHeight = element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
-
- if (mSetWidthInTheme) {
- hasWidth = true;
- }
-
- if (mSetHeightInTheme) {
- hasHeight = true;
- }
-
- if (hasWidth && hasHeight) {
- return;
- }
-
- String tag = element.getTagName();
- if (VIEW_MERGE.equals(tag)
- || VIEW_INCLUDE.equals(tag)
- || REQUEST_FOCUS.equals(tag)) {
- return;
- }
-
- String parentTag = element.getParentNode() != null
- ? element.getParentNode().getNodeName() : "";
- if (TABLE_LAYOUT.equals(parentTag)
- || TABLE_ROW.equals(parentTag)
- || GRID_LAYOUT.equals(parentTag)
- || FQCN_GRID_LAYOUT_V7.equals(parentTag)) {
- return;
- }
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- boolean certain = true;
- boolean isRoot = isRootElement(element);
- if (isRoot || isRootElement(element.getParentNode())
- && VIEW_MERGE.equals(parentTag)) {
- String name = LAYOUT_RESOURCE_PREFIX + getLayoutName(context.file);
- if (!hasWidth && mIncludedWidths != null) {
- hasWidth = mIncludedWidths.contains(name);
- // If the layout is *also* included in a context where the width
- // was not set, we're not certain; it's possible that
- if (mNotIncludedWidths != null && mNotIncludedWidths.contains(name)) {
- hasWidth = false;
- // If we only have a single layout we know that this layout isn't
- // always included with layout_width or layout_height set, but
- // if there are multiple layouts, it's possible that at runtime
- // we only load the size-less layout by the tag which includes
- // the size
- certain = !hasLayoutVariations(context.file);
- }
- }
- if (!hasHeight && mIncludedHeights != null) {
- hasHeight = mIncludedHeights.contains(name);
- if (mNotIncludedHeights != null && mNotIncludedHeights.contains(name)) {
- hasHeight = false;
- certain = !hasLayoutVariations(context.file);
- }
- }
- if (hasWidth && hasHeight) {
- return;
- }
- }
-
- if (!hasWidth || !hasHeight) {
- String style = element.getAttribute(ATTR_STYLE);
- if (style != null && !style.isEmpty()) {
- if (!hasWidth) {
- hasWidth = isWidthStyle(style);
- }
- if (!hasHeight) {
- hasHeight = isHeightStyle(style);
- }
- }
- if (hasWidth && hasHeight) {
- return;
- }
- }
-
- String message;
- if (!(hasWidth || hasHeight)) {
- if (certain) {
- message = "The required layout_width and layout_height attributes " +
- "are missing";
- } else {
- message = "The required layout_width and layout_height attributes " +
- "*may* be missing";
- }
- } else {
- String attribute = hasWidth ? ATTR_LAYOUT_HEIGHT : ATTR_LAYOUT_WIDTH;
- if (certain) {
- message = String.format("The required %1$s attribute is missing",
- attribute);
- } else {
- message = String.format("The required %1$s attribute *may* be missing",
- attribute);
- }
- }
- context.report(ISSUE, element, context.getLocation(element),
- message, null);
- }
- }
- }
-
- private void recordIncludeWidth(String layout, boolean providesWidth) {
- if (providesWidth) {
- if (mIncludedWidths == null) {
- mIncludedWidths = Sets.newHashSet();
- }
- mIncludedWidths.add(layout);
- } else {
- if (mNotIncludedWidths == null) {
- mNotIncludedWidths = Sets.newHashSet();
- }
- mNotIncludedWidths.add(layout);
- }
- }
-
- private void recordIncludeHeight(String layout, boolean providesHeight) {
- if (providesHeight) {
- if (mIncludedHeights == null) {
- mIncludedHeights = Sets.newHashSet();
- }
- mIncludedHeights.add(layout);
- } else {
- if (mNotIncludedHeights == null) {
- mNotIncludedHeights = Sets.newHashSet();
- }
- mNotIncludedHeights.add(layout);
- }
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("inflate"); //$NON-NLS-1$
- }
-
- @Override
- public void visitMethod(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull MethodInvocation call) {
- // Handle
- // View#inflate(Context context, int resource, ViewGroup root)
- // LayoutInflater#inflate(int resource, ViewGroup root)
- // LayoutInflater#inflate(int resource, ViewGroup root, boolean attachToRoot)
- StrictListAccessor<Expression, MethodInvocation> args = call.astArguments();
-
- String layout = null;
- int index = 0;
- for (Iterator<Expression> iterator = args.iterator(); iterator.hasNext(); index++) {
- Expression expression = iterator.next();
- if (expression instanceof Select) {
- Select outer = (Select) expression;
- Expression operand = outer.astOperand();
- if (operand instanceof Select) {
- Select inner = (Select) operand;
- if (inner.astOperand() instanceof VariableReference) {
- VariableReference reference = (VariableReference) inner.astOperand();
- if (FN_RESOURCE_BASE.equals(reference.astIdentifier().astValue())
- // TODO: constant
- && "layout".equals(inner.astIdentifier().astValue())) {
- layout = LAYOUT_RESOURCE_PREFIX + outer.astIdentifier().astValue();
- break;
- }
- }
- }
- }
- }
-
- if (layout == null) {
- lombok.ast.Node method = StringFormatDetector.getParentMethod(call);
- if (method != null) {
- // Must track local types
- index = 0;
- String name = StringFormatDetector.getResourceArg(method, call, index);
- if (name == null) {
- index = 1;
- name = StringFormatDetector.getResourceArg(method, call, index);
- }
- if (name != null) {
- layout = LAYOUT_RESOURCE_PREFIX + name;
- }
- }
- if (layout == null) {
- // Flow analysis didn't succeed
- return;
- }
- }
-
- // In all the applicable signatures, the view root argument is immediately after
- // the layout resource id.
- int viewRootPos = index + 1;
- if (viewRootPos < args.size()) {
- int i = 0;
- Iterator<Expression> iterator = args.iterator();
- while (iterator.hasNext() && i < viewRootPos) {
- iterator.next();
- i++;
- }
- if (iterator.hasNext()) {
- Expression viewRoot = iterator.next();
- if (viewRoot instanceof NullLiteral) {
- // Yep, this one inflates the given view with a null parent:
- // Tag it as such. For now just use the include data structure since
- // it has the same net effect
- recordIncludeWidth(layout, true);
- recordIncludeHeight(layout, true);
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ScrollViewChildDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ScrollViewChildDetector.java
deleted file mode 100644
index 81bb522..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ScrollViewChildDetector.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-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.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.SCROLL_VIEW;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Check which looks at the children of ScrollViews and ensures that they fill/match
- * the parent width instead of setting wrap_content.
- */
-public class ScrollViewChildDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ScrollViewSize", //$NON-NLS-1$
- "Checks that ScrollViews use wrap_content in scrolling dimension",
- // TODO add a better explanation here!
- "ScrollView children must set their `layout_width` or `layout_height` attributes " +
- "to `wrap_content` rather than `fill_parent` or `match_parent` in the scrolling " +
- "dimension",
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- ScrollViewChildDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link ScrollViewChildDetector} */
- public ScrollViewChildDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- SCROLL_VIEW,
- HORIZONTAL_SCROLL_VIEW
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- List<Element> children = LintUtils.getChildren(element);
- boolean isHorizontal = HORIZONTAL_SCROLL_VIEW.equals(element.getTagName());
- String attributeName = isHorizontal ? ATTR_LAYOUT_WIDTH : ATTR_LAYOUT_HEIGHT;
- for (Element child : children) {
- Attr sizeNode = child.getAttributeNodeNS(ANDROID_URI, attributeName);
- if (sizeNode == null) {
- return;
- }
- String value = sizeNode.getValue();
- if (VALUE_FILL_PARENT.equals(value) || VALUE_MATCH_PARENT.equals(value)) {
- String msg = String.format("This %1$s should use android:%2$s=\"wrap_content\"",
- child.getTagName(), attributeName);
- context.report(ISSUE, sizeNode, context.getLocation(sizeNode), msg,
- null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SdCardDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SdCardDetector.java
deleted file mode 100644
index c876b96..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SdCardDetector.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Node;
-import lombok.ast.StringLiteral;
-
-/**
- * Looks for hardcoded references to /sdcard/.
- */
-public class SdCardDetector extends Detector implements Detector.JavaScanner {
- /** Hardcoded /sdcard/ references */
- public static final Issue ISSUE = Issue.create(
- "SdCardPath", //$NON-NLS-1$
- "Looks for hardcoded references to /sdcard",
-
- "Your code should not reference the `/sdcard` path directly; instead use " +
- "`Environment.getExternalStorageDirectory().getPath()`.\n" +
- "\n" +
- "Similarly, do not reference the `/data/data/` path directly; it can vary " +
- "in multi-user scenarios. Instead, use " +
- "`Context.getFilesDir().getPath()`.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- SdCardDetector.class,
- Scope.JAVA_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/data/data-storage.html#filesExternal"); //$NON-NLS-1$
-
- /** Constructs a new {@link SdCardDetector} check */
- public SdCardDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- return Collections.<Class<? extends Node>>singletonList(StringLiteral.class);
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new StringChecker(context);
- }
-
- private static class StringChecker extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public StringChecker(JavaContext context) {
- mContext = context;
- }
-
- @Override
- public boolean visitStringLiteral(StringLiteral node) {
- String s = node.astValue();
- if (s.isEmpty()) {
- return false;
- }
- char c = s.charAt(0);
- if (c != '/' && c != 'f') {
- return false;
- }
-
- if (s.startsWith("/sdcard") //$NON-NLS-1$
- || s.startsWith("/mnt/sdcard/") //$NON-NLS-1$
- || s.startsWith("/system/media/sdcard") //$NON-NLS-1$
- || s.startsWith("file://sdcard/") //$NON-NLS-1$
- || s.startsWith("file:///sdcard/")) { //$NON-NLS-1$
- String message = "Do not hardcode \"/sdcard/\"; " +
- "use Environment.getExternalStorageDirectory().getPath() instead";
- Location location = mContext.getLocation(node);
- mContext.report(ISSUE, node, location, message, s);
- } else if (s.startsWith("/data/data/") //$NON-NLS-1$
- || s.startsWith("/data/user/")) { //$NON-NLS-1$
- String message = "Do not hardcode \"/data/\"; " +
- "use Context.getFilesDir().getPath() instead";
- Location location = mContext.getLocation(node);
- mContext.report(ISSUE, node, location, message, s);
- }
-
- return false;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecureRandomDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecureRandomDetector.java
deleted file mode 100644
index f1d349b..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecureRandomDetector.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.analysis.Analyzer;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-import org.objectweb.asm.tree.analysis.BasicInterpreter;
-import org.objectweb.asm.tree.analysis.BasicValue;
-import org.objectweb.asm.tree.analysis.Frame;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Checks for hardcoded seeds with random numbers.
- */
-public class SecureRandomDetector extends Detector implements ClassScanner {
- /** Unregistered activities and services */
- public static final Issue ISSUE = Issue.create(
- "SecureRandom", //$NON-NLS-1$
- "Looks for suspicious usage of the SecureRandom class",
-
- "Specifying a fixed seed will cause the instance to return a predictable sequence " +
- "of numbers. This may be useful for testing but it is not appropriate for secure use.",
-
- Category.PERFORMANCE,
- 9,
- Severity.WARNING,
- SecureRandomDetector.class,
- Scope.CLASS_FILE_SCOPE).
- setMoreInfo("http://developer.android.com/reference/java/security/SecureRandom.html");
-
- private static final String SET_SEED = "setSeed"; //$NON-NLS-1$
- private static final String OWNER_SECURE_RANDOM = "java/security/SecureRandom"; //$NON-NLS-1$
- private static final String OWNER_RANDOM = "java/util/Random"; //$NON-NLS-1$
- private static final String VM_SECURE_RANDOM = 'L' + OWNER_SECURE_RANDOM + ';';
- /** Method description for a method that takes a long argument (no return type specified */
- private static final String LONG_ARG = "(J)"; //$NON-NLS-1$
-
- /** Constructs a new {@link SecureRandomDetector} */
- public SecureRandomDetector() {
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Collections.singletonList(SET_SEED);
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- String owner = call.owner;
- String desc = call.desc;
- if (owner.equals(OWNER_SECURE_RANDOM)) {
- if (desc.startsWith(LONG_ARG)) {
- checkValidSetSeed(context, call);
- } else if (desc.startsWith("([B)")) { //$NON-NLS-1$
- // setSeed(byte[]) ...
- // We could do some flow analysis here to see whether the byte array getting
- // passed in appears to be fixed.
- // However, people calling this constructor rather than the simpler one
- // with a fixed integer are probably less likely to make that mistake... right?
- }
- } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) {
- // Called setSeed(long) on an instanceof a Random object. Flag this if the instance
- // is likely a SecureRandom.
-
- // Track allocations such that we know whether the type of the call
- // is on a SecureRandom rather than a Random
- Analyzer analyzer = new Analyzer(new BasicInterpreter() {
- @Override
- public BasicValue newValue(Type type) {
- if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) {
- return new BasicValue(type);
- }
- return super.newValue(type);
- }
- });
- try {
- Frame[] frames = analyzer.analyze(classNode.name, method);
- InsnList instructions = method.instructions;
- Frame frame = frames[instructions.indexOf(call)];
- int stackSlot = frame.getStackSize();
- for (Type type : Type.getArgumentTypes(desc)) {
- stackSlot -= type.getSize();
- }
- BasicValue stackValue = (BasicValue) frame.getStack(stackSlot);
- Type type = stackValue.getType();
- if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) {
- checkValidSetSeed(context, call);
- }
- } catch (AnalyzerException e) {
- context.log(e, null);
- }
- } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) {
- // Called setSeed(long) on an instanceof a Random object. Flag this if the instance
- // is likely a SecureRandom.
- // TODO
- }
- }
-
- private static void checkValidSetSeed(ClassContext context, MethodInsnNode call) {
- assert call.name.equals(SET_SEED);
-
- // Make sure the argument passed is not a literal
- AbstractInsnNode prev = LintUtils.getPrevInstruction(call);
- if (prev == null) {
- return;
- }
- int opcode = prev.getOpcode();
- if (opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 || opcode == Opcodes.LDC) {
- context.report(ISSUE, context.getLocation(call),
- "Do not call setSeed() on a SecureRandom with a fixed seed: " +
- "it is not secure. Use getSeed().",
- null);
- } else if (opcode == Opcodes.INVOKESTATIC) {
- String methodName = ((MethodInsnNode) prev).name;
- if (methodName.equals("currentTimeMillis") || methodName.equals("nanoTime")) {
- context.report(ISSUE, context.getLocation(call),
- "It is dangerous to seed SecureRandom with the current time because " +
- "that value is more predictable to an attacker than the default seed.",
- null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecurityDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecurityDetector.java
deleted file mode 100644
index b6cc957..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SecurityDetector.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_EXPORTED;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PATH;
-import static com.android.SdkConstants.ATTR_PATH_PATTERN;
-import static com.android.SdkConstants.ATTR_PATH_PREFIX;
-import static com.android.SdkConstants.ATTR_PERMISSION;
-import static com.android.SdkConstants.ATTR_READ_PERMISSION;
-import static com.android.SdkConstants.ATTR_WRITE_PERMISSION;
-import static com.android.SdkConstants.TAG_ACTIVITY;
-import static com.android.SdkConstants.TAG_APPLICATION;
-import static com.android.SdkConstants.TAG_GRANT_PERMISSION;
-import static com.android.SdkConstants.TAG_INTENT_FILTER;
-import static com.android.SdkConstants.TAG_PATH_PERMISSION;
-import static com.android.SdkConstants.TAG_PROVIDER;
-import static com.android.SdkConstants.TAG_RECEIVER;
-import static com.android.SdkConstants.TAG_SERVICE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Identifier;
-import lombok.ast.MethodInvocation;
-import lombok.ast.StrictListAccessor;
-
-/**
- * Checks that exported services request a permission.
- */
-public class SecurityDetector extends Detector implements Detector.XmlScanner,
- Detector.JavaScanner {
-
- /** Exported services */
- public static final Issue EXPORTED_SERVICE = Issue.create(
- "ExportedService", //$NON-NLS-1$
- "Checks for exported services that do not require permissions",
- "Exported services (services which either set `exported=true` or contain " +
- "an intent-filter and do not specify `exported=false`) should define a " +
- "permission that an entity must have in order to launch the service " +
- "or bind to it. Without this, any application can use this service.",
- Category.SECURITY,
- 5,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Exported content providers */
- public static final Issue EXPORTED_PROVIDER = Issue.create(
- "ExportedContentProvider", //$NON-NLS-1$
- "Checks for exported content providers that do not require permissions",
- "Content providers are exported by default and any application on the " +
- "system can potentially use them to read and write data. If the content " +
- "provider provides access to sensitive data, it should be protected by " +
- "specifying `export=false` in the manifest or by protecting it with a " +
- "permission that can be granted to other applications.",
- Category.SECURITY,
- 5,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Exported receivers */
- public static final Issue EXPORTED_RECEIVER = Issue.create(
- "ExportedReceiver", //$NON-NLS-1$
- "Checks for exported receivers that do not require permissions",
- "Exported receivers (receivers which either set `exported=true` or contain " +
- "an intent-filter and do not specify `exported=false`) should define a " +
- "permission that an entity must have in order to launch the receiver " +
- "or bind to it. Without this, any application can use this receiver.",
- Category.SECURITY,
- 5,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Content provides which grant all URIs access */
- public static final Issue OPEN_PROVIDER = Issue.create(
- "GrantAllUris", //$NON-NLS-1$
- "Checks for <grant-uri-permission> elements where everything is shared",
- "The `<grant-uri-permission>` element allows specific paths to be shared. " +
- "This detector checks for a path URL of just '/' (everything), which is " +
- "probably not what you want; you should limit access to a subset.",
- Category.SECURITY,
- 7,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.MANIFEST_SCOPE);
-
- /** Using the world-writable flag */
- public static final Issue WORLD_WRITEABLE = Issue.create(
- "WorldWriteableFiles", //$NON-NLS-1$
- "Checks for openFileOutput() and getSharedPreferences() calls passing " +
- "MODE_WORLD_WRITEABLE",
- "There are cases where it is appropriate for an application to write " +
- "world writeable files, but these should be reviewed carefully to " +
- "ensure that they contain no private data, and that if the file is " +
- "modified by a malicious application it does not trick or compromise " +
- "your application.",
- Category.SECURITY,
- 4,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
-
- /** Using the world-readable flag */
- public static final Issue WORLD_READABLE = Issue.create(
- "WorldReadableFiles", //$NON-NLS-1$
- "Checks for openFileOutput() and getSharedPreferences() calls passing " +
- "MODE_WORLD_READABLE",
- "There are cases where it is appropriate for an application to write " +
- "world readable files, but these should be reviewed carefully to " +
- "ensure that they contain no private data that is leaked to other " +
- "applications.",
- Category.SECURITY,
- 4,
- Severity.WARNING,
- SecurityDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Constructs a new {@link SecurityDetector} check */
- public SecurityDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return file.getName().equals(ANDROID_MANIFEST_XML);
- }
-
- // ---- Implements Detector.XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_SERVICE,
- TAG_GRANT_PERMISSION,
- TAG_PROVIDER,
- TAG_ACTIVITY,
- TAG_RECEIVER
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String tag = element.getTagName();
- if (tag.equals(TAG_SERVICE)) {
- checkService(context, element);
- } else if (tag.equals(TAG_GRANT_PERMISSION)) {
- checkGrantPermission(context, element);
- } else if (tag.equals(TAG_PROVIDER)) {
- checkProvider(context, element);
- } else if (tag.equals(TAG_RECEIVER)) {
- checkReceiver(context, element);
- }
- }
-
- private static boolean getExported(Element element) {
- // Used to check whether an activity, service or broadcast receiver is exported.
- String exportValue = element.getAttributeNS(ANDROID_URI, ATTR_EXPORTED);
- if (exportValue != null && !exportValue.isEmpty()) {
- return Boolean.valueOf(exportValue);
- } else {
- for (Element child : LintUtils.getChildren(element)) {
- if (child.getTagName().equals(TAG_INTENT_FILTER)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private static boolean isUnprotectedByPermission(Element element) {
- // Used to check whether an activity, service or broadcast receiver are
- // protected by a permission.
- String permission = element.getAttributeNS(ANDROID_URI, ATTR_PERMISSION);
- if (permission == null || permission.isEmpty()) {
- Node parent = element.getParentNode();
- if (parent.getNodeType() == Node.ELEMENT_NODE
- && parent.getNodeName().equals(TAG_APPLICATION)) {
- Element application = (Element) parent;
- permission = application.getAttributeNS(ANDROID_URI, ATTR_PERMISSION);
- return permission == null || permission.isEmpty();
- }
- }
-
- return false;
- }
-
- private static boolean isLauncher(Element element) {
- // Checks whether an element is a launcher activity.
- for (Element child : LintUtils.getChildren(element)) {
- if (child.getTagName().equals(TAG_INTENT_FILTER)) {
- for (Element innerChild: LintUtils.getChildren(child)) {
- if (innerChild.getTagName().equals("category")) { //$NON-NLS-1$
- String categoryString = innerChild.getAttributeNS(ANDROID_URI, ATTR_NAME);
- return "android.intent.category.LAUNCHER".equals(categoryString); //$NON-NLS-1$
- }
- }
- }
- }
-
- return false;
- }
-
- private static boolean isStandardReceiver(Element element) {
- // Checks whether a broadcast receiver receives a standard Android action
- for (Element child : LintUtils.getChildren(element)) {
- if (child.getTagName().equals(TAG_INTENT_FILTER)) {
- for (Element innerChild : LintUtils.getChildren(child)) {
- if (innerChild.getTagName().equals("action")) { //$NON-NLS-1$
- String categoryString = innerChild.getAttributeNS(ANDROID_URI, ATTR_NAME);
- return categoryString.startsWith("android."); //$NON-NLS-1$
- }
- }
- }
- }
- return false;
- }
-
- private static void checkReceiver(XmlContext context, Element element) {
- if (getExported(element) && isUnprotectedByPermission(element) &&
- !isStandardReceiver(element)) {
- // No declared permission for this exported receiver: complain
- context.report(EXPORTED_RECEIVER, element, context.getLocation(element),
- "Exported receiver does not require permission", null);
- }
- }
-
- private static void checkService(XmlContext context, Element element) {
- if (getExported(element) && isUnprotectedByPermission(element)) {
- // No declared permission for this exported service: complain
- context.report(EXPORTED_SERVICE, element, context.getLocation(element),
- "Exported service does not require permission", null);
- }
- }
-
- private static void checkGrantPermission(XmlContext context, Element element) {
- Attr path = element.getAttributeNodeNS(ANDROID_URI, ATTR_PATH);
- Attr prefix = element.getAttributeNodeNS(ANDROID_URI, ATTR_PATH_PREFIX);
- Attr pattern = element.getAttributeNodeNS(ANDROID_URI, ATTR_PATH_PATTERN);
-
- String msg = "Content provider shares everything; this is potentially dangerous.";
- if (path != null && path.getValue().equals("/")) { //$NON-NLS-1$
- context.report(OPEN_PROVIDER, path, context.getLocation(path), msg, null);
- }
- if (prefix != null && prefix.getValue().equals("/")) { //$NON-NLS-1$
- context.report(OPEN_PROVIDER, prefix, context.getLocation(prefix), msg, null);
- }
- if (pattern != null && (pattern.getValue().equals("/") //$NON-NLS-1$
- /* || pattern.getValue().equals(".*")*/)) {
- context.report(OPEN_PROVIDER, pattern, context.getLocation(pattern), msg, null);
- }
- }
-
- private static void checkProvider(XmlContext context, Element element) {
- String exportValue = element.getAttributeNS(ANDROID_URI, ATTR_EXPORTED);
- // Content providers are exported by default
- boolean exported = true;
- if (exportValue != null && !exportValue.isEmpty()) {
- exported = Boolean.valueOf(exportValue);
- }
-
- if (exported) {
- // Just check for some use of permissions. Other Lint checks can check the saneness
- // of the permissions. We'll accept the permission, readPermission, or writePermission
- // attributes on the provider element, or a path-permission element.
- String permission = element.getAttributeNS(ANDROID_URI, ATTR_READ_PERMISSION);
- if (permission == null || permission.isEmpty()) {
- permission = element.getAttributeNS(ANDROID_URI, ATTR_WRITE_PERMISSION);
- if (permission == null || permission.isEmpty()) {
- permission = element.getAttributeNS(ANDROID_URI, ATTR_PERMISSION);
- if (permission == null || permission.isEmpty()) {
- // No permission attributes? Check for path-permission.
-
- // TODO: Add a Lint check to ensure the path-permission is good, similar to
- // the grant-uri-permission check.
- boolean hasPermission = false;
- for (Element child : LintUtils.getChildren(element)) {
- String tag = child.getTagName();
- if (tag.equals(TAG_PATH_PERMISSION)) {
- hasPermission = true;
- break;
- }
- }
-
- if (!hasPermission) {
- context.report(EXPORTED_PROVIDER, element,
- context.getLocation(element),
- "Exported content providers can provide access to " +
- "potentially sensitive data",
- null);
- }
- }
- }
- }
- }
- }
-
- // ---- Implements Detector.JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- // These are the API calls that can accept a MODE_WORLD_READABLE/MODE_WORLD_WRITABLE
- // argument.
- List<String> values = new ArrayList<String>(2);
- values.add("openFileOutput"); //$NON-NLS-1$
- values.add("getSharedPreferences"); //$NON-NLS-1$
- return values;
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- StrictListAccessor<Expression,MethodInvocation> args = node.astArguments();
- Iterator<Expression> iterator = args.iterator();
- while (iterator.hasNext()) {
- iterator.next().accept(visitor);
- }
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new IdentifierVisitor(context);
- }
-
- private static class IdentifierVisitor extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public IdentifierVisitor(JavaContext context) {
- super();
- mContext = context;
- }
-
- @Override
- public boolean visitIdentifier(Identifier node) {
- if ("MODE_WORLD_WRITEABLE".equals(node.getDescription())) { //$NON-NLS-1$
- Location location = mContext.getLocation(node);
- mContext.report(WORLD_WRITEABLE, node, location,
- "Using MODE_WORLD_WRITEABLE when creating files can be " +
- "risky, review carefully",
- null);
- } else if ("MODE_WORLD_READABLE".equals(node.getDescription())) { //$NON-NLS-1$
- Location location = mContext.getLocation(node);
- mContext.report(WORLD_READABLE, node, location,
- "Using MODE_WORLD_READABLE when creating files can be " +
- "risky, review carefully",
- null);
- }
-
- return false;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java
deleted file mode 100644
index 4b4ba01..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.MethodInvocation;
-
-/**
- * Looks for invocations of android.webkit.WebSettings.setJavaScriptEnabled.
- */
-public class SetJavaScriptEnabledDetector extends Detector implements Detector.JavaScanner {
- /** Invocations of setJavaScriptEnabled */
- public static final Issue ISSUE = Issue.create("SetJavaScriptEnabled", //$NON-NLS-1$
- "Looks for invocations of android.webkit.WebSettings.setJavaScriptEnabled",
-
- "Your code should not invoke `setJavaScriptEnabled` if you are not sure that " +
- "your app really requires JavaScript support.",
-
- Category.SECURITY,
- 6,
- Severity.WARNING,
- SetJavaScriptEnabledDetector.class,
- Scope.JAVA_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/practices/security.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link SetJavaScriptEnabledDetector} check */
- public SetJavaScriptEnabledDetector() {
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- if (node.astArguments().size() == 1
- && !node.astArguments().first().toString().equals("false")) { //$NON-NLS-1$
- context.report(ISSUE, node, context.getLocation(node),
- "Using setJavaScriptEnabled can introduce XSS vulnerabilities " +
- "into you application, review carefully.",
- null);
- }
- }
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("setJavaScriptEnabled");
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SharedPrefsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SharedPrefsDetector.java
deleted file mode 100644
index 76887a5..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SharedPrefsDetector.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.NormalTypeBody;
-import lombok.ast.Return;
-import lombok.ast.VariableDeclaration;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableReference;
-
-/**
- * Detector looking for SharedPreferences.edit() calls without a corresponding
- * commit() or apply() call
- */
-public class SharedPrefsDetector extends Detector implements Detector.JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "CommitPrefEdits", //$NON-NLS-1$
- "Looks for code editing a SharedPreference but forgetting to call commit() on it",
-
- "After calling `edit()` on a `SharedPreference`, you must call `commit()` " +
- "or `apply()` on the editor to save the results.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- SharedPrefsDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Constructs a new {@link SharedPrefsDetector} check */
- public SharedPrefsDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("edit"); //$NON-NLS-1$
- }
-
- @Nullable
- private static NormalTypeBody findSurroundingTypeBody(Node scope) {
- while (scope != null) {
- Class<? extends Node> type = scope.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == NormalTypeBody.class) {
- return (NormalTypeBody) scope;
- }
-
- scope = scope.getParent();
- }
-
- return null;
- }
-
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- assert node.astName().astValue().equals("edit");
- Expression operand = node.astOperand();
- if (operand == null) {
- return;
- }
-
- // Looking for the specific pattern where you assign the edit() result
- // to a local variable; this means we won't recognize some other usages
- // of the API (e.g. assigning it to a previously declared variable) but
- // is needed until we have type attribution in the AST itself.
- Node parent = node.getParent();
- VariableDefinition definition = getLhs(parent);
- boolean allowCommitBeforeTarget;
- if (definition == null) {
- if (operand instanceof VariableReference) {
- NormalTypeBody body = findSurroundingTypeBody(parent);
- if (body == null) {
- return;
- }
- String variableName = ((VariableReference) operand).astIdentifier().astValue();
- String type = getFieldType(body, variableName);
- if (type == null || !type.equals("SharedPreferences")) { //$NON-NLS-1$
- return;
- }
- allowCommitBeforeTarget = true;
- } else {
- return;
- }
- } else {
- String type = definition.astTypeReference().toString();
- if (!type.endsWith("SharedPreferences.Editor")) { //$NON-NLS-1$
- if (!type.equals("Editor") || //$NON-NLS-1$
- !LintUtils.isImported(context.compilationUnit,
- "android.content.SharedPreferences.Editor")) { //$NON-NLS-1$
- return;
- }
- }
- allowCommitBeforeTarget = false;
- }
-
- Node method = JavaContext.findSurroundingMethod(parent);
- if (method == null) {
- return;
- }
-
- CommitFinder finder = new CommitFinder(node, allowCommitBeforeTarget);
- method.accept(finder);
- if (!finder.isCommitCalled()) {
- context.report(ISSUE, method, context.getLocation(node),
- "SharedPreferences.edit() without a corresponding commit() or apply() call",
- null);
- }
- }
-
- @Nullable
- private static String getFieldType(@NonNull NormalTypeBody cls, @NonNull String name) {
- List<Node> children = cls.getChildren();
- for (Node child : children) {
- if (child.getClass() == VariableDeclaration.class) {
- VariableDeclaration declaration = (VariableDeclaration) child;
- VariableDefinition definition = declaration.astDefinition();
- return definition.astTypeReference().toString();
- }
- }
-
- return null;
- }
-
- @Nullable
- private static VariableDefinition getLhs(@NonNull Node node) {
- while (node != null) {
- Class<? extends Node> type = node.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == MethodDeclaration.class || type == ConstructorDeclaration.class) {
- return null;
- }
- if (type == VariableDefinition.class) {
- return (VariableDefinition) node;
- }
-
- node = node.getParent();
- }
-
- return null;
- }
-
- private static class CommitFinder extends ForwardingAstVisitor {
- /** The target edit call */
- private final MethodInvocation mTarget;
- /** whether it allows the commit call to be seen before the target node */
- private final boolean mAllowCommitBeforeTarget;
- /** Whether we've found one of the commit/cancel methods */
- private boolean mFound;
- /** Whether we've seen the target edit node yet */
- private boolean mSeenTarget;
-
- private CommitFinder(MethodInvocation target, boolean allowCommitBeforeTarget) {
- mTarget = target;
- mAllowCommitBeforeTarget = allowCommitBeforeTarget;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (node == mTarget) {
- mSeenTarget = true;
- } else if (mAllowCommitBeforeTarget || mSeenTarget || node.astOperand() == mTarget) {
- String name = node.astName().astValue();
- if ("commit".equals(name) || "apply".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
- // TODO: Do more flow analysis to see whether we're really calling commit/apply
- // on the right type of object?
- mFound = true;
- }
- }
-
- return super.visitMethodInvocation(node);
- }
-
- @Override
- public boolean visitReturn(Return node) {
- if (node.astValue() == mTarget) {
- // If you just do "return editor.commit() don't warn
- mFound = true;
- }
- return super.visitReturn(node);
- }
-
- boolean isCommitCalled() {
- return mFound;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StateListDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StateListDetector.java
deleted file mode 100644
index c0dea30..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StateListDetector.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Checks for unreachable states in an Android state list definition
- */
-public class StateListDetector extends ResourceXmlDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "StateListReachable", //$NON-NLS-1$
- "Looks for unreachable states in a <selector>",
- "In a selector, only the last child in the state list should omit a " +
- "state qualifier. If not, all subsequent items in the list will be ignored " +
- "since the given item will match all.",
- Category.CORRECTNESS,
- 5,
- Severity.WARNING,
- StateListDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- private static final String STATE_PREFIX = "state_"; //$NON-NLS-1$
-
- /** Constructs a new {@link StateListDetector} */
- public StateListDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.DRAWABLE;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- // TODO: Look for views that don't specify
- // Display the error token somewhere so it can be suppressed
- // Emit warning at the end "run with --help to learn how to suppress types of errors/checks";
- // ("...and this message.")
-
- Element root = document.getDocumentElement();
- if (root != null && root.getTagName().equals("selector")) { //$NON-NLS-1$
- List<Element> children = LintUtils.getChildren(root);
- Map<Element, Set<String>> states =
- new HashMap<Element, Set<String>>(children.size());
-
- for (int i = 0; i < children.size(); i++) {
- Element child = children.get(i);
- NamedNodeMap attributes = child.getAttributes();
- Set<String> stateNames = new HashSet<String>(attributes.getLength());
- states.put(child, stateNames);
-
- for (int j = 0; j < attributes.getLength(); j++) {
- Attr attribute = (Attr) attributes.item(j);
- String name = attribute.getLocalName();
- if (name == null) {
- continue;
- }
- if (name.startsWith(STATE_PREFIX)) {
- stateNames.add(name + '=' + attribute.getValue());
- } else {
- String namespaceUri = attribute.getNamespaceURI();
- if (namespaceUri != null && !namespaceUri.isEmpty() &&
- !ANDROID_URI.equals(namespaceUri)) {
- // There is a custom attribute on this item.
- // This could be a state, see
- // http://code.google.com/p/android/issues/detail?id=22339
- // so don't flag this one.
- stateNames.add(attribute.getName() + '=' + attribute.getValue());
- }
- }
- }
- }
-
- // See if for each state, any subsequent state fully contains all the same
- // state requirements
-
- for (int i = 0; i < children.size() - 1; i++) {
- Element prev = children.get(i);
- Set<String> prevStates = states.get(prev);
- assert prevStates != null : prev;
- for (int j = i + 1; j < children.size(); j++) {
- Element current = children.get(j);
- Set<String> currentStates = states.get(current);
- assert currentStates != null : current;
- if (currentStates.containsAll(prevStates)) {
- Location location = context.getLocation(current);
- Location secondary = context.getLocation(prev);
- secondary.setMessage("Earlier item which masks item");
- location.setSecondary(secondary);
- context.report(ISSUE, current, location, String.format(
- "This item is unreachable because a previous item (item #%1$d) is a more general match than this one",
- i + 1), null);
- // Don't keep reporting errors for all the remaining cases in this file
- return;
- }
- }
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java
deleted file mode 100644
index 033996e..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StringFormatDetector.java
+++ /dev/null
@@ -1,1299 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.FORMAT_METHOD;
-import static com.android.SdkConstants.GET_STRING_METHOD;
-import static com.android.SdkConstants.TAG_STRING;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.IJavaParser;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Position;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.CharLiteral;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Expression;
-import lombok.ast.FloatingPointLiteral;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.IntegralLiteral;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.NullLiteral;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-import lombok.ast.VariableDefinitionEntry;
-import lombok.ast.VariableReference;
-
-/**
- * Check which looks for problems with formatting strings such as inconsistencies between
- * translations or between string declaration and string usage in Java.
- * <p>
- * TODO: Handle Resources.getQuantityString as well
- */
-public class StringFormatDetector extends ResourceXmlDetector implements Detector.JavaScanner {
- /** Whether formatting strings are invalid */
- public static final Issue INVALID = Issue.create(
- "StringFormatInvalid", //$NON-NLS-1$
- "Checks that format strings are valid",
-
- "If a string contains a '%' character, then the string may be a formatting string " +
- "which will be passed to `String.format` from Java code to replace each '%' " +
- "occurrence with specific values.\n" +
- "\n" +
- "This lint warning checks for two related problems:\n" +
- "(1) Formatting strings that are invalid, meaning that `String.format` will throw " +
- "exceptions at runtime when attempting to use the format string.\n" +
- "(2) Strings containing '%' that are not formatting strings getting passed to " +
- "a `String.format` call. In this case the '%' will need to be escaped as '%%'.\n" +
- "\n" +
- "NOTE: Not all Strings which look like formatting strings are intended for " +
- "use by `String.format`; for example, they may contain date formats intended " +
- "for `android.text.format.Time#format()`. Lint cannot always figure out that " +
- "a String is a date format, so you may get false warnings in those scenarios. " +
- "See the suppress help topic for information on how to suppress errors in " +
- "that case.",
-
- Category.MESSAGES,
- 9,
- Severity.ERROR,
- StringFormatDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Whether formatting argument types are consistent across translations */
- public static final Issue ARG_COUNT = Issue.create(
- "StringFormatCount", //$NON-NLS-1$
- "Ensures that all format strings are used and that the same number is defined "
- + "across translations",
-
- "When a formatted string takes arguments, it usually needs to reference the " +
- "same arguments in all translations. There are cases where this is not the case, " +
- "so this issue is a warning rather than an error by default. However, this usually " +
- "happens when a language is not translated or updated correctly.",
- Category.MESSAGES,
- 5,
- Severity.WARNING,
- StringFormatDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Whether the string format supplied in a call to String.format matches the format string */
- public static final Issue ARG_TYPES = Issue.create(
- "StringFormatMatches", //$NON-NLS-1$
- "Ensures that the format used in <string> definitions is compatible with the "
- + "String.format call",
-
- "This lint check ensures the following:\n" +
- "(1) If there are multiple translations of the format string, then all translations " +
- "use the same type for the same numbered arguments\n" +
- "(2) The usage of the format string in Java is consistent with the format string, " +
- "meaning that the parameter types passed to String.format matches those in the " +
- "format string.",
- Category.MESSAGES,
- 9,
- Severity.ERROR,
- StringFormatDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.JAVA_FILE));
-
- /**
- * Map from a format string name to a list of declaration file and actual
- * formatting string content. We're using a list since a format string can be
- * defined multiple times, usually for different translations.
- */
- private Map<String, List<Pair<Handle, String>>> mFormatStrings;
-
- /**
- * Map of strings that contain percents that aren't formatting strings; these
- * should not be passed to String.format.
- */
- private final Map<String, Handle> mNotFormatStrings = new HashMap<String, Handle>();
-
- /**
- * Set of strings that have an unknown format such as date formatting; we should not
- * flag these as invalid when used from a String#format call
- */
- private Set<String> mIgnoreStrings;
-
- /** Constructs a new {@link StringFormatDetector} check */
- public StringFormatDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- if (LintUtils.endsWith(file.getName(), DOT_JAVA)) {
- return mFormatStrings != null;
- }
-
- return super.appliesTo(context, file);
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(TAG_STRING);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- NodeList childNodes = element.getChildNodes();
- if (childNodes.getLength() > 0) {
- if (childNodes.getLength() == 1) {
- Node child = childNodes.item(0);
- if (child.getNodeType() == Node.TEXT_NODE) {
- checkTextNode(context, element, strip(child.getNodeValue()));
- }
- } else {
- // Concatenate children and build up a plain string.
- // This is needed to handle xliff localization documents,
- // but this needs more work so ignore compound XML documents as
- // string values for now:
- //StringBuilder sb = new StringBuilder();
- //addText(sb, element);
- //if (sb.length() > 0) {
- // checkTextNode(context, element, sb.toString());
- //}
- }
- }
- }
-
- //private static void addText(StringBuilder sb, Node node) {
- // if (node.getNodeType() == Node.TEXT_NODE) {
- // sb.append(strip(node.getNodeValue().trim()));
- // } else {
- // NodeList childNodes = node.getChildNodes();
- // for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- // addText(sb, childNodes.item(i));
- // }
- // }
- //}
-
- private static String strip(String s) {
- if (s.length() < 2) {
- return s;
- }
- char first = s.charAt(0);
- char last = s.charAt(s.length() - 1);
- if (first == last && (first == '\'' || first == '"')) {
- return s.substring(1, s.length() - 1);
- }
-
- return s;
- }
-
- private void checkTextNode(XmlContext context, Element element, String text) {
- String name = null;
- boolean found = false;
-
- // Look at the String and see if it's a format string (contains
- // positional %'s)
- for (int j = 0, m = text.length(); j < m; j++) {
- char c = text.charAt(j);
- if (c == '\\') {
- j++;
- }
- if (c == '%') {
- if (name == null) {
- name = element.getAttribute(ATTR_NAME);
- }
-
- // Also make sure this String isn't an unformatted String
- String formatted = element.getAttribute("formatted"); //$NON-NLS-1$
- if (!formatted.isEmpty() && !Boolean.parseBoolean(formatted)) {
- if (!mNotFormatStrings.containsKey(name)) {
- Handle handle = context.parser.createLocationHandle(context, element);
- handle.setClientData(element);
- mNotFormatStrings.put(name, handle);
- }
- return;
- }
-
- // See if it's not a format string, e.g. "Battery charge is 100%!".
- // If so we want to record this name in a special list such that we can
- // make sure you don't attempt to reference this string from a String.format
- // call.
- Matcher matcher = FORMAT.matcher(text);
- if (!matcher.find(j)) {
- if (!mNotFormatStrings.containsKey(name)) {
- Handle handle = context.parser.createLocationHandle(context, element);
- handle.setClientData(element);
- mNotFormatStrings.put(name, handle);
- }
- return;
- }
-
- String conversion = matcher.group(6);
- int conversionClass = getConversionClass(conversion.charAt(0));
- if (conversionClass == CONVERSION_CLASS_UNKNOWN || matcher.group(5) != null) {
- if (mIgnoreStrings == null) {
- mIgnoreStrings = new HashSet<String>();
- }
- mIgnoreStrings.add(name);
-
- // Don't process any other strings here; some of them could
- // accidentally look like a string, e.g. "%H" is a hash code conversion
- // in String.format (and hour in Time formatting).
- return;
- }
-
- found = true;
- j++; // Ensure that when we process a "%%" we don't separately check the second %
- }
- }
-
- if (found && name != null) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- // Record it for analysis when seen in Java code
- if (mFormatStrings == null) {
- mFormatStrings = new HashMap<String, List<Pair<Handle,String>>>();
- }
-
- List<Pair<Handle, String>> list = mFormatStrings.get(name);
- if (list == null) {
- list = new ArrayList<Pair<Handle, String>>();
- mFormatStrings.put(name, list);
- }
- Handle handle = context.parser.createLocationHandle(context, element);
- handle.setClientData(element);
- list.add(Pair.of(handle, text));
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mFormatStrings != null) {
- boolean checkCount = context.isEnabled(ARG_COUNT);
- boolean checkValid = context.isEnabled(INVALID);
- boolean checkTypes = context.isEnabled(ARG_TYPES);
-
- // Ensure that all the format strings are consistent with respect to each other;
- // e.g. they all have the same number of arguments, they all use all the
- // arguments, and they all use the same types for all the numbered arguments
- for (Map.Entry<String, List<Pair<Handle, String>>> entry : mFormatStrings.entrySet()) {
- String name = entry.getKey();
- List<Pair<Handle, String>> list = entry.getValue();
-
- // Check argument counts
- if (checkCount) {
- checkArity(context, name, list);
- }
-
- // Check argument types (and also make sure that the formatting strings are valid)
- if (checkValid || checkTypes) {
- checkTypes(context, checkValid, checkTypes, name, list);
- }
- }
- }
- }
-
- private static void checkTypes(Context context, boolean checkValid,
- boolean checkTypes, String name, List<Pair<Handle, String>> list) {
- Map<Integer, String> types = new HashMap<Integer, String>();
- Map<Integer, Handle> typeDefinition = new HashMap<Integer, Handle>();
- for (Pair<Handle, String> pair : list) {
- Handle handle = pair.getFirst();
- String formatString = pair.getSecond();
-
- //boolean warned = false;
- Matcher matcher = FORMAT.matcher(formatString);
- int index = 0;
- int prevIndex = 0;
- int nextNumber = 1;
- while (true) {
- if (matcher.find(index)) {
- int matchStart = matcher.start();
- // Make sure this is not an escaped '%'
- for (; prevIndex < matchStart; prevIndex++) {
- char c = formatString.charAt(prevIndex);
- if (c == '\\') {
- prevIndex++;
- }
- }
- if (prevIndex > matchStart) {
- // We're in an escape, ignore this result
- index = prevIndex;
- continue;
- }
-
- index = matcher.end(); // Ensure loop proceeds
- String str = formatString.substring(matchStart, matcher.end());
- if (str.equals("%%")) { //$NON-NLS-1$
- // Just an escaped %
- continue;
- }
-
- if (checkValid) {
- // Make sure it's a valid format string
- if (str.length() > 2 && str.charAt(str.length() - 2) == ' ') {
- char last = str.charAt(str.length() - 1);
- // If you forget to include the conversion character, e.g.
- // "Weight=%1$ g" instead of "Weight=%1$d g", then
- // you're going to end up with a format string interpreted as
- // "%1$ g". This means that the space character is interpreted
- // as a flag character, but it can only be a flag character
- // when used in conjunction with the numeric conversion
- // formats (d, o, x, X). If that's not the case, make a
- // dedicated error message
- if (last != 'd' && last != 'o' && last != 'x' && last != 'X') {
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(INVALID,
- (Node) clientData)) {
- return;
- }
- }
-
- Location location = handle.resolve();
- String message = String.format(
- "Incorrect formatting string %1$s; missing conversion " +
- "character in '%2$s' ?", name, str);
- context.report(INVALID, location, message, null);
- //warned = true;
- continue;
- }
- }
- }
-
- if (!checkTypes) {
- continue;
- }
-
- // Shouldn't throw a number format exception since we've already
- // matched the pattern in the regexp
- int number;
- String numberString = matcher.group(1);
- if (numberString != null) {
- // Strip off trailing $
- numberString = numberString.substring(0, numberString.length() - 1);
- number = Integer.parseInt(numberString);
- nextNumber = number + 1;
- } else {
- number = nextNumber++;
- }
- String format = matcher.group(6);
- String currentFormat = types.get(number);
- if (currentFormat == null) {
- types.put(number, format);
- typeDefinition.put(number, handle);
- } else if (!currentFormat.equals(format)
- && isIncompatible(currentFormat.charAt(0), format.charAt(0))) {
-
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ARG_TYPES, (Node) clientData)) {
- return;
- }
- }
-
- Location location = handle.resolve();
- // Attempt to limit the location range to just the formatting
- // string in question
- location = refineLocation(context, location, formatString,
- matcher.start(), matcher.end());
- Location otherLocation = typeDefinition.get(number).resolve();
- otherLocation.setMessage("Conflicting argument type here");
- location.setSecondary(otherLocation);
- File f = otherLocation.getFile();
- String message = String.format(
- "Inconsistent formatting types for argument #%1$d in " +
- "format string %2$s ('%3$s'): Found both '%4$s' and '%5$s' " +
- "(in %6$s)",
- number, name,
- str,
- currentFormat, format,
- f.getParentFile().getName() + File.separator + f.getName());
- //warned = true;
- context.report(ARG_TYPES, location, message, null);
- break;
- }
- } else {
- break;
- }
- }
-
- // Check that the format string is valid by actually attempting to instantiate
- // it. We only do this if we haven't already complained about this string
- // for other reasons.
- /* Check disabled for now: it had many false reports due to conversion
- * errors (which is expected since we just pass in strings), but once those
- * are eliminated there aren't really any other valid error messages returned
- * (for example, calling the formatter with bogus formatting flags always just
- * returns a "conversion" error. It looks like we'd need to actually pass compatible
- * arguments to trigger other types of formatting errors such as precision errors.
- if (!warned && checkValid) {
- try {
- formatter.format(formatString, "", "", "", "", "", "", "",
- "", "", "", "", "", "", "");
-
- } catch (IllegalFormatException t) { // TODO: UnknownFormatConversionException
- if (!t.getLocalizedMessage().contains(" != ")
- && !t.getLocalizedMessage().contains("Conversion")) {
- Location location = handle.resolve();
- context.report(INVALID, location,
- String.format("Wrong format for %1$s: %2$s",
- name, t.getLocalizedMessage()), null);
- }
- }
- }
- */
- }
- }
-
- /**
- * Returns true if two String.format conversions are "incompatible" (meaning
- * that using these two for the same argument across different translations
- * is more likely an error than intentional. Some conversions are
- * incompatible, e.g. "d" and "s" where one is a number and string, whereas
- * others may work (e.g. float versus integer) but are probably not
- * intentional.
- */
- private static boolean isIncompatible(char conversion1, char conversion2) {
- int class1 = getConversionClass(conversion1);
- int class2 = getConversionClass(conversion2);
- return class1 != class2
- && class1 != CONVERSION_CLASS_UNKNOWN
- && class2 != CONVERSION_CLASS_UNKNOWN;
- }
-
- private static final int CONVERSION_CLASS_UNKNOWN = 0;
- private static final int CONVERSION_CLASS_STRING = 1;
- private static final int CONVERSION_CLASS_CHARACTER = 2;
- private static final int CONVERSION_CLASS_INTEGER = 3;
- private static final int CONVERSION_CLASS_FLOAT = 4;
- private static final int CONVERSION_CLASS_BOOLEAN = 5;
- private static final int CONVERSION_CLASS_HASHCODE = 6;
- private static final int CONVERSION_CLASS_PERCENT = 7;
- private static final int CONVERSION_CLASS_NEWLINE = 8;
- private static final int CONVERSION_CLASS_DATETIME = 9;
-
- private static int getConversionClass(char conversion) {
- // See http://developer.android.com/reference/java/util/Formatter.html
- switch (conversion) {
- case 't': // Time/date conversion
- case 'T':
- return CONVERSION_CLASS_DATETIME;
- case 's': // string
- case 'S': // Uppercase string
- return CONVERSION_CLASS_STRING;
- case 'c': // character
- case 'C': // Uppercase character
- return CONVERSION_CLASS_CHARACTER;
- case 'd': // decimal
- case 'o': // octal
- case 'x': // hex
- case 'X':
- return CONVERSION_CLASS_INTEGER;
- case 'f': // decimal float
- case 'e': // exponential float
- case 'E':
- case 'g': // decimal or exponential depending on size
- case 'G':
- case 'a': // hex float
- case 'A':
- return CONVERSION_CLASS_FLOAT;
- case 'b': // boolean
- case 'B':
- return CONVERSION_CLASS_BOOLEAN;
- case 'h': // boolean
- case 'H':
- return CONVERSION_CLASS_HASHCODE;
- case '%': // literal
- return CONVERSION_CLASS_PERCENT;
- case 'n': // literal
- return CONVERSION_CLASS_NEWLINE;
- }
-
- return CONVERSION_CLASS_UNKNOWN;
- }
-
- private static Location refineLocation(Context context, Location location,
- String formatString, int substringStart, int substringEnd) {
- Position startLocation = location.getStart();
- Position endLocation = location.getStart();
- if (startLocation != null && endLocation != null) {
- int startOffset = startLocation.getOffset();
- int endOffset = endLocation.getOffset();
- if (startOffset >= 0) {
- String contents = context.getClient().readFile(location.getFile());
- if (contents != null
- && endOffset <= contents.length() && startOffset < endOffset) {
- int formatOffset = contents.indexOf(formatString, startOffset);
- if (formatOffset != -1 && formatOffset <= endOffset) {
- return Location.create(context.file, contents,
- formatOffset + substringStart, formatOffset + substringEnd);
- }
- }
- }
- }
-
- return location;
- }
-
- /**
- * Check that the number of arguments in the format string is consistent
- * across translations, and that all arguments are used
- */
- private static void checkArity(Context context, String name, List<Pair<Handle, String>> list) {
- // Check to make sure that the argument counts and types are consistent
- int prevCount = -1;
- for (Pair<Handle, String> pair : list) {
- Set<Integer> indices = new HashSet<Integer>();
- int count = getFormatArgumentCount(pair.getSecond(), indices);
- Handle handle = pair.getFirst();
- if (prevCount != -1 && prevCount != count) {
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ARG_COUNT, (Node) clientData)) {
- return;
- }
- }
- Location location = handle.resolve();
- Location secondary = list.get(0).getFirst().resolve();
- secondary.setMessage("Conflicting number of arguments here");
- location.setSecondary(secondary);
- String message = String.format(
- "Inconsistent number of arguments in formatting string %1$s; " +
- "found both %2$d and %3$d", name, prevCount, count);
- context.report(ARG_COUNT, location, message, null);
- break;
- }
-
- for (int i = 1; i <= count; i++) {
- if (!indices.contains(i)) {
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(ARG_COUNT, (Node) clientData)) {
- return;
- }
- }
-
- Set<Integer> all = new HashSet<Integer>();
- for (int j = 1; j < count; j++) {
- all.add(j);
- }
- all.removeAll(indices);
- List<Integer> sorted = new ArrayList<Integer>(all);
- Collections.sort(sorted);
- Location location = handle.resolve();
- String message = String.format(
- "Formatting string '%1$s' is not referencing numbered arguments %2$s",
- name, sorted);
- context.report(ARG_COUNT, location, message, null);
- break;
- }
- }
-
- prevCount = count;
- }
- }
-
- // See java.util.Formatter docs
- private static final Pattern FORMAT = Pattern.compile(
- // Generic format:
- // %[argument_index$][flags][width][.precision]conversion
- //
- "%" + //$NON-NLS-1$
- // Argument Index
- "(\\d+\\$)?" + //$NON-NLS-1$
- // Flags
- "([-+#, 0(\\<]*)?" + //$NON-NLS-1$
- // Width
- "(\\d+)?" + //$NON-NLS-1$
- // Precision
- "(\\.\\d+)?" + //$NON-NLS-1$
- // Conversion. These are all a single character, except date/time conversions
- // which take a prefix of t/T:
- "([tT])?" + //$NON-NLS-1$
- // The current set of conversion characters are
- // b,h,s,c,d,o,x,e,f,g,a,t (as well as all those as upper-case characters), plus
- // n for newlines and % as a literal %. And then there are all the time/date
- // characters: HIKLm etc. Just match on all characters here since there should
- // be at least one.
- "([a-zA-Z%])"); //$NON-NLS-1$
-
- /** Given a format string returns the format type of the given argument */
- @VisibleForTesting
- static String getFormatArgumentType(String s, int argument) {
- Matcher matcher = FORMAT.matcher(s);
- int index = 0;
- int prevIndex = 0;
- int nextNumber = 1;
- while (true) {
- if (matcher.find(index)) {
- int matchStart = matcher.start();
- // Make sure this is not an escaped '%'
- for (; prevIndex < matchStart; prevIndex++) {
- char c = s.charAt(prevIndex);
- if (c == '\\') {
- prevIndex++;
- }
- }
- if (prevIndex > matchStart) {
- // We're in an escape, ignore this result
- index = prevIndex;
- continue;
- }
-
- // Shouldn't throw a number format exception since we've already
- // matched the pattern in the regexp
- int number;
- String numberString = matcher.group(1);
- if (numberString != null) {
- // Strip off trailing $
- numberString = numberString.substring(0, numberString.length() - 1);
- number = Integer.parseInt(numberString);
- nextNumber = number + 1;
- } else {
- number = nextNumber++;
- }
-
- if (number == argument) {
- return matcher.group(6);
- }
- index = matcher.end();
- } else {
- break;
- }
- }
-
- return null;
- }
-
- /**
- * Given a format string returns the number of required arguments. If the
- * {@code seenArguments} parameter is not null, put the indices of any
- * observed arguments into it.
- */
- @VisibleForTesting
- static int getFormatArgumentCount(String s, Set<Integer> seenArguments) {
- Matcher matcher = FORMAT.matcher(s);
- int index = 0;
- int prevIndex = 0;
- int nextNumber = 1;
- int max = 0;
- while (true) {
- if (matcher.find(index)) {
- if ("%".equals(matcher.group(6))) { //$NON-NLS-1$
- index = matcher.end();
- continue;
- }
- int matchStart = matcher.start();
- // Make sure this is not an escaped '%'
- for (; prevIndex < matchStart; prevIndex++) {
- char c = s.charAt(prevIndex);
- if (c == '\\') {
- prevIndex++;
- }
- }
- if (prevIndex > matchStart) {
- // We're in an escape, ignore this result
- index = prevIndex;
- continue;
- }
-
- // Shouldn't throw a number format exception since we've already
- // matched the pattern in the regexp
- int number;
- String numberString = matcher.group(1);
- if (numberString != null) {
- // Strip off trailing $
- numberString = numberString.substring(0, numberString.length() - 1);
- number = Integer.parseInt(numberString);
- nextNumber = number + 1;
- } else {
- number = nextNumber++;
- }
-
- if (number > max) {
- max = number;
- }
- if (seenArguments != null) {
- seenArguments.add(number);
- }
-
- index = matcher.end();
- } else {
- break;
- }
- }
-
- return max;
- }
-
- /**
- * Determines whether the given {@link String#format(String, Object...)}
- * formatting string is "locale dependent", meaning that its output depends
- * on the locale. This is the case if it for example references decimal
- * numbers of dates and times.
- *
- * @param format the format string
- * @return true if the format is locale sensitive, false otherwise
- */
- public static boolean isLocaleSpecific(@NonNull String format) {
- if (format.indexOf('%') == -1) {
- return false;
- }
-
- String s = format;
- Matcher matcher = FORMAT.matcher(s);
- int index = 0;
- int prevIndex = 0;
- while (true) {
- if (matcher.find(index)) {
- int matchStart = matcher.start();
- // Make sure this is not an escaped '%'
- for (; prevIndex < matchStart; prevIndex++) {
- char c = s.charAt(prevIndex);
- if (c == '\\') {
- prevIndex++;
- }
- }
- if (prevIndex > matchStart) {
- // We're in an escape, ignore this result
- index = prevIndex;
- continue;
- }
-
- String type = matcher.group(6);
- if (!type.isEmpty()) {
- char t = type.charAt(0);
-
- // The following formatting characters are locale sensitive:
- switch (t) {
- case 'd': // decimal integer
- case 'e': // scientific
- case 'E':
- case 'f': // decimal float
- case 'g': // general
- case 'G':
- case 't': // date/time
- case 'T':
- return true;
- }
- }
- index = matcher.end();
- } else {
- break;
- }
- }
-
- return false;
- }
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Arrays.asList(FORMAT_METHOD, GET_STRING_METHOD);
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- if (mFormatStrings == null) {
- return;
- }
-
- String methodName = node.astName().getDescription();
- if (methodName.equals(FORMAT_METHOD)) {
- // String.format(getResources().getString(R.string.foo), arg1, arg2, ...)
- // Check that the arguments in R.string.foo match arg1, arg2, ...
- if (node.astOperand() instanceof VariableReference) {
- VariableReference ref = (VariableReference) node.astOperand();
- if ("String".equals(ref.astIdentifier().astValue())) { //$NON-NLS-1$
- // Found a String.format call
- // Look inside to see if we can find an R string
- // Find surrounding method
- checkFormatCall(context, node);
- }
- }
- } else {
- // getResources().getString(R.string.foo, arg1, arg2, ...)
- // Check that the arguments in R.string.foo match arg1, arg2, ...
- if (node.astArguments().size() > 1 && node.astOperand() != null ) {
- checkFormatCall(context, node);
- }
- }
- }
-
- private void checkFormatCall(JavaContext context, MethodInvocation node) {
- lombok.ast.Node current = getParentMethod(node);
- if (current != null) {
- checkStringFormatCall(context, current, node);
- }
- }
-
- /**
- * Check the given String.format call (with the given arguments) to see if
- * the string format is being used correctly
- *
- * @param context the context to report errors to
- * @param method the method containing the {@link String#format} call
- * @param call the AST node for the {@link String#format}
- */
- private void checkStringFormatCall(
- JavaContext context,
- lombok.ast.Node method,
- MethodInvocation call) {
-
- StrictListAccessor<Expression, MethodInvocation> args = call.astArguments();
- if (args.isEmpty()) {
- return;
- }
-
- StringTracker tracker = new StringTracker(method, call, 0);
- method.accept(tracker);
- String name = tracker.getFormatStringName();
- if (name == null) {
- return;
- }
-
- if (mIgnoreStrings != null && mIgnoreStrings.contains(name)) {
- return;
- }
-
- if (mNotFormatStrings.containsKey(name)) {
- Handle handle = mNotFormatStrings.get(name);
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(INVALID, (Node) clientData)) {
- return;
- }
- }
- Location location = handle.resolve();
- String message = String.format(
- "Format string '%1$s' is not a valid format string so it should not be " +
- "passed to String.format",
- name);
- context.report(INVALID, call, location, message, null);
- return;
- }
-
- // TODO: Need type information in the AST
- Iterator<Expression> argIterator = args.iterator();
- Expression first = argIterator.next();
- Expression second = argIterator.hasNext() ? argIterator.next() : null;
- String firstName = first.toString();
- boolean specifiesLocale = firstName.startsWith("Locale.") //$NON-NLS-1$
- || firstName.contains("locale") //$NON-NLS-1$
- || firstName.equals("null") //$NON-NLS-1$
- || second != null && second.toString().contains("getString"); //$NON-NLS-1$
-
- List<Pair<Handle, String>> list = mFormatStrings.get(name);
- if (list != null) {
- for (Pair<Handle, String> pair : list) {
- String s = pair.getSecond();
- int count = getFormatArgumentCount(s, null);
- Handle handle = pair.getFirst();
- if (count != args.size() - 1 - (specifiesLocale ? 1 : 0)) {
- Location location = context.parser.getLocation(context, call);
- Location secondary = handle.resolve();
- secondary.setMessage(String.format("This definition requires %1$d arguments",
- count));
- location.setSecondary(secondary);
- String message = String.format(
- "Wrong argument count, format string %1$s requires %2$d but format " +
- "call supplies %3$d",
- name, count, args.size() - 1);
- context.report(ARG_TYPES, method, location, message, null);
- } else {
- for (int i = 1; i <= count; i++) {
- int argumentIndex = i + (specifiesLocale ? 1 : 0);
- Class<?> type = tracker.getArgumentType(argumentIndex);
- if (type != null) {
- boolean valid = true;
- String formatType = getFormatArgumentType(s, i);
- char last = formatType.charAt(formatType.length() - 1);
- if (formatType.length() >= 2 &&
- Character.toLowerCase(
- formatType.charAt(formatType.length() - 2)) == 't') {
- // Date time conversion.
- // TODO
- continue;
- }
- switch (last) {
- // Booleans. It's okay to pass objects to these;
- // it will print "true" if non-null, but it's
- // unusual and probably not intended.
- case 'b':
- case 'B':
- valid = type == Boolean.TYPE;
- break;
-
- // Numeric: integer and floats in various formats
- case 'x':
- case 'X':
- case 'd':
- case 'o':
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- case 'a':
- case 'A':
- valid = type == Integer.TYPE
- || type == Float.TYPE;
- break;
- case 'c':
- case 'C':
- // Unicode character
- valid = type == Character.TYPE;
- break;
- case 'h':
- case 'H': // Hex print of hash code of objects
- case 's':
- case 'S':
- // String. Can pass anything, but warn about
- // numbers since you may have meant more
- // specific formatting. Use special issue
- // explanation for this?
- valid = type != Boolean.TYPE &&
- !type.isAssignableFrom(Number.class);
- break;
- }
-
- if (!valid) {
- IJavaParser parser = context.parser;
- Expression argument = tracker.getArgument(argumentIndex);
- Location location = parser.getLocation(context, argument);
- Location secondary = handle.resolve();
- secondary.setMessage("Conflicting argument declaration here");
- location.setSecondary(secondary);
-
- String message = String.format(
- "Wrong argument type for formatting argument '#%1$d' " +
- "in %2$s: conversion is '%3$s', received %4$s",
- i, name, formatType, type.getSimpleName());
- context.report(ARG_TYPES, method, location, message, null);
- }
- }
- }
- }
- }
- }
- }
-
- /** Returns the parent method of the given AST node */
- @Nullable
- static lombok.ast.Node getParentMethod(@NonNull lombok.ast.Node node) {
- lombok.ast.Node current = node.getParent();
- while (current != null
- && !(current instanceof MethodDeclaration)
- && !(current instanceof ConstructorDeclaration)) {
- current = current.getParent();
- }
-
- return current;
- }
-
- /** Returns the resource name corresponding to the first argument in the given call */
- static String getResourceForFirstArg(lombok.ast.Node method, lombok.ast.Node call) {
- assert call instanceof MethodInvocation || call instanceof ConstructorInvocation;
- StringTracker tracker = new StringTracker(method, call, 0);
- method.accept(tracker);
- String name = tracker.getFormatStringName();
-
- return name;
- }
-
- /** Returns the resource name corresponding to the given argument in the given call */
- static String getResourceArg(lombok.ast.Node method, lombok.ast.Node call, int argIndex) {
- assert call instanceof MethodInvocation || call instanceof ConstructorInvocation;
- StringTracker tracker = new StringTracker(method, call, argIndex);
- method.accept(tracker);
- String name = tracker.getFormatStringName();
-
- return name;
- }
-
- /**
- * Given a variable reference, finds the original R.string value corresponding to it.
- * For example:
- * <pre>
- * {@code
- * String target = "World";
- * String hello = getResources().getString(R.string.hello);
- * String output = String.format(hello, target);
- * }
- * </pre>
- *
- * Given the {@code String.format} call, we want to find out what R.string resource
- * corresponds to the first argument, in this case {@code R.string.hello}.
- * To do this, we look for R.string references, and track those through assignments
- * until we reach the target node.
- * <p>
- * In addition, it also does some primitive type tracking such that it (in some cases)
- * can answer questions about the types of variables. This allows it to check whether
- * certain argument types are valid. Note however that it does not do full-blown
- * type analysis by checking method call signatures and so on.
- */
- private static class StringTracker extends ForwardingAstVisitor {
- /** Method we're searching within */
- private final lombok.ast.Node mTop;
- /** The argument index in the method we're targeting */
- private final int mArgIndex;
- /** Map from variable name to corresponding string resource name */
- private final Map<String, String> mMap = new HashMap<String, String>();
- /** Map from variable name to corresponding type */
- private final Map<String, Class<?>> mTypes = new HashMap<String, Class<?>>();
- /** The AST node for the String.format we're interested in */
- private final lombok.ast.Node mTargetNode;
- private boolean mDone;
- /**
- * Result: the name of the string resource being passed to the
- * String.format, if any
- */
- private String mName;
-
- public StringTracker(lombok.ast.Node top, lombok.ast.Node targetNode, int argIndex) {
- mTop = top;
- mArgIndex = argIndex;
- mTargetNode = targetNode;
- }
-
- public String getFormatStringName() {
- return mName;
- }
-
- /** Returns the argument type of the given formatting argument of the
- * target node. Note: This is in the formatting string, which is one higher
- * than the String.format parameter number, since the first argument is the
- * formatting string itself.
- *
- * @param argument the argument number
- * @return the class (such as {@link Integer#TYPE} etc) or null if not known
- */
- public Class<?> getArgumentType(int argument) {
- Expression arg = getArgument(argument);
- if (arg != null) {
- Class<?> type = getType(arg);
- if (type != null) {
- return type;
- }
- }
-
- return null;
- }
-
- public Expression getArgument(int argument) {
- if (!(mTargetNode instanceof MethodInvocation)) {
- return null;
- }
- MethodInvocation call = (MethodInvocation) mTargetNode;
- StrictListAccessor<Expression, MethodInvocation> args = call.astArguments();
- if (argument >= args.size()) {
- return null;
- }
-
- Iterator<Expression> iterator = args.iterator();
- int index = 0;
- while (iterator.hasNext()) {
- Expression arg = iterator.next();
- if (index++ == argument) {
- return arg;
- }
- }
-
- return null;
- }
-
- @Override
- public boolean visitNode(lombok.ast.Node node) {
- if (mDone) {
- return true;
- }
-
- return super.visitNode(node);
- }
-
- @Override
- public boolean visitVariableReference(VariableReference node) {
- if (node.astIdentifier().getDescription().equals("R") && //$NON-NLS-1$
- node.getParent() instanceof Select &&
- node.getParent().getParent() instanceof Select) {
-
- // See if we're on the right hand side of an assignment
- lombok.ast.Node current = node.getParent().getParent();
- String reference = ((Select) current).astIdentifier().astValue();
-
- while (current != mTop && !(current instanceof VariableDefinitionEntry)) {
- if (current == mTargetNode) {
- mName = reference;
- mDone = true;
- return false;
- }
- current = current.getParent();
- }
- if (current instanceof VariableDefinitionEntry) {
- VariableDefinitionEntry entry = (VariableDefinitionEntry) current;
- String variable = entry.astName().astValue();
- mMap.put(variable, reference);
- }
- }
-
- return false;
- }
-
- @Nullable
- private Expression getTargetArgument() {
- Iterator<Expression> iterator;
- if (mTargetNode instanceof MethodInvocation) {
- iterator = ((MethodInvocation) mTargetNode).astArguments().iterator();
- } else if (mTargetNode instanceof ConstructorInvocation) {
- iterator = ((ConstructorInvocation) mTargetNode).astArguments().iterator();
- } else {
- return null;
- }
- int i = 0;
- while (i < mArgIndex && iterator.hasNext()) {
- iterator.next();
- i++;
- }
- if (iterator.hasNext()) {
- return iterator.next();
- }
-
- return null;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (node == mTargetNode) {
- Expression arg = getTargetArgument();
- if (arg instanceof VariableReference) {
- VariableReference reference = (VariableReference) arg;
- String variable = reference.astIdentifier().astValue();
- mName = mMap.get(variable);
- mDone = true;
- return true;
- }
- }
-
- // Is this a getString() call? On a resource object? If so,
- // promote the resource argument up to the left hand side
- return super.visitMethodInvocation(node);
- }
-
- @Override
- public boolean visitConstructorInvocation(ConstructorInvocation node) {
- if (node == mTargetNode) {
- Expression arg = getTargetArgument();
- if (arg instanceof VariableReference) {
- VariableReference reference = (VariableReference) arg;
- String variable = reference.astIdentifier().astValue();
- mName = mMap.get(variable);
- mDone = true;
- return true;
- }
- }
-
- // Is this a getString() call? On a resource object? If so,
- // promote the resource argument up to the left hand side
- return super.visitConstructorInvocation(node);
- }
-
- @Override
- public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
- String name = node.astName().astValue();
- Expression rhs = node.astInitializer();
- Class<?> type = getType(rhs);
- if (type != null) {
- mTypes.put(name, type);
- } else {
- // Make sure we're not visiting the String.format node itself. If you have
- // msg = String.format("%1$s", msg)
- // then we'd be wiping out the type of "msg" before visiting the
- // String.format call!
- if (rhs != mTargetNode) {
- mTypes.remove(name);
- }
- }
-
- return super.visitVariableDefinitionEntry(node);
- }
-
- private Class<?> getType(Expression expression) {
- if (expression instanceof VariableReference) {
- VariableReference reference = (VariableReference) expression;
- String variable = reference.astIdentifier().astValue();
- return mTypes.get(variable);
- } else if (expression instanceof MethodInvocation) {
- MethodInvocation method = (MethodInvocation) expression;
- String methodName = method.astName().astValue();
- if (methodName.equals(GET_STRING_METHOD)) {
- return String.class;
- }
- } else if (expression instanceof StringLiteral) {
- return String.class;
- } else if (expression instanceof IntegralLiteral) {
- return Integer.TYPE;
- } else if (expression instanceof FloatingPointLiteral) {
- return Float.TYPE;
- } else if (expression instanceof CharLiteral) {
- return Character.TYPE;
- } else if (expression instanceof NullLiteral) {
- return Object.class;
- }
-
- return null;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StyleCycleDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StyleCycleDetector.java
deleted file mode 100644
index 8ce103b..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/StyleCycleDetector.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_PARENT;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.TAG_STYLE;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Checks for cycles in style definitions
- */
-public class StyleCycleDetector extends ResourceXmlDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "StyleCycle", //$NON-NLS-1$
- "Looks for cycles in style definitions",
- "There should be no cycles in style definitions as this can lead to runtime " +
- "exceptions.",
- Category.CORRECTNESS,
- 8,
- Severity.FATAL,
- StyleCycleDetector.class,
- Scope.RESOURCE_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/ui/themes.html#Inheritance"); //$NON-NLS-1$
-
- /** Constructs a new {@link StyleCycleDetector} */
- public StyleCycleDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singleton(TAG_STYLE);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- Attr parentNode = element.getAttributeNode(ATTR_PARENT);
- if (parentNode != null) {
- String parent = parentNode.getValue();
- String name = element.getAttribute(ATTR_NAME);
- if (parent.endsWith(name) &&
- parent.equals(STYLE_RESOURCE_PREFIX + name)) {
- context.report(ISSUE, parentNode, context.getLocation(parentNode),
- String.format("Style %1$s should not extend itself", name), null);
- } else if (parent.startsWith(STYLE_RESOURCE_PREFIX)
- && parent.startsWith(name, STYLE_RESOURCE_PREFIX.length())
- && parent.startsWith(".", STYLE_RESOURCE_PREFIX.length() + name.length())) {
- context.report(ISSUE, parentNode, context.getLocation(parentNode),
- String.format("Potential cycle: %1$s is the implied parent of %2$s and " +
- "this defines the opposite", name,
- parent.substring(STYLE_RESOURCE_PREFIX.length())), null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SystemPermissionsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SystemPermissionsDetector.java
deleted file mode 100644
index 21fb6c0..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/SystemPermissionsDetector.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.TAG_USES_PERMISSION;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-
-/**
- * Checks if an application wants to use permissions that can only be used by
- * system applications.
- */
-public class SystemPermissionsDetector extends Detector implements Detector.XmlScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ProtectedPermissions", //$NON-NLS-1$
- "Looks for permissions that are only granted to system apps",
-
- "Permissions with the protection level signature or signatureOrSystem are only " +
- "granted to system apps. If an app is a regular non-system app, it will never be " +
- "able to use these permissions.",
-
- Category.CORRECTNESS,
- 5,
- Severity.ERROR,
- SystemPermissionsDetector.class,
- EnumSet.of(Scope.MANIFEST));
-
- // List of permissions have the protection levels signature or systemOrSignature.
- // This list must be sorted alphabetically.
- private static final String[] SYSTEM_PERMISSIONS = new String[] {
- "android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE",
- "android.permission.ACCESS_CACHE_FILESYSTEM",
- "android.permission.ACCESS_CHECKIN_PROPERTIES",
- "android.permission.ACCESS_MTP",
- "android.permission.ACCESS_SURFACE_FLINGER",
- "android.permission.ACCOUNT_MANAGER",
- "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK",
- "android.permission.ASEC_ACCESS",
- "android.permission.ASEC_CREATE",
- "android.permission.ASEC_DESTROY",
- "android.permission.ASEC_MOUNT_UNMOUNT",
- "android.permission.ASEC_RENAME",
- "android.permission.BACKUP",
- "android.permission.BIND_APPWIDGET",
- "android.permission.BIND_DEVICE_ADMIN",
- "android.permission.BIND_INPUT_METHOD",
- "android.permission.BIND_PACKAGE_VERIFIER",
- "android.permission.BIND_REMOTEVIEWS",
- "android.permission.BIND_TEXT_SERVICE",
- "android.permission.BIND_VPN_SERVICE",
- "android.permission.BIND_WALLPAPER",
- "android.permission.BRICK",
- "android.permission.BROADCAST_PACKAGE_REMOVED",
- "android.permission.BROADCAST_SMS",
- "android.permission.BROADCAST_WAP_PUSH",
- "android.permission.CALL_PRIVILEGED",
- "android.permission.CHANGE_BACKGROUND_DATA_SETTING",
- "android.permission.CHANGE_COMPONENT_ENABLED_STATE",
- "android.permission.CLEAR_APP_USER_DATA",
- "android.permission.CONFIRM_FULL_BACKUP",
- "android.permission.CONNECTIVITY_INTERNAL",
- "android.permission.CONTROL_LOCATION_UPDATES",
- "android.permission.COPY_PROTECTED_DATA",
- "android.permission.CRYPT_KEEPER",
- "android.permission.DELETE_CACHE_FILES",
- "android.permission.DELETE_PACKAGES",
- "android.permission.DEVICE_POWER",
- "android.permission.DIAGNOSTIC",
- "android.permission.DUMP",
- "android.permission.FACTORY_TEST",
- "android.permission.FORCE_BACK",
- "android.permission.FORCE_STOP_PACKAGES",
- "android.permission.GLOBAL_SEARCH",
- "android.permission.GLOBAL_SEARCH_CONTROL",
- "android.permission.HARDWARE_TEST",
- "android.permission.INJECT_EVENTS",
- "android.permission.INSTALL_LOCATION_PROVIDER",
- "android.permission.INSTALL_PACKAGES",
- "android.permission.INTERNAL_SYSTEM_WINDOW",
- "android.permission.MANAGE_APP_TOKENS",
- "android.permission.MANAGE_NETWORK_POLICY",
- "android.permission.MANAGE_USB",
- "android.permission.MASTER_CLEAR",
- "android.permission.MODIFY_NETWORK_ACCOUNTING",
- "android.permission.MODIFY_PHONE_STATE",
- "android.permission.MOVE_PACKAGE",
- "android.permission.NET_ADMIN",
- "android.permission.MODIFY_PHONE_STATE",
- "android.permission.PACKAGE_USAGE_STATS",
- "android.permission.PACKAGE_VERIFICATION_AGENT",
- "android.permission.PERFORM_CDMA_PROVISIONING",
- "android.permission.READ_FRAME_BUFFER",
- "android.permission.READ_INPUT_STATE",
- "android.permission.READ_NETWORK_USAGE_HISTORY",
- "android.permission.READ_PRIVILEGED_PHONE_STATE",
- "android.permission.REBOOT",
- "android.permission.RECEIVE_EMERGENCY_BROADCAST",
- "android.permission.REMOVE_TASKS",
- "android.permission.RETRIEVE_WINDOW_CONTENT",
- "android.permission.SEND_SMS_NO_CONFIRMATION",
- "android.permission.SET_ACTIVITY_WATCHER",
- "android.permission.SET_ORIENTATION",
- "android.permission.SET_POINTER_SPEED",
- "android.permission.SET_PREFERRED_APPLICATIONS",
- "android.permission.SET_SCREEN_COMPATIBILITY",
- "android.permission.SET_TIME",
- "android.permission.SET_WALLPAPER_COMPONENT",
- "android.permission.SHUTDOWN",
- "android.permission.STATUS_BAR",
- "android.permission.STATUS_BAR_SERVICE",
- "android.permission.STOP_APP_SWITCHES",
- "android.permission.UPDATE_DEVICE_STATS",
- "android.permission.WRITE_APN_SETTINGS",
- "android.permission.WRITE_GSERVICES",
- "android.permission.WRITE_MEDIA_STORAGE",
- "android.permission.WRITE_SECURE_SETTINGS"
- };
-
- /** Constructs a new {@link SystemPermissionsDetector} check */
- public SystemPermissionsDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return file.getName().equals(ANDROID_MANIFEST_XML);
- }
-
- // ---- Implements Detector.XmlScanner ----
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(TAG_USES_PERMISSION);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
- if (nameNode != null) {
- String permissionName = nameNode.getValue();
- if (Arrays.binarySearch(SYSTEM_PERMISSIONS, permissionName) >= 0) {
- context.report(ISSUE, element, context.getLocation(nameNode),
- "Permission is only granted to system apps", null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextFieldDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextFieldDetector.java
deleted file mode 100644
index a059f5c..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextFieldDetector.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_HINT;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_INPUT_METHOD;
-import static com.android.SdkConstants.ATTR_INPUT_TYPE;
-import static com.android.SdkConstants.ATTR_PASSWORD;
-import static com.android.SdkConstants.ATTR_PHONE_NUMBER;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.EDIT_TEXT;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Checks for usability problems in text fields: omitting inputType, or omitting a hint.
- */
-public class TextFieldDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "TextFields", //$NON-NLS-1$
- "Looks for text fields missing inputType or hint settings",
-
- "Providing an `inputType` attribute on a text field improves usability " +
- "because depending on the data to be input, optimized keyboards can be shown " +
- "to the user (such as just digits and parentheses for a phone number). Similarly," +
- "a hint attribute displays a hint to the user for what is expected in the " +
- "text field.\n" +
- "\n" +
- "The lint detector also looks at the `id` of the view, and if the id offers a " +
- "hint of the purpose of the field (for example, the `id` contains the phrase " +
- "`phone` or `email`), then lint will also ensure that the `inputType` contains " +
- "the corresponding type attributes.\n" +
- "\n" +
- "If you really want to keep the text field generic, you can suppress this warning " +
- "by setting `inputType=\"text\"`.",
-
- Category.USABILITY,
- 5,
- Severity.WARNING,
- TextFieldDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link TextFieldDetector} */
- public TextFieldDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(EDIT_TEXT);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String style = element.getAttribute(ATTR_STYLE);
- if (style != null && !style.isEmpty()) {
- // The input type might be specified via a style. This will require
- // us to track these (similar to what is done for the
- // RequiredAttributeDetector to track layout_width and layout_height
- // in style declarations). For now, simply ignore these elements
- // to avoid producing false positives.
- return;
- }
-
- Attr inputTypeNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_INPUT_TYPE);
- if (inputTypeNode == null &&
- !element.hasAttributeNS(ANDROID_URI, ATTR_HINT)) {
- // Also make sure the EditText does not set an inputMethod in which case
- // an inputType might be provided from the input.
- if (element.hasAttributeNS(ANDROID_URI, ATTR_INPUT_METHOD)) {
- return;
- }
-
- context.report(ISSUE, element, context.getLocation(element),
- "This text field does not specify an inputType or a hint", null);
- }
-
- Attr idNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_ID);
- if (idNode == null) {
- return;
- }
- String id = idNode.getValue();
- if (id.isEmpty()) {
- return;
- }
- if (id.startsWith("editText")) { //$NON-NLS-1$
- // Just the default label
- return;
- }
-
- String inputType = "";
- if (inputTypeNode != null) {
- inputType = inputTypeNode.getValue();
- }
-
- // TODO: See if the name is just the default names (button1, editText1 etc)
- // and if so, do nothing
- // TODO: Unit test this
-
- if (containsWord(id, "phone", true, true)) { //$NON-NLS-1$
- if (!inputType.contains("phone") //$NON-NLS-1$
- && element.getAttributeNodeNS(ANDROID_URI, ATTR_PHONE_NUMBER) == null) {
- String message = String.format("The view name (%1$s) suggests this is a phone "
- + "number, but it does not include 'phone' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- return;
- }
-
- if (containsWord(id, "width", false, true)
- || containsWord(id, "height", false, true)
- || containsWord(id, "size", false, true)
- || containsWord(id, "length", false, true)
- || containsWord(id, "weight", false, true)
- || containsWord(id, "number", false, true)) {
- if (!inputType.contains("number") && !inputType.contains("phone")) { //$NON-NLS-1$
- String message = String.format("The view name (%1$s) suggests this is a number, "
- + "but it does not include a numeric inputType (such as 'numberSigned')",
- id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- return;
- }
-
- if (containsWord(id, "password", true, true)) { //$NON-NLS-1$
- if (!(inputType.contains("Password")) //$NON-NLS-1$
- && element.getAttributeNodeNS(ANDROID_URI, ATTR_PASSWORD) == null) {
- String message = String.format("The view name (%1$s) suggests this is a password, "
- + "but it does not include 'textPassword' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- return;
- }
-
- if (containsWord(id, "email", true, true)) { //$NON-NLS-1$
- if (!inputType.contains("Email")) { //$NON-NLS-1$
- String message = String.format("The view name (%1$s) suggests this is an e-mail "
- + "address, but it does not include 'textEmail' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- return;
- }
-
- if (endsWith(id, "pin", false, true)) { //$NON-NLS-1$
- if (!(inputType.contains("numberPassword")) //$NON-NLS-1$
- && element.getAttributeNodeNS(ANDROID_URI, ATTR_PASSWORD) == null) {
- String message = String.format("The view name (%1$s) suggests this is a password, "
- + "but it does not include 'numberPassword' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- return;
- }
-
- if ((containsWord(id, "uri") || containsWord(id, "url"))
- && !inputType.contains("textUri")) {
- String message = String.format("The view name (%1$s) suggests this is a URI, "
- + "but it does not include 'textUri' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
-
- if ((containsWord(id, "date")) //$NON-NLS-1$
- && !inputType.contains("date")) { //$NON-NLS-1$
- String message = String.format("The view name (%1$s) suggests this is a date, "
- + "but it does not include 'date' or 'datetime' in the inputType", id);
- reportMismatch(context, idNode, inputTypeNode, message);
- }
- }
-
- private static void reportMismatch(XmlContext context, Attr idNode, Attr inputTypeNode,
- String message) {
- Location location;
- if (inputTypeNode != null) {
- location = context.getLocation(inputTypeNode);
- Location secondary = context.getLocation(idNode);
- secondary.setMessage("id defined here");
- location.setSecondary(secondary);
- } else {
- location = context.getLocation(idNode);
- }
- context.report(ISSUE, idNode.getOwnerElement(), location, message, null);
- }
-
- /** Returns true if the given sentence contains a given word */
- @VisibleForTesting
- static boolean containsWord(String sentence, String word) {
- return containsWord(sentence, word, false, false);
- }
-
- /**
- * Returns true if the given sentence contains a given word
- * @param sentence the full sentence to search within
- * @param word the word to look for
- * @param allowPrefix if true, allow a prefix match even if the next character
- * is in the same word (same case or not an underscore)
- * @param allowSuffix if true, allow a suffix match even if the preceding character
- * is in the same word (same case or not an underscore)
- * @return true if the word is contained in the sentence
- */
- @VisibleForTesting
- static boolean containsWord(String sentence, String word, boolean allowPrefix,
- boolean allowSuffix) {
- return indexOfWord(sentence, word, allowPrefix, allowSuffix) != -1;
- }
-
- /** Returns true if the given sentence <b>ends</b> with a given word */
- private static boolean endsWith(String sentence, String word, boolean allowPrefix,
- boolean allowSuffix) {
- int index = indexOfWord(sentence, word, allowPrefix, allowSuffix);
-
- if (index != -1) {
- return index == sentence.length() - word.length();
- }
-
- return false;
- }
-
- /**
- * Returns the index of the given word in the given sentence, if any. It will match
- * across cases, and ignore words that seem to be just a substring in the middle
- * of another word.
- *
- * @param sentence the full sentence to search within
- * @param word the word to look for
- * @param allowPrefix if true, allow a prefix match even if the next character
- * is in the same word (same case or not an underscore)
- * @param allowSuffix if true, allow a suffix match even if the preceding character
- * is in the same word (same case or not an underscore)
- * @return true if the word is contained in the sentence
- */
- private static int indexOfWord(String sentence, String word, boolean allowPrefix,
- boolean allowSuffix) {
- if (sentence.isEmpty()) {
- return -1;
- }
- int wordLength = word.length();
- if (wordLength > sentence.length()) {
- return -1;
- }
-
- char firstUpper = Character.toUpperCase(word.charAt(0));
- char firstLower = Character.toLowerCase(firstUpper);
-
- int start = 0;
- if (sentence.startsWith(NEW_ID_PREFIX)) {
- start += NEW_ID_PREFIX.length();
- } else if (sentence.startsWith(ID_PREFIX)) {
- start += ID_PREFIX.length();
- }
-
- for (int i = start, n = sentence.length(), m = n - (wordLength - 1); i < m; i++) {
- char c = sentence.charAt(i);
- if (c == firstUpper || c == firstLower) {
- if (sentence.regionMatches(true, i, word, 0, wordLength)) {
- if (i <= start && allowPrefix) {
- return i;
- }
- if (i == m - 1 && allowSuffix) {
- return i;
- }
- if (i <= start || (sentence.charAt(i - 1) == '_')
- || Character.isUpperCase(c)) {
- if (i == m - 1) {
- return i;
- }
- char after = sentence.charAt(i + wordLength);
- if (after == '_' || Character.isUpperCase(after)) {
- return i;
- }
- }
- }
- }
- }
-
- return -1;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextViewDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextViewDetector.java
deleted file mode 100644
index 3e519cf..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TextViewDetector.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_AUTO_TEXT;
-import static com.android.SdkConstants.ATTR_BUFFER_TYPE;
-import static com.android.SdkConstants.ATTR_CAPITALIZE;
-import static com.android.SdkConstants.ATTR_CURSOR_VISIBLE;
-import static com.android.SdkConstants.ATTR_DIGITS;
-import static com.android.SdkConstants.ATTR_EDITABLE;
-import static com.android.SdkConstants.ATTR_EDITOR_EXTRAS;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_IME_ACTION_ID;
-import static com.android.SdkConstants.ATTR_IME_ACTION_LABEL;
-import static com.android.SdkConstants.ATTR_IME_OPTIONS;
-import static com.android.SdkConstants.ATTR_INPUT_METHOD;
-import static com.android.SdkConstants.ATTR_INPUT_TYPE;
-import static com.android.SdkConstants.ATTR_NUMERIC;
-import static com.android.SdkConstants.ATTR_PASSWORD;
-import static com.android.SdkConstants.ATTR_PHONE_NUMBER;
-import static com.android.SdkConstants.ATTR_PRIVATE_IME_OPTIONS;
-import static com.android.SdkConstants.ATTR_TEXT;
-import static com.android.SdkConstants.ATTR_TEXT_IS_SELECTABLE;
-import static com.android.SdkConstants.ATTR_VISIBILITY;
-import static com.android.SdkConstants.BUTTON;
-import static com.android.SdkConstants.CHECKED_TEXT_VIEW;
-import static com.android.SdkConstants.CHECK_BOX;
-import static com.android.SdkConstants.RADIO_BUTTON;
-import static com.android.SdkConstants.SWITCH;
-import static com.android.SdkConstants.TEXT_VIEW;
-import static com.android.SdkConstants.TOGGLE_BUTTON;
-import static com.android.SdkConstants.VALUE_EDITABLE;
-import static com.android.SdkConstants.VALUE_NONE;
-import static com.android.SdkConstants.VALUE_TRUE;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Checks for cases where a TextView should probably be an EditText instead
- */
-public class TextViewDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "TextViewEdits", //$NON-NLS-1$
- "Looks for TextViews being used for input",
-
- "Using a `<TextView>` to input text is generally an error, you should be " +
- "using `<EditText>` instead. `EditText` is a subclass of `TextView`, and some " +
- "of the editing support is provided by `TextView`, so it's possible to set " +
- "some input-related properties on a `TextView`. However, using a `TextView` " +
- "along with input attributes is usually a cut & paste error. To input " +
- "text you should be using `<EditText>`." +
- "\n" +
- "This check also checks subclasses of `TextView`, such as `Button` and `CheckBox`, " +
- "since these have the same issue: they should not be used with editable " +
- "attributes.",
-
- Category.CORRECTNESS,
- 7,
- Severity.WARNING,
- TextViewDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Text could be selectable */
- public static final Issue SELECTABLE = Issue.create(
- "SelectableText", //$NON-NLS-1$
- "Looks for TextViews which should probably allow their text to be selected",
-
- "If a `<TextView>` is used to display data, the user might want to copy that " +
- "data and paste it elsewhere. To allow this, the `<TextView>` should specify " +
- "`android:textIsSelectable=\"true\"`.\n" +
- "\n" +
- "This lint check looks for TextViews which are likely to be displaying data: " +
- "views whose text is set dynamically. This value will be ignored on platforms " +
- "older than API 11, so it is okay to set it regardless of your `minSdkVersion`.",
-
- Category.USABILITY,
- 7,
- Severity.WARNING,
- TextViewDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link TextViewDetector} */
- public TextViewDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TEXT_VIEW,
- BUTTON,
- TOGGLE_BUTTON,
- CHECK_BOX,
- RADIO_BUTTON,
- CHECKED_TEXT_VIEW,
- SWITCH
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (element.getTagName().equals(TEXT_VIEW)) {
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_TEXT)
- && element.hasAttributeNS(ANDROID_URI, ATTR_ID)
- && !element.hasAttributeNS(ANDROID_URI, ATTR_TEXT_IS_SELECTABLE)
- && !element.hasAttributeNS(ANDROID_URI, ATTR_VISIBILITY)
- && context.getMainProject().getTargetSdk() >= 11) {
- context.report(SELECTABLE, element, context.getLocation(element),
- "Consider making the text value selectable by specifying " +
- "android:textIsSelectable=\"true\"", null);
- }
- }
-
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- String name = attribute.getLocalName();
- if (name == null) {
- // Attribute not in a namespace; we only care about the android: ones
- continue;
- }
-
- boolean isEditAttribute = false;
- switch (name.charAt(0)) {
- case 'a': {
- isEditAttribute = name.equals(ATTR_AUTO_TEXT);
- break;
- }
- case 'b': {
- isEditAttribute = name.equals(ATTR_BUFFER_TYPE) &&
- attribute.getValue().equals(VALUE_EDITABLE);
- break;
- }
- case 'p': {
- isEditAttribute = name.equals(ATTR_PASSWORD)
- || name.equals(ATTR_PHONE_NUMBER)
- || name.equals(ATTR_PRIVATE_IME_OPTIONS);
- break;
- }
- case 'c': {
- isEditAttribute = name.equals(ATTR_CAPITALIZE)
- || name.equals(ATTR_CURSOR_VISIBLE);
- break;
- }
- case 'd': {
- isEditAttribute = name.equals(ATTR_DIGITS);
- break;
- }
- case 'e': {
- if (name.equals(ATTR_EDITABLE)) {
- isEditAttribute = attribute.getValue().equals(VALUE_TRUE);
- } else {
- isEditAttribute = name.equals(ATTR_EDITOR_EXTRAS);
- }
- break;
- }
- case 'i': {
- if (name.equals(ATTR_INPUT_TYPE)) {
- String value = attribute.getValue();
- isEditAttribute = !value.isEmpty() && !value.equals(VALUE_NONE);
- } else {
- isEditAttribute = name.equals(ATTR_INPUT_TYPE)
- || name.equals(ATTR_IME_OPTIONS)
- || name.equals(ATTR_IME_ACTION_LABEL)
- || name.equals(ATTR_IME_ACTION_ID)
- || name.equals(ATTR_INPUT_METHOD);
- }
- break;
- }
- case 'n': {
- isEditAttribute = name.equals(ATTR_NUMERIC);
- break;
- }
- }
-
- if (isEditAttribute && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- Location location = context.getLocation(attribute);
- String message;
- String view = element.getTagName();
- if (view.equals(TEXT_VIEW)) {
- message = String.format(
- "Attribute %1$s should not be used with <TextView>: " +
- "Change element type to <EditText> ?", attribute.getName());
- } else {
- message = String.format(
- "Attribute %1$s should not be used with <%2$s>: " +
- "intended for editable text widgets",
- attribute.getName(), view);
- }
- context.report(ISSUE, attribute, location, message, null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TitleDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TitleDetector.java
deleted file mode 100644
index 5fc5340..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TitleDetector.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_TITLE;
-import static com.android.SdkConstants.ATTR_VISIBLE;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.VALUE_FALSE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Detector.JavaScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Check which makes sure menu items specify a title
- */
-public class TitleDetector extends ResourceXmlDetector implements JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "MenuTitle", //$NON-NLS-1$
- "Ensures that all menu items supply a title",
-
- "From the action bar documentation:\n" +
- // u2014: em dash
- "\"It's important that you always define android:title for each menu item \u2014 " +
- "even if you don't declare that the title appear with the action item \u2014 for " +
- "three reasons:\n" +
- "\n" +
- "* If there's not enough room in the action bar for the action item, the menu " +
- "item appears in the overflow menu and only the title appears.\n" +
- "* Screen readers for sight-impaired users read the menu item's title.\n" +
- "* If the action item appears with only the icon, a user can long-press the item " +
- "to reveal a tool-tip that displays the action item's title.\n" +
- "The android:icon is always optional, but recommended.",
-
- Category.USABILITY,
- 5,
- Severity.WARNING,
- TitleDetector.class,
- Scope.RESOURCE_FILE_SCOPE).setMoreInfo(
- "http://developer.android.com/guide/topics/ui/actionbar.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link TitleDetector} */
- public TitleDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.MENU;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- @Nullable
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(TAG_ITEM);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (element.hasAttributeNS(ANDROID_URI, ATTR_TITLE)) {
- return;
- }
-
- // TODO: Find out if this is necessary on older versions too.
- // I swear I saw it mentioned.
- if (context.getMainProject().getTargetSdk() < 11) {
- return;
- }
-
- if (VALUE_FALSE.equals(element.getAttributeNS(ANDROID_URI, ATTR_VISIBLE))) {
- return;
- }
-
- String message = "Menu items should specify a title";
- context.report(ISSUE, element, context.getLocation(element), message, null);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java
deleted file mode 100644
index e245fe8..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ToastDetector.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Expression;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.IntegralLiteral;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Node;
-import lombok.ast.Return;
-import lombok.ast.StrictListAccessor;
-
-/** Detector looking for Toast.makeText() without a corresponding show() call */
-public class ToastDetector extends Detector implements Detector.JavaScanner {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ShowToast", //$NON-NLS-1$
- "Looks for code creating a Toast but forgetting to call show() on it",
-
- "`Toast.makeText()` creates a `Toast` but does *not* show it. You must call " +
- "`show()` on the resulting object to actually make the `Toast` appear.",
-
- Category.CORRECTNESS,
- 6,
- Severity.WARNING,
- ToastDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
-
- /** Constructs a new {@link ToastDetector} check */
- public ToastDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
-
- // ---- Implements JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("makeText"); //$NON-NLS-1$
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- assert node.astName().astValue().equals("makeText");
- if (node.astOperand() == null) {
- // "makeText()" in the code with no operand
- return;
- }
-
- String operand = node.astOperand().toString();
- if (!(operand.equals("Toast") || operand.endsWith(".Toast"))) {
- return;
- }
-
- // Make sure you pass the right kind of duration: it's not a delay, it's
- // LENGTH_SHORT or LENGTH_LONG
- // (see http://code.google.com/p/android/issues/detail?id=3655)
- StrictListAccessor<Expression, MethodInvocation> args = node.astArguments();
- if (args.size() == 3) {
- Expression duration = args.last();
- if (duration instanceof IntegralLiteral) {
- context.report(ISSUE, duration, context.getLocation(duration),
- "Expected duration Toast.LENGTH_SHORT or Toast.LENGTH_LONG, a custom " +
- "duration value is not supported",
- null);
- }
- }
-
- Node method = JavaContext.findSurroundingMethod(node.getParent());
- if (method == null) {
- return;
- }
-
- ShowFinder finder = new ShowFinder(node);
- method.accept(finder);
- if (!finder.isShowCalled()) {
- context.report(ISSUE, method, context.getLocation(node),
- "Toast created but not shown: did you forget to call show() ?", null);
- }
- }
-
- private static class ShowFinder extends ForwardingAstVisitor {
- /** The target makeText call */
- private final MethodInvocation mTarget;
- /** Whether we've found the show method */
- private boolean mFound;
- /** Whether we've seen the target makeText node yet */
- private boolean mSeenTarget;
-
- private ShowFinder(MethodInvocation target) {
- mTarget = target;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (node == mTarget) {
- mSeenTarget = true;
- } else if ((mSeenTarget || node.astOperand() == mTarget)
- && "show".equals(node.astName().astValue())) { //$NON-NLS-1$
- // TODO: Do more flow analysis to see whether we're really calling show
- // on the right type of object?
- mFound = true;
- }
-
- return true;
- }
-
- @Override
- public boolean visitReturn(Return node) {
- if (node.astValue() == mTarget) {
- // If you just do "return Toast.makeText(...) don't warn
- mFound = true;
- }
- return super.visitReturn(node);
- }
-
- boolean isShowCalled() {
- return mFound;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TooManyViewsDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TooManyViewsDetector.java
deleted file mode 100644
index 94a9611..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TooManyViewsDetector.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-
-/**
- * Checks whether a root FrameLayout can be replaced with a {@code <merge>} tag.
- */
-public class TooManyViewsDetector extends LayoutDetector {
- /** Issue of having too many views in a single layout */
- public static final Issue TOO_MANY = Issue.create(
- "TooManyViews", //$NON-NLS-1$
- "Checks whether a layout has too many views",
- "Using too many views in a single layout is bad for " +
- "performance. Consider using compound drawables or other tricks for " +
- "reducing the number of views in this layout.\n\n" +
- "The maximum view count defaults to 80 but can be configured with the " +
- "environment variable `ANDROID_LINT_MAX_VIEW_COUNT`.",
- Category.PERFORMANCE,
- 1,
- Severity.WARNING,
- TooManyViewsDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Issue of having too deep hierarchies in layouts */
- public static final Issue TOO_DEEP = Issue.create(
- "TooDeepLayout", //$NON-NLS-1$
- "Checks whether a layout hierarchy is too deep",
- "Layouts with too much nesting is bad for performance. " +
- "Consider using a flatter layout (such as `RelativeLayout` or `GridLayout`)." +
- "The default maximum depth is 10 but can be configured with the environment " +
- "variable `ANDROID_LINT_MAX_DEPTH`.",
- Category.PERFORMANCE,
- 1,
- Severity.WARNING,
- TooManyViewsDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- private static final int MAX_VIEW_COUNT;
- private static final int MAX_DEPTH;
- static {
- int maxViewCount = 0;
- int maxDepth = 0;
-
- String countValue = System.getenv("ANDROID_LINT_MAX_VIEW_COUNT"); //$NON-NLS-1$
- if (countValue != null) {
- try {
- maxViewCount = Integer.parseInt(countValue);
- } catch (NumberFormatException e) {
- // pass: set to default below
- }
- }
- String depthValue = System.getenv("ANDROID_LINT_MAX_DEPTH"); //$NON-NLS-1$
- if (depthValue != null) {
- try {
- maxDepth = Integer.parseInt(depthValue);
- } catch (NumberFormatException e) {
- // pass: set to default below
- }
- }
- if (maxViewCount == 0) {
- maxViewCount = 80;
- }
- if (maxDepth == 0) {
- maxDepth = 10;
- }
-
- MAX_VIEW_COUNT = maxViewCount;
- MAX_DEPTH = maxDepth;
- }
-
- private int mViewCount;
- private int mDepth;
- private boolean mWarnedAboutDepth;
-
- /** Constructs a new {@link TooManyViewsDetector} */
- public TooManyViewsDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- mViewCount = mDepth = 0;
- mWarnedAboutDepth = false;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return ALL;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- mViewCount++;
- mDepth++;
-
- if (mDepth == MAX_DEPTH && !mWarnedAboutDepth) {
- // Have to record whether or not we've warned since we could have many siblings
- // at the max level and we'd warn for each one. No need to do the same thing
- // for the view count error since we'll only have view count exactly equal the
- // max just once.
- mWarnedAboutDepth = true;
- String msg = String.format("%1$s has more than %2$d levels, bad for performance",
- context.file.getName(), MAX_DEPTH);
- context.report(TOO_DEEP, element, context.getLocation(element), msg, null);
- }
- if (mViewCount == MAX_VIEW_COUNT) {
- String msg = String.format("%1$s has more than %2$d views, bad for performance",
- context.file.getName(), MAX_VIEW_COUNT);
- context.report(TOO_MANY, element, context.getLocation(element), msg, null);
- }
- }
-
- @Override
- public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) {
- mDepth--;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java
deleted file mode 100644
index 0f892b1..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_PREFIX;
-import static com.android.SdkConstants.ATTR_LOCALE;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TRANSLATABLE;
-import static com.android.SdkConstants.STRING_PREFIX;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_STRING;
-import static com.android.SdkConstants.TAG_STRING_ARRAY;
-import static com.android.SdkConstants.TOOLS_URI;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-/**
- * Checks for incomplete translations - e.g. keys that are only present in some
- * locales but not all.
- */
-public class TranslationDetector extends ResourceXmlDetector {
- @VisibleForTesting
- static boolean sCompleteRegions =
- System.getenv("ANDROID_LINT_COMPLETE_REGIONS") != null; //$NON-NLS-1$
-
- private static final Pattern LANGUAGE_PATTERN = Pattern.compile("^[a-z]{2}$"); //$NON-NLS-1$
- private static final Pattern REGION_PATTERN = Pattern.compile("^r([A-Z]{2})$"); //$NON-NLS-1$
-
- /** Are all translations complete? */
- public static final Issue MISSING = Issue.create(
- "MissingTranslation", //$NON-NLS-1$
- "Checks for incomplete translations where not all strings are translated",
- "If an application has more than one locale, then all the strings declared in " +
- "one language should also be translated in all other languages.\n" +
- "\n" +
- "If the string should *not* be translated, you can add the attribute " +
- "`translatable=\"false\"` on the `<string>` element, or you can define all " +
- "your non-translatable strings in a resource file called `donottranslate.xml`. " +
- "Or, you can ignore the issue with a `tools:ignore=\"MissingTranslation\"` " +
- "attribute.\n" +
- "\n" +
- "By default this detector allows regions of a language to just provide a " +
- "subset of the strings and fall back to the standard language strings. " +
- "You can require all regions to provide a full translation by setting the " +
- "environment variable `ANDROID_LINT_COMPLETE_REGIONS`.\n" +
- "\n" +
- "You can tell lint (and other tools) which language is the default language " +
- "in your `res/values/` folder by specifying `tools:locale=\"languageCode\"` for " +
- "the root `<resources>` element in your resource file. (The `tools` prefix refers " +
- "to the namespace declaration `http://schemas.android.com/tools`.)",
- Category.MESSAGES,
- 8,
- Severity.FATAL,
- TranslationDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Are there extra translations that are "unused" (appear only in specific languages) ? */
- public static final Issue EXTRA = Issue.create(
- "ExtraTranslation", //$NON-NLS-1$
- "Checks for translations that appear to be unused (no default language string)",
- "If a string appears in a specific language translation file, but there is " +
- "no corresponding string in the default locale, then this string is probably " +
- "unused. (It's technically possible that your application is only intended to " +
- "run in a specific locale, but it's still a good idea to provide a fallback.).\n" +
- "\n" +
- "Note that these strings can lead to crashes if the string is looked up on any " +
- "locale not providing a translation, so it's important to clean them up.",
- Category.MESSAGES,
- 6,
- Severity.FATAL,
- TranslationDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- private Set<String> mNames;
- private Set<String> mTranslatedArrays;
- private Set<String> mNonTranslatable;
- private boolean mIgnoreFile;
- private Map<File, Set<String>> mFileToNames;
- private Map<File, String> mFileToLocale;
-
- /** Locations for each untranslated string name. Populated during phase 2, if necessary */
- private Map<String, Location> mMissingLocations;
-
- /** Locations for each extra translated string name. Populated during phase 2, if necessary */
- private Map<String, Location> mExtraLocations;
-
- /** Error messages for each untranslated string name. Populated during phase 2, if necessary */
- private Map<String, String> mDescriptions;
-
- /** Constructs a new {@link TranslationDetector} */
- public TranslationDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_STRING,
- TAG_STRING_ARRAY
- );
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- if (context.getDriver().getPhase() == 1) {
- mFileToNames = new HashMap<File, Set<String>>();
- }
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mNames = new HashSet<String>();
- }
-
- // Convention seen in various projects
- mIgnoreFile = context.file.getName().startsWith("donottranslate") //$NON-NLS-1$
- || UnusedResourceDetector.isAnalyticsFile(context);
-
- if (!context.getProject().getReportIssues()) {
- mIgnoreFile = true;
- }
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- if (context.getPhase() == 1) {
- // Store this layout's set of ids for full project analysis in afterCheckProject
- if (context.getProject().getReportIssues() && mNames != null) {
- mFileToNames.put(context.file, mNames);
-
- Element root = ((XmlContext) context).document.getDocumentElement();
- if (root != null) {
- String locale = root.getAttributeNS(TOOLS_URI, ATTR_LOCALE);
- if (locale != null && !locale.isEmpty()) {
- if (mFileToLocale == null) {
- mFileToLocale = Maps.newHashMap();
- }
- mFileToLocale.put(context.file, locale);
- }
- }
- }
-
- mNames = null;
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- // NOTE - this will look for the presence of translation strings.
- // If you create a resource folder but don't actually place a file in it
- // we won't detect that, but it seems like a smaller problem.
-
- checkTranslations(context);
-
- mFileToNames = null;
-
- if (mMissingLocations != null || mExtraLocations != null) {
- context.getDriver().requestRepeat(this, Scope.ALL_RESOURCES_SCOPE);
- }
- } else {
- assert context.getPhase() == 2;
-
- reportMap(context, MISSING, mMissingLocations);
- reportMap(context, EXTRA, mExtraLocations);
- mMissingLocations = null;
- mExtraLocations = null;
- mDescriptions = null;
- }
- }
-
- private void reportMap(Context context, Issue issue, Map<String, Location> map) {
- if (map != null) {
- for (Map.Entry<String, Location> entry : map.entrySet()) {
- Location location = entry.getValue();
- String name = entry.getKey();
- String message = mDescriptions.get(name);
-
- // We were prepending locations, but we want to prefer the base folders
- location = Location.reverse(location);
-
- context.report(issue, location, message, null);
- }
- }
- }
-
- private void checkTranslations(Context context) {
- // Only one file defining strings? If so, no problems.
- Set<File> files = mFileToNames.keySet();
- if (files.size() == 1) {
- return;
- }
-
- Set<File> parentFolders = new HashSet<File>();
- for (File file : files) {
- parentFolders.add(file.getParentFile());
- }
- if (parentFolders.size() == 1) {
- // Only one language - no problems.
- return;
- }
-
- boolean reportMissing = context.isEnabled(MISSING);
- boolean reportExtra = context.isEnabled(EXTRA);
-
- // res/strings.xml etc
- String defaultLanguage = "Default";
-
- Map<File, String> parentFolderToLanguage = new HashMap<File, String>();
- for (File parent : parentFolders) {
- String name = parent.getName();
-
- // Look up the language for this folder.
- String language = getLanguage(name);
- if (language == null) {
- language = defaultLanguage;
- }
-
- parentFolderToLanguage.put(parent, language);
- }
-
- int languageCount = parentFolderToLanguage.values().size();
- if (languageCount <= 1) {
- // At most one language -- no problems.
- return;
- }
-
- // Merge together the various files building up the translations for each language
- Map<String, Set<String>> languageToStrings =
- new HashMap<String, Set<String>>(languageCount);
- Set<String> allStrings = new HashSet<String>(200);
- for (File file : files) {
- String language = null;
- if (mFileToLocale != null) {
- String locale = mFileToLocale.get(file);
- if (locale != null) {
- int index = locale.indexOf('-');
- if (index != -1) {
- locale = locale.substring(0, index);
- }
- language = locale;
- }
- }
- if (language == null) {
- language = parentFolderToLanguage.get(file.getParentFile());
- }
- assert language != null : file.getParent();
- Set<String> fileStrings = mFileToNames.get(file);
-
- Set<String> languageStrings = languageToStrings.get(language);
- if (languageStrings == null) {
- // We don't need a copy; we're done with the string tables now so we
- // can modify them
- languageToStrings.put(language, fileStrings);
- } else {
- languageStrings.addAll(fileStrings);
- }
- allStrings.addAll(fileStrings);
- }
-
- Set<String> defaultStrings = languageToStrings.get(defaultLanguage);
- if (defaultStrings == null) {
- defaultStrings = new HashSet<String>();
- }
-
- // Fast check to see if there's no problem: if the default locale set is the
- // same as the all set (meaning there are no extra strings in the other languages)
- // then we can quickly determine if everything is okay by just making sure that
- // each language defines everything. If that's the case they will all have the same
- // string count.
- int stringCount = allStrings.size();
- if (stringCount == defaultStrings.size()) {
- boolean haveError = false;
- for (Map.Entry<String, Set<String>> entry : languageToStrings.entrySet()) {
- Set<String> strings = entry.getValue();
- if (stringCount != strings.size()) {
- haveError = true;
- break;
- }
- }
- if (!haveError) {
- return;
- }
- }
-
- // Do we need to resolve fallback strings for regions that only define a subset
- // of the strings in the language and fall back on the main language for the rest?
- if (!sCompleteRegions) {
- for (String l : languageToStrings.keySet()) {
- if (l.indexOf('-') != -1) {
- // Yes, we have regions. Merge all base language string names into each region.
- for (Map.Entry<String, Set<String>> entry : languageToStrings.entrySet()) {
- Set<String> strings = entry.getValue();
- if (stringCount != strings.size()) {
- String languageRegion = entry.getKey();
- int regionIndex = languageRegion.indexOf('-');
- if (regionIndex != -1) {
- String language = languageRegion.substring(0, regionIndex);
- Set<String> fallback = languageToStrings.get(language);
- if (fallback != null) {
- strings.addAll(fallback);
- }
- }
- }
- }
- // We only need to do this once; when we see the first region we know
- // we need to do it; once merged we can bail
- break;
- }
- }
- }
-
- List<String> languages = new ArrayList<String>(languageToStrings.keySet());
- Collections.sort(languages);
- for (String language : languages) {
- Set<String> strings = languageToStrings.get(language);
- if (defaultLanguage.equals(language)) {
- continue;
- }
-
- // if strings.size() == stringCount, then this language is defining everything,
- // both all the default language strings and the union of all extra strings
- // defined in other languages, so there's no problem.
- if (stringCount != strings.size()) {
- if (reportMissing) {
- Set<String> difference = Sets.difference(defaultStrings, strings);
- if (!difference.isEmpty()) {
- if (mMissingLocations == null) {
- mMissingLocations = new HashMap<String, Location>();
- }
- if (mDescriptions == null) {
- mDescriptions = new HashMap<String, String>();
- }
-
- for (String s : difference) {
- mMissingLocations.put(s, null);
- String message = mDescriptions.get(s);
- if (message == null) {
- message = String.format("\"%1$s\" is not translated in %2$s",
- s, language);
- } else {
- message = message + ", " + language;
- }
- mDescriptions.put(s, message);
- }
- }
- }
-
- if (reportExtra) {
- Set<String> difference = Sets.difference(strings, defaultStrings);
- if (!difference.isEmpty()) {
- if (mExtraLocations == null) {
- mExtraLocations = new HashMap<String, Location>();
- }
- if (mDescriptions == null) {
- mDescriptions = new HashMap<String, String>();
- }
-
- for (String s : difference) {
- if (mTranslatedArrays != null && mTranslatedArrays.contains(s)) {
- continue;
- }
- mExtraLocations.put(s, null);
- String message = String.format(
- "\"%1$s\" is translated here but not found in default locale", s);
- mDescriptions.put(s, message);
- }
- }
- }
- }
- }
- }
-
- /** Look up the language for the given folder name */
- private static String getLanguage(String name) {
- String[] segments = name.split("-"); //$NON-NLS-1$
-
- // TODO: To get an accurate answer, this should later do a
- // FolderConfiguration.getConfig(String[] folderSegments)
- // to obtain a FolderConfiguration, then call
- // getLanguageQualifier() on it, and if not null, call getValue() to get the
- // actual language value.
- // However, we don't have sdk_common on the build path for lint, so for now
- // use a simple guess about what constitutes a language qualifier here:
-
- String language = null;
- for (String segment : segments) {
- // Language
- if (language == null && segment.length() == 2
- && LANGUAGE_PATTERN.matcher(segment).matches()) {
- language = segment;
- }
-
- // Add in region
- if (language != null && segment.length() == 3
- && REGION_PATTERN.matcher(segment).matches()) {
- language = language + '-' + segment;
- break;
- }
- }
-
- return language;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (mIgnoreFile) {
- return;
- }
-
- Attr attribute = element.getAttributeNode(ATTR_NAME);
-
- if (context.getPhase() == 2) {
- // Just locating names requested in the {@link #mLocations} map
- if (attribute == null) {
- return;
- }
- String name = attribute.getValue();
- if (mMissingLocations != null && mMissingLocations.containsKey(name)) {
- String language = getLanguage(context.file.getParentFile().getName());
- if (language == null) {
- if (context.getDriver().isSuppressed(MISSING, element)) {
- mMissingLocations.remove(name);
- return;
- }
-
- Location location = context.getLocation(attribute);
- location.setClientData(element);
- location.setSecondary(mMissingLocations.get(name));
- mMissingLocations.put(name, location);
- }
- }
- if (mExtraLocations != null && mExtraLocations.containsKey(name)) {
- if (context.getDriver().isSuppressed(EXTRA, element)) {
- mExtraLocations.remove(name);
- return;
- }
- Location location = context.getLocation(attribute);
- location.setClientData(element);
- location.setMessage("Also translated here");
- location.setSecondary(mExtraLocations.get(name));
- mExtraLocations.put(name, location);
- }
- return;
- }
-
- assert context.getPhase() == 1;
- if (attribute == null || attribute.getValue().isEmpty()) {
- context.report(MISSING, element, context.getLocation(element),
- "Missing name attribute in <string> declaration", null);
- } else {
- String name = attribute.getValue();
-
- Attr translatable = element.getAttributeNode(ATTR_TRANSLATABLE);
- if (translatable != null && !Boolean.valueOf(translatable.getValue())) {
- String l = LintUtils.getLocaleAndRegion(context.file.getParentFile().getName());
- if (l != null) {
- context.report(EXTRA, translatable, context.getLocation(translatable),
- "Non-translatable resources should only be defined in the base " +
- "values/ folder", null);
- } else {
- if (mNonTranslatable == null) {
- mNonTranslatable = new HashSet<String>();
- }
- mNonTranslatable.add(name);
- }
- return;
- }
-
- if (element.getTagName().equals(TAG_STRING_ARRAY) &&
- allItemsAreReferences(element)) {
- // No need to provide translations for string arrays where all
- // the children items are defined as translated string resources,
- // e.g.
- // <string-array name="foo">
- // <item>@string/item1</item>
- // <item>@string/item2</item>
- // </string-array>
- // However, we need to remember these names such that we don't consider
- // these arrays "extra" if one of the *translated* versions of the array
- // perform an inline translation of an array item
- if (mTranslatedArrays == null) {
- mTranslatedArrays = new HashSet<String>();
- }
- mTranslatedArrays.add(name);
- return;
- }
-
- // Check for duplicate name definitions? No, because there can be
- // additional customizations like product=
- //if (mNames.contains(name)) {
- // context.mClient.report(ISSUE, context.getLocation(attribute),
- // String.format("Duplicate name %1$s, already defined earlier in this file",
- // name));
- //}
-
- mNames.add(name);
-
- if (mNonTranslatable != null && mNonTranslatable.contains(name)) {
- String message = String.format("The resource string \"%1$s\" has been marked as " +
- "translatable=\"false\"", name);
- context.report(EXTRA, attribute, context.getLocation(attribute), message, null);
- }
-
- // TBD: Also make sure that the strings are not empty or placeholders?
- }
- }
-
- private static boolean allItemsAreReferences(Element element) {
- assert element.getTagName().equals(TAG_STRING_ARRAY);
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node item = childNodes.item(i);
- if (item.getNodeType() == Node.ELEMENT_NODE &&
- TAG_ITEM.equals(item.getNodeName())) {
- NodeList itemChildren = item.getChildNodes();
- for (int j = 0, m = itemChildren.getLength(); j < m; j++) {
- Node valueNode = itemChildren.item(j);
- if (valueNode.getNodeType() == Node.TEXT_NODE) {
- String value = valueNode.getNodeValue().trim();
- if (!value.startsWith(ANDROID_PREFIX)
- && !value.startsWith(STRING_PREFIX)) {
- return false;
- }
- }
- }
- }
- }
-
- return true;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoDetector.java
deleted file mode 100644
index b9b889f..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoDetector.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_LOCALE;
-import static com.android.SdkConstants.FD_RES_VALUES;
-import static com.android.SdkConstants.TAG_STRING;
-import static com.android.SdkConstants.TOOLS_URI;
-import static com.android.tools.lint.checks.TypoLookup.isLetter;
-import static com.google.common.base.Objects.equal;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.base.Charsets;
-import com.google.common.base.Splitter;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Check which looks for likely typos in Strings.
- * <p>
- * TODO:
- * <ul>
- * <li> Add check of Java String literals too!
- * <li> Add support for <b>additional</b> languages. The typo detector is now
- * multilingual and looks for typos-*locale*.txt files to use. However,
- * we need to seed it with additional typo databases. I did some searching
- * and came up with some alternatives. Here's the strategy I used:
- * Used Google Translate to translate "Wikipedia Common Misspellings", and
- * then I went to google.no, google.fr etc searching with that translation, and
- * came up with what looks like wikipedia language local lists of typos.
- * This is how I found the Norwegian one for example:
- * <br>
- * http://no.wikipedia.org/wiki/Wikipedia:Liste_over_alminnelige_stavefeil/Maskinform
- * <br>
- * Here are some additional possibilities not yet processed:
- * <ul>
- * <li> French: http://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Liste_de_fautes_d'orthographe_courantes
- * (couldn't find a machine-readable version there?)
- * <li> Swedish:
- * http://sv.wikipedia.org/wiki/Wikipedia:Lista_%C3%B6ver_vanliga_spr%C3%A5kfel
- * (couldn't find a machine-readable version there?)
- * <li> German
- * http://de.wikipedia.org/wiki/Wikipedia:Liste_von_Tippfehlern/F%C3%BCr_Maschinen
- * </ul>
- * <li> Consider also digesting files like
- * http://sv.wikipedia.org/wiki/Wikipedia:AutoWikiBrowser/Typos
- * See http://en.wikipedia.org/wiki/Wikipedia:AutoWikiBrowser/User_manual.
- * </ul>
- */
-public class TypoDetector extends ResourceXmlDetector {
- @Nullable private TypoLookup mLookup;
- @Nullable private String mLastLanguage;
- @Nullable private String mLastRegion;
- @Nullable private String mLanguage;
- @Nullable private String mRegion;
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "Typos", //$NON-NLS-1$
- "Looks for typos in messages",
-
- "This check looks through the string definitions, and if it finds any words " +
- "that look like likely misspellings, they are flagged.",
- Category.MESSAGES,
- 7,
- Severity.WARNING,
- TypoDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new detector */
- public TypoDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- /** Look up the locale and region from the given parent folder name and store it
- * in {@link #mLanguage} and {@link #mRegion} */
- private void initLocale(@NonNull String parent) {
- mLanguage = null;
- mRegion = null;
-
- if (parent.equals(FD_RES_VALUES)) {
- return;
- }
-
- for (String qualifier : Splitter.on('-').split(parent)) {
- int qualifierLength = qualifier.length();
- if (qualifierLength == 2) {
- char first = qualifier.charAt(0);
- char second = qualifier.charAt(1);
- if (first >= 'a' && first <= 'z' && second >= 'a' && second <= 'z') {
- mLanguage = qualifier;
- }
- } else if (qualifierLength == 3 && qualifier.charAt(0) == 'r') {
- char first = qualifier.charAt(1);
- char second = qualifier.charAt(2);
- if (first >= 'A' && first <= 'Z' && second >= 'A' && second <= 'Z') {
- mRegion = new String(new char[] { first, second }); // Don't include the "r"
- }
- break;
- }
- }
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- initLocale(context.file.getParentFile().getName());
- if (mLanguage == null) {
- // Check to see if the user has specified the language for this folder
- // using a tools:locale attribute
- if (context instanceof XmlContext) {
- Element root = ((XmlContext) context).document.getDocumentElement();
- if (root != null) {
- String locale = root.getAttributeNS(TOOLS_URI, ATTR_LOCALE);
- if (locale != null && !locale.isEmpty()) {
- initLocale(FD_RES_VALUES + '-' + locale);
- }
- }
- }
-
- if (mLanguage == null) {
- mLanguage = "en"; //$NON-NLS-1$
- }
- }
-
- if (!equal(mLastLanguage, mLanguage) || !equal(mLastRegion, mRegion)) {
- mLookup = TypoLookup.get(context.getClient(), mLanguage, mRegion);
- mLastLanguage = mLanguage;
- mLastRegion = mRegion;
- }
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(TAG_STRING);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (mLookup == null) {
- return;
- }
-
- visit(context, element);
- }
-
- private void visit(XmlContext context, Node node) {
- if (node.getNodeType() == Node.TEXT_NODE) {
- // TODO: Figure out how to deal with entities
- check(context, node, node.getNodeValue());
- } else {
- NodeList children = node.getChildNodes();
- for (int i = 0, n = children.getLength(); i < n; i++) {
- visit(context, children.item(i));
- }
- }
- }
-
- private void check(XmlContext context, Node node, String text) {
- int max = text.length();
- int index = 0;
- boolean checkedTypos = false;
- while (index < max) {
- for (; index < max; index++) {
- char c = text.charAt(index);
- if (c == '\\') {
- index++;
- continue;
- } else if (Character.isLetter(c)) {
- break;
- }
- }
- if (index >= max) {
- return;
- }
- int begin = index;
- for (; index < max; index++) {
- char c = text.charAt(index);
- if (c == '\\') {
- index++;
- break;
- } else if (!Character.isLetter(c)) {
- break;
- } else if (text.charAt(index) >= 0x80) {
- // Switch to UTF-8 handling for this string
- if (checkedTypos) {
- // If we've already checked words we may have reported typos
- // so create a substring from the current word and on.
- byte[] utf8Text = text.substring(begin).getBytes(Charsets.UTF_8);
- check(context, node, utf8Text, 0, utf8Text.length, text, begin);
- } else {
- // If all we've done so far is skip whitespace (common scenario)
- // then no need to substring the text, just re-search with the
- // UTF-8 routines
- byte[] utf8Text = text.getBytes(Charsets.UTF_8);
- check(context, node, utf8Text, 0, utf8Text.length, text, 0);
- }
- return;
- }
- }
-
- int end = index;
- checkedTypos = true;
- List<String> replacements = mLookup.getTypos(text, begin, end);
- if (replacements != null) {
- reportTypo(context, node, text, begin, replacements);
- }
-
- index = end + 1;
- }
- }
-
- private void check(XmlContext context, Node node, byte[] utf8Text,
- int byteStart, int byteEnd, String text, int charStart) {
- int index = byteStart;
- while (index < byteEnd) {
- // Find beginning of word
- while (index < byteEnd) {
- byte b = utf8Text[index];
- if (b == '\\') {
- index++;
- charStart++;
- if (index < byteEnd) {
- b = utf8Text[index];
- }
- } else if (isLetter(b)) {
- break;
- }
- index++;
- if ((b & 0x80) == 0 || (b & 0xC0) == 0xC0) {
- // First characters in UTF-8 are always ASCII (0 high bit) or 11XXXXXX
- charStart++;
- }
- }
-
- if (index >= byteEnd) {
- return;
- }
- int charEnd = charStart;
- int begin = index;
-
- // Find end of word. Unicode has the nice property that even 2nd, 3rd and 4th
- // bytes won't match these ASCII characters (because the high bit must be set there)
- while (index < byteEnd) {
- byte b = utf8Text[index];
- if (b == '\\') {
- index++;
- charEnd++;
- if (index < byteEnd) {
- b = utf8Text[index++];
- if ((b & 0x80) == 0 || (b & 0xC0) == 0xC0) {
- charEnd++;
- }
- }
- break;
- } else if (!isLetter(b)) {
- break;
- }
- index++;
- if ((b & 0x80) == 0 || (b & 0xC0) == 0xC0) {
- // First characters in UTF-8 are always ASCII (0 high bit) or 11XXXXXX
- charEnd++;
- }
- }
-
- int end = index;
- List<String> replacements = mLookup.getTypos(utf8Text, begin, end);
- if (replacements != null) {
- reportTypo(context, node, text, charStart, replacements);
- }
-
- charStart = charEnd;
- }
- }
-
- /** Report the typo found at the given offset and suggest the given replacements */
- private static void reportTypo(XmlContext context, Node node, String text, int begin,
- List<String> replacements) {
- if (replacements.size() < 2) {
- return;
- }
-
- String typo = replacements.get(0);
- String word = text.substring(begin, begin + typo.length());
-
- String first = null;
- String message;
-
- boolean isCapitalized = Character.isUpperCase(word.charAt(0));
- StringBuilder sb = new StringBuilder(40);
- for (int i = 1, n = replacements.size(); i < n; i++) {
- String replacement = replacements.get(i);
- if (first == null) {
- first = replacement;
- }
- if (sb.length() > 0) {
- sb.append(" or ");
- }
- sb.append('"');
- if (isCapitalized) {
- sb.append(Character.toUpperCase(replacement.charAt(0)));
- sb.append(replacement.substring(1));
- } else {
- sb.append(replacement);
- }
- sb.append('"');
- }
-
- if (first != null && first.equalsIgnoreCase(word)) {
- if (first.equals(word)) {
- return;
- }
- message = String.format(
- "\"%1$s\" is usually capitalized as \"%2$s\"",
- word, first);
- } else {
- message = String.format(
- "\"%1$s\" is a common misspelling; did you mean %2$s ?",
- word, sb.toString());
- }
-
- int end = begin + word.length();
- context.report(ISSUE, node, context.getLocation(node, begin, end), message, null);
- }
-
- /** Returns the suggested replacements, if any, for the given typo. The error
- * message <b>must</b> be one supplied by lint.
- *
- * @param errorMessage the error message
- * @return a list of replacement words suggested by the error message
- */
- @Nullable
- public static List<String> getSuggestions(@NonNull String errorMessage) {
- // The words are all in quotes; the first word is the misspelling,
- // the other words are the suggested replacements
- List<String> words = new ArrayList<String>();
- // Skip the typo
- int index = errorMessage.indexOf('"');
- index = errorMessage.indexOf('"', index + 1);
- index++;
-
- while (true) {
- index = errorMessage.indexOf('"', index);
- if (index == -1) {
- break;
- }
- index++;
- int start = index;
- index = errorMessage.indexOf('"', index);
- if (index == -1) {
- index = errorMessage.length();
- }
- words.add(errorMessage.substring(start, index));
- index++;
- }
-
- return words;
- }
-
- /**
- * Returns the typo word in the error message from this detector
- *
- * @param errorMessage the error message produced earlier by this detector
- * @return the typo
- */
- @Nullable
- public static String getTypo(@NonNull String errorMessage) {
- // The words are all in quotes
- int index = errorMessage.indexOf('"');
- int start = index + 1;
- index = errorMessage.indexOf('"', start);
- if (index != -1) {
- return errorMessage.substring(start, index);
- }
-
- return null;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoLookup.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoLookup.java
deleted file mode 100644
index 7d9d8f2..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypoLookup.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.tools.lint.detector.api.LintUtils.assertionsEnabled;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.google.common.base.Charsets;
-import com.google.common.base.Splitter;
-import com.google.common.io.Files;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel.MapMode;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-import java.util.WeakHashMap;
-
-/**
- * Database of common typos / misspellings.
- */
-public class TypoLookup {
- private static final TypoLookup NONE = new TypoLookup();
-
- /** String separating misspellings and suggested replacements in the text file */
- private static final String WORD_SEPARATOR = "->"; //$NON-NLS-1$
-
- /** Relative path to the typos database file within the Lint installation */
- private static final String XML_FILE_PATH = "tools/support/typos-%1$s.txt"; //$NON-NLS-1$
- private static final String FILE_HEADER = "Typo database used by Android lint\000";
- private static final int BINARY_FORMAT_VERSION = 2;
- private static final boolean DEBUG_FORCE_REGENERATE_BINARY = false;
- private static final boolean DEBUG_SEARCH = false;
- private static final boolean WRITE_STATS = false;
- /** Default size to reserve for each API entry when creating byte buffer to build up data */
- private static final int BYTES_PER_ENTRY = 28;
-
- private final LintClient mClient;
- private final File mXmlFile;
- private final File mBinaryFile;
- private byte[] mData;
- private int[] mIndices;
- private int mWordCount;
-
- private static final WeakHashMap<String, TypoLookup> sInstanceMap =
- new WeakHashMap<String, TypoLookup>();
-
- /**
- * Returns an instance of the Typo database for the given locale
- *
- * @param client the client to associate with this database - used only for
- * logging. The database object may be shared among repeated
- * invocations, and in that case client used will be the one
- * originally passed in. In other words, this parameter may be
- * ignored if the client created is not new.
- * @param locale the locale to look up a typo database for (should be a
- * language code (ISO 639-1, two lowercase character names)
- * @param region the region to look up a typo database for (should be a two
- * letter ISO 3166-1 alpha-2 country code in upper case) language
- * code
- * @return a (possibly shared) instance of the typo database, or null if its
- * data can't be found
- */
- @Nullable
- public static TypoLookup get(@NonNull LintClient client, @NonNull String locale,
- @Nullable String region) {
- synchronized (TypoLookup.class) {
- String key = locale;
-
- if (region != null) {
- // Allow for region-specific dictionaries. See for example
- // http://en.wikipedia.org/wiki/American_and_British_English_spelling_differences
- assert region.length() == 2
- && Character.isUpperCase(region.charAt(0))
- && Character.isUpperCase(region.charAt(1)) : region;
- // Look for typos-en-rUS.txt etc
- key = locale + 'r' + region;
- }
-
- TypoLookup db = sInstanceMap.get(key);
- if (db == null) {
- String path = String.format(XML_FILE_PATH, key);
- File file = client.findResource(path);
- if (file == null) {
- // AOSP build environment?
- String build = System.getenv("ANDROID_BUILD_TOP"); //$NON-NLS-1$
- if (build != null) {
- file = new File(build, ("sdk/files/" //$NON-NLS-1$
- + path.substring(path.lastIndexOf('/') + 1))
- .replace('/', File.separatorChar));
- }
- }
-
- if (file == null || !file.exists()) {
- if (region != null) {
- // Fall back to the generic locale (non-region-specific) database
- return get(client, locale, null);
- }
- db = NONE;
- } else {
- db = get(client, file);
- assert db != null : file;
- }
- sInstanceMap.put(key, db);
- }
-
- if (db == NONE) {
- return null;
- } else {
- return db;
- }
- }
- }
-
- /**
- * Returns an instance of the typo database
- *
- * @param client the client to associate with this database - used only for
- * logging
- * @param xmlFile the XML file containing configuration data to use for this
- * database
- * @return a (possibly shared) instance of the typo database, or null
- * if its data can't be found
- */
- @Nullable
- private static TypoLookup get(LintClient client, File xmlFile) {
- if (!xmlFile.exists()) {
- client.log(null, "The typo database file %1$s does not exist", xmlFile);
- return null;
- }
-
- String name = xmlFile.getName();
- if (LintUtils.endsWith(name, DOT_XML)) {
- name = name.substring(0, name.length() - DOT_XML.length());
- }
- File cacheDir = client.getCacheDir(true/*create*/);
- if (cacheDir == null) {
- cacheDir = xmlFile.getParentFile();
- }
-
- File binaryData = new File(cacheDir, name
- // Incorporate version number in the filename to avoid upgrade filename
- // conflicts on Windows (such as issue #26663)
- + '-' + BINARY_FORMAT_VERSION + ".bin"); //$NON-NLS-1$
-
- if (DEBUG_FORCE_REGENERATE_BINARY) {
- System.err.println("\nTemporarily regenerating binary data unconditionally \nfrom "
- + xmlFile + "\nto " + binaryData);
- if (!createCache(client, xmlFile, binaryData)) {
- return null;
- }
- } else if (!binaryData.exists() || binaryData.lastModified() < xmlFile.lastModified()) {
- if (!createCache(client, xmlFile, binaryData)) {
- return null;
- }
- }
-
- if (!binaryData.exists()) {
- client.log(null, "The typo database file %1$s does not exist", binaryData);
- return null;
- }
-
- return new TypoLookup(client, xmlFile, binaryData);
- }
-
- private static boolean createCache(LintClient client, File xmlFile, File binaryData) {
- long begin = 0;
- if (WRITE_STATS) {
- begin = System.currentTimeMillis();
- }
-
- // Read in data
- List<String> lines;
- try {
- lines = Files.readLines(xmlFile, Charsets.UTF_8);
- } catch (IOException e) {
- client.log(e, "Can't read typo database file");
- return false;
- }
-
- if (WRITE_STATS) {
- long end = System.currentTimeMillis();
- System.out.println("Reading data structures took " + (end - begin) + " ms)");
- }
-
- try {
- writeDatabase(binaryData, lines);
- return true;
- } catch (IOException ioe) {
- client.log(ioe, "Can't write typo cache file");
- }
-
- return false;
- }
-
- /** Use one of the {@link #get} factory methods instead */
- private TypoLookup(
- @NonNull LintClient client,
- @NonNull File xmlFile,
- @Nullable File binaryFile) {
- mClient = client;
- mXmlFile = xmlFile;
- mBinaryFile = binaryFile;
-
- if (binaryFile != null) {
- readData();
- }
- }
-
- private TypoLookup() {
- mClient = null;
- mXmlFile = null;
- mBinaryFile = null;
- }
-
- private void readData() {
- if (!mBinaryFile.exists()) {
- mClient.log(null, "%1$s does not exist", mBinaryFile);
- return;
- }
- long start = System.currentTimeMillis();
- try {
- MappedByteBuffer buffer = Files.map(mBinaryFile, MapMode.READ_ONLY);
- assert buffer.order() == ByteOrder.BIG_ENDIAN;
-
- // First skip the header
- byte[] expectedHeader = FILE_HEADER.getBytes(Charsets.US_ASCII);
- buffer.rewind();
- for (int offset = 0; offset < expectedHeader.length; offset++) {
- if (expectedHeader[offset] != buffer.get()) {
- mClient.log(null, "Incorrect file header: not an typo database cache " +
- "file, or a corrupt cache file");
- return;
- }
- }
-
- // Read in the format number
- if (buffer.get() != BINARY_FORMAT_VERSION) {
- // Force regeneration of new binary data with up to date format
- if (createCache(mClient, mXmlFile, mBinaryFile)) {
- readData(); // Recurse
- }
-
- return;
- }
-
- mWordCount = buffer.getInt();
-
- // Read in the word table indices;
- int count = mWordCount;
- int[] offsets = new int[count];
-
- // Another idea: I can just store the DELTAS in the file (and add them up
- // when reading back in) such that it takes just ONE byte instead of four!
-
- for (int i = 0; i < count; i++) {
- offsets[i] = buffer.getInt();
- }
-
- // No need to read in the rest -- we'll just keep the whole byte array in memory
- // TODO: Make this code smarter/more efficient.
- int size = buffer.limit();
- byte[] b = new byte[size];
- buffer.rewind();
- buffer.get(b);
- mData = b;
- mIndices = offsets;
-
- // TODO: We only need to keep the data portion here since we've initialized
- // the offset array separately.
- // TODO: Investigate (profile) accessing the byte buffer directly instead of
- // accessing a byte array.
- } catch (IOException e) {
- mClient.log(e, null);
- }
- if (WRITE_STATS) {
- long end = System.currentTimeMillis();
- System.out.println("\nRead typo database in " + (end - start)
- + " milliseconds.");
- System.out.println("Size of data table: " + mData.length + " bytes ("
- + Integer.toString(mData.length/1024) + "k)\n");
- }
- }
-
- /** See the {@link #readData()} for documentation on the data format. */
- private static void writeDatabase(File file, List<String> lines) throws IOException {
- /*
- * 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded
- * as ASCII characters. The purpose of the header is to identify what the file
- * is for, for anyone attempting to open the file.
- * 2. A file version number. If the binary file does not match the reader's expected
- * version, it can ignore it (and regenerate the cache from XML).
- */
-
- // Drop comments etc
- List<String> words = new ArrayList<String>(lines.size());
- for (String line : lines) {
- if (!line.isEmpty() && Character.isLetter(line.charAt(0))) {
- int end = line.indexOf(WORD_SEPARATOR);
- if (end == -1) {
- end = line.trim().length();
- }
- String typo = line.substring(0, end).trim();
- String replacements = line.substring(end + WORD_SEPARATOR.length()).trim();
- if (replacements.isEmpty()) {
- // We don't support empty replacements
- continue;
- }
- String combined = typo + (char) 0 + replacements;
-
- words.add(combined);
- }
- }
-
- byte[][] wordArrays = new byte[words.size()][];
- for (int i = 0, n = words.size(); i < n; i++) {
- String word = words.get(i);
- wordArrays[i] = word.getBytes(Charsets.UTF_8);
- }
- // Sort words, using our own comparator to ensure that it matches the
- // binary search in getTypos()
- Comparator<byte[]> comparator = new Comparator<byte[]>() {
- @Override
- public int compare(byte[] o1, byte[] o2) {
- return TypoLookup.compare(o1, 0, (byte) 0, o2, 0, o2.length);
- }
- };
- Arrays.sort(wordArrays, comparator);
-
- int entryCount = wordArrays.length;
- int capacity = entryCount * BYTES_PER_ENTRY;
- ByteBuffer buffer = ByteBuffer.allocate(capacity);
- buffer.order(ByteOrder.BIG_ENDIAN);
- // 1. A file header, which is the exact contents of {@link FILE_HEADER} encoded
- // as ASCII characters. The purpose of the header is to identify what the file
- // is for, for anyone attempting to open the file.
- buffer.put(FILE_HEADER.getBytes(Charsets.US_ASCII));
-
- // 2. A file version number. If the binary file does not match the reader's expected
- // version, it can ignore it (and regenerate the cache from XML).
- buffer.put((byte) BINARY_FORMAT_VERSION);
-
- // 3. The number of words [1 int]
- buffer.putInt(entryCount);
-
- // 4. Word offset table (one integer per word, pointing to the byte offset in the
- // file (relative to the beginning of the file) where each word begins.
- // The words are always sorted alphabetically.
- int wordOffsetTable = buffer.position();
-
- // Reserve enough room for the offset table here: we will backfill it with pointers
- // as we're writing out the data structures below
- for (int i = 0, n = entryCount; i < n; i++) {
- buffer.putInt(0);
- }
-
- int nextEntry = buffer.position();
- int nextOffset = wordOffsetTable;
-
- // 7. Word entry table. Each word entry consists of the word, followed by the byte 0
- // as a terminator, followed by a comma separated list of suggestions (which
- // may be empty), or a final 0.
- for (int i = 0; i < entryCount; i++) {
- byte[] word = wordArrays[i];
- buffer.position(nextOffset);
- buffer.putInt(nextEntry);
- nextOffset = buffer.position();
- buffer.position(nextEntry);
-
- buffer.put(word); // already embeds 0 to separate typo from words
- buffer.put((byte) 0);
-
- nextEntry = buffer.position();
- }
-
- int size = buffer.position();
- assert size <= buffer.limit();
- buffer.mark();
-
- if (WRITE_STATS) {
- System.out.println("Wrote " + words.size() + " word entries");
- System.out.print("Actual binary size: " + size + " bytes");
- System.out.println(String.format(" (%.1fM)", size/(1024*1024.f)));
-
- System.out.println("Allocated size: " + (entryCount * BYTES_PER_ENTRY) + " bytes");
- System.out.println("Required bytes per entry: " + (size/ entryCount) + " bytes");
- }
-
- // Now dump this out as a file
- // There's probably an API to do this more efficiently; TODO: Look into this.
- byte[] b = new byte[size];
- buffer.rewind();
- buffer.get(b);
- FileOutputStream output = Files.newOutputStreamSupplier(file).getOutput();
- output.write(b);
- output.close();
- }
-
- // For debugging only
- private String dumpEntry(int offset) {
- if (DEBUG_SEARCH) {
- int end = offset;
- while (mData[end] != 0) {
- end++;
- }
- return new String(mData, offset, end - offset, Charsets.UTF_8);
- } else {
- return "<disabled>"; //$NON-NLS-1$
- }
- }
-
- /** Comparison function: *only* used for ASCII strings */
- @VisibleForTesting
- static int compare(byte[] data, int offset, byte terminator, CharSequence s,
- int begin, int end) {
- int i = offset;
- int j = begin;
- for (; ; i++, j++) {
- byte b = data[i];
- if (b == ' ') {
- // We've matched up to the space in a split-word typo, such as
- // in German all zu=>allzu; here we've matched just past "all".
- // Rather than terminating, attempt to continue in the buffer.
- if (j == end) {
- int max = s.length();
- if (end < max && s.charAt(end) == ' ') {
- // Find next word
- for (; end < max; end++) {
- char c = s.charAt(end);
- if (!Character.isLetter(c)) {
- if (c == ' ' && end == j) {
- continue;
- }
- break;
- }
- }
- }
- }
- }
-
- if (j == end) {
- break;
- }
-
- if (b == '*') {
- // Glob match (only supported at the end)
- return 0;
- }
- char c = s.charAt(j);
- byte cb = (byte) c;
- int delta = b - cb;
- if (delta != 0) {
- cb = (byte) Character.toLowerCase(c);
- if (b != cb) {
- // Ensure that it has the right sign
- b = (byte) Character.toLowerCase(b);
- delta = b - cb;
- if (delta != 0) {
- return delta;
- }
- }
- }
- }
-
- return data[i] - terminator;
- }
-
- /** Comparison function used for general UTF-8 encoded strings */
- @VisibleForTesting
- static int compare(byte[] data, int offset, byte terminator, byte[] s,
- int begin, int end) {
- int i = offset;
- int j = begin;
- for (; ; i++, j++) {
- byte b = data[i];
- if (b == ' ') {
- // We've matched up to the space in a split-word typo, such as
- // in German all zu=>allzu; here we've matched just past "all".
- // Rather than terminating, attempt to continue in the buffer.
- // We've matched up to the space in a split-word typo, such as
- // in German all zu=>allzu; here we've matched just past "all".
- // Rather than terminating, attempt to continue in the buffer.
- if (j == end) {
- int max = s.length;
- if (end < max && s[end] == ' ') {
- // Find next word
- for (; end < max; end++) {
- byte cb = s[end];
- if (!isLetter(cb)) {
- if (cb == ' ' && end == j) {
- continue;
- }
- break;
- }
- }
- }
- }
- }
-
- if (j == end) {
- break;
- }
- if (b == '*') {
- // Glob match (only supported at the end)
- return 0;
- }
- byte cb = s[j];
- int delta = b - cb;
- if (delta != 0) {
- cb = toLowerCase(cb);
- b = toLowerCase(b);
- delta = b - cb;
- if (delta != 0) {
- return delta;
- }
- }
-
- if (b == terminator || cb == terminator) {
- return delta;
- }
- }
-
- return data[i] - terminator;
- }
-
- /**
- * Look up whether this word is a typo, and if so, return the typo itself
- * and one or more likely meanings
- *
- * @param text the string containing the word
- * @param begin the index of the first character in the word
- * @param end the index of the first character after the word. Note that the
- * search may extend <b>beyond</b> this index, if for example the
- * word matches a multi-word typo in the dictionary
- * @return a list of the typo itself followed by the replacement strings if
- * the word represents a typo, and null otherwise
- */
- @Nullable
- public List<String> getTypos(@NonNull CharSequence text, int begin, int end) {
- assert end <= text.length();
-
- if (assertionsEnabled()) {
- for (int i = begin; i < end; i++) {
- char c = text.charAt(i);
- if (c >= 128) {
- assert false : "Call the UTF-8 version of this method instead";
- return null;
- }
- }
- }
-
- int low = 0;
- int high = mWordCount - 1;
- while (low <= high) {
- int middle = (low + high) >>> 1;
- int offset = mIndices[middle];
-
- if (DEBUG_SEARCH) {
- System.out.println("Comparing string " + text +" with entry at " + offset
- + ": " + dumpEntry(offset));
- }
-
- // Compare the word at the given index.
- int compare = compare(mData, offset, (byte) 0, text, begin, end);
-
- if (compare == 0) {
- offset = mIndices[middle];
-
- // Don't allow matching uncapitalized words, such as "enlish", when
- // the dictionary word is capitalized, "Enlish".
- if (mData[offset] != text.charAt(begin)
- && Character.isLowerCase(text.charAt(begin))) {
- return null;
- }
-
- // Make sure there is a case match; we only want to allow
- // matching capitalized words to capitalized typos or uncapitalized typos
- // (e.g. "Teh" and "teh" to "the"), but not uncapitalized words to capitalized
- // typos (e.g. "enlish" to "Enlish").
- String glob = null;
- for (int i = begin; ; i++) {
- byte b = mData[offset++];
- if (b == 0) {
- offset--;
- break;
- } else if (b == '*') {
- int globEnd = i;
- while (globEnd < text.length()
- && Character.isLetter(text.charAt(globEnd))) {
- globEnd++;
- }
- glob = text.subSequence(i, globEnd).toString();
- break;
- }
- char c = text.charAt(i);
- byte cb = (byte) c;
- if (b != cb && i > begin) {
- return null;
- }
- }
-
- return computeSuggestions(mIndices[middle], offset, glob);
- }
-
- if (compare < 0) {
- low = middle + 1;
- } else if (compare > 0) {
- high = middle - 1;
- } else {
- assert false; // compare == 0 already handled above
- return null;
- }
- }
-
- return null;
- }
-
- /**
- * Look up whether this word is a typo, and if so, return the typo itself
- * and one or more likely meanings
- *
- * @param utf8Text the string containing the word, encoded as UTF-8
- * @param begin the index of the first character in the word
- * @param end the index of the first character after the word. Note that the
- * search may extend <b>beyond</b> this index, if for example the
- * word matches a multi-word typo in the dictionary
- * @return a list of the typo itself followed by the replacement strings if
- * the word represents a typo, and null otherwise
- */
- @Nullable
- public List<String> getTypos(@NonNull byte[] utf8Text, int begin, int end) {
- assert end <= utf8Text.length;
-
- int low = 0;
- int high = mWordCount - 1;
- while (low <= high) {
- int middle = (low + high) >>> 1;
- int offset = mIndices[middle];
-
- if (DEBUG_SEARCH) {
- String s = new String(Arrays.copyOfRange(utf8Text, begin, end), Charsets.UTF_8);
- System.out.println("Comparing string " + s +" with entry at " + offset
- + ": " + dumpEntry(offset));
- System.out.println(" middle=" + middle + ", low=" + low + ", high=" + high);
- }
-
- // Compare the word at the given index.
- int compare = compare(mData, offset, (byte) 0, utf8Text, begin, end);
-
- if (DEBUG_SEARCH) {
- System.out.println(" signum=" + (int)Math.signum(compare) + ", delta=" + compare);
- }
-
- if (compare == 0) {
- offset = mIndices[middle];
-
- // Don't allow matching uncapitalized words, such as "enlish", when
- // the dictionary word is capitalized, "Enlish".
- if (mData[offset] != utf8Text[begin] && isUpperCase(mData[offset])) {
- return null;
- }
-
- // Make sure there is a case match; we only want to allow
- // matching capitalized words to capitalized typos or uncapitalized typos
- // (e.g. "Teh" and "teh" to "the"), but not uncapitalized words to capitalized
- // typos (e.g. "enlish" to "Enlish").
- String glob = null;
- for (int i = begin; ; i++) {
- byte b = mData[offset++];
- if (b == 0) {
- offset--;
- break;
- } else if (b == '*') {
- int globEnd = i;
- while (globEnd < utf8Text.length && isLetter(utf8Text[globEnd])) {
- globEnd++;
- }
- glob = new String(utf8Text, i, globEnd - i, Charsets.UTF_8);
- break;
- }
- byte cb = utf8Text[i];
- if (b != cb && i > begin) {
- return null;
- }
- }
-
- return computeSuggestions(mIndices[middle], offset, glob);
- }
-
- if (compare < 0) {
- low = middle + 1;
- } else if (compare > 0) {
- high = middle - 1;
- } else {
- assert false; // compare == 0 already handled above
- return null;
- }
- }
-
- return null;
- }
-
- private List<String> computeSuggestions(int begin, int offset, String glob) {
- String typo = new String(mData, begin, offset - begin, Charsets.UTF_8);
-
- if (glob != null) {
- typo = typo.replaceAll("\\*", glob); //$NON-NLS-1$
- }
-
- assert mData[offset] == 0;
- offset++;
- int replacementEnd = offset;
- while (mData[replacementEnd] != 0) {
- replacementEnd++;
- }
- String replacements = new String(mData, offset, replacementEnd - offset, Charsets.UTF_8);
- List<String> words = new ArrayList<String>();
- words.add(typo);
-
- // The first entry should be the typo itself. We need to pass this back since due
- // to multi-match words and globbing it could extend beyond the initial word range
-
- for (String s : Splitter.on(',').omitEmptyStrings().trimResults().split(replacements)) {
- if (glob != null) {
- // Need to append the glob string to each result
- words.add(s.replaceAll("\\*", glob)); //$NON-NLS-1$
- } else {
- words.add(s);
- }
- }
-
- return words;
- }
-
- // "Character" handling for bytes. This assumes that the bytes correspond to Unicode
- // characters in the ISO 8859-1 range, which is are encoded the same way in UTF-8.
- // This obviously won't work to for example uppercase to lowercase conversions for
- // multi byte characters, which means we simply won't catch typos if the dictionaries
- // contain these. None of the currently included dictionaries do. However, it does
- // help us properly deal with punctuation and spacing characters.
-
- static boolean isUpperCase(byte b) {
- return Character.isUpperCase((char) b);
- }
-
- static byte toLowerCase(byte b) {
- return (byte) Character.toLowerCase((char) b);
- }
-
- static boolean isSpace(byte b) {
- return Character.isWhitespace((char) b);
- }
-
- static boolean isLetter(byte b) {
- // Assume that multi byte characters represent letters in other languages.
- // Obviously, it could be unusual punctuation etc but letters are more likely
- // in this context.
- return Character.isLetter((char) b) || (b & 0x80) != 0;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypographyDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypographyDetector.java
deleted file mode 100644
index ae5f24c..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/TypographyDetector.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.TAG_STRING;
-import static com.android.SdkConstants.TAG_STRING_ARRAY;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks for various typographical issues in string definitions.
- */
-public class TypographyDetector extends ResourceXmlDetector {
- /** Replace hyphens with dashes? */
- public static final Issue DASHES = Issue.create(
- "TypographyDashes", //$NON-NLS-1$
- "Looks for usages of hyphens which can be replaced by n dash and m dash characters",
- "The \"n dash\" (\u2013, &#8211;) and the \"m dash\" (\u2014, &#8212;) " +
- "characters are used for ranges (n dash) and breaks (m dash). Using these " +
- "instead of plain hyphens can make text easier to read and your application " +
- "will look more polished.",
- Category.TYPOGRAPHY,
- 5,
- Severity.WARNING,
- TypographyDetector.class,
- Scope.RESOURCE_FILE_SCOPE).
- setMoreInfo("http://en.wikipedia.org/wiki/Dash"); //$NON-NLS-1$
-
- /** Replace dumb quotes with smart quotes? */
- public static final Issue QUOTES = Issue.create(
- "TypographyQuotes", //$NON-NLS-1$
- "Looks for straight quotes which can be replaced by curvy quotes",
- "Straight single quotes and double quotes, when used as a pair, can be replaced " +
- "by \"curvy quotes\" (or directional quotes). This can make the text more " +
- "readable.\n" +
- "\n" +
- "Note that you should never use grave accents and apostrophes to quote, " +
- "`like this'.\n" +
- "\n" +
- "(Also note that you should not use curvy quotes for code fragments.)",
- Category.TYPOGRAPHY,
- 5,
- Severity.WARNING,
- TypographyDetector.class,
- Scope.RESOURCE_FILE_SCOPE).
- setMoreInfo("http://en.wikipedia.org/wiki/Quotation_mark"). //$NON-NLS-1$
- // This feature is apparently controversial: recent apps have started using
- // straight quotes to avoid inconsistencies. Disabled by default for now.
- setEnabledByDefault(false);
-
- /** Replace fraction strings with fraction characters? */
- public static final Issue FRACTIONS = Issue.create(
- "TypographyFractions", //$NON-NLS-1$
- "Looks for fraction strings which can be replaced with a fraction character",
- "You can replace certain strings, such as 1/2, and 1/4, with dedicated " +
- "characters for these, such as \u00BD (&#189;) and \00BC (&#188;). " +
- "This can help make the text more readable.",
- Category.TYPOGRAPHY,
- 5,
- Severity.WARNING,
- TypographyDetector.class,
- Scope.RESOURCE_FILE_SCOPE).
- setMoreInfo("http://en.wikipedia.org/wiki/Number_Forms"); //$NON-NLS-1$
-
- /** Replace ... with the ellipsis character? */
- public static final Issue ELLIPSIS = Issue.create(
- "TypographyEllipsis", //$NON-NLS-1$
- "Looks for ellipsis strings (...) which can be replaced with an ellipsis character",
- "You can replace the string \"...\" with a dedicated ellipsis character, " +
- "ellipsis character (\u2026, &#8230;). This can help make the text more readable.",
- Category.TYPOGRAPHY,
- 5,
- Severity.WARNING,
- TypographyDetector.class,
- Scope.RESOURCE_FILE_SCOPE).
- setMoreInfo("http://en.wikipedia.org/wiki/Ellipsis"); //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue OTHER = Issue.create(
- "TypographyOther", //$NON-NLS-1$
- "Looks for miscellaneous typographical problems like replacing (c) with \u00A9",
- "This check looks for miscellaneous typographical problems and offers replacement " +
- "sequences that will make the text easier to read and your application more " +
- "polished.",
- Category.TYPOGRAPHY,
- 3,
- Severity.WARNING,
- TypographyDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- private static final String GRAVE_QUOTE_MESSAGE =
- "Avoid quoting with grave accents; use apostrophes or better yet directional quotes instead";
- private static final String ELLIPSIS_MESSAGE =
- "Replace \"...\" with ellipsis character (\u2026, &#8230;) ?";
- private static final String EN_DASH_MESSAGE =
- "Replace \"-\" with an \"en dash\" character (\u2013, &#8211;) ?";
- private static final String EM_DASH_MESSAGE =
- "Replace \"--\" with an \"em dash\" character (\u2014, &#8212;) ?";
- private static final String TYPOGRAPHIC_APOSTROPHE_MESSAGE =
- "Replace apostrophe (') with typographic apostrophe (\u2019, &#8217;) ?";
- private static final String SINGLE_QUOTE_MESSAGE =
- "Replace straight quotes ('') with directional quotes (\u2018\u2019, &#8216; and &#8217;) ?";
- private static final String DBL_QUOTES_MESSAGE =
- "Replace straight quotes (\") with directional quotes (\u201C\u201D, &#8220; and &#8221;) ?";
- private static final String COPYRIGHT_MESSAGE =
- "Replace (c) with copyright symbol \u00A9 (&#169;) ?";
-
- /**
- * Pattern used to detect scenarios which can be replaced with n dashes: a
- * numeric range with a hyphen in the middle (and possibly spaces)
- */
- @VisibleForTesting
- static final Pattern HYPHEN_RANGE_PATTERN =
- Pattern.compile(".*(\\d+\\s*)-(\\s*\\d+).*"); //$NON-NLS-1$
-
- /**
- * Pattern used to detect scenarios where a grave accent mark is used
- * to do ASCII quotations of the form `this'' or ``this'', which is frowned upon.
- * This pattern tries to avoid falsely complaining about strings like
- * "Type Option-` then 'Escape'."
- */
- @VisibleForTesting
- static final Pattern GRAVE_QUOTATION =
- Pattern.compile("(^[^`]*`[^'`]+'[^']*$)|(^[^`]*``[^'`]+''[^']*$)"); //$NON-NLS-1$
-
- /**
- * Pattern used to detect common fractions, e.g. 1/2, 1/3, 2/3, 1/4, 3/4 and
- * variations like 2 / 3, but not 11/22 and so on.
- */
- @VisibleForTesting
- static final Pattern FRACTION_PATTERN =
- Pattern.compile(".*\\b([13])\\s*/\\s*([234])\\b.*"); //$NON-NLS-1$
-
- /**
- * Pattern used to detect single quote strings, such as 'hello', but
- * not just quoted strings like 'Double quote: "', and not sentences
- * where there are multiple apostrophes but not in a quoting context such
- * as "Mind Your P's and Q's".
- */
- @VisibleForTesting
- static final Pattern SINGLE_QUOTE =
- Pattern.compile(".*\\W*'[^']+'(\\W.*)?"); //$NON-NLS-1$
-
- private static final String FRACTION_MESSAGE =
- "Use fraction character %1$c (%2$s) instead of %3$s ?";
-
- private static final String FRACTION_MESSAGE_PATTERN =
- "Use fraction character (.+) \\((.+)\\) instead of (.+) \\?";
-
- private boolean mCheckDashes;
- private boolean mCheckQuotes;
- private boolean mCheckFractions;
- private boolean mCheckEllipsis;
- private boolean mCheckMisc;
-
- /** Constructs a new {@link TypographyDetector} */
- public TypographyDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.VALUES;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_STRING,
- TAG_STRING_ARRAY
- );
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- mCheckDashes = context.isEnabled(DASHES);
- mCheckQuotes = context.isEnabled(QUOTES);
- mCheckFractions = context.isEnabled(FRACTIONS);
- mCheckEllipsis = context.isEnabled(ELLIPSIS);
- mCheckMisc = context.isEnabled(OTHER);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- String text = child.getNodeValue();
- checkText(context, element, child, text);
- } else if (child.getNodeType() == Node.ELEMENT_NODE &&
- child.getParentNode().getNodeName().equals(TAG_STRING_ARRAY)) {
- // String array item children
- NodeList items = child.getChildNodes();
- for (int j = 0, m = items.getLength(); j < m; j++) {
- Node item = items.item(j);
- if (item.getNodeType() == Node.TEXT_NODE) {
- String text = item.getNodeValue();
- checkText(context, child, item, text);
- }
- }
- }
- }
- }
-
- private void checkText(XmlContext context, Node element, Node textNode, String text) {
- if (mCheckEllipsis) {
- // Replace ... with ellipsis character?
- int ellipsis = text.indexOf("..."); //$NON-NLS-1$
- if (ellipsis != -1 && !text.startsWith(".", ellipsis + 3)) { //$NON-NLS-1$
- context.report(ELLIPSIS, element, context.getLocation(textNode),
- ELLIPSIS_MESSAGE, null);
- }
- }
-
- // Dashes
- if (mCheckDashes) {
- int hyphen = text.indexOf('-');
- if (hyphen != -1) {
- // n dash
- Matcher matcher = HYPHEN_RANGE_PATTERN.matcher(text);
- if (matcher.matches()) {
- // Make sure that if there is no space before digit there isn't
- // one on the left either -- since we don't want to consider
- // "1 2 -3" as a range from 2 to 3
- boolean isNegativeNumber =
- !Character.isWhitespace(matcher.group(2).charAt(0)) &&
- Character.isWhitespace(matcher.group(1).charAt(
- matcher.group(1).length() - 1));
- if (!isNegativeNumber && !isAnalyticsTrackingId((Element) element)) {
- context.report(DASHES, element, context.getLocation(textNode),
- EN_DASH_MESSAGE,
- null);
- }
- }
-
- // m dash
- int emdash = text.indexOf("--"); //$NON-NLS-1$
- // Don't suggest replacing -- or "--" with an m dash since these are sometimes
- // used as digit marker strings
- if (emdash > 1 && !text.startsWith("-", emdash + 2)) { //$NON-NLS-1$
- context.report(DASHES, element, context.getLocation(textNode),
- EM_DASH_MESSAGE, null);
- }
- }
- }
-
- if (mCheckQuotes) {
- // Check for single quotes that can be replaced with directional quotes
- int quoteStart = text.indexOf('\'');
- if (quoteStart != -1) {
- int quoteEnd = text.indexOf('\'', quoteStart + 1);
- if (quoteEnd != -1 && quoteEnd > quoteStart + 1
- && (quoteEnd < text.length() -1 || quoteStart > 0)
- && SINGLE_QUOTE.matcher(text).matches()) {
- context.report(QUOTES, element, context.getLocation(textNode),
- SINGLE_QUOTE_MESSAGE, null);
- return;
- }
-
- // Check for apostrophes that can be replaced by typographic apostrophes
- if (quoteEnd == -1 && quoteStart > 0
- && Character.isLetterOrDigit(text.charAt(quoteStart - 1))) {
- context.report(QUOTES, element, context.getLocation(textNode),
- TYPOGRAPHIC_APOSTROPHE_MESSAGE, null);
- return;
- }
- }
-
- // Check for double quotes that can be replaced by directional double quotes
- quoteStart = text.indexOf('"');
- if (quoteStart != -1) {
- int quoteEnd = text.indexOf('"', quoteStart + 1);
- if (quoteEnd != -1 && quoteEnd > quoteStart + 1) {
- if (quoteEnd < text.length() -1 || quoteStart > 0) {
- context.report(QUOTES, element, context.getLocation(textNode),
- DBL_QUOTES_MESSAGE, null);
- return;
- }
- }
- }
-
- // Check for grave accent quotations
- if (text.indexOf('`') != -1 && GRAVE_QUOTATION.matcher(text).matches()) {
- // Are we indenting ``like this'' or `this' ? If so, complain
- context.report(QUOTES, element, context.getLocation(textNode),
- GRAVE_QUOTE_MESSAGE, null);
- return;
- }
-
- // Consider suggesting other types of directional quotes, such as guillemets, in
- // other languages?
- // There are a lot of exceptions and special cases to be considered so
- // this will need careful implementation and testing.
- // See http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
- }
-
- // Fraction symbols?
- if (mCheckFractions && text.indexOf('/') != -1) {
- Matcher matcher = FRACTION_PATTERN.matcher(text);
- if (matcher.matches()) {
- String top = matcher.group(1); // Numerator
- String bottom = matcher.group(2); // Denominator
- if (top.equals("1") && bottom.equals("2")) { //$NON-NLS-1$ //$NON-NLS-2$
- context.report(FRACTIONS, element, context.getLocation(textNode),
- String.format(FRACTION_MESSAGE, '\u00BD', "&#189;", "1/2"), null);
- } else if (top.equals("1") && bottom.equals("4")) { //$NON-NLS-1$ //$NON-NLS-2$
- context.report(FRACTIONS, element, context.getLocation(textNode),
- String.format(FRACTION_MESSAGE, '\u00BC', "&#188;", "1/4"), null);
- } else if (top.equals("3") && bottom.equals("4")) { //$NON-NLS-1$ //$NON-NLS-2$
- context.report(FRACTIONS, element, context.getLocation(textNode),
- String.format(FRACTION_MESSAGE, '\u00BE', "&#190;", "3/4"), null);
- } else if (top.equals("1") && bottom.equals("3")) { //$NON-NLS-1$ //$NON-NLS-2$
- context.report(FRACTIONS, element, context.getLocation(textNode),
- String.format(FRACTION_MESSAGE, '\u2153', "&#8531;", "1/3"), null);
- } else if (top.equals("2") && bottom.equals("3")) { //$NON-NLS-1$ //$NON-NLS-2$
- context.report(FRACTIONS, element, context.getLocation(textNode),
- String.format(FRACTION_MESSAGE, '\u2154', "&#8532;", "2/3"), null);
- }
- }
- }
-
- if (mCheckMisc) {
- // Fix copyright symbol?
- if (text.indexOf('(') != -1
- && (text.contains("(c)") || text.contains("(C)"))) { //$NON-NLS-1$ //$NON-NLS-2$
- // Suggest replacing with copyright symbol?
- context.report(OTHER, element, context.getLocation(textNode),
- COPYRIGHT_MESSAGE, null);
- // Replace (R) and TM as well? There are unicode characters for these but they
- // are probably not very common within Android app strings.
- }
- }
- }
-
- private static boolean isAnalyticsTrackingId(Element element) {
- String name = element.getAttribute(ATTR_NAME);
- return "ga_trackingId".equals(name); //$NON-NLS-1$
- }
-
- /**
- * An object describing a single edit to be made. The offset points to a
- * location to start editing; the length is the number of characters to
- * delete, and the replaceWith string points to a string to insert at the
- * offset. Note that this can model not just replacement edits but deletions
- * (empty replaceWith) and insertions (replace length = 0) too.
- */
- public static class ReplaceEdit {
- /** The offset of the edit */
- public final int offset;
- /** The number of characters to delete at the offset */
- public final int length;
- /** The characters to insert at the offset */
- public final String replaceWith;
-
- /**
- * Creates a new replace edit
- *
- * @param offset the offset of the edit
- * @param length the number of characters to delete at the offset
- * @param replaceWith the characters to insert at the offset
- */
- public ReplaceEdit(int offset, int length, String replaceWith) {
- super();
- this.offset = offset;
- this.length = length;
- this.replaceWith = replaceWith;
- }
- }
-
- /**
- * Returns a list of edits to be applied to fix the suggestion made by the
- * given warning. The specific issue id and message should be the message
- * provided by this detector in an earlier run.
- * <p>
- * This is intended to help tools implement automatic fixes of these
- * warnings. The reason only the message and issue id can be provided
- * instead of actual state passed in the data field to a reporter is that
- * fix operation can be run much later than the lint is processed (for
- * example, in a subsequent run of the IDE when only the warnings have been
- * persisted),
- *
- * @param issueId the issue id, which should be the id for one of the
- * typography issues
- * @param message the actual error message, which should be a message
- * provided by this detector
- * @param textNode a text node which corresponds to the text node the
- * warning operated on
- * @return a list of edits, which is never null but could be empty. The
- * offsets in the edit objects are relative to the text node.
- */
- public static List<ReplaceEdit> getEdits(String issueId, String message, Node textNode) {
- return getEdits(issueId, message, textNode.getNodeValue());
- }
-
- /**
- * Returns a list of edits to be applied to fix the suggestion made by the
- * given warning. The specific issue id and message should be the message
- * provided by this detector in an earlier run.
- * <p>
- * This is intended to help tools implement automatic fixes of these
- * warnings. The reason only the message and issue id can be provided
- * instead of actual state passed in the data field to a reporter is that
- * fix operation can be run much later than the lint is processed (for
- * example, in a subsequent run of the IDE when only the warnings have been
- * persisted),
- *
- * @param issueId the issue id, which should be the id for one of the
- * typography issues
- * @param message the actual error message, which should be a message
- * provided by this detector
- * @param text the text of the XML node where the warning appeared
- * @return a list of edits, which is never null but could be empty. The
- * offsets in the edit objects are relative to the text node.
- */
- public static List<ReplaceEdit> getEdits(String issueId, String message, String text) {
- List<ReplaceEdit> edits = new ArrayList<ReplaceEdit>();
- if (message.equals(ELLIPSIS_MESSAGE)) {
- int offset = text.indexOf("..."); //$NON-NLS-1$
- if (offset != -1) {
- edits.add(new ReplaceEdit(offset, 3, "\u2026")); //$NON-NLS-1$
- }
- } else if (message.equals(EN_DASH_MESSAGE)) {
- int offset = text.indexOf('-');
- if (offset != -1) {
- edits.add(new ReplaceEdit(offset, 1, "\u2013")); //$NON-NLS-1$
- }
- } else if (message.equals(EM_DASH_MESSAGE)) {
- int offset = text.indexOf("--"); //$NON-NLS-1$
- if (offset != -1) {
- edits.add(new ReplaceEdit(offset, 2, "\u2014")); //$NON-NLS-1$
- }
- } else if (message.equals(TYPOGRAPHIC_APOSTROPHE_MESSAGE)) {
- int offset = text.indexOf('\'');
- if (offset != -1) {
- edits.add(new ReplaceEdit(offset, 1, "\u2019")); //$NON-NLS-1$
- }
- } else if (message.equals(COPYRIGHT_MESSAGE)) {
- int offset = text.indexOf("(c)"); //$NON-NLS-1$
- if (offset == -1) {
- offset = text.indexOf("(C)"); //$NON-NLS-1$
- }
- if (offset != -1) {
- edits.add(new ReplaceEdit(offset, 3, "\u00A9")); //$NON-NLS-1$
- }
- } else if (message.equals(SINGLE_QUOTE_MESSAGE)) {
- int offset = text.indexOf('\'');
- if (offset != -1) {
- int endOffset = text.indexOf('\'', offset + 1); //$NON-NLS-1$
- if (endOffset != -1) {
- edits.add(new ReplaceEdit(offset, 1, "\u2018")); //$NON-NLS-1$
- edits.add(new ReplaceEdit(endOffset, 1, "\u2019")); //$NON-NLS-1$
- }
- }
- } else if (message.equals(DBL_QUOTES_MESSAGE)) {
- int offset = text.indexOf('"');
- if (offset != -1) {
- int endOffset = text.indexOf('"', offset + 1);
- if (endOffset != -1) {
- edits.add(new ReplaceEdit(offset, 1, "\u201C")); //$NON-NLS-1$
- edits.add(new ReplaceEdit(endOffset, 1, "\u201D")); //$NON-NLS-1$
- }
- }
- } else if (message.equals(GRAVE_QUOTE_MESSAGE)) {
- int offset = text.indexOf('`');
- if (offset != -1) {
- int endOffset = text.indexOf('\'', offset + 1);
- if (endOffset != -1) {
- edits.add(new ReplaceEdit(offset, 1, "\u2018")); //$NON-NLS-1$
- edits.add(new ReplaceEdit(endOffset, 1, "\u2019")); //$NON-NLS-1$
- }
- }
- } else {
- Matcher matcher = Pattern.compile(FRACTION_MESSAGE_PATTERN).matcher(message);
- if (matcher.find()) {
- // "Use fraction character %1$c (%2$s) instead of %3$s ?";
- String replace = matcher.group(3);
- int offset = text.indexOf(replace);
- if (offset != -1) {
- String replaceWith = matcher.group(2);
- edits.add(new ReplaceEdit(offset, replace.length(), replaceWith));
- }
- }
- }
-
- return edits;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
deleted file mode 100644
index caa112a..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_REF_PREFIX;
-import static com.android.SdkConstants.DOT_GIF;
-import static com.android.SdkConstants.DOT_JPG;
-import static com.android.SdkConstants.DOT_PNG;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.RESOURCE_CLR_STYLEABLE;
-import static com.android.SdkConstants.RESOURCE_CLZ_ARRAY;
-import static com.android.SdkConstants.RESOURCE_CLZ_ID;
-import static com.android.SdkConstants.R_ATTR_PREFIX;
-import static com.android.SdkConstants.R_CLASS;
-import static com.android.SdkConstants.R_ID_PREFIX;
-import static com.android.SdkConstants.R_PREFIX;
-import static com.android.SdkConstants.TAG_ARRAY;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_PLURALS;
-import static com.android.SdkConstants.TAG_RESOURCES;
-import static com.android.SdkConstants.TAG_STRING_ARRAY;
-import static com.android.SdkConstants.TAG_STYLE;
-import static com.android.tools.lint.detector.api.LintUtils.endsWith;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.collect.Lists;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.NormalTypeBody;
-import lombok.ast.VariableDeclaration;
-import lombok.ast.VariableDefinition;
-
-/**
- * Finds unused resources.
- * <p>
- * Note: This detector currently performs *string* analysis to check Java files.
- * The Lint API needs an official Java AST API (or map to an existing one like
- * BCEL for bytecode analysis etc) and once it does this should be updated to
- * use it.
- */
-public class UnusedResourceDetector extends ResourceXmlDetector implements Detector.JavaScanner {
-
- /** Unused resources (other than ids). */
- public static final Issue ISSUE = Issue.create("UnusedResources", //$NON-NLS-1$
- "Looks for unused resources",
- "Unused resources make applications larger and slow down builds.",
- Category.PERFORMANCE,
- 3,
- Severity.WARNING,
- UnusedResourceDetector.class,
- EnumSet.of(Scope.MANIFEST, Scope.ALL_RESOURCE_FILES, Scope.ALL_JAVA_FILES));
-
- /** Unused id's */
- public static final Issue ISSUE_IDS = Issue.create("UnusedIds", //$NON-NLS-1$
- "Looks for unused id's",
- "This resource id definition appears not to be needed since it is not referenced " +
- "from anywhere. Having id definitions, even if unused, is not necessarily a bad " +
- "idea since they make working on layouts and menus easier, so there is not a " +
- "strong reason to delete these.",
- Category.PERFORMANCE,
- 1,
- Severity.WARNING,
- UnusedResourceDetector.class,
- EnumSet.of(Scope.MANIFEST, Scope.ALL_RESOURCE_FILES, Scope.ALL_JAVA_FILES))
- .setEnabledByDefault(false);
-
- private Set<String> mDeclarations;
- private Set<String> mReferences;
- private Map<String, Location> mUnused;
-
- /**
- * Constructs a new {@link UnusedResourceDetector}
- */
- public UnusedResourceDetector() {
- }
-
- @Override
- public void run(@NonNull Context context) {
- assert false;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return true;
- }
-
- @Override
- public void beforeCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mDeclarations = new HashSet<String>(300);
- mReferences = new HashSet<String>(300);
- }
- }
-
- // ---- Implements JavaScanner ----
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- File file = context.file;
-
- String fileName = file.getName();
- boolean isXmlFile = endsWith(fileName, DOT_XML);
- if (isXmlFile
- || endsWith(fileName, DOT_PNG)
- || endsWith(fileName, DOT_JPG)
- || endsWith(fileName, DOT_GIF)) {
- String parentName = file.getParentFile().getName();
- int dash = parentName.indexOf('-');
- String typeName = parentName.substring(0, dash == -1 ? parentName.length() : dash);
- ResourceType type = ResourceType.getEnum(typeName);
- if (type != null && LintUtils.isFileBasedResourceType(type)) {
- String baseName = fileName.substring(0, fileName.length() - DOT_XML.length());
- String resource = R_PREFIX + typeName + '.' + baseName;
- if (context.getPhase() == 1) {
- mDeclarations.add(resource);
- } else {
- assert context.getPhase() == 2;
- if (mUnused.containsKey(resource)) {
- // Check whether this is an XML document that has a tools:ignore attribute
- // on the document element: if so don't record it as a declaration.
- if (isXmlFile && context instanceof XmlContext) {
- XmlContext xmlContext = (XmlContext) context;
- if (xmlContext.document != null
- && xmlContext.document.getDocumentElement() != null) {
- Element root = xmlContext.document.getDocumentElement();
- if (xmlContext.getDriver().isSuppressed(ISSUE, root)) {
- // Also remove it from consideration such that even the
- // presence of this field in the R file is ignored.
- mUnused.remove(resource);
- return;
- }
- }
- }
-
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- mUnused.remove(resource);
- return;
- }
-
- recordLocation(resource, Location.create(file));
- }
- }
- }
- }
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (context.getPhase() == 1) {
- mDeclarations.removeAll(mReferences);
- Set<String> unused = mDeclarations;
- mReferences = null;
- mDeclarations = null;
-
- // Remove styles and attributes: they may be used, analysis isn't complete for these
- List<String> styles = new ArrayList<String>();
- for (String resource : unused) {
- // R.style.x, R.styleable.x, R.attr
- if (resource.startsWith("R.style") //$NON-NLS-1$
- || resource.startsWith("R.attr")) { //$NON-NLS-1$
- styles.add(resource);
- }
- }
- unused.removeAll(styles);
-
- // Remove id's if the user has disabled reporting issue ids
- if (!unused.isEmpty() && !context.isEnabled(ISSUE_IDS)) {
- // Remove all R.id references
- List<String> ids = new ArrayList<String>();
- for (String resource : unused) {
- if (resource.startsWith(R_ID_PREFIX)) {
- ids.add(resource);
- }
- }
- unused.removeAll(ids);
- }
-
- if (!unused.isEmpty() && !context.getDriver().hasParserErrors()) {
- mUnused = new HashMap<String, Location>(unused.size());
- for (String resource : unused) {
- mUnused.put(resource, null);
- }
-
- // Request another pass, and in the second pass we'll gather location
- // information for all declaration locations we've found
- context.requestRepeat(this, Scope.ALL_RESOURCES_SCOPE);
- }
- } else {
- assert context.getPhase() == 2;
-
- // Report any resources that we (for some reason) could not find a declaration
- // location for
- if (!mUnused.isEmpty()) {
- // Fill in locations for files that we didn't encounter in other ways
- for (Map.Entry<String, Location> entry : mUnused.entrySet()) {
- String resource = entry.getKey();
- Location location = entry.getValue();
- if (location != null) {
- continue;
- }
-
- // Try to figure out the file if it's a file based resource (such as R.layout) --
- // in that case we can figure out the filename since it has a simple mapping
- // from the resource name (though the presence of qualifiers like -land etc
- // makes it a little tricky if there's no base file provided)
- int secondDot = resource.indexOf('.', 2);
- String typeName = resource.substring(2, secondDot); // 2: Skip R.
- ResourceType type = ResourceType.getEnum(typeName);
- if (type != null && LintUtils.isFileBasedResourceType(type)) {
- String name = resource.substring(secondDot + 1);
-
- List<File> folders = Lists.newArrayList();
- List<File> resourceFolders = context.getProject().getResourceFolders();
- for (File res : resourceFolders) {
- File[] f = res.listFiles();
- if (f != null) {
- folders.addAll(Arrays.asList(f));
- }
- }
- if (folders != null) {
- // Process folders in alphabetical order such that we process
- // based folders first: we want the locations in base folder
- // order
- Collections.sort(folders, new Comparator<File>() {
- @Override
- public int compare(File file1, File file2) {
- return file1.getName().compareTo(file2.getName());
- }
- });
- for (File folder : folders) {
- if (folder.getName().startsWith(typeName)) {
- File[] files = folder.listFiles();
- if (files != null) {
- for (File file : files) {
- String fileName = file.getName();
- if (fileName.startsWith(name)
- && fileName.startsWith(".", //$NON-NLS-1$
- name.length())) {
- recordLocation(resource, Location.create(file));
- }
- }
- }
- }
- }
- }
- }
- }
-
- List<String> sorted = new ArrayList<String>(mUnused.keySet());
- Collections.sort(sorted);
-
- Boolean skippedLibraries = null;
-
- for (String resource : sorted) {
- Location location = mUnused.get(resource);
- if (location != null) {
- // We were prepending locations, but we want to prefer the base folders
- location = Location.reverse(location);
- }
-
- if (location == null) {
- if (skippedLibraries == null) {
- skippedLibraries = false;
- for (Project project : context.getDriver().getProjects()) {
- if (!project.getReportIssues()) {
- skippedLibraries = true;
- break;
- }
- }
- }
- if (skippedLibraries) {
- // Skip this resource if we don't have a location, and one or
- // more library projects were skipped; the resource was very
- // probably defined in that library project and only encountered
- // in the main project's java R file
- continue;
- }
- }
-
- String message = String.format("The resource %1$s appears to be unused",
- resource);
- Issue issue = getIssue(resource);
- // TODO: Compute applicable node scope
- context.report(issue, location, message, resource);
- }
- }
- }
- }
-
- private static Issue getIssue(String resource) {
- return resource.startsWith(R_ID_PREFIX) ? ISSUE_IDS : ISSUE;
- }
-
- private void recordLocation(String resource, Location location) {
- Location oldLocation = mUnused.get(resource);
- if (oldLocation != null) {
- location.setSecondary(oldLocation);
- }
- mUnused.put(resource, location);
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return ALL;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- TAG_STYLE,
- TAG_RESOURCES,
- TAG_ARRAY,
- TAG_STRING_ARRAY,
- TAG_PLURALS
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (TAG_RESOURCES.equals(element.getTagName())) {
- for (Element item : LintUtils.getChildren(element)) {
- Attr nameAttribute = item.getAttributeNode(ATTR_NAME);
- if (nameAttribute != null) {
- String name = nameAttribute.getValue();
- if (name.indexOf('.') != -1) {
- name = name.replace('.', '_');
- }
- String type = item.getTagName();
- if (type.equals(TAG_ITEM)) {
- type = RESOURCE_CLZ_ID;
- } else if (type.equals("declare-styleable")) { //$NON-NLS-1$
- type = RESOURCE_CLR_STYLEABLE;
- } else if (type.contains("array")) { //$NON-NLS-1$
- // <string-array> etc
- type = RESOURCE_CLZ_ARRAY;
- }
- String resource = R_PREFIX + type + '.' + name;
-
- if (context.getPhase() == 1) {
- mDeclarations.add(resource);
- checkChildRefs(item);
- } else {
- assert context.getPhase() == 2;
- if (mUnused.containsKey(resource)) {
- if (context.getDriver().isSuppressed(getIssue(resource), item)) {
- mUnused.remove(resource);
- continue;
- }
- if (!context.getProject().getReportIssues()) {
- mUnused.remove(resource);
- continue;
- }
- if (isAnalyticsFile(context)) {
- mUnused.remove(resource);
- continue;
- }
-
- recordLocation(resource, context.getLocation(nameAttribute));
- }
- }
- }
- }
- } else if (mReferences != null) {
- assert TAG_STYLE.equals(element.getTagName())
- || TAG_ARRAY.equals(element.getTagName())
- || TAG_PLURALS.equals(element.getTagName())
- || TAG_STRING_ARRAY.equals(element.getTagName());
- for (Element item : LintUtils.getChildren(element)) {
- checkChildRefs(item);
- }
- }
- }
-
- private static final String ANALYTICS_FILE = "analytics.xml"; //$NON-NLS-1$
-
- /**
- * Returns true if this XML file corresponds to an Analytics configuration file;
- * these contain some attributes read by the library which won't be flagged as
- * used by the application
- *
- * @param context the context used for scanning
- * @return true if the file represents an analytics file
- */
- public static boolean isAnalyticsFile(Context context) {
- File file = context.file;
- return file.getPath().endsWith(ANALYTICS_FILE) && file.getName().equals(ANALYTICS_FILE);
- }
-
- private void checkChildRefs(Element item) {
- // Look for ?attr/ and @dimen/foo etc references in the item children
- NodeList childNodes = item.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.TEXT_NODE) {
- String text = child.getNodeValue();
-
- int index = text.indexOf(ATTR_REF_PREFIX);
- if (index != -1) {
- String name = text.substring(index + ATTR_REF_PREFIX.length()).trim();
- mReferences.add(R_ATTR_PREFIX + name);
- } else {
- index = text.indexOf('@');
- if (index != -1 && text.indexOf('/', index) != -1
- && !text.startsWith("@android:", index)) { //$NON-NLS-1$
- // Compute R-string, e.g. @string/foo => R.string.foo
- String token = text.substring(index + 1).trim().replace('/', '.');
- String r = R_PREFIX + token;
- mReferences.add(r);
- }
- }
- }
- }
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String value = attribute.getValue();
-
- if (value.startsWith("@+") && !value.startsWith("@+android")) { //$NON-NLS-1$ //$NON-NLS-2$
- String resource = R_PREFIX + value.substring(2).replace('/', '.');
- // We already have the declarations when we scan the R file, but we're tracking
- // these here to get attributes for position info
-
- if (context.getPhase() == 1) {
- mDeclarations.add(resource);
- } else if (mUnused.containsKey(resource)) {
- if (context.getDriver().isSuppressed(getIssue(resource), attribute)) {
- mUnused.remove(resource);
- return;
- }
- if (!context.getProject().getReportIssues()) {
- mUnused.remove(resource);
- return;
- }
- recordLocation(resource, context.getLocation(attribute));
- return;
- }
- } else if (mReferences != null) {
- if (value.startsWith("@") //$NON-NLS-1$
- && !value.startsWith("@android:")) { //$NON-NLS-1$
- // Compute R-string, e.g. @string/foo => R.string.foo
- String r = R_PREFIX + value.substring(1).replace('/', '.');
- mReferences.add(r);
- } else if (value.startsWith(ATTR_REF_PREFIX)) {
- mReferences.add(R_ATTR_PREFIX + value.substring(ATTR_REF_PREFIX.length()));
- }
- }
-
- if (attribute.getNamespaceURI() != null
- && !ANDROID_URI.equals(attribute.getNamespaceURI()) && mReferences != null) {
- mReferences.add(R_ATTR_PREFIX + attribute.getLocalName());
- }
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.SLOW;
- }
-
- @Override
- public List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes() {
- return Collections.<Class<? extends lombok.ast.Node>>singletonList(ClassDeclaration.class);
- }
-
- @Override
- public boolean appliesToResourceRefs() {
- return true;
- }
-
- @Override
- public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull lombok.ast.Node node, @NonNull String type, @NonNull String name,
- boolean isFramework) {
- if (mReferences != null && !isFramework) {
- String reference = R_PREFIX + type + '.' + name;
- mReferences.add(reference);
- }
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- if (mReferences != null) {
- return new UnusedResourceVisitor();
- } else {
- // Second pass, computing resource declaration locations: No need to look at Java
- return null;
- }
- }
-
- // Look for references and declarations
- private class UnusedResourceVisitor extends ForwardingAstVisitor {
- @Override
- public boolean visitClassDeclaration(ClassDeclaration node) {
- // Look for declarations of R class fields and store them in
- // mDeclarations
- String description = node.getDescription();
- if (description.equals(R_CLASS)) {
- // This is an R class. We can process this class very deliberately.
- // The R class has a very specific AST format:
- // ClassDeclaration ("R")
- // NormalTypeBody
- // ClassDeclaration (e.g. "drawable")
- // NormalTypeBody
- // VariableDeclaration
- // VariableDefinition (e.g. "ic_launcher")
- for (lombok.ast.Node body : node.getChildren()) {
- if (body instanceof NormalTypeBody) {
- for (lombok.ast.Node subclass : body.getChildren()) {
- if (subclass instanceof ClassDeclaration) {
- String className = ((ClassDeclaration) subclass).getDescription();
- for (lombok.ast.Node innerBody : subclass.getChildren()) {
- if (innerBody instanceof NormalTypeBody) {
- for (lombok.ast.Node field : innerBody.getChildren()) {
- if (field instanceof VariableDeclaration) {
- for (lombok.ast.Node child : field.getChildren()) {
- if (child instanceof VariableDefinition) {
- VariableDefinition def =
- (VariableDefinition) child;
- String name = def.astVariables().first()
- .astName().astValue();
- String resource = R_PREFIX + className
- + '.' + name;
- mDeclarations.add(resource);
- } // Else: It could be a comment node
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UseCompoundDrawableDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UseCompoundDrawableDetector.java
deleted file mode 100644
index db5de4d..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UseCompoundDrawableDetector.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_LAYOUT_WEIGHT;
-import static com.android.SdkConstants.ATTR_SCALE_TYPE;
-import static com.android.SdkConstants.IMAGE_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.TEXT_VIEW;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Checks whether the current node can be replaced by a TextView using compound
- * drawables.
- */
-public class UseCompoundDrawableDetector extends LayoutDetector {
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "UseCompoundDrawables", //$NON-NLS-1$
- "Checks whether the current node can be replaced by a TextView using compound drawables.",
- "A `LinearLayout` which contains an `ImageView` and a `TextView` can be more " +
- "efficiently handled as a compound drawable (a single TextView, using the " +
- "`drawableTop`, `drawableLeft`, `drawableRight` and/or `drawableBottom` attributes " +
- "to draw one or more images adjacent to the text).\n" +
- "\n" +
- "If the two widgets are offset from each other with " +
- "margins, this can be replaced with a `drawablePadding` attribute.\n" +
- "\n" +
- "There's a lint quickfix to perform this conversion in the Eclipse plugin.",
- Category.PERFORMANCE,
- 6,
- Severity.WARNING,
- UseCompoundDrawableDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link UseCompoundDrawableDetector} */
- public UseCompoundDrawableDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Collections.singletonList(
- LINEAR_LAYOUT
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- int childCount = LintUtils.getChildCount(element);
- if (childCount == 2) {
- List<Element> children = LintUtils.getChildren(element);
- Element first = children.get(0);
- Element second = children.get(1);
- if ((first.getTagName().equals(IMAGE_VIEW) &&
- second.getTagName().equals(TEXT_VIEW) &&
- !first.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT)) ||
- ((second.getTagName().equals(IMAGE_VIEW) &&
- first.getTagName().equals(TEXT_VIEW) &&
- !second.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT)))) {
- // If the layout has a background, ignore since it would disappear from
- // the TextView
- if (element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND)) {
- return;
- }
-
- // Certain scale types cannot be done with compound drawables
- String scaleType = first.getTagName().equals(IMAGE_VIEW)
- ? first.getAttributeNS(ANDROID_URI, ATTR_SCALE_TYPE)
- : second.getAttributeNS(ANDROID_URI, ATTR_SCALE_TYPE);
- if (scaleType != null && !scaleType.isEmpty()) {
- // For now, ignore if any scale type is set
- return;
- }
-
- context.report(ISSUE, element, context.getLocation(element),
- "This tag and its children can be replaced by one <TextView/> and " +
- "a compound drawable", null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UselessViewDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UselessViewDetector.java
deleted file mode 100644
index 867c3c4..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/UselessViewDetector.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.FRAME_LAYOUT;
-import static com.android.SdkConstants.GRID_LAYOUT;
-import static com.android.SdkConstants.GRID_VIEW;
-import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.VIEW_MERGE;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.SCROLL_VIEW;
-import static com.android.SdkConstants.TABLE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Checks whether the current node can be removed without affecting the layout.
- */
-public class UselessViewDetector extends LayoutDetector {
- /** Issue of including a parent that has no value on its own */
- public static final Issue USELESS_PARENT = Issue.create(
- "UselessParent", //$NON-NLS-1$
- "Checks whether a parent layout can be removed.",
- "A layout with children that has no siblings, is not a scrollview or " +
- "a root layout, and does not have a background, can be removed and have " +
- "its children moved directly into the parent for a flatter and more " +
- "efficient layout hierarchy.",
- Category.PERFORMANCE,
- 2,
- Severity.WARNING,
- UselessViewDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Issue of including a leaf that isn't shown */
- public static final Issue USELESS_LEAF = Issue.create(
- "UselessLeaf", //$NON-NLS-1$
- "Checks whether a leaf layout can be removed.",
- "A layout that has no children or no background can often be removed (since it " +
- "is invisible) for a flatter and more efficient layout hierarchy.",
- Category.PERFORMANCE,
- 2,
- Severity.WARNING,
- UselessViewDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link UselessViewDetector} */
- public UselessViewDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- private static final List<String> CONTAINERS = new ArrayList<String>(18);
- static {
- CONTAINERS.add(ABSOLUTE_LAYOUT);
- CONTAINERS.add(FRAME_LAYOUT);
- CONTAINERS.add(GRID_LAYOUT);
- CONTAINERS.add(GRID_VIEW);
- CONTAINERS.add(HORIZONTAL_SCROLL_VIEW);
- CONTAINERS.add("ImageSwitcher"); //$NON-NLS-1$
- CONTAINERS.add(LINEAR_LAYOUT);
- CONTAINERS.add(RADIO_GROUP);
- CONTAINERS.add(RELATIVE_LAYOUT);
- CONTAINERS.add(SCROLL_VIEW);
- CONTAINERS.add("SlidingDrawer"); //$NON-NLS-1$
- CONTAINERS.add("StackView"); //$NON-NLS-1$
- CONTAINERS.add(TABLE_LAYOUT);
- CONTAINERS.add(TABLE_ROW);
- CONTAINERS.add("TextSwitcher"); //$NON-NLS-1$
- CONTAINERS.add("ViewAnimator"); //$NON-NLS-1$
- CONTAINERS.add("ViewFlipper"); //$NON-NLS-1$
- CONTAINERS.add("ViewSwitcher"); //$NON-NLS-1$
- // Available ViewGroups that are not included by this check:
- // CONTAINERS.add("android.gesture.GestureOverlayView");
- // CONTAINERS.add("AdapterViewFlipper");
- // CONTAINERS.add("DialerFilter");
- // CONTAINERS.add("ExpandableListView");
- // CONTAINERS.add("ListView");
- // CONTAINERS.add("MediaController");
- // CONTAINERS.add("merge");
- // CONTAINERS.add("SearchView");
- // CONTAINERS.add("TabWidget");
- // CONTAINERS.add("TabHost");
- }
- @Override
- public Collection<String> getApplicableElements() {
- return CONTAINERS;
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- int childCount = LintUtils.getChildCount(element);
- if (childCount == 0) {
- // Check to see if this is a leaf layout that can be removed
- checkUselessLeaf(context, element);
- } else {
- // Check to see if this is a middle-man layout which can be removed
- checkUselessMiddleLayout(context, element);
- }
- }
-
- // This is the old UselessLayoutCheck from layoutopt
- private static void checkUselessMiddleLayout(XmlContext context, Element element) {
- // Conditions:
- // - The node has children
- // - The node does not have siblings
- // - The node's parent is not a scroll view (horizontal or vertical)
- // - The node does not have a background or its parent does not have a
- // background or neither the node and its parent have a background
- // - The parent is not a <merge/>
-
- Node parentNode = element.getParentNode();
- if (parentNode.getNodeType() != Node.ELEMENT_NODE) {
- // Can't remove root
- return;
- }
-
- Element parent = (Element) parentNode;
- String parentTag = parent.getTagName();
- if (parentTag.equals(SCROLL_VIEW) || parentTag.equals(HORIZONTAL_SCROLL_VIEW) ||
- parentTag.equals(VIEW_MERGE)) {
- // Can't remove if the parent is a scroll view or a merge
- return;
- }
-
- // This method is only called when we've already ensured that it has children
- assert LintUtils.getChildCount(element) > 0;
-
- int parentChildCount = LintUtils.getChildCount(parent);
- if (parentChildCount != 1) {
- // Don't remove if the node has siblings
- return;
- }
-
- // - A parent can be removed if it doesn't have a background
- // - A parent can be removed if has a background *and* the child does not have a
- // background (in which case, just move the background over to the child, remove
- // the parent)
- // - If both child and parent have a background, the parent cannot be removed (a
- // background can be translucent, have transparent padding, etc.)
- boolean nodeHasBackground = element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND);
- boolean parentHasBackground = parent.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND);
- if (nodeHasBackground && parentHasBackground) {
- // Can't remove because both define a background, and they might both be
- // visible (e.g. through transparency or padding).
- return;
- }
-
- // Certain parents are special - such as the TabHost and the GestureOverlayView -
- // where we want to leave things alone.
- if (!CONTAINERS.contains(parentTag)) {
- return;
- }
-
- boolean hasId = element.hasAttributeNS(ANDROID_URI, ATTR_ID);
- Location location = context.getLocation(element);
- String tag = element.getTagName();
- String format;
- if (hasId) {
- format = "This %1$s layout or its %2$s parent is possibly useless";
- } else {
- format = "This %1$s layout or its %2$s parent is useless";
- }
- if (nodeHasBackground || parentHasBackground) {
- format += "; transfer the background attribute to the other view";
- }
- String message = String.format(format, tag, parentTag);
- context.report(USELESS_PARENT, element, location, message, null);
- }
-
- // This is the old UselessView check from layoutopt
- private static void checkUselessLeaf(XmlContext context, Element element) {
- assert LintUtils.getChildCount(element) == 0;
-
- // Conditions:
- // - The node is a container view (LinearLayout, etc.)
- // - The node has no id
- // - The node has no background
- // - The node has no children
- // - The node has no style
- // - The node is not a root
-
- if (element.hasAttributeNS(ANDROID_URI, ATTR_ID)) {
- return;
- }
-
- if (element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND)) {
- return;
- }
-
- if (element.hasAttribute(ATTR_STYLE)) {
- return;
- }
-
- if (element == context.document.getDocumentElement()) {
- return;
- }
-
- Location location = context.getLocation(element);
- String tag = element.getTagName();
- String message = String.format(
- "This %1$s view is useless (no children, no background, no id, no style)", tag);
- context.report(USELESS_LEAF, element, location, message, null);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Utf8Detector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Utf8Detector.java
deleted file mode 100644
index 2e23483..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/Utf8Detector.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Document;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Checks that the encoding used in resource files is always UTF-8.
- */
-public class Utf8Detector extends LayoutDetector {
- /** Detects non-utf8 encodings */
- public static final Issue ISSUE = Issue.create(
- "EnforceUTF8", //$NON-NLS-1$
- "Checks that all XML resource files are using UTF-8 as the file encoding",
- "XML supports encoding in a wide variety of character sets. However, not all " +
- "tools handle the XML encoding attribute correctly, and nearly all Android " +
- "apps use UTF-8, so by using UTF-8 you can protect yourself against subtle " +
- "bugs when using non-ASCII characters.",
- Category.I18N,
- 2,
- Severity.WARNING,
- Utf8Detector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** See http://www.w3.org/TR/REC-xml/#NT-EncodingDecl */
- private static final Pattern ENCODING_PATTERN =
- Pattern.compile("encoding=['\"](\\S*)['\"]");//$NON-NLS-1$
-
- /** Constructs a new {@link Utf8Detector} */
- public Utf8Detector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- String xml = context.getContents();
- if (xml == null) {
- return;
- }
-
- // AAPT: The prologue must be in the first line
- int lineEnd = 0;
- int max = xml.length();
- for (; lineEnd < max; lineEnd++) {
- char c = xml.charAt(lineEnd);
- if (c == '\n' || c == '\r') {
- break;
- }
- }
-
- for (int i = 16; i < lineEnd - 5; i++) { // +4: Skip at least <?xml encoding="
- if ((xml.charAt(i) == 'u' || xml.charAt(i) == 'U')
- && (xml.charAt(i + 1) == 't' || xml.charAt(i + 1) == 'T')
- && (xml.charAt(i + 2) == 'f' || xml.charAt(i + 2) == 'F')
- && (xml.charAt(i + 3) == '-' || xml.charAt(i + 3) == '_')
- && (xml.charAt(i + 4) == '8')) {
- return;
- }
- }
-
- int encodingIndex = xml.lastIndexOf("encoding", lineEnd); //$NON-NLS-1$
- if (encodingIndex != -1) {
- Matcher matcher = ENCODING_PATTERN.matcher(xml);
- if (matcher.find(encodingIndex)) {
- String encoding = matcher.group(1);
- Location location = Location.create(context.file, xml,
- matcher.start(1), matcher.end(1));
- context.report(ISSUE, null, location, String.format(
- "%1$s: Not using UTF-8 as the file encoding. This can lead to subtle " +
- "bugs with non-ascii characters", encoding), null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java
deleted file mode 100644
index 4bffdd7..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewConstructorDetector.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.CONSTRUCTOR_NAME;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Looks for custom views that do not define the view constructors needed by UI builders
- */
-public class ViewConstructorDetector extends Detector implements Detector.ClassScanner {
- private static final String SIG1 =
- "(Landroid/content/Context;)V"; //$NON-NLS-1$
- private static final String SIG2 =
- "(Landroid/content/Context;Landroid/util/AttributeSet;)V"; //$NON-NLS-1$
- private static final String SIG3 =
- "(Landroid/content/Context;Landroid/util/AttributeSet;I)V"; //$NON-NLS-1$
-
- /** The main issue discovered by this detector */
- public static final Issue ISSUE = Issue.create(
- "ViewConstructor", //$NON-NLS-1$
- "Checks that custom views define the expected constructors",
-
- "Some layout tools (such as the Android layout editor for Eclipse) needs to " +
- "find a constructor with one of the following signatures:\n" +
- "* `View(Context context)`\n" +
- "* `View(Context context, AttributeSet attrs)`\n" +
- "* `View(Context context, AttributeSet attrs, int defStyle)`\n" +
- "\n" +
- "If your custom view needs to perform initialization which does not apply when " +
- "used in a layout editor, you can surround the given code with a check to " +
- "see if `View#isInEditMode()` is false, since that method will return `false` " +
- "at runtime but true within a user interface editor.",
-
- Category.USABILITY,
- 3,
- Severity.WARNING,
- ViewConstructorDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- /** Constructs a new {@link ViewConstructorDetector} check */
- public ViewConstructorDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- if (classNode.name.indexOf('$') != -1
- && (classNode.access & Opcodes.ACC_STATIC) == 0) {
- // Ignore inner classes that aren't static: we can't create these
- // anyway since we'd need the outer instance
- return;
- }
-
- // Ignore abstract classes
- if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
- return;
- }
-
- if (isViewClass(context, classNode)) {
- checkConstructors(context, classNode);
- }
- }
-
- private static boolean isViewClass(ClassContext context, ClassNode node) {
- String superName = node.superName;
- while (superName != null) {
- if (superName.equals("android/view/View") //$NON-NLS-1$
- || superName.equals("android/view/ViewGroup") //$NON-NLS-1$
- || superName.startsWith("android/widget/") //$NON-NLS-1$
- && !((superName.endsWith("Adapter") //$NON-NLS-1$
- || superName.endsWith("Controller") //$NON-NLS-1$
- || superName.endsWith("Service") //$NON-NLS-1$
- || superName.endsWith("Provider") //$NON-NLS-1$
- || superName.endsWith("Filter")))) { //$NON-NLS-1$
- return true;
- }
-
- superName = context.getDriver().getSuperClass(superName);
- }
-
- return false;
- }
-
- private static void checkConstructors(ClassContext context, ClassNode classNode) {
- // Look through constructors
- @SuppressWarnings("rawtypes")
- List methods = classNode.methods;
- for (Object methodObject : methods) {
- MethodNode method = (MethodNode) methodObject;
- if (method.name.equals(CONSTRUCTOR_NAME)) {
- String desc = method.desc;
- if (desc.equals(SIG1) || desc.equals(SIG2) || desc.equals(SIG3)) {
- return;
- }
- }
- }
-
- // If we get this far, none of the expected constructors were found.
-
- // Use location of one of the constructors?
- String message = String.format(
- "Custom view %1$s is missing constructor used by tools: " +
- "(Context) or (Context,AttributeSet) or (Context,AttributeSet,int)",
- classNode.name);
- File sourceFile = context.getSourceFile();
- Location location = Location.create(sourceFile != null
- ? sourceFile : context.file);
- context.report(ISSUE, location, message, null /*data*/);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTagDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTagDetector.java
deleted file mode 100644
index 46e24cc..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTagDetector.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.analysis.Analyzer;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-import org.objectweb.asm.tree.analysis.BasicInterpreter;
-import org.objectweb.asm.tree.analysis.BasicValue;
-import org.objectweb.asm.tree.analysis.Frame;
-
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-
-/**
- * Checks for missing view tag detectors
- */
-public class ViewTagDetector extends Detector implements ClassScanner {
- /** Using setTag and leaking memory */
- public static final Issue ISSUE = Issue.create(
- "ViewTag", //$NON-NLS-1$
- "Finds potential leaks when using View.setTag",
-
- "Prior to Android 4.0, the implementation of View.setTag(int, Object) would " +
- "store the objects in a static map, where the values were strongly referenced. " +
- "This means that if the object contains any references pointing back to the " +
- "context, the context (which points to pretty much everything else) will leak. " +
- "If you pass a view, the view provides a reference to the context " +
- "that created it. Similarly, view holders typically contain a view, and cursors " +
- "are sometimes also associated with views.",
-
- Category.PERFORMANCE,
- 6,
- Severity.WARNING,
- ViewTagDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.CLASS_FILE));
-
- /** Constructs a new {@link ViewTagDetector} */
- public ViewTagDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Collections.singletonList("setTag"); //$NON-NLS-1$
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- // The leak behavior is fixed in ICS:
- // http://code.google.com/p/android/issues/detail?id=18273
- if (context.getMainProject().getMinSdk() >= 14) {
- return;
- }
-
- String owner = call.owner;
- String desc = call.desc;
- if (owner.equals("android/view/View") //$NON-NLS-1$
- && desc.equals("(ILjava/lang/Object;)V")) { //$NON-NLS-1$
- Analyzer analyzer = new Analyzer(new BasicInterpreter() {
- @Override
- public BasicValue newValue(Type type) {
- if (type == null) {
- return BasicValue.UNINITIALIZED_VALUE;
- } else if (type.getSort() == Type.VOID) {
- return null;
- } else {
- return new BasicValue(type);
- }
- }
- });
- try {
- Frame[] frames = analyzer.analyze(classNode.name, method);
- InsnList instructions = method.instructions;
- Frame frame = frames[instructions.indexOf(call)];
- if (frame.getStackSize() < 3) {
- return;
- }
- BasicValue stackValue = (BasicValue) frame.getStack(2);
- Type type = stackValue.getType();
- if (type == null) {
- return;
- }
-
- String internalName = type.getInternalName();
- String className = type.getClassName();
- LintDriver driver = context.getDriver();
-
- SdkInfo sdkInfo = context.getClient().getSdkInfo(context.getMainProject());
- String objectType = null;
- while (className != null) {
- if (className.equals("android.view.View")) { //$NON-NLS-1$
- objectType = "views";
- break;
- } else if (className.endsWith("ViewHolder")) { //$NON-NLS-1$
- objectType = "view holders";
- break;
- } else if (className.endsWith("Cursor") //$NON-NLS-1$
- && className.startsWith("android.")) { //$NON-NLS-1$
- objectType = "cursors";
- break;
- }
-
- // TBD: Bitmaps, drawables? That's tricky, because as explained in
- // http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
- // apparently these are used along with nulling out the callbacks,
- // and that's harder to detect here
-
- String parent = sdkInfo.getParentViewClass(className);
- if (parent == null) {
- if (internalName == null) {
- internalName = className.replace('.', '/');
- }
- assert internalName != null;
- parent = driver.getSuperClass(internalName);
- }
- className = parent;
- internalName = null;
- }
-
- if (objectType != null) {
- Location location = context.getLocation(call);
- String message = String.format("Avoid setting %1$s as values for setTag: " +
- "Can lead to memory leaks in versions older than Android 4.0",
- objectType);
- context.report(ISSUE, method, call, location, message, null);
- }
- } catch (AnalyzerException e) {
- context.log(e, null);
- }
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTypeDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTypeDetector.java
deleted file mode 100644
index bad5d50..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ViewTypeDetector.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ATTR_CLASS;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.VIEW_TAG;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.base.Joiner;
-
-import org.w3c.dom.Attr;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.Cast;
-import lombok.ast.Expression;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Select;
-import lombok.ast.StrictListAccessor;
-
-/** Detector for finding inconsistent usage of views and casts */
-public class ViewTypeDetector extends ResourceXmlDetector implements Detector.JavaScanner {
- /** Mismatched view types */
- public static final Issue ISSUE = Issue.create("WrongViewCast", //$NON-NLS-1$
- "Looks for incorrect casts to views that according to the XML are of a different type",
- "Keeps track of the view types associated with ids and if it finds a usage of " +
- "the id in the Java code it ensures that it is treated as the same type.",
- Category.CORRECTNESS,
- 9,
- Severity.ERROR,
- ViewTypeDetector.class,
- EnumSet.of(Scope.ALL_RESOURCE_FILES, Scope.ALL_JAVA_FILES));
-
- private final Map<String, Object> mIdToViewTag = new HashMap<String, Object>(50);
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.SLOW;
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT;
- }
-
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- if (LintUtils.endsWith(file.getName(), DOT_JAVA)) {
- return true;
- }
-
- return super.appliesTo(context, file);
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_ID);
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- String view = attribute.getOwnerElement().getTagName();
- String value = attribute.getValue();
- String id = null;
- if (value.startsWith(ID_PREFIX)) {
- id = value.substring(ID_PREFIX.length());
- } else if (value.startsWith(NEW_ID_PREFIX)) {
- id = value.substring(NEW_ID_PREFIX.length());
- } // else: could be @android id
-
- if (id != null) {
- if (view.equals(VIEW_TAG)) {
- view = attribute.getOwnerElement().getAttribute(ATTR_CLASS);
- }
-
- Object existing = mIdToViewTag.get(id);
- if (existing == null) {
- mIdToViewTag.put(id, view);
- } else if (existing instanceof String) {
- String existingString = (String) existing;
- if (!existingString.equals(view)) {
- // Convert to list
- List<String> list = new ArrayList<String>(2);
- list.add((String) existing);
- list.add(view);
- mIdToViewTag.put(id, list);
- }
- } else if (existing instanceof List<?>) {
- @SuppressWarnings("unchecked")
- List<String> list = (List<String>) existing;
- if (!list.contains(view)) {
- list.add(view);
- }
- }
- }
- }
-
- // ---- Implements Detector.JavaScanner ----
-
- @Override
- public List<String> getApplicableMethodNames() {
- return Collections.singletonList("findViewById"); //$NON-NLS-1$
- }
-
- @Override
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- assert node.astName().getDescription().equals("findViewById");
- if (node.getParent() instanceof Cast) {
- Cast cast = (Cast) node.getParent();
- String castType = cast.astTypeReference().getTypeName();
- StrictListAccessor<Expression, MethodInvocation> args = node.astArguments();
- if (args.size() == 1) {
- Expression first = args.first();
- // TODO: Do flow analysis as in the StringFormatDetector in order
- // to handle variable references too
- if (first instanceof Select) {
- String resource = first.toString();
- if (resource.startsWith("R.id.")) { //$NON-NLS-1$
- String id = ((Select) first).astIdentifier().astValue();
- Object types = mIdToViewTag.get(id);
- if (types instanceof String) {
- String layoutType = (String) types;
- checkCompatible(context, castType, layoutType, null, cast);
- } else if (types instanceof List<?>) {
- @SuppressWarnings("unchecked")
- List<String> layoutTypes = (List<String>) types;
- checkCompatible(context, castType, null, layoutTypes, cast);
- }
- }
- }
- }
- }
- }
-
- /** Check if the view and cast type are compatible */
- private static void checkCompatible(JavaContext context, String castType, String layoutType,
- List<String> layoutTypes, Cast node) {
- assert layoutType == null || layoutTypes == null; // Should only specify one or the other
- boolean compatible = true;
- if (layoutType != null) {
- if (!layoutType.equals(castType)
- && !context.getSdkInfo().isSubViewOf(castType, layoutType)) {
- compatible = false;
- }
- } else {
- compatible = false;
- assert layoutTypes != null;
- for (String type : layoutTypes) {
- if (type.equals(castType)
- || context.getSdkInfo().isSubViewOf(castType, type)) {
- compatible = true;
- break;
- }
- }
- }
-
- if (!compatible) {
- if (layoutType == null) {
- layoutType = Joiner.on("|").join(layoutTypes);
- }
- String message = String.format(
- "Unexpected cast to %1$s: layout tag was %2$s",
- castType, layoutType);
- context.report(ISSUE, node, context.parser.getLocation(context, node), message,
- null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WakelockDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WakelockDetector.java
deleted file mode 100644
index 47410eb..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WakelockDetector.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_APP_ACTIVITY;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.checks.ControlFlowGraph.Node;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.JumpInsnNode;
-import org.objectweb.asm.tree.LdcInsnNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.analysis.AnalyzerException;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Checks for problems with wakelocks (such as failing to release them)
- * which can lead to unnecessary battery usage.
- */
-public class WakelockDetector extends Detector implements ClassScanner {
-
- /** Problems using wakelocks */
- public static final Issue ISSUE = Issue.create(
- "Wakelock", //$NON-NLS-1$
- "Looks for problems with wakelock usage",
-
- "Failing to release a wakelock properly can keep the Android device in " +
- "a high power mode, which reduces battery life. There are several causes " +
- "of this, such as releasing the wake lock in `onDestroy()` instead of in " +
- "`onPause()`, failing to call `release()` in all possible code paths after " +
- "an `acquire()`, and so on.\n" +
- "\n" +
- "NOTE: If you are using the lock just to keep the screen on, you should " +
- "strongly consider using `FLAG_KEEP_SCREEN_ON` instead. This window flag " +
- "will be correctly managed by the platform as the user moves between " +
- "applications and doesn't require a special permission. See " +
- "http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_KEEP_SCREEN_ON.",
-
- Category.PERFORMANCE,
- 9,
- Severity.WARNING,
- WakelockDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- private static final String WAKELOCK_OWNER = "android/os/PowerManager$WakeLock"; //$NON-NLS-1$
- private static final String RELEASE_METHOD = "release"; //$NON-NLS-1$
- private static final String ACQUIRE_METHOD = "acquire"; //$NON-NLS-1$
- private static final String IS_HELD_METHOD = "isHeld"; //$NON-NLS-1$
- private static final String POWER_MANAGER = "android/os/PowerManager"; //$NON-NLS-1$
- private static final String NEW_WAKE_LOCK_METHOD = "newWakeLock"; //$NON-NLS-1$
-
- /** Print diagnostics during analysis (display flow control graph etc).
- * Make sure you add the asm-debug or asm-util jars to the runtime classpath
- * as well since the opcode integer to string mapping display routine looks for
- * it via reflection. */
- private static final boolean DEBUG = false;
-
- /** Constructs a new {@link WakelockDetector} */
- public WakelockDetector() {
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mHasAcquire && !mHasRelease && context.getDriver().getPhase() == 1) {
- // Gather positions of the acquire calls
- context.getDriver().requestRepeat(this, Scope.CLASS_FILE_SCOPE);
- }
- }
-
- // ---- Implements ClassScanner ----
-
- /** Whether any {@code acquire()} calls have been encountered */
- private boolean mHasAcquire;
-
- /** Whether any {@code release()} calls have been encountered */
- private boolean mHasRelease;
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Arrays.asList(ACQUIRE_METHOD, RELEASE_METHOD, NEW_WAKE_LOCK_METHOD);
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- if (call.owner.equals(WAKELOCK_OWNER)) {
- String name = call.name;
- if (name.equals(ACQUIRE_METHOD)) {
- mHasAcquire = true;
-
- if (context.getDriver().getPhase() == 2) {
- assert !mHasRelease;
- context.report(ISSUE, method, call, context.getLocation(call),
- "Found a wakelock acquire() but no release() calls anywhere",
- null);
- } else {
- assert context.getDriver().getPhase() == 1;
- // Perform flow analysis in this method to see if we're
- // performing an acquire/release block, where there are code paths
- // between the acquire and release which can result in the
- // release call not getting reached.
- checkFlow(context, classNode, method, call);
- }
- } else if (name.equals(RELEASE_METHOD)) {
- mHasRelease = true;
-
- // See if the release is happening in an onDestroy method, in an
- // activity.
- if ("onDestroy".equals(method.name) //$NON-NLS-1$
- && context.getDriver().isSubclassOf(
- classNode, ANDROID_APP_ACTIVITY)) {
- context.report(ISSUE, method, call, context.getLocation(call),
- "Wakelocks should be released in onPause, not onDestroy",
- null);
- }
- }
- } else if (call.owner.equals(POWER_MANAGER)) {
- if (call.name.equals(NEW_WAKE_LOCK_METHOD)) {
- AbstractInsnNode prev = LintUtils.getPrevInstruction(call);
- if (prev == null) {
- return;
- }
- prev = LintUtils.getPrevInstruction(prev);
- if (prev == null || prev.getOpcode() != Opcodes.LDC) {
- return;
- }
- LdcInsnNode ldc = (LdcInsnNode) prev;
- Object constant = ldc.cst;
- if (constant instanceof Integer) {
- int flag = ((Integer) constant).intValue();
- // Constant values are copied into the bytecode so we have to compare
- // values; however, that means the values are part of the API
- final int PARTIAL_WAKE_LOCK = 0x00000001;
- final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
- final int both = PARTIAL_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP;
- if ((flag & both) == both) {
- context.report(ISSUE, method, call, context.getLocation(call),
- "Should not set both PARTIAL_WAKE_LOCK and ACQUIRE_CAUSES_WAKEUP. "
- + "If you do not want the screen to turn on, get rid of "
- + "ACQUIRE_CAUSES_WAKEUP",
- null);
- }
- }
-
- }
- }
- }
-
- private void checkFlow(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode acquire) {
- // Track allocations such that we know whether the type of the call
- // is on a SecureRandom rather than a Random
- final InsnList instructions = method.instructions;
- MethodInsnNode release = null;
-
- // Find release call
- for (int i = 0, n = instructions.size(); i < n; i++) {
- AbstractInsnNode instruction = instructions.get(i);
- int type = instruction.getType();
- if (type == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode call = (MethodInsnNode) instruction;
- if (call.name.equals(RELEASE_METHOD) &&
- call.owner.equals(WAKELOCK_OWNER)) {
- release = call;
- break;
- }
- }
- }
-
- if (release == null) {
- // Didn't find both acquire and release in this method; no point in doing
- // local flow analysis
- return;
- }
-
- try {
- MyGraph graph = new MyGraph();
- ControlFlowGraph.create(graph, classNode, method);
-
- if (DEBUG) {
- // Requires util package
- //ClassNode clazz = classNode;
- //clazz.accept(new TraceClassVisitor(new PrintWriter(System.out)));
- System.out.println(graph.toString(graph.getNode(acquire)));
- }
-
- int status = dfs(graph.getNode(acquire));
- if ((status & SEEN_RETURN) != 0) {
- String message;
- if ((status & SEEN_EXCEPTION) != 0) {
- message = "The release() call is not always reached (via exceptional flow)";
- } else {
- message = "The release() call is not always reached";
- }
-
- context.report(ISSUE, method, acquire,
- context.getLocation(release), message, null);
- }
- } catch (AnalyzerException e) {
- context.log(e, null);
- }
- }
-
- private static final int SEEN_TARGET = 1;
- private static final int SEEN_BRANCH = 2;
- private static final int SEEN_EXCEPTION = 4;
- private static final int SEEN_RETURN = 8;
-
- /** TODO RENAME */
- private static class MyGraph extends ControlFlowGraph {
- @Override
- protected void add(@NonNull AbstractInsnNode from, @NonNull AbstractInsnNode to) {
- if (from.getOpcode() == Opcodes.IFNULL) {
- JumpInsnNode jump = (JumpInsnNode) from;
- if (jump.label == to) {
- // Skip jump targets on null if it's surrounding the release call
- //
- // if (lock != null) {
- // lock.release();
- // }
- //
- // The above shouldn't be considered a scenario where release() may not
- // be called.
- AbstractInsnNode next = LintUtils.getNextInstruction(from);
- if (next != null && next.getType() == AbstractInsnNode.VAR_INSN) {
- next = LintUtils.getNextInstruction(next);
- if (next != null && next.getType() == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode method = (MethodInsnNode) next;
- if (method.name.equals(RELEASE_METHOD) &&
- method.owner.equals(WAKELOCK_OWNER)) {
- // This isn't entirely correct; this will also trigger
- // for "if (lock == null) { lock.release(); }" but that's
- // not likely (and caught by other null checking in tools)
- return;
- }
- }
- }
- }
- } else if (from.getOpcode() == Opcodes.IFEQ) {
- JumpInsnNode jump = (JumpInsnNode) from;
- if (jump.label == to) {
- AbstractInsnNode prev = LintUtils.getPrevInstruction(from);
- if (prev != null && prev.getType() == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode method = (MethodInsnNode) prev;
- if (method.name.equals(IS_HELD_METHOD) &&
- method.owner.equals(WAKELOCK_OWNER)) {
- AbstractInsnNode next = LintUtils.getNextInstruction(from);
- if (next != null) {
- super.add(from, next);
- return;
- }
- }
- }
- }
- }
-
- super.add(from, to);
- }
- }
-
- /** Search from the given node towards the target; return false if we reach
- * an exit point such as a return or a call on the way there that is not within
- * a try/catch clause.
- *
- * @param node the current node
- * @return true if the target was reached
- * XXX RETURN VALUES ARE WRONG AS OF RIGHT NOW
- */
- protected int dfs(ControlFlowGraph.Node node) {
- AbstractInsnNode instruction = node.instruction;
- if (instruction.getType() == AbstractInsnNode.JUMP_INSN) {
- int opcode = instruction.getOpcode();
- if (opcode == Opcodes.RETURN || opcode == Opcodes.ARETURN
- || opcode == Opcodes.LRETURN || opcode == Opcodes.IRETURN
- || opcode == Opcodes.DRETURN || opcode == Opcodes.FRETURN
- || opcode == Opcodes.ATHROW) {
- if (DEBUG) {
- System.out.println("Found exit via explicit return: " //$NON-NLS-1$
- + node.toString(false));
- }
- return SEEN_RETURN;
- }
- }
-
- if (!DEBUG) {
- // There are no cycles, so no *NEED* for this, though it does avoid
- // researching shared labels. However, it makes debugging harder (no re-entry)
- // so this is only done when debugging is off
- if (node.visit != 0) {
- return 0;
- }
- node.visit = 1;
- }
-
- // Look for the target. This is any method call node which is a release on the
- // lock (later also check it's the same instance, though that's harder).
- // This is because finally blocks tend to be inlined so from a single try/catch/finally
- // with a release() in the finally, the bytecode can contain multiple repeated
- // (inlined) release() calls.
- if (instruction.getType() == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode method = (MethodInsnNode) instruction;
- if (method.name.equals(RELEASE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
- return SEEN_TARGET;
- } else if (method.name.equals(ACQUIRE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
- // OK
- } else if (method.name.equals(IS_HELD_METHOD) && method.owner.equals(WAKELOCK_OWNER)) {
- // OK
- } else {
- // Some non acquire/release method call: if this is not associated with a
- // try-catch block, it would mean the exception would exit the method,
- // which would be an error
- if (node.exceptions == null || node.exceptions.isEmpty()) {
- // Look up the corresponding frame, if any
- AbstractInsnNode curr = method.getPrevious();
- boolean foundFrame = false;
- while (curr != null) {
- if (curr.getType() == AbstractInsnNode.FRAME) {
- foundFrame = true;
- break;
- }
- curr = curr.getPrevious();
- }
-
- if (!foundFrame) {
- if (DEBUG) {
- System.out.println("Found exit via unguarded method call: " //$NON-NLS-1$
- + node.toString(false));
- }
- return SEEN_RETURN;
- }
- }
- }
- }
-
- // if (node.instruction is a call, and the call is not caught by
- // a try/catch block (provided the release is not inside the try/catch block)
- // then return false
- int status = 0;
-
- boolean implicitReturn = true;
- List<Node> successors = node.successors;
- List<Node> exceptions = node.exceptions;
- if (exceptions != null) {
- if (!exceptions.isEmpty()) {
- implicitReturn = false;
- }
- for (Node successor : exceptions) {
- status = dfs(successor) | status;
- if ((status & SEEN_RETURN) != 0) {
- if (DEBUG) {
- System.out.println("Found exit via exception: " //$NON-NLS-1$
- + node.toString(false));
- }
- return status;
- }
- }
-
- if (status != 0) {
- status |= SEEN_EXCEPTION;
- }
- }
-
- if (successors != null) {
- if (!successors.isEmpty()) {
- implicitReturn = false;
- if (successors.size() > 1) {
- status |= SEEN_BRANCH;
- }
- }
- for (Node successor : successors) {
- status = dfs(successor) | status;
- if ((status & SEEN_RETURN) != 0) {
- if (DEBUG) {
- System.out.println("Found exit via branches: " //$NON-NLS-1$
- + node.toString(false));
- }
- return status;
- }
- }
- }
-
- if (implicitReturn) {
- status |= SEEN_RETURN;
- if (DEBUG) {
- System.out.println("Found exit: via implicit return: " //$NON-NLS-1$
- + node.toString(false));
- }
- }
-
- return status;
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCallDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCallDetector.java
deleted file mode 100644
index 174f915..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCallDetector.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.tools.lint.checks.JavaPerformanceDetector.ON_DRAW;
-import static com.android.tools.lint.checks.JavaPerformanceDetector.ON_LAYOUT;
-import static com.android.tools.lint.checks.JavaPerformanceDetector.ON_MEASURE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Checks for cases where the wrong call is being made
- */
-public class WrongCallDetector extends Detector implements ClassScanner {
- /** Calling the wrong method */
- public static final Issue ISSUE = Issue.create(
- "WrongCall", //$NON-NLS-1$
- "Finds cases where the wrong call is made, such as calling onMeasure instead of measure",
-
- "Custom views typically need to call `measure()` on their children, not `onMeasure`. " +
- "Ditto for onDraw, onLayout, etc.",
-
- Category.CORRECTNESS,
- 6,
- Severity.ERROR,
- WrongCallDetector.class,
- Scope.CLASS_FILE_SCOPE);
-
- /** Constructs a new {@link WrongCallDetector} */
- public WrongCallDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements ClassScanner ----
-
- @Override
- @Nullable
- public List<String> getApplicableCallNames() {
- return Arrays.asList(
- ON_DRAW,
- ON_MEASURE,
- ON_LAYOUT
- );
- }
-
- @Override
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- String name = call.name;
- // Call is only allowed if it is both only called on the super class (invoke special)
- // as well as within the same overriding method (e.g. you can't call super.onLayout
- // from the onMeasure method)
- if (call.getOpcode() != Opcodes.INVOKESPECIAL || !name.equals(method.name)) {
- String suggestion = Character.toLowerCase(name.charAt(2)) + name.substring(3);
- String message = String.format(
- "Suspicious method call; should probably call \"%1$s\" rather than \"%2$s\"",
- suggestion, name);
- context.report(ISSUE, method, call, context.getLocation(call), message, null);
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCaseDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCaseDetector.java
deleted file mode 100644
index d15af9a..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongCaseDetector.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Element;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Check which looks for missing wrong case usage for certain layout tags.
- *
- * @todo Generalize this to handling spelling errors in general.
- */
-public class WrongCaseDetector extends LayoutDetector {
- /** Using the wrong case for layout tags */
- public static final Issue WRONGCASE = Issue.create(
- "WrongCase", //$NON-NLS-1$
- "Ensures that the correct case is used for special layout tags such as <fragment>",
-
- ""
- + "Most layout tags, such as <Button>, refer to actual view classes and are therefore "
- + "capitalized. However, there are exceptions such as <fragment> and <include>. This "
- + "lint check looks for incorrect capitalizations.",
-
- Category.CORRECTNESS,
- 8,
- Severity.WARNING,
- WrongCaseDetector.class,
- Scope.RESOURCE_FILE_SCOPE)
- .setMoreInfo("http://developer.android.com/guide/components/fragments.html"); //$NON-NLS-1$
-
- /** Constructs a new {@link WrongCaseDetector} */
- public WrongCaseDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(
- "Fragment", //$NON-NLS-1$
- "RequestFocus", //$NON-NLS-1$
- "Include", //$NON-NLS-1$
- "Merge"
- );
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- String tag = element.getTagName();
- String correct = Character.toLowerCase(tag.charAt(0)) + tag.substring(1);
- context.report(WRONGCASE, element, context.getLocation(element),
- String.format("Invalid tag <%1$s>; should be <%2$s>", tag, correct), null);
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongIdDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongIdDetector.java
deleted file mode 100644
index e0e2d0a..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongIdDetector.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_TYPE;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.VALUE_ID;
-import static com.android.tools.lint.detector.api.LintUtils.stripIdPrefix;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.IDomParser;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Location.Handle;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.android.utils.Pair;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Checks for duplicate ids within a layout and within an included layout
- */
-public class WrongIdDetector extends LayoutDetector {
-
- /** Ids bound to widgets in any of the layout files */
- private final Set<String> mGlobalIds = new HashSet<String>(100);
-
- /** Ids bound to widgets in the current layout file */
- private Set<String> mFileIds;
-
- /** Ids declared in a value's file, e.g. {@code <item type="id" name="foo"/>} */
- private Set<String> mDeclaredIds;
-
- /**
- * Location handles for the various id references that were not found as
- * defined in the same layout, to be checked after the whole project has
- * been scanned
- */
- private List<Pair<String, Location.Handle>> mHandles;
-
- /** List of RelativeLayout elements in the current layout */
- private List<Element> mRelativeLayouts;
-
- /** Reference to an unknown id */
- public static final Issue UNKNOWN_ID = Issue.create(
- "UnknownId", //$NON-NLS-1$
- "Checks for id references in RelativeLayouts that are not defined elsewhere",
- "The `@+id/` syntax refers to an existing id, or creates a new one if it has " +
- "not already been defined elsewhere. However, this means that if you have a " +
- "typo in your reference, or if the referred view no longer exists, you do not " +
- "get a warning since the id will be created on demand. This check catches " +
- "errors where you have renamed an id without updating all of the references to " +
- "it.",
- Category.CORRECTNESS,
- 8,
- Severity.FATAL,
- WrongIdDetector.class,
- Scope.ALL_RESOURCES_SCOPE);
-
- /** Reference to an id that is not in the current layout */
- public static final Issue UNKNOWN_ID_LAYOUT = Issue.create(
- "UnknownIdInLayout", //$NON-NLS-1$
- "Makes sure that @+id references refer to views in the same layout",
-
- "The `@+id/` syntax refers to an existing id, or creates a new one if it has " +
- "not already been defined elsewhere. However, this means that if you have a " +
- "typo in your reference, or if the referred view no longer exists, you do not " +
- "get a warning since the id will be created on demand.\n" +
- "\n" +
- "This is sometimes intentional, for example where you are referring to a view " +
- "which is provided in a different layout via an include. However, it is usually " +
- "an accident where you have a typo or you have renamed a view without updating " +
- "all the references to it.",
-
- Category.CORRECTNESS,
- 5,
- Severity.WARNING,
- WrongIdDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a duplicate id check */
- public WrongIdDetector() {
- }
-
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES;
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public Collection<String> getApplicableAttributes() {
- return Collections.singletonList(ATTR_ID);
- }
-
- @Override
- public Collection<String> getApplicableElements() {
- return Arrays.asList(RELATIVE_LAYOUT, TAG_ITEM);
- }
-
- @Override
- public void beforeCheckFile(@NonNull Context context) {
- mFileIds = new HashSet<String>();
- mRelativeLayouts = null;
- }
-
- @Override
- public void afterCheckFile(@NonNull Context context) {
- if (mRelativeLayouts != null) {
- if (!context.getProject().getReportIssues()) {
- // If this is a library project not being analyzed, ignore it
- return;
- }
-
- for (Element layout : mRelativeLayouts) {
- NodeList children = layout.getChildNodes();
- for (int j = 0, childCount = children.getLength(); j < childCount; j++) {
- Node child = children.item(j);
- if (child.getNodeType() != Node.ELEMENT_NODE) {
- continue;
- }
- Element element = (Element) child;
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attr = (Attr) attributes.item(i);
- String value = attr.getValue();
- if ((value.startsWith(NEW_ID_PREFIX) ||
- value.startsWith(ID_PREFIX))
- && ANDROID_URI.equals(attr.getNamespaceURI())
- && attr.getLocalName().startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) {
- if (!idDefined(mFileIds, value)) {
- // Stash a reference to this id and location such that
- // we can check after the *whole* layout has been processed,
- // since it's too early to conclude here that the id does
- // not exist (you are allowed to have forward references)
- XmlContext xmlContext = (XmlContext) context;
- IDomParser parser = xmlContext.parser;
- Handle handle = parser.createLocationHandle(xmlContext, attr);
- handle.setClientData(attr);
-
- if (mHandles == null) {
- mHandles = new ArrayList<Pair<String,Handle>>();
- }
- mHandles.add(Pair.of(value, handle));
- }
- }
- }
- }
- }
- }
-
- mFileIds = null;
- }
-
- @Override
- public void afterCheckProject(@NonNull Context context) {
- if (mHandles != null) {
- boolean checkSameLayout = context.isEnabled(UNKNOWN_ID_LAYOUT);
- boolean checkExists = context.isEnabled(UNKNOWN_ID);
- boolean projectScope = context.getScope().contains(Scope.ALL_RESOURCE_FILES);
- for (Pair<String, Handle> pair : mHandles) {
- String id = pair.getFirst();
- boolean isBound = idDefined(mGlobalIds, id);
- if (!isBound && checkExists && projectScope) {
- Handle handle = pair.getSecond();
- boolean isDeclared = idDefined(mDeclaredIds, id);
- id = stripIdPrefix(id);
- String suggestionMessage;
- List<String> suggestions = getSpellingSuggestions(id, mGlobalIds);
- if (suggestions.size() > 1) {
- suggestionMessage = String.format(" Did you mean one of {%2$s} ?",
- id, Joiner.on(", ").join(suggestions));
- } else if (!suggestions.isEmpty()) {
- suggestionMessage = String.format(" Did you mean %2$s ?",
- id, suggestions.get(0));
- } else {
- suggestionMessage = "";
- }
- String message;
- if (isDeclared) {
- message = String.format(
- "The id \"%1$s\" is defined but not assigned to any views.%2$s",
- id, suggestionMessage);
- } else {
- message = String.format(
- "The id \"%1$s\" is not defined anywhere.%2$s",
- id, suggestionMessage);
- }
- report(context, UNKNOWN_ID, handle, message);
- } else if (checkSameLayout && (!projectScope || isBound)
- && id.startsWith(NEW_ID_PREFIX)) {
- // The id was defined, but in a different layout. Usually not intentional
- // (might be referring to a random other view that happens to have the same
- // name.)
- Handle handle = pair.getSecond();
- report(context, UNKNOWN_ID_LAYOUT, handle,
- String.format(
- "The id \"%1$s\" is not referring to any views in this layout",
- stripIdPrefix(id)));
- }
- }
- }
- }
-
- private static void report(Context context, Issue issue, Handle handle, String message) {
- Location location = handle.resolve();
- Object clientData = handle.getClientData();
- if (clientData instanceof Node) {
- if (context.getDriver().isSuppressed(issue, (Node) clientData)) {
- return;
- }
- }
-
- context.report(issue, location, message, null);
- }
-
- @Override
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- if (element.getTagName().equals(RELATIVE_LAYOUT)) {
- if (mRelativeLayouts == null) {
- mRelativeLayouts = new ArrayList<Element>();
- }
- mRelativeLayouts.add(element);
- } else {
- assert element.getTagName().equals(TAG_ITEM);
- String type = element.getAttribute(ATTR_TYPE);
- if (VALUE_ID.equals(type)) {
- String name = element.getAttribute(ATTR_NAME);
- if (!name.isEmpty()) {
- if (mDeclaredIds == null) {
- mDeclaredIds = Sets.newHashSet();
- }
- mDeclaredIds.add(ID_PREFIX + name);
- }
- }
- }
- }
-
- @Override
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- assert attribute.getName().equals(ATTR_ID) || attribute.getLocalName().equals(ATTR_ID);
- String id = attribute.getValue();
- mFileIds.add(id);
- mGlobalIds.add(id);
- }
-
- private static boolean idDefined(Set<String> ids, String id) {
- if (ids == null) {
- return false;
- }
- boolean definedLocally = ids.contains(id);
- if (!definedLocally) {
- if (id.startsWith(NEW_ID_PREFIX)) {
- definedLocally = ids.contains(ID_PREFIX +
- id.substring(NEW_ID_PREFIX.length()));
- } else if (id.startsWith(ID_PREFIX)) {
- definedLocally = ids.contains(NEW_ID_PREFIX +
- id.substring(ID_PREFIX.length()));
- }
- }
-
- return definedLocally;
- }
-
- private static List<String> getSpellingSuggestions(String id, Collection<String> ids) {
- int maxDistance = id.length() >= 4 ? 2 : 1;
-
- // Look for typos and try to match with custom views and android views
- Multimap<Integer, String> matches = ArrayListMultimap.create(2, 10);
- int count = 0;
- if (!ids.isEmpty()) {
- for (String matchWith : ids) {
- matchWith = stripIdPrefix(matchWith);
- if (Math.abs(id.length() - matchWith.length()) > maxDistance) {
- // The string lengths differ more than the allowed edit distance;
- // no point in even attempting to compute the edit distance (requires
- // O(n*m) storage and O(n*m) speed, where n and m are the string lengths)
- continue;
- }
- int distance = LintUtils.editDistance(id, matchWith);
- if (distance <= maxDistance) {
- matches.put(distance, matchWith);
- }
-
- if (count++ > 100) {
- // Make sure that for huge projects we don't completely grind to a halt
- break;
- }
- }
- }
-
- for (int i = 0; i < maxDistance; i++) {
- Collection<String> strings = matches.get(i);
- if (strings != null && !strings.isEmpty()) {
- List<String> suggestions = new ArrayList<String>(strings);
- Collections.sort(suggestions);
- return suggestions;
- }
- }
-
- return Collections.emptyList();
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongImportDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongImportDetector.java
deleted file mode 100644
index 64f3ce1..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongImportDetector.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-
-import java.util.Collections;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.ImportDeclaration;
-import lombok.ast.Node;
-
-/**
- * Checks for "import android.R", which seems to be a common source of confusion
- * (see for example http://stackoverflow.com/questions/885009/r-cannot-be-resolved-android-error
- * and many other forums).
- * <p>
- * The root cause is probably this (from http://source.android.com/source/using-eclipse.html) :
- * <blockquote> Note: Eclipse sometimes likes to add an import android.R
- * statement at the top of your files that use resources, especially when you
- * ask eclipse to sort or otherwise manage imports. This will cause your make to
- * break. Look out for these erroneous import statements and delete them.
- * </blockquote>
- */
-public class WrongImportDetector extends Detector implements Detector.JavaScanner {
- /** Is android.R being imported? */
- public static final Issue ISSUE = Issue.create("SuspiciousImport", //$NON-NLS-1$
- "Checks for 'import android.R' statements, which are usually accidental",
- "Importing `android.R` is usually not intentional; it sometimes happens when " +
- "you use an IDE and ask it to automatically add imports at a time when your " +
- "project's R class it not present.\n" +
- "\n" +
- "Once the import is there you might get a lot of \"confusing\" error messages " +
- "because of course the fields available on `android.R` are not the ones you'd " +
- "expect from just looking at your own `R` class.",
- Category.CORRECTNESS,
- 9,
- Severity.WARNING,
- WrongImportDetector.class,
- Scope.JAVA_FILE_SCOPE);
-
- /** Constructs a new {@link WrongImportDetector} check */
- public WrongImportDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- // ---- Implements Detector.JavaScanner ----
-
- @Override
- public List<Class<? extends Node>> getApplicableNodeTypes() {
- return Collections.<Class<? extends Node>> singletonList(
- ImportDeclaration.class);
- }
-
- @Override
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return new ImportVisitor(context);
- }
-
- private static class ImportVisitor extends ForwardingAstVisitor {
- private final JavaContext mContext;
-
- public ImportVisitor(JavaContext context) {
- super();
- mContext = context;
- }
-
- @Override
- public boolean visitImportDeclaration(ImportDeclaration node) {
- String fqn = node.asFullyQualifiedName();
- if (fqn.equals("android.R")) { //$NON-NLS-1$
- Location location = mContext.getLocation(node);
- mContext.report(ISSUE, node, location,
- "Don't include android.R here; use a fully qualified name for "
- + "each usage instead", null);
- }
- return false;
- }
- }
-}
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongLocationDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongLocationDetector.java
deleted file mode 100644
index 37ffbeb..0000000
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/WrongLocationDetector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.tools.lint.checks;
-
-import static com.android.SdkConstants.TAG_RESOURCES;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LayoutDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.Speed;
-import com.android.tools.lint.detector.api.XmlContext;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-/** Looks for problems with XML files being placed in the wrong folder */
-public class WrongLocationDetector extends LayoutDetector {
- /** Main issue investigated by this detector */
- public static final Issue ISSUE = Issue.create(
- "WrongFolder", //$NON-NLS-1$
-
- "Finds resource files that are placed in the wrong folders",
-
- "Resource files are sometimes placed in the wrong folder, and it can lead to " +
- "subtle bugs that are hard to understand. This check looks for problems in this " +
- "area, such as attempting to place a layout \"alias\" file in a `layout/` folder " +
- "rather than the `values/` folder where it belongs.",
- Category.CORRECTNESS,
- 8,
- Severity.ERROR,
- WrongLocationDetector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /** Constructs a new {@link WrongLocationDetector} check */
- public WrongLocationDetector() {
- }
-
- @NonNull
- @Override
- public Speed getSpeed() {
- return Speed.FAST;
- }
-
- @Override
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- Element root = document.getDocumentElement();
- if (root != null && root.getTagName().equals(TAG_RESOURCES)) {
- context.report(ISSUE, root, context.getLocation(root),
- "This file should be placed in a values/ folder, not a layout/ folder", null);
- }
- }
-}
diff --git a/manifmerger/Android.mk b/manifmerger/Android.mk
index b1f1ac7..b07af36 100644
--- a/manifmerger/Android.mk
+++ b/manifmerger/Android.mk
@@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# The manifest-merger code has moved to tools/base/manifmerger.
-# The rule below uses the prebuilt manifmerger.jar if found.
+# The rule below uses the prebuilt manifmerger.jar.
#
# If you want to run the tests, cd to tools/base/manifmerger
# and run ./gradlew :manifmerger:test
@@ -26,7 +26,7 @@ LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := common sdklib
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java b/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java
index 894408c..5dc7e7b 100644
--- a/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java
+++ b/monkeyrunner/src/com/android/monkeyrunner/MonkeyDevice.java
@@ -66,6 +66,9 @@ public class MonkeyDevice extends PyObject implements ClassDictInit {
@MonkeyRunnerExported(doc = "Sends a DOWN event, immediately followed by an UP event when used with touch() or press()")
public static final String DOWN_AND_UP = TouchPressType.DOWN_AND_UP.getIdentifier();
+ @MonkeyRunnerExported(doc = "Sends a MOVE event when used with touch().")
+ public static final String MOVE = TouchPressType.MOVE.getIdentifier();
+
private IChimpDevice impl;
public MonkeyDevice(IChimpDevice impl) {
diff --git a/sdk_common/.classpath b/sdk_common/.classpath
index 1afd216..e5bbc54 100644
--- a/sdk_common/.classpath
+++ b/sdk_common/.classpath
@@ -6,6 +6,6 @@
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar" sourcepath="/ANDROID_SRC/prebuilts/tools/common/guava-tools/src.zip"/>
<classpathentry combineaccessrules="false" kind="src" path="/common"/>
- <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/sdklib"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/sdk_common/Android.mk b/sdk_common/Android.mk
index 51c5919..17c78cb 100644
--- a/sdk_common/Android.mk
+++ b/sdk_common/Android.mk
@@ -16,7 +16,11 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
+# The sdk_common code has moved to tools/base/sdk_common.
+# The rule below uses the prebuilt sdk_common.jar.
+#
+# If you want to run the tests, cd to tools/base/sdk_common
+# and run ./gradlew :sdk_common:test
LOCAL_JAVA_LIBRARIES := \
layoutlib_api \
@@ -26,7 +30,10 @@ LOCAL_JAVA_LIBRARIES := \
sdklib
LOCAL_MODULE := sdk_common
-
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_PREBUILT_JAVA_LIBRARIES := \
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/sdk_common/src/com/android/ide/common/rendering/HardwareConfigHelper.java b/sdk_common/src/com/android/ide/common/rendering/HardwareConfigHelper.java
deleted file mode 100644
index afca8fe..0000000
--- a/sdk_common/src/com/android/ide/common/rendering/HardwareConfigHelper.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering;
-
-import com.android.annotations.NonNull;
-import com.android.ide.common.rendering.api.HardwareConfig;
-import com.android.resources.ScreenOrientation;
-import com.android.sdklib.devices.ButtonType;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.Screen;
-
-/**
- * Helper method to create a {@link HardwareConfig} object.
- *
- * The base data comes from a {@link Device} object, with additional data provided on the helper
- * object.
- *
- * Since {@link HardwareConfig} is immutable, this allows creating one in several (optional)
- * steps more easily.
- *
- */
-public class HardwareConfigHelper {
-
- private final @NonNull Device mDevice;
- private @NonNull ScreenOrientation mScreenOrientation = ScreenOrientation.PORTRAIT;
-
- // optional
- private int mMaxRenderWidth = -1;
- private int mMaxRenderHeight = -1;
- private int mOverrideRenderWidth = -1;
- private int mOverrideRenderHeight = -1;
-
- /**
- * Creates a new helper for a given device.
- * @param device the device to provide the base data.
- */
- public HardwareConfigHelper(@NonNull Device device) {
- mDevice = device;
- }
-
- /**
- * Sets the orientation of the config.
- * @param screenOrientation the orientation.
- * @return this (such that chains of setters can be stringed together)
- */
- @NonNull
- public HardwareConfigHelper setOrientation(@NonNull ScreenOrientation screenOrientation) {
- mScreenOrientation = screenOrientation;
- return this;
- }
-
- /**
- * Overrides the width and height to be used during rendering.
- *
- * A value of -1 will make the rendering use the normal width and height coming from the
- * {@link Device} object.
- *
- * @param overrideRenderWidth the width in pixels of the layout to be rendered
- * @param overrideRenderHeight the height in pixels of the layout to be rendered
- * @return this (such that chains of setters can be stringed together)
- */
- @NonNull
- public HardwareConfigHelper setOverrideRenderSize(int overrideRenderWidth,
- int overrideRenderHeight) {
- mOverrideRenderWidth = overrideRenderWidth;
- mOverrideRenderHeight = overrideRenderHeight;
- return this;
- }
-
- /**
- * Sets the max width and height to be used during rendering.
- *
- * A value of -1 will make the rendering use the normal width and height coming from the
- * {@link Device} object.
- *
- * @param maxRenderWidth the max width in pixels of the layout to be rendered
- * @param maxRenderHeight the max height in pixels of the layout to be rendered
- * @return this (such that chains of setters can be stringed together)
- */
- @NonNull
- public HardwareConfigHelper setMaxRenderSize(int maxRenderWidth, int maxRenderHeight) {
- mMaxRenderWidth = maxRenderWidth;
- mMaxRenderHeight = maxRenderHeight;
- return this;
- }
-
- /**
- * Creates and returns the HardwareConfig object.
- * @return the config
- */
- @NonNull
- public HardwareConfig getConfig() {
- Screen screen = mDevice.getDefaultHardware().getScreen();
-
- // compute width and height to take orientation into account.
- int x = screen.getXDimension();
- int y = screen.getYDimension();
- int width, height;
-
- if (x > y) {
- if (mScreenOrientation == ScreenOrientation.LANDSCAPE) {
- width = x;
- height = y;
- } else {
- width = y;
- height = x;
- }
- } else {
- if (mScreenOrientation == ScreenOrientation.LANDSCAPE) {
- width = y;
- height = x;
- } else {
- width = x;
- height = y;
- }
- }
-
- if (mOverrideRenderHeight != -1) {
- width = mOverrideRenderWidth;
- }
-
- if (mOverrideRenderHeight != -1) {
- height = mOverrideRenderHeight;
- }
-
- if (mMaxRenderWidth != -1) {
- width = mMaxRenderWidth;
- }
-
- if (mMaxRenderHeight != -1) {
- height = mMaxRenderHeight;
- }
-
- return new HardwareConfig(
- width,
- height,
- screen.getPixelDensity(),
- (float) screen.getXdpi(),
- (float) screen.getYdpi(),
- screen.getSize(),
- mScreenOrientation,
- mDevice.getDefaultHardware().getButtonType() == ButtonType.SOFT);
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/rendering/LayoutLibrary.java b/sdk_common/src/com/android/ide/common/rendering/LayoutLibrary.java
deleted file mode 100644
index 0a353f9..0000000
--- a/sdk_common/src/com/android/ide/common/rendering/LayoutLibrary.java
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering;
-
-import static com.android.ide.common.rendering.api.Result.Status.ERROR_REFLECTION;
-
-import com.android.ide.common.rendering.api.Bridge;
-import com.android.ide.common.rendering.api.Capability;
-import com.android.ide.common.rendering.api.DrawableParams;
-import com.android.ide.common.rendering.api.ILayoutPullParser;
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.RenderSession;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.Result.Status;
-import com.android.ide.common.rendering.api.SessionParams;
-import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
-import com.android.ide.common.rendering.api.ViewInfo;
-import com.android.ide.common.rendering.legacy.ILegacyPullParser;
-import com.android.ide.common.rendering.legacy.LegacyCallback;
-import com.android.ide.common.resources.ResourceResolver;
-import com.android.ide.common.sdk.LoadStatus;
-import com.android.layoutlib.api.ILayoutBridge;
-import com.android.layoutlib.api.ILayoutLog;
-import com.android.layoutlib.api.ILayoutResult;
-import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IXmlPullParser;
-import com.android.resources.ResourceType;
-import com.android.utils.ILogger;
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Class to use the Layout library.
- * <p/>
- * Use {@link #load(String, ILogger)} to load the jar file.
- * <p/>
- * Use the layout library with:
- * {@link #init(String, Map)}, {@link #supports(Capability)}, {@link #createSession(SessionParams)},
- * {@link #dispose()}, {@link #clearCaches(Object)}.
- *
- * <p/>
- * For client wanting to access both new and old (pre API level 5) layout libraries, it is
- * important that the following interfaces be used:<br>
- * {@link ILegacyPullParser} instead of {@link ILayoutPullParser}<br>
- * {@link LegacyCallback} instead of {@link com.android.ide.common.rendering.api.IProjectCallback}.
- * <p/>
- * These interfaces will ensure that both new and older Layout libraries can be accessed.
- */
-@SuppressWarnings("deprecation")
-public class LayoutLibrary {
-
- public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$
-
- /** Link to the layout bridge */
- private final Bridge mBridge;
- /** Link to a ILayoutBridge in case loaded an older library */
- private final ILayoutBridge mLegacyBridge;
- /** Status of the layoutlib.jar loading */
- private final LoadStatus mStatus;
- /** Message associated with the {@link LoadStatus}. This is mostly used when
- * {@link #getStatus()} returns {@link LoadStatus#FAILED}.
- */
- private final String mLoadMessage;
- /** classloader used to load the jar file */
- private final ClassLoader mClassLoader;
-
- // Reflection data for older Layout Libraries.
- private Method mViewGetParentMethod;
- private Method mViewGetBaselineMethod;
- private Method mViewParentIndexOfChildMethod;
- private Class<?> mMarginLayoutParamClass;
- private Field mLeftMarginField;
- private Field mTopMarginField;
- private Field mRightMarginField;
- private Field mBottomMarginField;
-
- /**
- * Returns the {@link LoadStatus} of the loading of the layoutlib jar file.
- */
- public LoadStatus getStatus() {
- return mStatus;
- }
-
- /** Returns the message associated with the {@link LoadStatus}. This is mostly used when
- * {@link #getStatus()} returns {@link LoadStatus#FAILED}.
- */
- public String getLoadMessage() {
- return mLoadMessage;
- }
-
- /**
- * Returns the classloader used to load the classes in the layoutlib jar file.
- */
- public ClassLoader getClassLoader() {
- return mClassLoader;
- }
-
- /**
- * Loads the layoutlib.jar file located at the given path and returns a {@link LayoutLibrary}
- * object representing the result.
- * <p/>
- * If loading failed {@link #getStatus()} will reflect this, and {@link #getBridge()} will
- * return null.
- *
- * @param layoutLibJarOsPath the path of the jar file
- * @param log an optional log file.
- * @return a {@link LayoutLibrary} object always.
- */
- public static LayoutLibrary load(String layoutLibJarOsPath, ILogger log, String toolName) {
-
- LoadStatus status = LoadStatus.LOADING;
- String message = null;
- Bridge bridge = null;
- ILayoutBridge legacyBridge = null;
- ClassLoader classLoader = null;
-
- try {
- // get the URL for the file.
- File f = new File(layoutLibJarOsPath);
- if (f.isFile() == false) {
- if (log != null) {
- log.error(null, "layoutlib.jar is missing!"); //$NON-NLS-1$
- }
- } else {
- URI uri = f.toURI();
- URL url = uri.toURL();
-
- // create a class loader. Because this jar reference interfaces
- // that are in the editors plugin, it's important to provide
- // a parent class loader.
- classLoader = new URLClassLoader(
- new URL[] { url },
- LayoutLibrary.class.getClassLoader());
-
- // load the class
- Class<?> clazz = classLoader.loadClass(CLASS_BRIDGE);
- if (clazz != null) {
- // instantiate an object of the class.
- Constructor<?> constructor = clazz.getConstructor();
- if (constructor != null) {
- Object bridgeObject = constructor.newInstance();
- if (bridgeObject instanceof Bridge) {
- bridge = (Bridge)bridgeObject;
- } else if (bridgeObject instanceof ILayoutBridge) {
- legacyBridge = (ILayoutBridge) bridgeObject;
- }
- }
- }
-
- if (bridge == null && legacyBridge == null) {
- status = LoadStatus.FAILED;
- message = "Failed to load " + CLASS_BRIDGE; //$NON-NLS-1$
- if (log != null) {
- log.error(null,
- "Failed to load " + //$NON-NLS-1$
- CLASS_BRIDGE +
- " from " + //$NON-NLS-1$
- layoutLibJarOsPath);
- }
- } else {
- // mark the lib as loaded, unless it's overridden below.
- status = LoadStatus.LOADED;
-
- // check the API, only if it's not a legacy bridge
- if (bridge != null) {
- int api = bridge.getApiLevel();
- if (api > Bridge.API_CURRENT) {
- status = LoadStatus.FAILED;
- message = String.format(
- "This version of the rendering library is more recent than your version of %1$s. Please update %1$s", toolName);
- }
- }
- }
- }
- } catch (Throwable t) {
- status = LoadStatus.FAILED;
- Throwable cause = t;
- while (cause.getCause() != null) {
- cause = cause.getCause();
- }
- message = "Failed to load the LayoutLib: " + cause.getMessage();
- // log the error.
- if (log != null) {
- log.error(t, message);
- }
- }
-
- return new LayoutLibrary(bridge, legacyBridge, classLoader, status, message);
- }
-
- // ------ Layout Lib API proxy
-
- /**
- * Returns the API level of the layout library.
- */
- public int getApiLevel() {
- if (mBridge != null) {
- return mBridge.getApiLevel();
- }
-
- if (mLegacyBridge != null) {
- return getLegacyApiLevel();
- }
-
- return 0;
- }
-
- /**
- * Returns the revision of the library inside a given (layoutlib) API level.
- * The true version number of the library is {@link #getApiLevel()}.{@link #getRevision()}
- */
- public int getRevision() {
- if (mBridge != null) {
- return mBridge.getRevision();
- }
-
- return 0;
- }
-
- /**
- * Returns whether the LayoutLibrary supports a given {@link Capability}.
- * @return true if it supports it.
- *
- * @see Bridge#getCapabilities()
- *
- */
- public boolean supports(Capability capability) {
- if (mBridge != null) {
- return mBridge.getCapabilities().contains(capability);
- }
-
- if (mLegacyBridge != null) {
- switch (capability) {
- case UNBOUND_RENDERING:
- // legacy stops at 4. 5 is new API.
- return getLegacyApiLevel() == 4;
- }
- }
-
- return false;
- }
-
- /**
- * Initializes the Layout Library object. This must be called before any other action is taken
- * on the instance.
- *
- * @param platformProperties The build properties for the platform.
- * @param fontLocation the location of the fonts in the SDK target.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }. This is typically
- * read from attrs.xml in the SDK target.
- * @param log a {@link LayoutLog} object. Can be null.
- * @return true if success.
- *
- * @see Bridge#init(String, Map)
- */
- public boolean init(Map<String, String> platformProperties,
- File fontLocation,
- Map<String, Map<String, Integer>> enumValueMap,
- LayoutLog log) {
- if (mBridge != null) {
- return mBridge.init(platformProperties, fontLocation, enumValueMap, log);
- } else if (mLegacyBridge != null) {
- return mLegacyBridge.init(fontLocation.getAbsolutePath(), enumValueMap);
- }
-
- return false;
- }
-
- /**
- * Prepares the layoutlib to unloaded.
- *
- * @see Bridge#dispose()
- */
- public boolean dispose() {
- if (mBridge != null) {
- return mBridge.dispose();
- }
-
- return true;
- }
-
- /**
- * Starts a layout session by inflating and rendering it. The method returns a
- * {@link RenderSession} on which further actions can be taken.
- * <p/>
- * Before taking further actions on the scene, it is recommended to use
- * {@link #supports(Capability)} to check what the scene can do.
- *
- * @return a new {@link ILayoutScene} object that contains the result of the scene creation and
- * first rendering or null if {@link #getStatus()} doesn't return {@link LoadStatus#LOADED}.
- *
- * @see Bridge#createSession(SessionParams)
- */
- public RenderSession createSession(SessionParams params) {
- if (mBridge != null) {
- RenderSession session = mBridge.createSession(params);
- if (params.getExtendedViewInfoMode() &&
- mBridge.getCapabilities().contains(Capability.EXTENDED_VIEWINFO) == false) {
- // Extended view info was requested but the layoutlib does not support it.
- // Add it manually.
- List<ViewInfo> infoList = session.getRootViews();
- if (infoList != null) {
- for (ViewInfo info : infoList) {
- addExtendedViewInfo(info);
- }
- }
- }
-
- return session;
- } else if (mLegacyBridge != null) {
- return createLegacySession(params);
- }
-
- return null;
- }
-
- /**
- * Renders a Drawable. If the rendering is successful, the result image is accessible through
- * {@link Result#getData()}. It is of type {@link BufferedImage}
- * @param params the rendering parameters.
- * @return the result of the action.
- */
- public Result renderDrawable(DrawableParams params) {
- if (mBridge != null) {
- return mBridge.renderDrawable(params);
- }
-
- return Status.NOT_IMPLEMENTED.createResult();
- }
-
- /**
- * Clears the resource cache for a specific project.
- * <p/>This cache contains bitmaps and nine patches that are loaded from the disk and reused
- * until this method is called.
- * <p/>The cache is not configuration dependent and should only be cleared when a
- * resource changes (at this time only bitmaps and 9 patches go into the cache).
- *
- * @param projectKey the key for the project.
- *
- * @see Bridge#clearCaches(Object)
- */
- public void clearCaches(Object projectKey) {
- if (mBridge != null) {
- mBridge.clearCaches(projectKey);
- } else if (mLegacyBridge != null) {
- mLegacyBridge.clearCaches(projectKey);
- }
- }
-
- /**
- * Utility method returning the parent of a given view object.
- *
- * @param viewObject the object for which to return the parent.
- *
- * @return a {@link Result} indicating the status of the action, and if success, the parent
- * object in {@link Result#getData()}
- */
- public Result getViewParent(Object viewObject) {
- if (mBridge != null) {
- Result r = mBridge.getViewParent(viewObject);
- if (r.isSuccess()) {
- return r;
- }
- }
-
- return getViewParentWithReflection(viewObject);
- }
-
- /**
- * Utility method returning the index of a given view in its parent.
- * @param viewObject the object for which to return the index.
- *
- * @return a {@link Result} indicating the status of the action, and if success, the index in
- * the parent in {@link Result#getData()}
- */
- public Result getViewIndex(Object viewObject) {
- if (mBridge != null) {
- Result r = mBridge.getViewIndex(viewObject);
- if (r.isSuccess()) {
- return r;
- }
- }
-
- return getViewIndexReflection(viewObject);
- }
-
- // ------ Implementation
-
- private LayoutLibrary(Bridge bridge, ILayoutBridge legacyBridge, ClassLoader classLoader,
- LoadStatus status, String message) {
- mBridge = bridge;
- mLegacyBridge = legacyBridge;
- mClassLoader = classLoader;
- mStatus = status;
- mLoadMessage = message;
- }
-
- /**
- * Returns the API level of the legacy bridge.
- * <p/>
- * This handles the case where ILayoutBridge does not have a {@link ILayoutBridge#getApiLevel()}
- * (at API level 1).
- * <p/>
- * {@link ILayoutBridge#getApiLevel()} should never called directly.
- *
- * @return the api level of {@link #mLegacyBridge}.
- */
- private int getLegacyApiLevel() {
- int apiLevel = 1;
- try {
- apiLevel = mLegacyBridge.getApiLevel();
- } catch (AbstractMethodError e) {
- // the first version of the api did not have this method
- // so this is 1
- }
-
- return apiLevel;
- }
-
- private RenderSession createLegacySession(SessionParams params) {
- if (params.getLayoutDescription() instanceof IXmlPullParser == false) {
- throw new IllegalArgumentException("Parser must be of type ILegacyPullParser");
- }
- if (params.getProjectCallback() instanceof
- com.android.layoutlib.api.IProjectCallback == false) {
- throw new IllegalArgumentException("Project callback must be of type ILegacyCallback");
- }
-
- if (params.getResources() instanceof ResourceResolver == false) {
- throw new IllegalArgumentException("RenderResources object must be of type ResourceResolver");
- }
-
- ResourceResolver resources = (ResourceResolver) params.getResources();
-
- int apiLevel = getLegacyApiLevel();
-
- // create a log wrapper since the older api requires a ILayoutLog
- final LayoutLog log = params.getLog();
- ILayoutLog logWrapper = new ILayoutLog() {
-
- @Override
- public void warning(String message) {
- log.warning(null, message, null /*data*/);
- }
-
- @Override
- public void error(Throwable t) {
- log.error(null, "error!", t, null /*data*/);
- }
-
- @Override
- public void error(String message) {
- log.error(null, message, null /*data*/);
- }
- };
-
-
- // convert the map of ResourceValue into IResourceValue. Super ugly but works.
-
- Map<String, Map<String, IResourceValue>> projectMap = convertMap(
- resources.getProjectResources());
- Map<String, Map<String, IResourceValue>> frameworkMap = convertMap(
- resources.getFrameworkResources());
-
- ILayoutResult result = null;
-
- if (apiLevel == 4) {
- // Final ILayoutBridge API added support for "render full height"
- result = mLegacyBridge.computeLayout(
- (IXmlPullParser) params.getLayoutDescription(),
- params.getProjectKey(),
- params.getScreenWidth(), params.getScreenHeight(),
- params.getRenderingMode() == RenderingMode.FULL_EXPAND ? true : false,
- params.getDensity().getDpiValue(), params.getXdpi(), params.getYdpi(),
- resources.getThemeName(), resources.isProjectTheme(),
- projectMap, frameworkMap,
- (IProjectCallback) params.getProjectCallback(),
- logWrapper);
- } else if (apiLevel == 3) {
- // api 3 add density support.
- result = mLegacyBridge.computeLayout(
- (IXmlPullParser) params.getLayoutDescription(), params.getProjectKey(),
- params.getScreenWidth(), params.getScreenHeight(),
- params.getDensity().getDpiValue(), params.getXdpi(), params.getYdpi(),
- resources.getThemeName(), resources.isProjectTheme(),
- projectMap, frameworkMap,
- (IProjectCallback) params.getProjectCallback(), logWrapper);
- } else if (apiLevel == 2) {
- // api 2 added boolean for separation of project/framework theme
- result = mLegacyBridge.computeLayout(
- (IXmlPullParser) params.getLayoutDescription(), params.getProjectKey(),
- params.getScreenWidth(), params.getScreenHeight(),
- resources.getThemeName(), resources.isProjectTheme(),
- projectMap, frameworkMap,
- (IProjectCallback) params.getProjectCallback(), logWrapper);
- } else {
- // First api with no density/dpi, and project theme boolean mixed
- // into the theme name.
-
- // change the string if it's a custom theme to make sure we can
- // differentiate them
- String themeName = resources.getThemeName();
- if (resources.isProjectTheme()) {
- themeName = "*" + themeName; //$NON-NLS-1$
- }
-
- result = mLegacyBridge.computeLayout(
- (IXmlPullParser) params.getLayoutDescription(), params.getProjectKey(),
- params.getScreenWidth(), params.getScreenHeight(),
- themeName,
- projectMap, frameworkMap,
- (IProjectCallback) params.getProjectCallback(), logWrapper);
- }
-
- // clean up that is not done by the ILayoutBridge itself
- legacyCleanUp();
-
- return convertToScene(result);
- }
-
- @SuppressWarnings("unchecked")
- private Map<String, Map<String, IResourceValue>> convertMap(
- Map<ResourceType, Map<String, ResourceValue>> map) {
- Map<String, Map<String, IResourceValue>> result =
- new HashMap<String, Map<String, IResourceValue>>();
-
- for (Entry<ResourceType, Map<String, ResourceValue>> entry : map.entrySet()) {
- // ugly case but works.
- result.put(entry.getKey().getName(),
- (Map) entry.getValue());
- }
-
- return result;
- }
-
- /**
- * Converts a {@link ILayoutResult} to a {@link RenderSession}.
- */
- private RenderSession convertToScene(ILayoutResult result) {
-
- Result sceneResult;
- ViewInfo rootViewInfo = null;
-
- if (result.getSuccess() == ILayoutResult.SUCCESS) {
- sceneResult = Status.SUCCESS.createResult();
- ILayoutViewInfo oldRootView = result.getRootView();
- if (oldRootView != null) {
- rootViewInfo = convertToViewInfo(oldRootView);
- }
- } else {
- sceneResult = Status.ERROR_UNKNOWN.createResult(result.getErrorMessage());
- }
-
- // create a BasicLayoutScene. This will return the given values but return the default
- // implementation for all method.
- // ADT should gracefully handle the default implementations of LayoutScene
- return new StaticRenderSession(sceneResult, rootViewInfo, result.getImage());
- }
-
- /**
- * Converts a {@link ILayoutViewInfo} (and its children) to a {@link ViewInfo}.
- */
- private ViewInfo convertToViewInfo(ILayoutViewInfo view) {
- // create the view info.
- ViewInfo viewInfo = new ViewInfo(view.getName(), view.getViewKey(),
- view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-
- // then convert the children
- ILayoutViewInfo[] children = view.getChildren();
- if (children != null) {
- ArrayList<ViewInfo> convertedChildren = new ArrayList<ViewInfo>(children.length);
- for (ILayoutViewInfo child : children) {
- convertedChildren.add(convertToViewInfo(child));
- }
- viewInfo.setChildren(convertedChildren);
- }
-
- return viewInfo;
- }
-
- /**
- * Post rendering clean-up that must be done here because it's not done in any layoutlib using
- * {@link ILayoutBridge}.
- */
- private void legacyCleanUp() {
- try {
- Class<?> looperClass = mClassLoader.loadClass("android.os.Looper"); //$NON-NLS-1$
- Field threadLocalField = looperClass.getField("sThreadLocal"); //$NON-NLS-1$
- if (threadLocalField != null) {
- threadLocalField.setAccessible(true);
- // get object. Field is static so no need to pass an object
- ThreadLocal<?> threadLocal = (ThreadLocal<?>) threadLocalField.get(null);
- if (threadLocal != null) {
- threadLocal.remove();
- }
- }
- } catch (Exception e) {
- // do nothing.
- }
- }
-
- private Result getViewParentWithReflection(Object viewObject) {
- // default implementation using reflection.
- try {
- if (mViewGetParentMethod == null) {
- Class<?> viewClass = Class.forName("android.view.View");
- mViewGetParentMethod = viewClass.getMethod("getParent");
- }
-
- return Status.SUCCESS.createResult(mViewGetParentMethod.invoke(viewObject));
- } catch (Exception e) {
- // Catch all for the reflection calls.
- return ERROR_REFLECTION.createResult(null, e);
- }
- }
-
- /**
- * Utility method returning the index of a given view in its parent.
- * @param viewObject the object for which to return the index.
- *
- * @return a {@link Result} indicating the status of the action, and if success, the index in
- * the parent in {@link Result#getData()}
- */
- private Result getViewIndexReflection(Object viewObject) {
- // default implementation using reflection.
- try {
- Class<?> viewClass = Class.forName("android.view.View");
-
- if (mViewGetParentMethod == null) {
- mViewGetParentMethod = viewClass.getMethod("getParent");
- }
-
- Object parentObject = mViewGetParentMethod.invoke(viewObject);
-
- if (mViewParentIndexOfChildMethod == null) {
- Class<?> viewParentClass = Class.forName("android.view.ViewParent");
- mViewParentIndexOfChildMethod = viewParentClass.getMethod("indexOfChild",
- viewClass);
- }
-
- return Status.SUCCESS.createResult(
- mViewParentIndexOfChildMethod.invoke(parentObject, viewObject));
- } catch (Exception e) {
- // Catch all for the reflection calls.
- return ERROR_REFLECTION.createResult(null, e);
- }
- }
-
- private void addExtendedViewInfo(ViewInfo info) {
- computeExtendedViewInfo(info);
-
- List<ViewInfo> children = info.getChildren();
- for (ViewInfo child : children) {
- addExtendedViewInfo(child);
- }
- }
-
- private void computeExtendedViewInfo(ViewInfo info) {
- Object viewObject = info.getViewObject();
- Object params = info.getLayoutParamsObject();
-
- int baseLine = getViewBaselineReflection(viewObject);
- int leftMargin = 0;
- int topMargin = 0;
- int rightMargin = 0;
- int bottomMargin = 0;
-
- try {
- if (mMarginLayoutParamClass == null) {
- mMarginLayoutParamClass = Class.forName(
- "android.view.ViewGroup$MarginLayoutParams");
-
- mLeftMarginField = mMarginLayoutParamClass.getField("leftMargin");
- mTopMarginField = mMarginLayoutParamClass.getField("topMargin");
- mRightMarginField = mMarginLayoutParamClass.getField("rightMargin");
- mBottomMarginField = mMarginLayoutParamClass.getField("bottomMargin");
- }
-
- if (mMarginLayoutParamClass.isAssignableFrom(params.getClass())) {
-
- leftMargin = (Integer)mLeftMarginField.get(params);
- topMargin = (Integer)mTopMarginField.get(params);
- rightMargin = (Integer)mRightMarginField.get(params);
- bottomMargin = (Integer)mBottomMarginField.get(params);
- }
-
- } catch (Exception e) {
- // just use 'unknown' value.
- leftMargin = Integer.MIN_VALUE;
- topMargin = Integer.MIN_VALUE;
- rightMargin = Integer.MIN_VALUE;
- bottomMargin = Integer.MIN_VALUE;
- }
-
- info.setExtendedInfo(baseLine, leftMargin, topMargin, rightMargin, bottomMargin);
- }
-
- /**
- * Utility method returning the baseline value for a given view object. This basically returns
- * View.getBaseline().
- *
- * @param viewObject the object for which to return the index.
- *
- * @return the baseline value or -1 if not applicable to the view object or if this layout
- * library does not implement this method.
- */
- private int getViewBaselineReflection(Object viewObject) {
- // default implementation using reflection.
- try {
- if (mViewGetBaselineMethod == null) {
- Class<?> viewClass = Class.forName("android.view.View");
- mViewGetBaselineMethod = viewClass.getMethod("getBaseline");
- }
-
- Object result = mViewGetBaselineMethod.invoke(viewObject);
- if (result instanceof Integer) {
- return ((Integer)result).intValue();
- }
-
- } catch (Exception e) {
- // Catch all for the reflection calls.
- }
-
- return Integer.MIN_VALUE;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/rendering/StaticRenderSession.java b/sdk_common/src/com/android/ide/common/rendering/StaticRenderSession.java
deleted file mode 100644
index c122c1c..0000000
--- a/sdk_common/src/com/android/ide/common/rendering/StaticRenderSession.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering;
-
-import com.android.ide.common.rendering.api.RenderSession;
-import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.ViewInfo;
-
-import java.awt.image.BufferedImage;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Static {@link RenderSession} returning a given {@link Result}, {@link ViewInfo} and
- * {@link BufferedImage}.
- * <p/>
- * All other methods are untouched from the base implementation provided by the API.
- * <p/>
- * This is meant to be used as a wrapper around the static results. No further operations are
- * possible.
- *
- */
-public class StaticRenderSession extends RenderSession {
-
- private final Result mResult;
- private final List<ViewInfo> mRootViewInfo;
- private final BufferedImage mImage;
-
- public StaticRenderSession(Result result, ViewInfo rootViewInfo, BufferedImage image) {
- mResult = result;
- mRootViewInfo = Collections.singletonList(rootViewInfo);
- mImage = image;
- }
-
- @Override
- public Result getResult() {
- return mResult;
- }
-
- @Override
- public List<ViewInfo> getRootViews() {
- return mRootViewInfo;
- }
-
- @Override
- public BufferedImage getImage() {
- return mImage;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/rendering/legacy/ILegacyPullParser.java b/sdk_common/src/com/android/ide/common/rendering/legacy/ILegacyPullParser.java
deleted file mode 100644
index a71e190..0000000
--- a/sdk_common/src/com/android/ide/common/rendering/legacy/ILegacyPullParser.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.legacy;
-
-import com.android.ide.common.rendering.api.ILayoutPullParser;
-import com.android.layoutlib.api.IXmlPullParser;
-
-/**
- * Intermediary interface extending both old and new project pull parsers from the layout lib API.
- *
- * Clients should use this instead of {@link ILayoutPullParser} or {@link IXmlPullParser}.
- *
- */
-@SuppressWarnings("deprecation")
-public interface ILegacyPullParser extends ILayoutPullParser, IXmlPullParser {
-
-}
diff --git a/sdk_common/src/com/android/ide/common/rendering/legacy/LegacyCallback.java b/sdk_common/src/com/android/ide/common/rendering/legacy/LegacyCallback.java
deleted file mode 100644
index 67e6a7b..0000000
--- a/sdk_common/src/com/android/ide/common/rendering/legacy/LegacyCallback.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.rendering.legacy;
-
-import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.resources.ResourceType;
-import com.android.util.Pair;
-
-/**
- * Intermediary class implementing parts of both the old and new project call back from the
- * layout lib API.
- *
- * Clients should use this instead of {@link IProjectCallback} to target both old and new
- * Layout Libraries.
- *
- */
-@SuppressWarnings("deprecation")
-public abstract class LegacyCallback implements
- com.android.ide.common.rendering.api.IProjectCallback,
- com.android.layoutlib.api.IProjectCallback {
-
- // ------ implementation of the old interface using the new interface.
-
- @Override
- public final Integer getResourceValue(String type, String name) {
- return getResourceId(ResourceType.getEnum(type), name);
- }
-
- @Override
- public final String[] resolveResourceValue(int id) {
- Pair<ResourceType, String> info = resolveResourceId(id);
- if (info != null) {
- return new String[] { info.getSecond(), info.getFirst().getName() };
- }
-
- return null;
- }
-
- @Override
- public final String resolveResourceValue(int[] id) {
- return resolveResourceId(id);
- }
-
- // ------
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/FrameworkResourceItem.java b/sdk_common/src/com/android/ide/common/resources/FrameworkResourceItem.java
deleted file mode 100644
index 70bbcef..0000000
--- a/sdk_common/src/com/android/ide/common/resources/FrameworkResourceItem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * A custom {@link ResourceItem} for resources provided by the framework.
- *
- * The main change is that {@link #isEditableDirectly()} returns false.
- */
-class FrameworkResourceItem extends ResourceItem {
-
- FrameworkResourceItem(String name) {
- super(name);
- }
-
- @Override
- public boolean isEditableDirectly() {
- return false;
- }
-
- @Override
- public String toString() {
- return "FrameworkResourceItem [mName=" + getName() + ", mFiles=" //$NON-NLS-1$ //$NON-NLS-2$
- + getSourceFileList() + "]"; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/FrameworkResources.java b/sdk_common/src/com/android/ide/common/resources/FrameworkResources.java
deleted file mode 100755
index fe8e197..0000000
--- a/sdk_common/src/com/android/ide/common/resources/FrameworkResources.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.resources.ResourceType;
-import com.android.utils.ILogger;
-import com.google.common.base.Charsets;
-
-import org.kxml2.io.KXmlParser;
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Framework resources repository.
- *
- * This behaves the same as {@link ResourceRepository} except that it differentiates between
- * resources that are public and non public.
- * {@link #getResources(ResourceType)} and {@link #hasResourcesOfType(ResourceType)} only return
- * public resources. This is typically used to display resource lists in the UI.
- *
- * {@link #getConfiguredResources(com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration)}
- * returns all resources, even the non public ones so that this can be used for rendering.
- */
-public class FrameworkResources extends ResourceRepository {
-
- /**
- * Map of {@link ResourceType} to list of items. It is guaranteed to contain a list for all
- * possible values of ResourceType.
- */
- protected final Map<ResourceType, List<ResourceItem>> mPublicResourceMap =
- new EnumMap<ResourceType, List<ResourceItem>>(ResourceType.class);
-
- public FrameworkResources(@NonNull IAbstractFolder resFolder) {
- super(resFolder, true /*isFrameworkRepository*/);
- }
-
- /**
- * Returns a {@link Collection} (always non null, but can be empty) of <b>public</b>
- * {@link ResourceItem} matching a given {@link ResourceType}.
- *
- * @param type the type of the resources to return
- * @return a collection of items, possible empty.
- */
- @Override
- @NonNull
- public List<ResourceItem> getResourceItemsOfType(@NonNull ResourceType type) {
- return mPublicResourceMap.get(type);
- }
-
- /**
- * Returns whether the repository has <b>public</b> resources of a given {@link ResourceType}.
- * @param type the type of resource to check.
- * @return true if the repository contains resources of the given type, false otherwise.
- */
- @Override
- public boolean hasResourcesOfType(@NonNull ResourceType type) {
- return mPublicResourceMap.get(type).size() > 0;
- }
-
- @Override
- @NonNull
- protected ResourceItem createResourceItem(@NonNull String name) {
- return new FrameworkResourceItem(name);
- }
-
- /**
- * Reads the public.xml file in data/res/values/ for a given resource folder and builds up
- * a map of public resources.
- *
- * This map is a subset of the full resource map that only contains framework resources
- * that are public.
- *
- * @param resFolder The root folder of the resources
- * @param logger a logger to report issues to
- */
- public void loadPublicResources(@Nullable ILogger logger) {
- IAbstractFolder valueFolder = getResFolder().getFolder(SdkConstants.FD_RES_VALUES);
- if (valueFolder.exists() == false) {
- return;
- }
-
- IAbstractFile publicXmlFile = valueFolder.getFile("public.xml"); //$NON-NLS-1$
- if (publicXmlFile.exists()) {
- Reader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(publicXmlFile.getContents(),
- Charsets.UTF_8));
- KXmlParser parser = new KXmlParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(reader);
-
- ResourceType lastType = null;
- String lastTypeName = "";
- while (true) {
- int event = parser.next();
- if (event == XmlPullParser.START_TAG) {
- // As of API 15 there are a number of "java-symbol" entries here
- if (!parser.getName().equals("public")) { //$NON-NLS-1$
- continue;
- }
-
- String name = null;
- String typeName = null;
- for (int i = 0, n = parser.getAttributeCount(); i < n; i++) {
- String attribute = parser.getAttributeName(i);
-
- if (attribute.equals("name")) { //$NON-NLS-1$
- name = parser.getAttributeValue(i);
- if (typeName != null) {
- // Skip id attribute processing
- break;
- }
- } else if (attribute.equals("type")) { //$NON-NLS-1$
- typeName = parser.getAttributeValue(i);
- }
- }
-
- if (name != null && typeName != null) {
- ResourceType type = null;
- if (typeName.equals(lastTypeName)) {
- type = lastType;
- } else {
- type = ResourceType.getEnum(typeName);
- lastType = type;
- lastTypeName = typeName;
- }
- if (type != null) {
- ResourceItem match = null;
- Map<String, ResourceItem> map = mResourceMap.get(type);
- if (map != null) {
- match = map.get(name);
- }
-
- if (match != null) {
- List<ResourceItem> publicList = mPublicResourceMap.get(type);
- if (publicList == null) {
- // Pick initial size for the list to hold the public
- // resources. We could just use map.size() here,
- // but they're usually much bigger; for example,
- // in one platform version, there are 1500 drawables
- // and 1200 strings but only 175 and 25 public ones
- // respectively.
- int size;
- switch (type) {
- case STYLE: size = 500; break;
- case ATTR: size = 1000; break;
- case DRAWABLE: size = 200; break;
- case ID: size = 50; break;
- case LAYOUT:
- case COLOR:
- case STRING:
- case ANIM:
- case INTERPOLATOR:
- size = 30;
- break;
- default:
- size = 10;
- break;
- }
- publicList = new ArrayList<ResourceItem>(size);
- mPublicResourceMap.put(type, publicList);
- }
-
- publicList.add(match);
- } else {
- // log that there's a public resource that doesn't actually
- // exist?
- }
- } else {
- // log that there was a reference to a typo that doesn't actually
- // exist?
- }
- }
- } else if (event == XmlPullParser.END_DOCUMENT) {
- break;
- }
- }
- } catch (Exception e) {
- if (logger != null) {
- logger.error(e, "Can't read and parse public attribute list");
- }
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- // Nothing to be done here - we don't care if it closed or not.
- }
- }
- }
- }
-
- // put unmodifiable list for all res type in the public resource map
- // this will simplify access
- for (ResourceType type : ResourceType.values()) {
- List<ResourceItem> list = mPublicResourceMap.get(type);
- if (list == null) {
- list = Collections.emptyList();
- } else {
- list = Collections.unmodifiableList(list);
- }
-
- // put the new list in the map
- mPublicResourceMap.put(type, list);
- }
- }
-}
-
diff --git a/sdk_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java b/sdk_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java
deleted file mode 100644
index 9ff1748..0000000
--- a/sdk_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.ide.common.rendering.api.DensityBasedResourceValue;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
-import com.android.ide.common.resources.configuration.DensityQualifier;
-import com.android.io.IAbstractFile;
-import com.android.io.StreamException;
-import com.android.resources.ResourceType;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Represents a resource file that also generates ID resources.
- * <p/>
- * This is typically an XML file in res/layout or res/menu
- */
-public final class IdGeneratingResourceFile extends ResourceFile
- implements IValueResourceRepository {
-
- private final Map<String, ResourceValue> mIdResources =
- new HashMap<String, ResourceValue>();
-
- private final Collection<ResourceType> mResourceTypeList;
-
- private final String mFileName;
-
- private final ResourceType mFileType;
-
- private final ResourceValue mFileValue;
-
- public IdGeneratingResourceFile(IAbstractFile file, ResourceFolder folder, ResourceType type) {
- super(file, folder);
-
- mFileType = type;
-
- // Set up our resource types
- mResourceTypeList = new HashSet<ResourceType>();
- mResourceTypeList.add(mFileType);
- mResourceTypeList.add(ResourceType.ID);
-
- // compute the resource name
- mFileName = getFileName(type);
-
- // Get the resource value of this file as a whole layout
- mFileValue = getFileValue(file, folder);
- }
-
- @Override
- protected void load(ScanningContext context) {
- // Parse the file and look for @+id/ entries
- parseFileForIds(context);
-
- // create the resource items in the repository
- updateResourceItems(context);
- }
-
- @Override
- protected void update(ScanningContext context) {
- // Copy the previous list of ID names
- Set<String> oldIdNames = new HashSet<String>(mIdResources.keySet());
-
- // reset current content.
- mIdResources.clear();
-
- // need to parse the file and find the IDs.
- if (!parseFileForIds(context)) {
- context.requestFullAapt();
- // Continue through to updating the resource item here since it
- // will make for example layout rendering more accurate until
- // aapt is re-run
- }
-
- // We only need to update the repository if our IDs have changed
- Set<String> keySet = mIdResources.keySet();
- assert keySet != oldIdNames;
- if (oldIdNames.equals(keySet) == false) {
- updateResourceItems(context);
- }
- }
-
- @Override
- protected void dispose(ScanningContext context) {
- ResourceRepository repository = getRepository();
-
- // Remove declarations from this file from the repository
- repository.removeFile(mResourceTypeList, this);
-
- // Ask for an ID refresh since we'll be taking away ID generating items
- context.requestFullAapt();
- }
-
- @Override
- public Collection<ResourceType> getResourceTypes() {
- return mResourceTypeList;
- }
-
- @Override
- public boolean hasResources(ResourceType type) {
- return (type == mFileType) || (type == ResourceType.ID && !mIdResources.isEmpty());
- }
-
- @Override
- public ResourceValue getValue(ResourceType type, String name) {
- // Check to see if they're asking for one of the right types:
- if (type != mFileType && type != ResourceType.ID) {
- return null;
- }
-
- // If they're looking for a resource of this type with this name give them the whole file
- if (type == mFileType && name.equals(mFileName)) {
- return mFileValue;
- } else {
- // Otherwise try to return them an ID
- // the map will return null if it's not found
- return mIdResources.get(name);
- }
- }
-
- /**
- * Looks through the file represented for Ids and adds them to
- * our id repository
- *
- * @return true if parsing succeeds and false if it fails
- */
- private boolean parseFileForIds(ScanningContext context) {
- IdResourceParser parser = new IdResourceParser(this, context, isFramework());
- try {
- IAbstractFile file = getFile();
- return parser.parse(mFileType, file.getOsLocation(), file.getContents());
- } catch (IOException e) {
- // Pass
- } catch (StreamException e) {
- // Pass
- }
-
- return false;
- }
-
- /**
- * Add the resources represented by this file to the repository
- */
- private void updateResourceItems(ScanningContext context) {
- ResourceRepository repository = getRepository();
-
- // remove this file from all existing ResourceItem.
- repository.removeFile(mResourceTypeList, this);
-
- // First add this as a layout file
- ResourceItem item = repository.getResourceItem(mFileType, mFileName);
- item.add(this);
-
- // Now iterate through our IDs and add
- for (String idName : mIdResources.keySet()) {
- item = repository.getResourceItem(ResourceType.ID, idName);
- // add this file to the list of files generating ID resources.
- item.add(this);
- }
-
- // Ask the repository for an ID refresh
- context.requestFullAapt();
- }
-
- /**
- * Returns the resource value associated with this whole file as a layout resource
- * @param file the file handler that represents this file
- * @param folder the folder this file is under
- * @return a resource value associated with this layout
- */
- private ResourceValue getFileValue(IAbstractFile file, ResourceFolder folder) {
- // test if there's a density qualifier associated with the resource
- DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
-
- ResourceValue value;
- if (qualifier == null) {
- value = new ResourceValue(mFileType, mFileName,
- file.getOsLocation(), isFramework());
- } else {
- value = new DensityBasedResourceValue(
- mFileType, mFileName,
- file.getOsLocation(),
- qualifier.getValue(),
- isFramework());
- }
- return value;
- }
-
-
- /**
- * Returns the name of this resource.
- */
- private String getFileName(ResourceType type) {
- // get the name from the filename.
- String name = getFile().getName();
-
- int pos = name.indexOf('.');
- if (pos != -1) {
- name = name.substring(0, pos);
- }
-
- return name;
- }
-
- @Override
- public void addResourceValue(ResourceValue value) {
- // Just overwrite collisions. We're only interested in the unique
- // IDs declared
- mIdResources.put(value.getName(), value);
- }
-
- @Override
- public boolean hasResourceValue(ResourceType type, String name) {
- if (type == ResourceType.ID) {
- return mIdResources.containsKey(name);
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/IdResourceParser.java b/sdk_common/src/com/android/ide/common/resources/IdResourceParser.java
deleted file mode 100644
index 60c1725..0000000
--- a/sdk_common/src/com/android/ide/common/resources/IdResourceParser.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.annotations.NonNull;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
-import com.android.resources.ResourceType;
-import com.google.common.io.Closeables;
-
-import org.kxml2.io.KXmlParser;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Parser for scanning an id-generating resource file such as a layout or a menu
- * file, which registers any ids it encounters with an
- * {@link IValueResourceRepository}, and which registers errors with a
- * {@link ScanningContext}.
- */
-public class IdResourceParser {
- private final IValueResourceRepository mRepository;
- private final boolean mIsFramework;
- private ScanningContext mContext;
-
- /**
- * Creates a new {@link IdResourceParser}
- *
- * @param repository value repository for registering resource declaration
- * @param context a context object with state for the current update, such
- * as a place to stash errors encountered
- * @param isFramework true if scanning a framework resource
- */
- public IdResourceParser(
- @NonNull IValueResourceRepository repository,
- @NonNull ScanningContext context,
- boolean isFramework) {
- mRepository = repository;
- mContext = context;
- mIsFramework = isFramework;
- }
-
- /**
- * Parse the given input and register ids with the given
- * {@link IValueResourceRepository}.
- *
- * @param type the type of resource being scanned
- * @param path the full OS path to the file being parsed
- * @param input the input stream of the XML to be parsed (will be closed by this method)
- * @return true if parsing succeeds and false if it fails
- * @throws IOException if reading the contents fails
- */
- public boolean parse(ResourceType type, final String path, InputStream input)
- throws IOException {
- KXmlParser parser = new KXmlParser();
- try {
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-
- if (input instanceof FileInputStream) {
- input = new BufferedInputStream(input);
- }
- parser.setInput(input, "UTF-8"); //$NON-NLS-1$
-
- return parse(type, path, parser);
- } catch (XmlPullParserException e) {
- String message = e.getMessage();
-
- // Strip off position description
- int index = message.indexOf("(position:"); //$NON-NLS-1$ (Hardcoded in KXml)
- if (index != -1) {
- message = message.substring(0, index);
- }
-
- String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$
- path, parser.getLineNumber(), message);
- mContext.addError(error);
- return false;
- } catch (RuntimeException e) {
- // Some exceptions are thrown by the KXmlParser that are not XmlPullParserExceptions,
- // such as this one:
- // java.lang.RuntimeException: Undefined Prefix: w in org.kxml2.io.KXmlParser@...
- // at org.kxml2.io.KXmlParser.adjustNsp(Unknown Source)
- // at org.kxml2.io.KXmlParser.parseStartTag(Unknown Source)
- String message = e.getMessage();
- String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$
- path, parser.getLineNumber(), message);
- mContext.addError(error);
- return false;
- } finally {
- Closeables.closeQuietly(input);
- }
- }
-
- private boolean parse(ResourceType type, String path, KXmlParser parser)
- throws XmlPullParserException, IOException {
- boolean valid = true;
- boolean checkForErrors = !mIsFramework && !mContext.needsFullAapt();
-
- while (true) {
- int event = parser.next();
- if (event == XmlPullParser.START_TAG) {
- for (int i = 0, n = parser.getAttributeCount(); i < n; i++) {
- String attribute = parser.getAttributeName(i);
- String value = parser.getAttributeValue(i);
- assert value != null : attribute;
-
- if (checkForErrors) {
- String uri = parser.getAttributeNamespace(i);
- if (!mContext.checkValue(uri, attribute, value)) {
- mContext.requestFullAapt();
- checkForErrors = false;
- valid = false;
- }
- }
-
- if (value.startsWith("@+")) { //$NON-NLS-1$
- // Strip out the @+id/ or @+android:id/ section
- String id = value.substring(value.indexOf('/') + 1);
- ResourceValue newId = new ResourceValue(ResourceType.ID, id,
- mIsFramework);
- mRepository.addResourceValue(newId);
- }
- }
- } else if (event == XmlPullParser.END_DOCUMENT) {
- break;
- }
- }
-
- return valid;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/InlineResourceItem.java b/sdk_common/src/com/android/ide/common/resources/InlineResourceItem.java
deleted file mode 100644
index 37fdc81..0000000
--- a/sdk_common/src/com/android/ide/common/resources/InlineResourceItem.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.resources.ResourceType;
-
-
-/**
- * Represents a resource item that has been declared inline in another resource file.
- *
- * This covers the typical ID declaration of "@+id/foo", but does not cover normal value
- * resources declared in strings.xml or other similar value files.
- *
- * This resource will return {@code true} for {@link #isDeclaredInline()} and {@code false} for
- * {@link #isEditableDirectly()}.
- */
-public class InlineResourceItem extends ResourceItem {
-
- private ResourceValue mValue = null;
-
- /**
- * Constructs a new inline ResourceItem.
- * @param name the name of the resource as it appears in the XML and R.java files.
- */
- public InlineResourceItem(String name) {
- super(name);
- }
-
- @Override
- public boolean isDeclaredInline() {
- return true;
- }
-
- @Override
- public boolean isEditableDirectly() {
- return false;
- }
-
- @Override
- public ResourceValue getResourceValue(ResourceType type, FolderConfiguration referenceConfig,
- boolean isFramework) {
- assert type == ResourceType.ID;
- if (mValue == null) {
- mValue = new ResourceValue(type, getName(), isFramework);
- }
-
- return mValue;
- }
-
- @Override
- public String toString() {
- return "InlineResourceItem [mName=" + getName() + ", mFiles=" //$NON-NLS-1$ //$NON-NLS-2$
- + getSourceFileList() + "]"; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/IntArrayWrapper.java b/sdk_common/src/com/android/ide/common/resources/IntArrayWrapper.java
deleted file mode 100644
index 668c677..0000000
--- a/sdk_common/src/com/android/ide/common/resources/IntArrayWrapper.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import java.util.Arrays;
-
-
-/**
- * Wrapper around a int[] to provide hashCode/equals support.
- */
-public final class IntArrayWrapper {
-
- private int[] mData;
-
- public IntArrayWrapper(int[] data) {
- mData = data;
- }
-
- public void set(int[] data) {
- mData = data;
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(mData);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (getClass().equals(obj.getClass())) {
- return Arrays.equals(mData, ((IntArrayWrapper)obj).mData);
- }
-
- return super.equals(obj);
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/MultiResourceFile.java b/sdk_common/src/com/android/ide/common/resources/MultiResourceFile.java
deleted file mode 100644
index c9a8bc7..0000000
--- a/sdk_common/src/com/android/ide/common/resources/MultiResourceFile.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
-import com.android.io.IAbstractFile;
-import com.android.io.StreamException;
-import com.android.resources.ResourceType;
-
-import org.xml.sax.SAXException;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Represents a resource file able to declare multiple resources, which could be of
- * different {@link ResourceType}.
- * <p/>
- * This is typically an XML file inside res/values.
- */
-public final class MultiResourceFile extends ResourceFile implements IValueResourceRepository {
-
- private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
-
- private final Map<ResourceType, Map<String, ResourceValue>> mResourceItems =
- new EnumMap<ResourceType, Map<String, ResourceValue>>(ResourceType.class);
-
- private Collection<ResourceType> mResourceTypeList = null;
-
- public MultiResourceFile(IAbstractFile file, ResourceFolder folder) {
- super(file, folder);
- }
-
- // Boolean flag to track whether a named element has been added or removed, thus requiring
- // a new ID table to be generated
- private boolean mNeedIdRefresh;
-
- @Override
- protected void load(ScanningContext context) {
- // need to parse the file and find the content.
- parseFile();
-
- // create new ResourceItems for the new content.
- mResourceTypeList = Collections.unmodifiableCollection(mResourceItems.keySet());
-
- // We need an ID generation step
- mNeedIdRefresh = true;
-
- // create/update the resource items.
- updateResourceItems(context);
- }
-
- @Override
- protected void update(ScanningContext context) {
- // Reset the ID generation flag
- mNeedIdRefresh = false;
-
- // Copy the previous version of our list of ResourceItems and types
- Map<ResourceType, Map<String, ResourceValue>> oldResourceItems
- = new EnumMap<ResourceType, Map<String, ResourceValue>>(mResourceItems);
-
- // reset current content.
- mResourceItems.clear();
-
- // need to parse the file and find the content.
- parseFile();
-
- // create new ResourceItems for the new content.
- mResourceTypeList = Collections.unmodifiableCollection(mResourceItems.keySet());
-
- // Check to see if any names have changed. If so, mark the flag so updateResourceItems
- // can notify the ResourceRepository that an ID refresh is needed
- if (oldResourceItems.keySet().equals(mResourceItems.keySet())) {
- for (ResourceType type : mResourceTypeList) {
- // We just need to check the names of the items.
- // If there are new or removed names then we'll have to regenerate IDs
- if (mResourceItems.get(type).keySet()
- .equals(oldResourceItems.get(type).keySet()) == false) {
- mNeedIdRefresh = true;
- }
- }
- } else {
- // If our type list is different, obviously the names will be different
- mNeedIdRefresh = true;
- }
- // create/update the resource items.
- updateResourceItems(context);
- }
-
- @Override
- protected void dispose(ScanningContext context) {
- ResourceRepository repository = getRepository();
-
- // only remove this file from all existing ResourceItem.
- repository.removeFile(mResourceTypeList, this);
-
- // We'll need an ID refresh because we deleted items
- context.requestFullAapt();
-
- // don't need to touch the content, it'll get reclaimed as this objects disappear.
- // In the mean time other objects may need to access it.
- }
-
- @Override
- public Collection<ResourceType> getResourceTypes() {
- return mResourceTypeList;
- }
-
- @Override
- public boolean hasResources(ResourceType type) {
- Map<String, ResourceValue> list = mResourceItems.get(type);
- return (list != null && list.size() > 0);
- }
-
- private void updateResourceItems(ScanningContext context) {
- ResourceRepository repository = getRepository();
-
- // remove this file from all existing ResourceItem.
- repository.removeFile(mResourceTypeList, this);
-
- for (ResourceType type : mResourceTypeList) {
- Map<String, ResourceValue> list = mResourceItems.get(type);
-
- if (list != null) {
- Collection<ResourceValue> values = list.values();
- for (ResourceValue res : values) {
- ResourceItem item = repository.getResourceItem(type, res.getName());
-
- // add this file to the list of files generating this resource item.
- item.add(this);
- }
- }
- }
-
- // If we need an ID refresh, ask the repository for that now
- if (mNeedIdRefresh) {
- context.requestFullAapt();
- }
- }
-
- /**
- * Parses the file and creates a list of {@link ResourceType}.
- */
- private void parseFile() {
- try {
- SAXParser parser = sParserFactory.newSAXParser();
- parser.parse(getFile().getContents(), new ValueResourceParser(this, isFramework()));
- } catch (ParserConfigurationException e) {
- } catch (SAXException e) {
- } catch (IOException e) {
- } catch (StreamException e) {
- }
- }
-
- /**
- * Adds a resource item to the list
- * @param value The value of the resource.
- */
- @Override
- public void addResourceValue(ResourceValue value) {
- ResourceType resType = value.getResourceType();
-
- Map<String, ResourceValue> list = mResourceItems.get(resType);
-
- // if the list does not exist, create it.
- if (list == null) {
- list = new HashMap<String, ResourceValue>();
- mResourceItems.put(resType, list);
- } else {
- // look for a possible value already existing.
- ResourceValue oldValue = list.get(value.getName());
-
- if (oldValue != null) {
- oldValue.replaceWith(value);
- return;
- }
- }
-
- // empty list or no match found? add the given resource
- list.put(value.getName(), value);
- }
-
- @Override
- public boolean hasResourceValue(ResourceType type, String name) {
- Map<String, ResourceValue> map = mResourceItems.get(type);
- return map != null && map.containsKey(name);
- }
-
- @Override
- public ResourceValue getValue(ResourceType type, String name) {
- // get the list for the given type
- Map<String, ResourceValue> list = mResourceItems.get(type);
-
- if (list != null) {
- return list.get(name);
- }
-
- return null;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceDeltaKind.java b/sdk_common/src/com/android/ide/common/resources/ResourceDeltaKind.java
deleted file mode 100644
index 769b6ea..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceDeltaKind.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-/**
- * Enum indicating a type of resource change.
- *
- * This is similar, and can be easily mapped to Eclipse's integer constants in IResourceDelta.
- */
-public enum ResourceDeltaKind {
- CHANGED, ADDED, REMOVED;
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceFile.java b/sdk_common/src/com/android/ide/common/resources/ResourceFile.java
deleted file mode 100644
index 378602a..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceFile.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.configuration.Configurable;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.io.IAbstractFile;
-import com.android.resources.ResourceType;
-
-import java.util.Collection;
-
-/**
- * Represents a Resource file (a file under $Project/res/)
- */
-public abstract class ResourceFile implements Configurable {
-
- private final IAbstractFile mFile;
- private final ResourceFolder mFolder;
-
- protected ResourceFile(IAbstractFile file, ResourceFolder folder) {
- mFile = file;
- mFolder = folder;
- }
-
- protected abstract void load(ScanningContext context);
- protected abstract void update(ScanningContext context);
- protected abstract void dispose(ScanningContext context);
-
- @Override
- public FolderConfiguration getConfiguration() {
- return mFolder.getConfiguration();
- }
-
- /**
- * Returns the IFile associated with the ResourceFile.
- */
- public final IAbstractFile getFile() {
- return mFile;
- }
-
- /**
- * Returns the parent folder as a {@link ResourceFolder}.
- */
- public final ResourceFolder getFolder() {
- return mFolder;
- }
-
- public final ResourceRepository getRepository() {
- return mFolder.getRepository();
- }
-
- /**
- * Returns whether the resource is a framework resource.
- */
- public final boolean isFramework() {
- return mFolder.getRepository().isFrameworkRepository();
- }
-
- /**
- * Returns the list of {@link ResourceType} generated by the file. This is never null.
- */
- public abstract Collection<ResourceType> getResourceTypes();
-
- /**
- * Returns whether the file generated a resource of a specific type.
- * @param type The {@link ResourceType}
- */
- public abstract boolean hasResources(ResourceType type);
-
- /**
- * Returns the value of a resource generated by this file by {@link ResourceType} and name.
- * <p/>If no resource match, <code>null</code> is returned.
- * @param type the type of the resource.
- * @param name the name of the resource.
- */
- public abstract ResourceValue getValue(ResourceType type, String name);
-
- @Override
- public String toString() {
- return mFile.toString();
- }
-}
-
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceFolder.java b/sdk_common/src/com/android/ide/common/resources/ResourceFolder.java
deleted file mode 100644
index d6464c8..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceFolder.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.annotations.VisibleForTesting;
-import com.android.annotations.VisibleForTesting.Visibility;
-import com.android.ide.common.resources.configuration.Configurable;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Resource Folder class. Contains list of {@link ResourceFile}s,
- * the {@link FolderConfiguration}, and a link to the {@link IAbstractFolder} object.
- */
-public final class ResourceFolder implements Configurable {
- final ResourceFolderType mType;
- final FolderConfiguration mConfiguration;
- IAbstractFolder mFolder;
- List<ResourceFile> mFiles = null;
- Map<String, ResourceFile> mNames = null;
- private final ResourceRepository mRepository;
-
- /**
- * Creates a new {@link ResourceFolder}
- * @param type The type of the folder
- * @param config The configuration of the folder
- * @param folder The associated {@link IAbstractFolder} object.
- * @param repository The associated {@link ResourceRepository}
- */
- protected ResourceFolder(ResourceFolderType type, FolderConfiguration config,
- IAbstractFolder folder, ResourceRepository repository) {
- mType = type;
- mConfiguration = config;
- mFolder = folder;
- mRepository = repository;
- }
-
- /**
- * Processes a file and adds it to its parent folder resource.
- *
- * @param file the underlying resource file.
- * @param kind the file change kind.
- * @param context a context object with state for the current update, such
- * as a place to stash errors encountered
- * @return the {@link ResourceFile} that was created.
- */
- public ResourceFile processFile(IAbstractFile file, ResourceDeltaKind kind,
- ScanningContext context) {
- // look for this file if it's already been created
- ResourceFile resFile = getFile(file, context);
-
- if (resFile == null) {
- if (kind != ResourceDeltaKind.REMOVED) {
- // create a ResourceFile for it.
-
- resFile = createResourceFile(file);
- resFile.load(context);
-
- // add it to the folder
- addFile(resFile);
- }
- } else {
- if (kind == ResourceDeltaKind.REMOVED) {
- removeFile(resFile, context);
- } else {
- resFile.update(context);
- }
- }
-
- return resFile;
- }
-
- private ResourceFile createResourceFile(IAbstractFile file) {
- // check if that's a single or multi resource type folder. For now we define this by
- // the number of possible resource type output by files in the folder.
- // We have a special case for layout/menu folders which can also generate IDs.
- // This does
- // not make the difference between several resource types from a single file or
- // the ability to have 2 files in the same folder generating 2 different types of
- // resource. The former is handled by MultiResourceFile properly while we don't
- // handle the latter. If we were to add this behavior we'd have to change this call.
- List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(mType);
-
- ResourceFile resFile = null;
- if (types.size() == 1) {
- resFile = new SingleResourceFile(file, this);
- } else if (types.contains(ResourceType.LAYOUT)) {
- resFile = new IdGeneratingResourceFile(file, this, ResourceType.LAYOUT);
- } else if (types.contains(ResourceType.MENU)) {
- resFile = new IdGeneratingResourceFile(file, this, ResourceType.MENU);
- } else {
- resFile = new MultiResourceFile(file, this);
- }
- return resFile;
- }
-
- /**
- * Adds a {@link ResourceFile} to the folder.
- * @param file The {@link ResourceFile}.
- */
- @VisibleForTesting(visibility=Visibility.PROTECTED)
- public void addFile(ResourceFile file) {
- if (mFiles == null) {
- int initialSize = 16;
- if (mRepository.isFrameworkRepository()) {
- String name = mFolder.getName();
- // Pick some reasonable initial sizes for framework data structures
- // since they are typically (a) large and (b) their sizes are roughly known
- // in advance
- switch (mType) {
- case DRAWABLE: {
- // See if it's one of the -mdpi, -hdpi etc folders which
- // are large (~1250 items)
- int index = name.indexOf('-');
- if (index == -1) {
- initialSize = 230; // "drawable" folder
- } else {
- index = name.indexOf('-', index + 1);
- if (index == -1) {
- // One of the "drawable-<density>" folders
- initialSize = 1260;
- } else {
- // "drawable-sw600dp-hdpi" etc
- initialSize = 30;
- }
- }
- break;
- }
- case LAYOUT: {
- // The main layout folder has about ~185 layouts in it;
- // the others are small
- if (name.indexOf('-') == -1) {
- initialSize = 200;
- }
- break;
- }
- case VALUES: {
- if (name.indexOf('-') == -1) {
- initialSize = 32;
- } else {
- initialSize = 4;
- }
- break;
- }
- case ANIM: initialSize = 85; break;
- case COLOR: initialSize = 32; break;
- case RAW: initialSize = 4; break;
- default:
- // Stick with the 16 default
- break;
- }
- }
-
- mFiles = new ArrayList<ResourceFile>(initialSize);
- mNames = new HashMap<String, ResourceFile>(initialSize, 2.0f);
- }
-
- mFiles.add(file);
- mNames.put(file.getFile().getName(), file);
- }
-
- protected void removeFile(ResourceFile file, ScanningContext context) {
- file.dispose(context);
- mFiles.remove(file);
- mNames.remove(file.getFile().getName());
- }
-
- protected void dispose(ScanningContext context) {
- if (mFiles != null) {
- for (ResourceFile file : mFiles) {
- file.dispose(context);
- }
-
- mFiles.clear();
- mNames.clear();
- }
- }
-
- /**
- * Returns the {@link IAbstractFolder} associated with this object.
- */
- public IAbstractFolder getFolder() {
- return mFolder;
- }
-
- /**
- * Returns the {@link ResourceFolderType} of this object.
- */
- public ResourceFolderType getType() {
- return mType;
- }
-
- public ResourceRepository getRepository() {
- return mRepository;
- }
-
- /**
- * Returns the list of {@link ResourceType}s generated by the files inside this folder.
- */
- public Collection<ResourceType> getResourceTypes() {
- ArrayList<ResourceType> list = new ArrayList<ResourceType>();
-
- if (mFiles != null) {
- for (ResourceFile file : mFiles) {
- Collection<ResourceType> types = file.getResourceTypes();
-
- // loop through those and add them to the main list,
- // if they are not already present
- for (ResourceType resType : types) {
- if (list.indexOf(resType) == -1) {
- list.add(resType);
- }
- }
- }
- }
-
- return list;
- }
-
- @Override
- public FolderConfiguration getConfiguration() {
- return mConfiguration;
- }
-
- /**
- * Returns whether the folder contains a file with the given name.
- * @param name the name of the file.
- */
- public boolean hasFile(String name) {
- if (mNames != null && mNames.containsKey(name)) {
- return true;
- }
-
- // Note: mNames.containsKey(name) is faster, but doesn't give the same result; this
- // method seems to be called on this ResourceFolder before it has been processed,
- // so we need to use the file system check instead:
- return mFolder.hasFile(name);
- }
-
- /**
- * Returns the {@link ResourceFile} matching a {@link IAbstractFile} object.
- *
- * @param file The {@link IAbstractFile} object.
- * @param context a context object with state for the current update, such
- * as a place to stash errors encountered
- * @return the {@link ResourceFile} or null if no match was found.
- */
- private ResourceFile getFile(IAbstractFile file, ScanningContext context) {
- assert mFolder.equals(file.getParentFolder());
-
- if (mNames != null) {
- ResourceFile resFile = mNames.get(file.getName());
- if (resFile != null) {
- return resFile;
- }
- }
-
- // If the file actually exists, the resource folder may not have been
- // scanned yet; add it lazily
- if (file.exists()) {
- ResourceFile resFile = createResourceFile(file);
- resFile.load(context);
- addFile(resFile);
- return resFile;
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ResourceFile} matching a given name.
- * @param filename The name of the file to return.
- * @return the {@link ResourceFile} or <code>null</code> if no match was found.
- */
- public ResourceFile getFile(String filename) {
- if (mNames != null) {
- ResourceFile resFile = mNames.get(filename);
- if (resFile != null) {
- return resFile;
- }
- }
-
- // If the file actually exists, the resource folder may not have been
- // scanned yet; add it lazily
- IAbstractFile file = mFolder.getFile(filename);
- if (file != null && file.exists()) {
- ResourceFile resFile = createResourceFile(file);
- resFile.load(new ScanningContext(mRepository));
- addFile(resFile);
- return resFile;
- }
-
- return null;
- }
-
- /**
- * Returns whether a file in the folder is generating a resource of a specified type.
- * @param type The {@link ResourceType} being looked up.
- */
- public boolean hasResources(ResourceType type) {
- // Check if the folder type is able to generate resource of the type that was asked.
- // this is a first check to avoid going through the files.
- List<ResourceFolderType> folderTypes = FolderTypeRelationship.getRelatedFolders(type);
-
- boolean valid = false;
- for (ResourceFolderType rft : folderTypes) {
- if (rft == mType) {
- valid = true;
- break;
- }
- }
-
- if (valid) {
- if (mFiles != null) {
- for (ResourceFile f : mFiles) {
- if (f.hasResources(type)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- @Override
- public String toString() {
- return mFolder.toString();
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceItem.java b/sdk_common/src/com/android/ide/common/resources/ResourceItem.java
deleted file mode 100644
index 49396eb..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceItem.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.resources.ResourceType;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * An android resource.
- *
- * This is a representation of the resource, not of its value(s). It gives access to all
- * the source files that generate this particular resource which then can be used to access
- * the actual value(s).
- *
- * @see ResourceFile#getResources(ResourceType, ResourceRepository)
- */
-public class ResourceItem implements Comparable<ResourceItem> {
-
- private final static Comparator<ResourceFile> sComparator = new Comparator<ResourceFile>() {
- @Override
- public int compare(ResourceFile file1, ResourceFile file2) {
- // get both FolderConfiguration and compare them
- FolderConfiguration fc1 = file1.getFolder().getConfiguration();
- FolderConfiguration fc2 = file2.getFolder().getConfiguration();
-
- return fc1.compareTo(fc2);
- }
- };
-
- private final String mName;
-
- /**
- * List of files generating this ResourceItem.
- */
- private final List<ResourceFile> mFiles = new ArrayList<ResourceFile>();
-
- /**
- * Constructs a new ResourceItem.
- * @param name the name of the resource as it appears in the XML and R.java files.
- */
- public ResourceItem(String name) {
- mName = name;
- }
-
- /**
- * Returns the name of the resource.
- */
- public final String getName() {
- return mName;
- }
-
- /**
- * Compares the {@link ResourceItem} to another.
- * @param other the ResourceItem to be compared to.
- */
- @Override
- public int compareTo(ResourceItem other) {
- return mName.compareTo(other.mName);
- }
-
- /**
- * Returns whether the resource is editable directly.
- * <p/>
- * This is typically the case for resources that don't have alternate versions, or resources
- * of type {@link ResourceType#ID} that aren't declared inline.
- */
- public boolean isEditableDirectly() {
- return hasAlternates() == false;
- }
-
- /**
- * Returns whether the ID resource has been declared inline inside another resource XML file.
- * If the resource type is not {@link ResourceType#ID}, this will always return {@code false}.
- */
- public boolean isDeclaredInline() {
- return false;
- }
-
- /**
- * Returns a {@link ResourceValue} for this item based on the given configuration.
- * If the ResourceItem has several source files, one will be selected based on the config.
- * @param type the type of the resource. This is necessary because ResourceItem doesn't embed
- * its type, but ResourceValue does.
- * @param referenceConfig the config of the resource item.
- * @param isFramework whether the resource is a framework value. Same as the type.
- * @return a ResourceValue or null if none match the config.
- */
- public ResourceValue getResourceValue(ResourceType type, FolderConfiguration referenceConfig,
- boolean isFramework) {
- // look for the best match for the given configuration
- // the match has to be of type ResourceFile since that's what the input list contains
- ResourceFile match = (ResourceFile) referenceConfig.findMatchingConfigurable(mFiles);
-
- if (match != null) {
- // get the value of this configured resource.
- return match.getValue(type, mName);
- }
-
- return null;
- }
-
- /**
- * Adds a new source file.
- * @param file the source file.
- */
- protected void add(ResourceFile file) {
- mFiles.add(file);
- }
-
- /**
- * Removes a file from the list of source files.
- * @param file the file to remove
- */
- protected void removeFile(ResourceFile file) {
- mFiles.remove(file);
- }
-
- /**
- * Returns {@code true} if the item has no source file.
- * @return
- */
- protected boolean hasNoSourceFile() {
- return mFiles.size() == 0;
- }
-
- /**
- * Reset the item by emptying its source file list.
- */
- protected void reset() {
- mFiles.clear();
- }
-
- /**
- * Returns the sorted list of {@link ResourceItem} objects for this resource item.
- */
- public ResourceFile[] getSourceFileArray() {
- ArrayList<ResourceFile> list = new ArrayList<ResourceFile>();
- list.addAll(mFiles);
-
- Collections.sort(list, sComparator);
-
- return list.toArray(new ResourceFile[list.size()]);
- }
-
- /**
- * Returns the list of source file for this resource.
- */
- public List<ResourceFile> getSourceFileList() {
- return Collections.unmodifiableList(mFiles);
- }
-
- /**
- * Returns if the resource has at least one non-default version.
- *
- * @see ResourceFile#getConfiguration()
- * @see FolderConfiguration#isDefault()
- */
- public boolean hasAlternates() {
- for (ResourceFile file : mFiles) {
- if (file.getFolder().getConfiguration().isDefault() == false) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the resource has a default version, with no qualifier.
- *
- * @see ResourceFile#getConfiguration()
- * @see FolderConfiguration#isDefault()
- */
- public boolean hasDefault() {
- for (ResourceFile file : mFiles) {
- if (file.getFolder().getConfiguration().isDefault()) {
- return true;
- }
- }
-
- // We only want to return false if there's no default and more than 0 items.
- return (mFiles.size() == 0);
- }
-
- /**
- * Returns the number of alternate versions for this resource.
- *
- * @see ResourceFile#getConfiguration()
- * @see FolderConfiguration#isDefault()
- */
- public int getAlternateCount() {
- int count = 0;
- for (ResourceFile file : mFiles) {
- if (file.getFolder().getConfiguration().isDefault() == false) {
- count++;
- }
- }
-
- return count;
- }
-
- /**
- * Returns a formatted string usable in an XML to use for the {@link ResourceItem}.
- * @param system Whether this is a system resource or a project resource.
- * @return a string in the format @[type]/[name]
- */
- public String getXmlString(ResourceType type, boolean system) {
- if (type == ResourceType.ID && isDeclaredInline()) {
- return (system ? "@android:" : "@+") + type.getName() + "/" + mName; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- return (system ? "@android:" : "@") + type.getName() + "/" + mName; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- @Override
- public String toString() {
- return "ResourceItem [mName=" + mName + ", mFiles=" + mFiles + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceRepository.java b/sdk_common/src/com/android/ide/common/resources/ResourceRepository.java
deleted file mode 100755
index a3b20ed..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceRepository.java
+++ /dev/null
@@ -1,960 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.SdkConstants.ATTR_REF_PREFIX;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.PREFIX_THEME_REF;
-import static com.android.SdkConstants.RESOURCE_CLZ_ATTR;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.configuration.Configurable;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LanguageQualifier;
-import com.android.ide.common.resources.configuration.RegionQualifier;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.io.IAbstractResource;
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-import com.android.utils.Pair;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-/**
- * Base class for resource repository.
- *
- * A repository is both a file representation of a resource folder and a representation
- * of the generated resources, organized by type.
- *
- * {@link #getResourceFolder(IAbstractFolder)} and {@link #getSourceFiles(ResourceType, String, FolderConfiguration)}
- * give access to the folders and files of the resource folder.
- *
- * {@link #getResources(ResourceType)} gives access to the resources directly.
- *
- */
-public abstract class ResourceRepository {
-
- private final IAbstractFolder mResourceFolder;
-
- protected Map<ResourceFolderType, List<ResourceFolder>> mFolderMap =
- new EnumMap<ResourceFolderType, List<ResourceFolder>>(ResourceFolderType.class);
-
- protected Map<ResourceType, Map<String, ResourceItem>> mResourceMap =
- new EnumMap<ResourceType, Map<String, ResourceItem>>(
- ResourceType.class);
-
- private Map<Map<String, ResourceItem>, Collection<ResourceItem>> mReadOnlyListMap =
- new IdentityHashMap<Map<String, ResourceItem>, Collection<ResourceItem>>();
-
- private final boolean mFrameworkRepository;
- private boolean mCleared = true;
- private boolean mInitializing = false;
-
- protected final IntArrayWrapper mWrapper = new IntArrayWrapper(null);
-
- /**
- * Makes a resource repository
- * @param resFolder the resource folder of the repository.
- * @param isFrameworkRepository whether the repository is for framework resources.
- */
- protected ResourceRepository(@NonNull IAbstractFolder resFolder,
- boolean isFrameworkRepository) {
- mResourceFolder = resFolder;
- mFrameworkRepository = isFrameworkRepository;
- }
-
- public IAbstractFolder getResFolder() {
- return mResourceFolder;
- }
-
- public boolean isFrameworkRepository() {
- return mFrameworkRepository;
- }
-
- public synchronized void clear() {
- mCleared = true;
- mFolderMap = new EnumMap<ResourceFolderType, List<ResourceFolder>>(
- ResourceFolderType.class);
- mResourceMap = new EnumMap<ResourceType, Map<String, ResourceItem>>(
- ResourceType.class);
-
- mReadOnlyListMap =
- new IdentityHashMap<Map<String, ResourceItem>, Collection<ResourceItem>>();
- }
-
- /**
- * Ensures that the repository has been initialized again after a call to
- * {@link ResourceRepository#clear()}
- *
- * @return true if the repository was just re-initialized.
- */
- public synchronized boolean ensureInitialized() {
- if (mCleared && !mInitializing) {
- ScanningContext context = new ScanningContext(this);
- mInitializing = true;
-
- IAbstractResource[] resources = mResourceFolder.listMembers();
-
- for (IAbstractResource res : resources) {
- if (res instanceof IAbstractFolder) {
- IAbstractFolder folder = (IAbstractFolder)res;
- ResourceFolder resFolder = processFolder(folder);
-
- if (resFolder != null) {
- // now we process the content of the folder
- IAbstractResource[] files = folder.listMembers();
-
- for (IAbstractResource fileRes : files) {
- if (fileRes instanceof IAbstractFile) {
- IAbstractFile file = (IAbstractFile)fileRes;
-
- resFolder.processFile(file, ResourceDeltaKind.ADDED, context);
- }
- }
- }
- }
- }
-
- mInitializing = false;
- mCleared = false;
- return true;
- }
-
- return false;
- }
-
- /**
- * Adds a Folder Configuration to the project.
- * @param type The resource type.
- * @param config The resource configuration.
- * @param folder The workspace folder object.
- * @return the {@link ResourceFolder} object associated to this folder.
- */
- private ResourceFolder add(
- @NonNull ResourceFolderType type,
- @NonNull FolderConfiguration config,
- @NonNull IAbstractFolder folder) {
- // get the list for the resource type
- List<ResourceFolder> list = mFolderMap.get(type);
-
- if (list == null) {
- list = new ArrayList<ResourceFolder>();
-
- ResourceFolder cf = new ResourceFolder(type, config, folder, this);
- list.add(cf);
-
- mFolderMap.put(type, list);
-
- return cf;
- }
-
- // look for an already existing folder configuration.
- for (ResourceFolder cFolder : list) {
- if (cFolder.mConfiguration.equals(config)) {
- // config already exist. Nothing to be done really, besides making sure
- // the IAbstractFolder object is up to date.
- cFolder.mFolder = folder;
- return cFolder;
- }
- }
-
- // If we arrive here, this means we didn't find a matching configuration.
- // So we add one.
- ResourceFolder cf = new ResourceFolder(type, config, folder, this);
- list.add(cf);
-
- return cf;
- }
-
- /**
- * Removes a {@link ResourceFolder} associated with the specified {@link IAbstractFolder}.
- * @param type The type of the folder
- * @param removedFolder the IAbstractFolder object.
- * @param context the scanning context
- * @return the {@link ResourceFolder} that was removed, or null if no matches were found.
- */
- @Nullable
- public ResourceFolder removeFolder(
- @NonNull ResourceFolderType type,
- @NonNull IAbstractFolder removedFolder,
- @Nullable ScanningContext context) {
- ensureInitialized();
-
- // get the list of folders for the resource type.
- List<ResourceFolder> list = mFolderMap.get(type);
-
- if (list != null) {
- int count = list.size();
- for (int i = 0 ; i < count ; i++) {
- ResourceFolder resFolder = list.get(i);
- IAbstractFolder folder = resFolder.getFolder();
- if (removedFolder.equals(folder)) {
- // we found the matching ResourceFolder. we need to remove it.
- list.remove(i);
-
- // remove its content
- resFolder.dispose(context);
-
- return resFolder;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns true if this resource repository contains a resource of the given
- * name.
- *
- * @param url the resource URL
- * @return true if the resource is known
- */
- public boolean hasResourceItem(@NonNull String url) {
- // Handle theme references
- if (url.startsWith(PREFIX_THEME_REF)) {
- String remainder = url.substring(PREFIX_THEME_REF.length());
- if (url.startsWith(ATTR_REF_PREFIX)) {
- url = PREFIX_RESOURCE_REF + url.substring(PREFIX_THEME_REF.length());
- return hasResourceItem(url);
- }
- int colon = url.indexOf(':');
- if (colon != -1) {
- // Convert from ?android:progressBarStyleBig to ?android:attr/progressBarStyleBig
- if (remainder.indexOf('/', colon) == -1) {
- remainder = remainder.substring(0, colon) + RESOURCE_CLZ_ATTR + '/'
- + remainder.substring(colon);
- }
- url = PREFIX_RESOURCE_REF + remainder;
- return hasResourceItem(url);
- } else {
- int slash = url.indexOf('/');
- if (slash == -1) {
- url = PREFIX_RESOURCE_REF + RESOURCE_CLZ_ATTR + '/' + remainder;
- return hasResourceItem(url);
- }
- }
- }
-
- if (!url.startsWith(PREFIX_RESOURCE_REF)) {
- return false;
- }
-
- assert url.startsWith("@") || url.startsWith("?") : url;
-
- ensureInitialized();
-
- int typeEnd = url.indexOf('/', 1);
- if (typeEnd != -1) {
- int nameBegin = typeEnd + 1;
-
- // Skip @ and @+
- int typeBegin = url.startsWith("@+") ? 2 : 1; //$NON-NLS-1$
-
- int colon = url.lastIndexOf(':', typeEnd);
- if (colon != -1) {
- typeBegin = colon + 1;
- }
- String typeName = url.substring(typeBegin, typeEnd);
- ResourceType type = ResourceType.getEnum(typeName);
- if (type != null) {
- String name = url.substring(nameBegin);
- return hasResourceItem(type, name);
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if this resource repository contains a resource of the given
- * name.
- *
- * @param type the type of resource to look up
- * @param name the name of the resource
- * @return true if the resource is known
- */
- public boolean hasResourceItem(@NonNull ResourceType type, @NonNull String name) {
- ensureInitialized();
-
- Map<String, ResourceItem> map = mResourceMap.get(type);
-
- if (map != null) {
-
- ResourceItem resourceItem = map.get(name);
- if (resourceItem != null) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns a {@link ResourceItem} matching the given {@link ResourceType} and name. If none
- * exist, it creates one.
- *
- * @param type the resource type
- * @param name the name of the resource.
- * @return A resource item matching the type and name.
- */
- @NonNull
- protected ResourceItem getResourceItem(@NonNull ResourceType type, @NonNull String name) {
- ensureInitialized();
-
- // looking for an existing ResourceItem with this type and name
- ResourceItem item = findDeclaredResourceItem(type, name);
-
- // create one if there isn't one already, or if the existing one is inlined, since
- // clearly we need a non inlined one (the inline one is removed too)
- if (item == null || item.isDeclaredInline()) {
- ResourceItem oldItem = item != null && item.isDeclaredInline() ? item : null;
-
- item = createResourceItem(name);
-
- Map<String, ResourceItem> map = mResourceMap.get(type);
-
- if (map == null) {
- if (isFrameworkRepository()) {
- // Pick initial size for the maps. Also change the load factor to 1.0
- // to avoid rehashing the whole table when we (as expected) get near
- // the known rough size of each resource type map.
- int size;
- switch (type) {
- // Based on counts in API 16. Going back to API 10, the counts
- // are roughly 25-50% smaller (e.g. compared to the top 5 types below
- // the fractions are 1107 vs 1734, 831 vs 1508, 895 vs 1255,
- // 733 vs 1064 and 171 vs 783.
- case PUBLIC: size = 1734; break;
- case DRAWABLE: size = 1508; break;
- case STRING: size = 1255; break;
- case ATTR: size = 1064; break;
- case STYLE: size = 783; break;
- case ID: size = 347; break;
- case DECLARE_STYLEABLE: size = 210; break;
- case LAYOUT: size = 187; break;
- case COLOR: size = 120; break;
- case ANIM: size = 95; break;
- case DIMEN: size = 81; break;
- case BOOL: size = 54; break;
- case INTEGER: size = 52; break;
- case ARRAY: size = 51; break;
- case PLURALS: size = 20; break;
- case XML: size = 14; break;
- case INTERPOLATOR : size = 13; break;
- case ANIMATOR: size = 8; break;
- case RAW: size = 4; break;
- case MENU: size = 2; break;
- case MIPMAP: size = 2; break;
- case FRACTION: size = 1; break;
- default:
- size = 2;
- }
- map = new HashMap<String, ResourceItem>(size, 1.0f);
- } else {
- map = new HashMap<String, ResourceItem>();
- }
- mResourceMap.put(type, map);
- }
-
- map.put(item.getName(), item);
-
- if (oldItem != null) {
- map.remove(oldItem.getName());
-
- }
- }
-
- return item;
- }
-
- /**
- * Creates a resource item with the given name.
- * @param name the name of the resource
- * @return a new ResourceItem (or child class) instance.
- */
- @NonNull
- protected abstract ResourceItem createResourceItem(@NonNull String name);
-
- /**
- * Processes a folder and adds it to the list of existing folders.
- * @param folder the folder to process
- * @return the ResourceFolder created from this folder, or null if the process failed.
- */
- @Nullable
- public ResourceFolder processFolder(@NonNull IAbstractFolder folder) {
- ensureInitialized();
-
- // split the name of the folder in segments.
- String[] folderSegments = folder.getName().split(SdkConstants.RES_QUALIFIER_SEP);
-
- // get the enum for the resource type.
- ResourceFolderType type = ResourceFolderType.getTypeByName(folderSegments[0]);
-
- if (type != null) {
- // get the folder configuration.
- FolderConfiguration config = FolderConfiguration.getConfig(folderSegments);
-
- if (config != null) {
- return add(type, config, folder);
- }
- }
-
- return null;
- }
-
- /**
- * Returns a list of {@link ResourceFolder} for a specific {@link ResourceFolderType}.
- * @param type The {@link ResourceFolderType}
- */
- @Nullable
- public List<ResourceFolder> getFolders(@NonNull ResourceFolderType type) {
- ensureInitialized();
-
- return mFolderMap.get(type);
- }
-
- @NonNull
- public List<ResourceType> getAvailableResourceTypes() {
- ensureInitialized();
-
- List<ResourceType> list = new ArrayList<ResourceType>();
-
- // For each key, we check if there's a single ResourceType match.
- // If not, we look for the actual content to give us the resource type.
-
- for (ResourceFolderType folderType : mFolderMap.keySet()) {
- List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(folderType);
- if (types.size() == 1) {
- // before we add it we check if it's not already present, since a ResourceType
- // could be created from multiple folders, even for the folders that only create
- // one type of resource (drawable for instance, can be created from drawable/ and
- // values/)
- if (list.contains(types.get(0)) == false) {
- list.add(types.get(0));
- }
- } else {
- // there isn't a single resource type out of this folder, so we look for all
- // content.
- List<ResourceFolder> folders = mFolderMap.get(folderType);
- if (folders != null) {
- for (ResourceFolder folder : folders) {
- Collection<ResourceType> folderContent = folder.getResourceTypes();
-
- // then we add them, but only if they aren't already in the list.
- for (ResourceType folderResType : folderContent) {
- if (list.contains(folderResType) == false) {
- list.add(folderResType);
- }
- }
- }
- }
- }
- }
-
- return list;
- }
-
- /**
- * Returns a list of {@link ResourceItem} matching a given {@link ResourceType}.
- * @param type the type of the resource items to return
- * @return a non null collection of resource items
- */
- @NonNull
- public Collection<ResourceItem> getResourceItemsOfType(@NonNull ResourceType type) {
- ensureInitialized();
-
- Map<String, ResourceItem> map = mResourceMap.get(type);
-
- if (map == null) {
- return Collections.emptyList();
- }
-
- Collection<ResourceItem> roList = mReadOnlyListMap.get(map);
- if (roList == null) {
- roList = Collections.unmodifiableCollection(map.values());
- mReadOnlyListMap.put(map, roList);
- }
-
- return roList;
- }
-
- /**
- * Returns whether the repository has resources of a given {@link ResourceType}.
- * @param type the type of resource to check.
- * @return true if the repository contains resources of the given type, false otherwise.
- */
- public boolean hasResourcesOfType(@NonNull ResourceType type) {
- ensureInitialized();
-
- Map<String, ResourceItem> items = mResourceMap.get(type);
- return (items != null && items.size() > 0);
- }
-
- /**
- * Returns the {@link ResourceFolder} associated with a {@link IAbstractFolder}.
- * @param folder The {@link IAbstractFolder} object.
- * @return the {@link ResourceFolder} or null if it was not found.
- */
- @Nullable
- public ResourceFolder getResourceFolder(@NonNull IAbstractFolder folder) {
- ensureInitialized();
-
- Collection<List<ResourceFolder>> values = mFolderMap.values();
-
- for (List<ResourceFolder> list : values) {
- for (ResourceFolder resFolder : list) {
- IAbstractFolder wrapper = resFolder.getFolder();
- if (wrapper.equals(folder)) {
- return resFolder;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ResourceFile} matching the given name,
- * {@link ResourceFolderType} and configuration.
- * <p/>
- * This only works with files generating one resource named after the file
- * (for instance, layouts, bitmap based drawable, xml, anims).
- *
- * @param name the resource name or file name
- * @param type the folder type search for
- * @param config the folder configuration to match for
- * @return the matching file or <code>null</code> if no match was found.
- */
- @Nullable
- public ResourceFile getMatchingFile(
- @NonNull String name,
- @NonNull ResourceFolderType type,
- @NonNull FolderConfiguration config) {
- List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(type);
- for (ResourceType t : types) {
- if (t == ResourceType.ID) {
- continue;
- }
- ResourceFile match = getMatchingFile(name, type, config);
- if (match != null) {
- return match;
- }
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ResourceFile} matching the given name,
- * {@link ResourceType} and configuration.
- * <p/>
- * This only works with files generating one resource named after the file
- * (for instance, layouts, bitmap based drawable, xml, anims).
- *
- * @param name the resource name or file name
- * @param type the folder type search for
- * @param config the folder configuration to match for
- * @return the matching file or <code>null</code> if no match was found.
- */
- @Nullable
- public ResourceFile getMatchingFile(
- @NonNull String name,
- @NonNull ResourceType type,
- @NonNull FolderConfiguration config) {
- ensureInitialized();
-
- String resourceName = name;
- int dot = resourceName.indexOf('.');
- if (dot != -1) {
- resourceName = resourceName.substring(0, dot);
- }
-
- Map<String, ResourceItem> items = mResourceMap.get(type);
- if (items != null) {
- ResourceItem item = items.get(resourceName);
- if (item != null) {
- List<ResourceFile> files = item.getSourceFileList();
- if (files != null) {
- if (files.size() > 1) {
- ResourceValue value = item.getResourceValue(type, config,
- isFrameworkRepository());
- if (value != null) {
- String v = value.getValue();
- if (v != null) {
- Pair<ResourceType, String> pair = parseResource(v);
- if (pair != null) {
- return getMatchingFile(pair.getSecond(), pair.getFirst(),
- config);
- } else {
- // Looks like the resource value is pointing to a file
- // It's most likely one of the source files for this
- // resource item, so check those first
- for (ResourceFile f : files) {
- if (v.equals(f.getFile().getOsLocation())) {
- // Found the file
- return f;
- }
- }
-
- // No; look up the resource file from the full path
- File file = new File(v);
- if (file.exists()) {
- ResourceFile f = findResourceFile(file);
- if (f != null) {
- return f;
- }
- }
- }
- }
- }
- } else if (files.size() == 1) {
- // Single file: see if it matches
- ResourceFile matchingFile = files.get(0);
- if (matchingFile.getFolder().getConfiguration().isMatchFor(config)) {
- return matchingFile;
- }
- }
- }
- }
- }
-
- return null;
- }
-
- @Nullable
- private ResourceFile findResourceFile(@NonNull File file) {
- // Look up the right resource file for this path
- String parentName = file.getParentFile().getName();
- IAbstractFolder folder = getResFolder().getFolder(parentName);
- if (folder != null) {
- ResourceFolder resourceFolder = getResourceFolder(folder);
- if (resourceFolder != null) {
- ResourceFile resourceFile = resourceFolder.getFile(file.getName());
- if (resourceFile != null) {
- return resourceFile;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns the list of source files for a given resource.
- * Optionally, if a {@link FolderConfiguration} is given, then only the best
- * match for this config is returned.
- *
- * @param type the type of the resource.
- * @param name the name of the resource.
- * @param referenceConfig an optional config for which only the best match will be returned.
- *
- * @return a list of files generating this resource or null if it was not found.
- */
- @Nullable
- public List<ResourceFile> getSourceFiles(@NonNull ResourceType type, @NonNull String name,
- @Nullable FolderConfiguration referenceConfig) {
- ensureInitialized();
-
- Collection<ResourceItem> items = getResourceItemsOfType(type);
-
- for (ResourceItem item : items) {
- if (name.equals(item.getName())) {
- if (referenceConfig != null) {
- Configurable match = referenceConfig.findMatchingConfigurable(
- item.getSourceFileList());
-
- if (match instanceof ResourceFile) {
- return Collections.singletonList((ResourceFile) match);
- }
-
- return null;
- }
- return item.getSourceFileList();
- }
- }
-
- return null;
- }
-
- /**
- * Returns the resources values matching a given {@link FolderConfiguration}.
- *
- * @param referenceConfig the configuration that each value must match.
- * @return a map with guaranteed to contain an entry for each {@link ResourceType}
- */
- @NonNull
- public Map<ResourceType, Map<String, ResourceValue>> getConfiguredResources(
- @NonNull FolderConfiguration referenceConfig) {
- ensureInitialized();
-
- return doGetConfiguredResources(referenceConfig);
- }
-
- /**
- * Returns the resources values matching a given {@link FolderConfiguration} for the current
- * project.
- *
- * @param referenceConfig the configuration that each value must match.
- * @return a map with guaranteed to contain an entry for each {@link ResourceType}
- */
- @NonNull
- protected final Map<ResourceType, Map<String, ResourceValue>> doGetConfiguredResources(
- @NonNull FolderConfiguration referenceConfig) {
- ensureInitialized();
-
- Map<ResourceType, Map<String, ResourceValue>> map =
- new EnumMap<ResourceType, Map<String, ResourceValue>>(ResourceType.class);
-
- for (ResourceType key : ResourceType.values()) {
- // get the local results and put them in the map
- map.put(key, getConfiguredResource(key, referenceConfig));
- }
-
- return map;
- }
-
- /**
- * Returns the sorted list of languages used in the resources.
- */
- @NonNull
- public SortedSet<String> getLanguages() {
- ensureInitialized();
-
- SortedSet<String> set = new TreeSet<String>();
-
- Collection<List<ResourceFolder>> folderList = mFolderMap.values();
- for (List<ResourceFolder> folderSubList : folderList) {
- for (ResourceFolder folder : folderSubList) {
- FolderConfiguration config = folder.getConfiguration();
- LanguageQualifier lang = config.getLanguageQualifier();
- if (lang != null) {
- set.add(lang.getShortDisplayValue());
- }
- }
- }
-
- return set;
- }
-
- /**
- * Returns the sorted list of regions used in the resources with the given language.
- * @param currentLanguage the current language the region must be associated with.
- */
- @NonNull
- public SortedSet<String> getRegions(@NonNull String currentLanguage) {
- ensureInitialized();
-
- SortedSet<String> set = new TreeSet<String>();
-
- Collection<List<ResourceFolder>> folderList = mFolderMap.values();
- for (List<ResourceFolder> folderSubList : folderList) {
- for (ResourceFolder folder : folderSubList) {
- FolderConfiguration config = folder.getConfiguration();
-
- // get the language
- LanguageQualifier lang = config.getLanguageQualifier();
- if (lang != null && lang.getShortDisplayValue().equals(currentLanguage)) {
- RegionQualifier region = config.getRegionQualifier();
- if (region != null) {
- set.add(region.getShortDisplayValue());
- }
- }
- }
- }
-
- return set;
- }
-
- /**
- * Loads the resources.
- */
- public void loadResources() {
- clear();
- ensureInitialized();
- }
-
- protected void removeFile(@NonNull Collection<ResourceType> types,
- @NonNull ResourceFile file) {
- ensureInitialized();
-
- for (ResourceType type : types) {
- removeFile(type, file);
- }
- }
-
- protected void removeFile(@NonNull ResourceType type, @NonNull ResourceFile file) {
- Map<String, ResourceItem> map = mResourceMap.get(type);
- if (map != null) {
- Collection<ResourceItem> values = map.values();
- for (ResourceItem item : values) {
- item.removeFile(file);
- }
- }
- }
-
- /**
- * Returns a map of (resource name, resource value) for the given {@link ResourceType}.
- * <p/>The values returned are taken from the resource files best matching a given
- * {@link FolderConfiguration}.
- * @param type the type of the resources.
- * @param referenceConfig the configuration to best match.
- */
- @NonNull
- private Map<String, ResourceValue> getConfiguredResource(@NonNull ResourceType type,
- @NonNull FolderConfiguration referenceConfig) {
-
- // get the resource item for the given type
- Map<String, ResourceItem> items = mResourceMap.get(type);
- if (items == null) {
- return new HashMap<String, ResourceValue>();
- }
-
- // create the map
- HashMap<String, ResourceValue> map = new HashMap<String, ResourceValue>(items.size());
-
- for (ResourceItem item : items.values()) {
- ResourceValue value = item.getResourceValue(type, referenceConfig,
- isFrameworkRepository());
- if (value != null) {
- map.put(item.getName(), value);
- }
- }
-
- return map;
- }
-
-
- /**
- * Cleans up the repository of resource items that have no source file anymore.
- */
- public void postUpdateCleanUp() {
- // Since removed files/folders remove source files from existing ResourceItem, loop through
- // all resource items and remove the ones that have no source files.
-
- Collection<Map<String, ResourceItem>> maps = mResourceMap.values();
- for (Map<String, ResourceItem> map : maps) {
- Set<String> keySet = map.keySet();
- Iterator<String> iterator = keySet.iterator();
- while (iterator.hasNext()) {
- String name = iterator.next();
- ResourceItem resourceItem = map.get(name);
- if (resourceItem.hasNoSourceFile()) {
- iterator.remove();
- }
- }
- }
- }
-
- /**
- * Looks up an existing {@link ResourceItem} by {@link ResourceType} and name. This
- * ignores inline resources.
- * @param type the Resource Type.
- * @param name the Resource name.
- * @return the existing ResourceItem or null if no match was found.
- */
- @Nullable
- private ResourceItem findDeclaredResourceItem(@NonNull ResourceType type,
- @NonNull String name) {
- Map<String, ResourceItem> map = mResourceMap.get(type);
-
- if (map != null) {
- ResourceItem resourceItem = map.get(name);
- if (resourceItem != null && !resourceItem.isDeclaredInline()) {
- return resourceItem;
- }
- }
-
- return null;
- }
-
- /**
- * Return the resource type of the given url, and the resource name
- *
- * @param url the resource url to be parsed
- * @return a pair of the resource type and the resource name
- */
- public static Pair<ResourceType,String> parseResource(String url) {
- // Handle theme references
- if (url.startsWith(PREFIX_THEME_REF)) {
- String remainder = url.substring(PREFIX_THEME_REF.length());
- if (url.startsWith(ATTR_REF_PREFIX)) {
- url = PREFIX_RESOURCE_REF + url.substring(PREFIX_THEME_REF.length());
- return parseResource(url);
- }
- int colon = url.indexOf(':');
- if (colon != -1) {
- // Convert from ?android:progressBarStyleBig to ?android:attr/progressBarStyleBig
- if (remainder.indexOf('/', colon) == -1) {
- remainder = remainder.substring(0, colon) + RESOURCE_CLZ_ATTR + '/'
- + remainder.substring(colon);
- }
- url = PREFIX_RESOURCE_REF + remainder;
- return parseResource(url);
- } else {
- int slash = url.indexOf('/');
- if (slash == -1) {
- url = PREFIX_RESOURCE_REF + RESOURCE_CLZ_ATTR + '/' + remainder;
- return parseResource(url);
- }
- }
- }
-
- if (!url.startsWith(PREFIX_RESOURCE_REF)) {
- return null;
- }
- int typeEnd = url.indexOf('/', 1);
- if (typeEnd == -1) {
- return null;
- }
- int nameBegin = typeEnd + 1;
-
- // Skip @ and @+
- int typeBegin = url.startsWith("@+") ? 2 : 1; //$NON-NLS-1$
-
- int colon = url.lastIndexOf(':', typeEnd);
- if (colon != -1) {
- typeBegin = colon + 1;
- }
- String typeName = url.substring(typeBegin, typeEnd);
- ResourceType type = ResourceType.getEnum(typeName);
- if (type == null) {
- return null;
- }
- String name = url.substring(nameBegin);
-
- return Pair.of(type, name);
- }
-}
-
diff --git a/sdk_common/src/com/android/ide/common/resources/ResourceResolver.java b/sdk_common/src/com/android/ide/common/resources/ResourceResolver.java
deleted file mode 100644
index 219c93f..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ResourceResolver.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.SdkConstants.ANDROID_PREFIX;
-import static com.android.SdkConstants.ANDROID_THEME_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.REFERENCE_STYLE;
-
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.RenderResources;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.resources.ResourceType;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ResourceResolver extends RenderResources {
-
- private final Map<ResourceType, Map<String, ResourceValue>> mProjectResources;
- private final Map<ResourceType, Map<String, ResourceValue>> mFrameworkResources;
-
- private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap =
- new HashMap<StyleResourceValue, StyleResourceValue>();
-
- private StyleResourceValue mTheme;
-
- private FrameworkResourceIdProvider mFrameworkProvider;
- private LayoutLog mLogger;
- private String mThemeName;
- private boolean mIsProjectTheme;
-
- private ResourceResolver(
- Map<ResourceType, Map<String, ResourceValue>> projectResources,
- Map<ResourceType, Map<String, ResourceValue>> frameworkResources) {
- mProjectResources = projectResources;
- mFrameworkResources = frameworkResources;
- }
-
- /**
- * Creates a new {@link ResourceResolver} object.
- *
- * @param projectResources the project resources.
- * @param frameworkResources the framework resources.
- * @param themeName the name of the current theme.
- * @param isProjectTheme Is this a project theme?
- * @return a new {@link ResourceResolver}
- */
- public static ResourceResolver create(
- Map<ResourceType, Map<String, ResourceValue>> projectResources,
- Map<ResourceType, Map<String, ResourceValue>> frameworkResources,
- String themeName, boolean isProjectTheme) {
-
- ResourceResolver resolver = new ResourceResolver(
- projectResources, frameworkResources);
-
- resolver.computeStyleMaps(themeName, isProjectTheme);
-
- return resolver;
- }
-
- // ---- Methods to help dealing with older LayoutLibs.
-
- public String getThemeName() {
- return mThemeName;
- }
-
- public boolean isProjectTheme() {
- return mIsProjectTheme;
- }
-
- public Map<ResourceType, Map<String, ResourceValue>> getProjectResources() {
- return mProjectResources;
- }
-
- public Map<ResourceType, Map<String, ResourceValue>> getFrameworkResources() {
- return mFrameworkResources;
- }
-
- // ---- RenderResources Methods
-
- @Override
- public void setFrameworkResourceIdProvider(FrameworkResourceIdProvider provider) {
- mFrameworkProvider = provider;
- }
-
- @Override
- public void setLogger(LayoutLog logger) {
- mLogger = logger;
- }
-
- @Override
- public StyleResourceValue getCurrentTheme() {
- return mTheme;
- }
-
- @Override
- public StyleResourceValue getTheme(String name, boolean frameworkTheme) {
- ResourceValue theme = null;
-
- if (frameworkTheme) {
- Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(
- ResourceType.STYLE);
- theme = frameworkStyleMap.get(name);
- } else {
- Map<String, ResourceValue> projectStyleMap = mProjectResources.get(ResourceType.STYLE);
- theme = projectStyleMap.get(name);
- }
-
- if (theme instanceof StyleResourceValue) {
- return (StyleResourceValue) theme;
- }
-
- return null;
- }
-
- @Override
- public boolean themeIsParentOf(StyleResourceValue parentTheme, StyleResourceValue childTheme) {
- do {
- childTheme = mStyleInheritanceMap.get(childTheme);
- if (childTheme == null) {
- return false;
- } else if (childTheme == parentTheme) {
- return true;
- }
- } while (true);
- }
-
- @Override
- public ResourceValue getFrameworkResource(ResourceType resourceType, String resourceName) {
- return getResource(resourceType, resourceName, mFrameworkResources);
- }
-
- @Override
- public ResourceValue getProjectResource(ResourceType resourceType, String resourceName) {
- return getResource(resourceType, resourceName, mProjectResources);
- }
-
- @Override
- @Deprecated
- public ResourceValue findItemInStyle(StyleResourceValue style, String attrName) {
- // this method is deprecated because it doesn't know about the namespace of the
- // attribute so we search for the project namespace first and then in the
- // android namespace if needed.
- ResourceValue item = findItemInStyle(style, attrName, false /*isFrameworkAttr*/);
- if (item == null) {
- item = findItemInStyle(style, attrName, true /*isFrameworkAttr*/);
- }
-
- return item;
- }
-
- @Override
- public ResourceValue findItemInStyle(StyleResourceValue style, String itemName,
- boolean isFrameworkAttr) {
- ResourceValue item = style.findValue(itemName, isFrameworkAttr);
-
- // if we didn't find it, we look in the parent style (if applicable)
- if (item == null && mStyleInheritanceMap != null) {
- StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
- if (parentStyle != null) {
- return findItemInStyle(parentStyle, itemName, isFrameworkAttr);
- }
- }
-
- return item;
- }
-
- @Override
- public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
- if (reference == null) {
- return null;
- }
- if (reference.startsWith(PREFIX_THEME_REF)
- && reference.length() > PREFIX_THEME_REF.length()) {
- // no theme? no need to go further!
- if (mTheme == null) {
- return null;
- }
-
- boolean frameworkOnly = false;
-
- // eliminate the prefix from the string
- String originalReference = reference;
- if (reference.startsWith(ANDROID_THEME_PREFIX)) {
- frameworkOnly = true;
- reference = reference.substring(ANDROID_THEME_PREFIX.length());
- } else {
- reference = reference.substring(PREFIX_THEME_REF.length());
- }
-
- // at this point, value can contain type/name (drawable/foo for instance).
- // split it to make sure.
- String[] segments = reference.split("/");
-
- // we look for the referenced item name.
- String referenceName = null;
-
- if (segments.length == 2) {
- // there was a resType in the reference. If it's attr, we ignore it
- // else, we assert for now.
- if (ResourceType.ATTR.getName().equals(segments[0])) {
- referenceName = segments[1];
- } else {
- // At this time, no support for ?type/name where type is not "attr"
- return null;
- }
- } else {
- // it's just an item name.
- referenceName = segments[0];
-
- // Make sure it looks like a resource name; if not, it could just be a string
- // which starts with a ?
- if (!Character.isJavaIdentifierStart(referenceName.charAt(0))) {
- return null;
- }
- for (int i = 1, n = referenceName.length(); i < n; i++) {
- char c = referenceName.charAt(i);
- if (!Character.isJavaIdentifierPart(c) && c != '.') {
- return null;
- }
- }
- }
-
- // now we look for android: in the referenceName in order to support format
- // such as: ?attr/android:name
- if (referenceName.startsWith(PREFIX_ANDROID)) {
- frameworkOnly = true;
- referenceName = referenceName.substring(PREFIX_ANDROID.length());
- }
-
- // Now look for the item in the theme, starting with the current one.
- ResourceValue item = findItemInStyle(mTheme, referenceName,
- forceFrameworkOnly || frameworkOnly);
-
- if (item == null && mLogger != null) {
- mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
- String.format("Couldn't find theme resource %1$s for the current theme",
- reference),
- new ResourceValue(ResourceType.ATTR, originalReference, frameworkOnly));
- }
-
- return item;
- } else if (reference.startsWith(PREFIX_RESOURCE_REF)) {
- boolean frameworkOnly = false;
-
- // check for the specific null reference value.
- if (REFERENCE_NULL.equals(reference)) {
- return null;
- }
-
- // Eliminate the prefix from the string.
- if (reference.startsWith(ANDROID_PREFIX)) {
- frameworkOnly = true;
- reference = reference.substring(ANDROID_PREFIX.length());
- } else {
- reference = reference.substring(PREFIX_RESOURCE_REF.length());
- }
-
- // at this point, value contains type/[android:]name (drawable/foo for instance)
- String[] segments = reference.split("/");
- if (segments.length != 2) {
- return null;
- }
-
- // now we look for android: in the resource name in order to support format
- // such as: @drawable/android:name
- String referenceName = segments[1];
- if (referenceName.startsWith(PREFIX_ANDROID)) {
- frameworkOnly = true;
- referenceName = referenceName.substring(PREFIX_ANDROID.length());
- }
-
- ResourceType type = ResourceType.getEnum(segments[0]);
-
- // unknown type?
- if (type == null) {
- return null;
- }
-
- // Make sure it looks like a resource name; if not, it could just be a string
- // which starts with a ?
- if (!Character.isJavaIdentifierStart(referenceName.charAt(0))) {
- return null;
- }
- for (int i = 1, n = referenceName.length(); i < n; i++) {
- char c = referenceName.charAt(i);
- if (!Character.isJavaIdentifierPart(c) && c != '.') {
- return null;
- }
- }
-
- return findResValue(type, referenceName,
- forceFrameworkOnly ? true :frameworkOnly);
- }
-
- // Looks like the value didn't reference anything. Return null.
- return null;
- }
-
- @Override
- public ResourceValue resolveValue(ResourceType type, String name, String value,
- boolean isFrameworkValue) {
- if (value == null) {
- return null;
- }
-
- // get the ResourceValue referenced by this value
- ResourceValue resValue = findResValue(value, isFrameworkValue);
-
- // if resValue is null, but value is not null, this means it was not a reference.
- // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
- // matter.
- if (resValue == null) {
- return new ResourceValue(type, name, value, isFrameworkValue);
- }
-
- // we resolved a first reference, but we need to make sure this isn't a reference also.
- return resolveResValue(resValue);
- }
-
- @Override
- public ResourceValue resolveResValue(ResourceValue resValue) {
- if (resValue == null) {
- return null;
- }
-
- // if the resource value is null, we simply return it.
- String value = resValue.getValue();
- if (value == null) {
- return resValue;
- }
-
- // else attempt to find another ResourceValue referenced by this one.
- ResourceValue resolvedResValue = findResValue(value, resValue.isFramework());
-
- // if the value did not reference anything, then we simply return the input value
- if (resolvedResValue == null) {
- return resValue;
- }
-
- // detect potential loop due to mishandled namespace in attributes
- if (resValue == resolvedResValue) {
- if (mLogger != null) {
- mLogger.error(LayoutLog.TAG_BROKEN,
- String.format("Potential stackoverflow trying to resolve '%s'. Render may not be accurate.", value),
- null);
- }
- return resValue;
- }
-
- // otherwise, we attempt to resolve this new value as well
- return resolveResValue(resolvedResValue);
- }
-
- // ---- Private helper methods.
-
- /**
- * Searches for, and returns a {@link ResourceValue} by its name, and type.
- * @param resType the type of the resource
- * @param resName the name of the resource
- * @param frameworkOnly if <code>true</code>, the method does not search in the
- * project resources
- */
- private ResourceValue findResValue(ResourceType resType, String resName,
- boolean frameworkOnly) {
- // map of ResouceValue for the given type
- Map<String, ResourceValue> typeMap;
-
- // if allowed, search in the project resources first.
- if (frameworkOnly == false) {
- typeMap = mProjectResources.get(resType);
- ResourceValue item = typeMap.get(resName);
- if (item != null) {
- return item;
- }
- }
-
- // now search in the framework resources.
- typeMap = mFrameworkResources.get(resType);
- ResourceValue item = typeMap.get(resName);
- if (item != null) {
- return item;
- }
-
- // if it was not found and the type is an id, it is possible that the ID was
- // generated dynamically when compiling the framework resources.
- // Look for it in the R map.
- if (mFrameworkProvider != null && resType == ResourceType.ID) {
- if (mFrameworkProvider.getId(resType, resName) != null) {
- return new ResourceValue(resType, resName, true);
- }
- }
-
- // didn't find the resource anywhere.
- if (mLogger != null) {
- mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE,
- "Couldn't resolve resource @" +
- (frameworkOnly ? "android:" : "") + resType + "/" + resName,
- new ResourceValue(resType, resName, frameworkOnly));
- }
- return null;
- }
-
- private ResourceValue getResource(ResourceType resourceType, String resourceName,
- Map<ResourceType, Map<String, ResourceValue>> resourceRepository) {
- Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
- if (typeMap != null) {
- ResourceValue item = typeMap.get(resourceName);
- if (item != null) {
- item = resolveResValue(item);
- return item;
- }
- }
-
- // didn't find the resource anywhere.
- return null;
-
- }
-
- /**
- * Compute style information from the given list of style for the project and framework.
- * @param themeName the name of the current theme.
- * @param isProjectTheme Is this a project theme?
- */
- private void computeStyleMaps(String themeName, boolean isProjectTheme) {
- mThemeName = themeName;
- mIsProjectTheme = isProjectTheme;
- Map<String, ResourceValue> projectStyleMap = mProjectResources.get(ResourceType.STYLE);
- Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(ResourceType.STYLE);
-
- // first, get the theme
- ResourceValue theme = null;
-
- // project theme names have been prepended with a *
- if (isProjectTheme) {
- theme = projectStyleMap.get(themeName);
- } else {
- theme = frameworkStyleMap.get(themeName);
- }
-
- if (theme instanceof StyleResourceValue) {
- // compute the inheritance map for both the project and framework styles
- computeStyleInheritance(projectStyleMap.values(), projectStyleMap,
- frameworkStyleMap);
-
- // Compute the style inheritance for the framework styles/themes.
- // Since, for those, the style parent values do not contain 'android:'
- // we want to force looking in the framework style only to avoid using
- // similarly named styles from the project.
- // To do this, we pass null in lieu of the project style map.
- computeStyleInheritance(frameworkStyleMap.values(), null /*inProjectStyleMap */,
- frameworkStyleMap);
-
- mTheme = (StyleResourceValue) theme;
- }
- }
-
-
-
- /**
- * Compute the parent style for all the styles in a given list.
- * @param styles the styles for which we compute the parent.
- * @param inProjectStyleMap the map of project styles.
- * @param inFrameworkStyleMap the map of framework styles.
- * @param outInheritanceMap the map of style inheritance. This is filled by the method.
- */
- private void computeStyleInheritance(Collection<ResourceValue> styles,
- Map<String, ResourceValue> inProjectStyleMap,
- Map<String, ResourceValue> inFrameworkStyleMap) {
- for (ResourceValue value : styles) {
- if (value instanceof StyleResourceValue) {
- StyleResourceValue style = (StyleResourceValue)value;
- StyleResourceValue parentStyle = null;
-
- // first look for a specified parent.
- String parentName = style.getParentStyle();
-
- // no specified parent? try to infer it from the name of the style.
- if (parentName == null) {
- parentName = getParentName(value.getName());
- }
-
- if (parentName != null) {
- parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
- if (parentStyle != null) {
- mStyleInheritanceMap.put(style, parentStyle);
- }
- }
- }
- }
- }
-
-
- /**
- * Computes the name of the parent style, or <code>null</code> if the style is a root style.
- */
- private String getParentName(String styleName) {
- int index = styleName.lastIndexOf('.');
- if (index != -1) {
- return styleName.substring(0, index);
- }
-
- return null;
- }
-
- /**
- * Searches for and returns the {@link StyleResourceValue} from a given name.
- * <p/>The format of the name can be:
- * <ul>
- * <li>[android:]&lt;name&gt;</li>
- * <li>[android:]style/&lt;name&gt;</li>
- * <li>@[android:]style/&lt;name&gt;</li>
- * </ul>
- * @param parentName the name of the style.
- * @param inProjectStyleMap the project style map. Can be <code>null</code>
- * @param inFrameworkStyleMap the framework style map.
- * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
- */
- private StyleResourceValue getStyle(String parentName,
- Map<String, ResourceValue> inProjectStyleMap,
- Map<String, ResourceValue> inFrameworkStyleMap) {
- boolean frameworkOnly = false;
-
- String name = parentName;
-
- // remove the useless @ if it's there
- if (name.startsWith(PREFIX_RESOURCE_REF)) {
- name = name.substring(PREFIX_RESOURCE_REF.length());
- }
-
- // check for framework identifier.
- if (name.startsWith(PREFIX_ANDROID)) {
- frameworkOnly = true;
- name = name.substring(PREFIX_ANDROID.length());
- }
-
- // at this point we could have the format <type>/<name>. we want only the name as long as
- // the type is style.
- if (name.startsWith(REFERENCE_STYLE)) {
- name = name.substring(REFERENCE_STYLE.length());
- } else if (name.indexOf('/') != -1) {
- return null;
- }
-
- ResourceValue parent = null;
-
- // if allowed, search in the project resources.
- if (frameworkOnly == false && inProjectStyleMap != null) {
- parent = inProjectStyleMap.get(name);
- }
-
- // if not found, then look in the framework resources.
- if (parent == null) {
- parent = inFrameworkStyleMap.get(name);
- }
-
- // make sure the result is the proper class type and return it.
- if (parent instanceof StyleResourceValue) {
- return (StyleResourceValue)parent;
- }
-
- if (mLogger != null) {
- mLogger.error(LayoutLog.TAG_RESOURCES_RESOLVE,
- String.format("Unable to resolve parent style name: %s", parentName),
- null /*data*/);
- }
-
- return null;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ScanningContext.java b/sdk_common/src/com/android/ide/common/resources/ScanningContext.java
deleted file mode 100644
index 43561e8..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ScanningContext.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.resources;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link ScanningContext} keeps track of state during a resource file scan,
- * such as any parsing errors encountered, whether Android ids have changed, and
- * so on.
- */
-public class ScanningContext {
- protected final ResourceRepository mRepository;
- private boolean mNeedsFullAapt;
- private List<String> mErrors = null;
-
- /**
- * Constructs a new {@link ScanningContext}
- *
- * @param repository the associated resource repository
- */
- public ScanningContext(@NonNull ResourceRepository repository) {
- super();
- mRepository = repository;
- }
-
- /**
- * Returns a list of errors encountered during scanning
- *
- * @return a list of errors encountered during scanning (or null)
- */
- @Nullable
- public List<String> getErrors() {
- return mErrors;
- }
-
- /**
- * Adds the given error to the scanning context. The error should use the
- * same syntax as real aapt error messages such that the aapt parser can
- * properly detect the filename, line number, etc.
- *
- * @param error the error message, including file name and line number at
- * the beginning
- */
- public void addError(@NonNull String error) {
- if (mErrors == null) {
- mErrors = new ArrayList<String>();
- }
- mErrors.add(error);
- }
-
- /**
- * Returns the repository associated with this scanning context
- *
- * @return the associated repository, never null
- */
- @NonNull
- public ResourceRepository getRepository() {
- return mRepository;
- }
-
- /**
- * Marks that a full aapt compilation of the resources is necessary because it has
- * detected a change that cannot be incrementally handled.
- */
- protected void requestFullAapt() {
- mNeedsFullAapt = true;
- }
-
- /**
- * Returns whether this repository has been marked as "dirty"; if one or
- * more of the constituent files have declared that the resource item names
- * that they provide have changed.
- *
- * @return true if a full aapt compilation is required
- */
- public boolean needsFullAapt() {
- return mNeedsFullAapt;
- }
-
- /**
- * Asks the context to check whether the given attribute name and value is valid
- * in this context.
- *
- * @param uri the XML namespace URI
- * @param name the attribute local name
- * @param value the attribute value
- * @return true if the attribute is valid
- */
- public boolean checkValue(@Nullable String uri, @NonNull String name, @NonNull String value) {
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/SingleResourceFile.java b/sdk_common/src/com/android/ide/common/resources/SingleResourceFile.java
deleted file mode 100644
index 8e394d3..0000000
--- a/sdk_common/src/com/android/ide/common/resources/SingleResourceFile.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.SdkConstants.DOT_XML;
-
-import com.android.ide.common.rendering.api.DensityBasedResourceValue;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.configuration.DensityQualifier;
-import com.android.io.IAbstractFile;
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceType;
-import com.android.utils.SdkUtils;
-
-import java.util.Collection;
-import java.util.List;
-
-import javax.xml.parsers.SAXParserFactory;
-
-/**
- * Represents a resource file describing a single resource.
- * <p/>
- * This is typically an XML file inside res/anim, res/layout, or res/menu or an image file
- * under res/drawable.
- */
-public class SingleResourceFile extends ResourceFile {
-
- private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
- static {
- sParserFactory.setNamespaceAware(true);
- }
-
- private final String mResourceName;
- private final ResourceType mType;
- private ResourceValue mValue;
-
- public SingleResourceFile(IAbstractFile file, ResourceFolder folder) {
- super(file, folder);
-
- // we need to infer the type of the resource from the folder type.
- // This is easy since this is a single Resource file.
- List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(folder.getType());
- mType = types.get(0);
-
- // compute the resource name
- mResourceName = getResourceName(mType);
-
- // test if there's a density qualifier associated with the resource
- DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
-
- if (qualifier == null) {
- mValue = new ResourceValue(mType, getResourceName(mType),
- file.getOsLocation(), isFramework());
- } else {
- mValue = new DensityBasedResourceValue(
- mType,
- getResourceName(mType),
- file.getOsLocation(),
- qualifier.getValue(),
- isFramework());
- }
- }
-
- @Override
- protected void load(ScanningContext context) {
- // get a resource item matching the given type and name
- ResourceItem item = getRepository().getResourceItem(mType, mResourceName);
-
- // add this file to the list of files generating this resource item.
- item.add(this);
-
- // Ask for an ID refresh since we're adding an item that will generate an ID
- context.requestFullAapt();
- }
-
- @Override
- protected void update(ScanningContext context) {
- // when this happens, nothing needs to be done since the file only generates
- // a single resources that doesn't actually change (its content is the file path)
-
- // However, we should check for newly introduced errors
- // Parse the file and look for @+id/ entries
- validateAttributes(context);
- }
-
- @Override
- protected void dispose(ScanningContext context) {
- // only remove this file from the existing ResourceItem.
- getFolder().getRepository().removeFile(mType, this);
-
- // Ask for an ID refresh since we're removing an item that previously generated an ID
- context.requestFullAapt();
-
- // don't need to touch the content, it'll get reclaimed as this objects disappear.
- // In the mean time other objects may need to access it.
- }
-
- @Override
- public Collection<ResourceType> getResourceTypes() {
- return FolderTypeRelationship.getRelatedResourceTypes(getFolder().getType());
- }
-
- @Override
- public boolean hasResources(ResourceType type) {
- return FolderTypeRelationship.match(type, getFolder().getType());
- }
-
- /*
- * (non-Javadoc)
- * @see com.android.ide.eclipse.editors.resources.manager.ResourceFile#getValue(com.android.ide.eclipse.common.resources.ResourceType, java.lang.String)
- *
- * This particular implementation does not care about the type or name since a
- * SingleResourceFile represents a file generating only one resource.
- * The value returned is the full absolute path of the file in OS form.
- */
- @Override
- public ResourceValue getValue(ResourceType type, String name) {
- return mValue;
- }
-
- /**
- * Returns the name of the resources.
- */
- private String getResourceName(ResourceType type) {
- // get the name from the filename.
- String name = getFile().getName();
-
- int pos = name.indexOf('.');
- if (pos != -1) {
- name = name.substring(0, pos);
- }
-
- return name;
- }
-
- /**
- * Validates the associated resource file to make sure the attribute references are valid
- *
- * @return true if parsing succeeds and false if it fails
- */
- private boolean validateAttributes(ScanningContext context) {
- // We only need to check if it's a non-framework file (and an XML file; skip .png's)
- if (!isFramework() && SdkUtils.endsWith(getFile().getName(), DOT_XML)) {
- ValidatingResourceParser parser = new ValidatingResourceParser(context, false);
- try {
- IAbstractFile file = getFile();
- return parser.parse(file.getOsLocation(), file.getContents());
- } catch (Exception e) {
- context.needsFullAapt();
- }
-
- return false;
- }
-
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ValidatingResourceParser.java b/sdk_common/src/com/android/ide/common/resources/ValidatingResourceParser.java
deleted file mode 100644
index b477b8f..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ValidatingResourceParser.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import com.android.annotations.NonNull;
-import com.google.common.io.Closeables;
-
-import org.kxml2.io.KXmlParser;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Parser for scanning an XML resource file and validating all framework
- * attribute references in it. If an error is found, the associated context
- * is marked as needing a full AAPT run.
- */
-public class ValidatingResourceParser {
- private final boolean mIsFramework;
- private ScanningContext mContext;
-
- /**
- * Creates a new {@link ValidatingResourceParser}
- *
- * @param context a context object with state for the current update, such
- * as a place to stash errors encountered
- * @param isFramework true if scanning a framework resource
- */
- public ValidatingResourceParser(
- @NonNull ScanningContext context,
- boolean isFramework) {
- mContext = context;
- mIsFramework = isFramework;
- }
-
- /**
- * Parse the given input and return false if it contains errors, <b>or</b> if
- * the context is already tagged as needing a full aapt run.
- *
- * @param path the full OS path to the file being parsed
- * @param input the input stream of the XML to be parsed (will be closed by this method)
- * @return true if parsing succeeds and false if it fails
- * @throws IOException if reading the contents fails
- */
- public boolean parse(final String path, InputStream input)
- throws IOException {
- // No need to validate framework files
- if (mIsFramework) {
- Closeables.closeQuietly(input);
- return true;
- }
- if (mContext.needsFullAapt()) {
- Closeables.closeQuietly(input);
- return false;
- }
-
- KXmlParser parser = new KXmlParser();
- try {
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-
- if (input instanceof FileInputStream) {
- input = new BufferedInputStream(input);
- }
- parser.setInput(input, "UTF-8"); //$NON-NLS-1$
-
- return parse(path, parser);
- } catch (XmlPullParserException e) {
- String message = e.getMessage();
-
- // Strip off position description
- int index = message.indexOf("(position:"); //$NON-NLS-1$ (Hardcoded in KXml)
- if (index != -1) {
- message = message.substring(0, index);
- }
-
- String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$
- path, parser.getLineNumber(), message);
- mContext.addError(error);
- return false;
- } catch (RuntimeException e) {
- // Some exceptions are thrown by the KXmlParser that are not XmlPullParserExceptions,
- // such as this one:
- // java.lang.RuntimeException: Undefined Prefix: w in org.kxml2.io.KXmlParser@...
- // at org.kxml2.io.KXmlParser.adjustNsp(Unknown Source)
- // at org.kxml2.io.KXmlParser.parseStartTag(Unknown Source)
- String message = e.getMessage();
- String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$
- path, parser.getLineNumber(), message);
- mContext.addError(error);
- return false;
- } finally {
- Closeables.closeQuietly(input);
- }
- }
-
- private boolean parse(String path, KXmlParser parser)
- throws XmlPullParserException, IOException {
- boolean checkForErrors = !mIsFramework && !mContext.needsFullAapt();
-
- while (true) {
- int event = parser.next();
- if (event == XmlPullParser.START_TAG) {
- for (int i = 0, n = parser.getAttributeCount(); i < n; i++) {
- String attribute = parser.getAttributeName(i);
- String value = parser.getAttributeValue(i);
- assert value != null : attribute;
-
- if (checkForErrors) {
- String uri = parser.getAttributeNamespace(i);
- if (!mContext.checkValue(uri, attribute, value)) {
- mContext.requestFullAapt();
- return false;
- }
- }
- }
- } else if (event == XmlPullParser.END_DOCUMENT) {
- break;
- }
- }
-
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/ValueResourceParser.java b/sdk_common/src/com/android/ide/common/resources/ValueResourceParser.java
deleted file mode 100644
index aa1f4b8..0000000
--- a/sdk_common/src/com/android/ide/common/resources/ValueResourceParser.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.SdkConstants.AMP_ENTITY;
-import static com.android.SdkConstants.LT_ENTITY;
-
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.rendering.api.AttrResourceValue;
-import com.android.ide.common.rendering.api.DeclareStyleableResourceValue;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.resources.ResourceType;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * SAX handler to parser value resource files.
- */
-public final class ValueResourceParser extends DefaultHandler {
-
- // TODO: reuse definitions from somewhere else.
- private final static String NODE_RESOURCES = "resources";
- private final static String NODE_ITEM = "item";
- private final static String ATTR_NAME = "name";
- private final static String ATTR_TYPE = "type";
- private final static String ATTR_PARENT = "parent";
- private final static String ATTR_VALUE = "value";
-
- private final static String DEFAULT_NS_PREFIX = "android:";
- private final static int DEFAULT_NS_PREFIX_LEN = DEFAULT_NS_PREFIX.length();
-
- public interface IValueResourceRepository {
- void addResourceValue(ResourceValue value);
- boolean hasResourceValue(ResourceType type, String name);
- }
-
- private boolean inResources = false;
- private int mDepth = 0;
- private ResourceValue mCurrentValue = null;
- private StyleResourceValue mCurrentStyle = null;
- private DeclareStyleableResourceValue mCurrentDeclareStyleable = null;
- private AttrResourceValue mCurrentAttr;
- private IValueResourceRepository mRepository;
- private final boolean mIsFramework;
-
- public ValueResourceParser(IValueResourceRepository repository, boolean isFramework) {
- mRepository = repository;
- mIsFramework = isFramework;
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (mCurrentValue != null) {
- mCurrentValue.setValue(unescapeResourceString(mCurrentValue.getValue(), false, true));
- }
-
- if (inResources && qName.equals(NODE_RESOURCES)) {
- inResources = false;
- } else if (mDepth == 2) {
- mCurrentValue = null;
- mCurrentStyle = null;
- mCurrentDeclareStyleable = null;
- mCurrentAttr = null;
- } else if (mDepth == 3) {
- mCurrentValue = null;
- if (mCurrentDeclareStyleable != null) {
- mCurrentAttr = null;
- }
- }
-
- mDepth--;
- super.endElement(uri, localName, qName);
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes)
- throws SAXException {
- try {
- mDepth++;
- if (inResources == false && mDepth == 1) {
- if (qName.equals(NODE_RESOURCES)) {
- inResources = true;
- }
- } else if (mDepth == 2 && inResources == true) {
- ResourceType type = getType(qName, attributes);
-
- if (type != null) {
- // get the resource name
- String name = attributes.getValue(ATTR_NAME);
- if (name != null) {
- switch (type) {
- case STYLE:
- String parent = attributes.getValue(ATTR_PARENT);
- mCurrentStyle = new StyleResourceValue(type, name, parent,
- mIsFramework);
- mRepository.addResourceValue(mCurrentStyle);
- break;
- case DECLARE_STYLEABLE:
- mCurrentDeclareStyleable = new DeclareStyleableResourceValue(
- type, name, mIsFramework);
- mRepository.addResourceValue(mCurrentDeclareStyleable);
- break;
- case ATTR:
- mCurrentAttr = new AttrResourceValue(type, name, mIsFramework);
- mRepository.addResourceValue(mCurrentAttr);
- break;
- default:
- mCurrentValue = new ResourceValue(type, name, mIsFramework);
- mRepository.addResourceValue(mCurrentValue);
- break;
- }
- }
- }
- } else if (mDepth == 3) {
- // get the resource name
- String name = attributes.getValue(ATTR_NAME);
- if (name != null) {
-
- if (mCurrentStyle != null) {
- // is the attribute in the android namespace?
- boolean isFrameworkAttr = mIsFramework;
- if (name.startsWith(DEFAULT_NS_PREFIX)) {
- name = name.substring(DEFAULT_NS_PREFIX_LEN);
- isFrameworkAttr = true;
- }
-
- mCurrentValue = new ResourceValue(null, name, mIsFramework);
- mCurrentStyle.addValue(mCurrentValue, isFrameworkAttr);
- } else if (mCurrentDeclareStyleable != null) {
- // is the attribute in the android namespace?
- boolean isFramework = mIsFramework;
- if (name.startsWith(DEFAULT_NS_PREFIX)) {
- name = name.substring(DEFAULT_NS_PREFIX_LEN);
- isFramework = true;
- }
-
- mCurrentAttr = new AttrResourceValue(ResourceType.ATTR, name, isFramework);
- mCurrentDeclareStyleable.addValue(mCurrentAttr);
-
- // also add it to the repository.
- mRepository.addResourceValue(mCurrentAttr);
-
- } else if (mCurrentAttr != null) {
- // get the enum/flag value
- String value = attributes.getValue(ATTR_VALUE);
-
- try {
- // Integer.decode/parseInt can't deal with hex value > 0x7FFFFFFF so we
- // use Long.decode instead.
- mCurrentAttr.addValue(name, (int)(long)Long.decode(value));
- } catch (NumberFormatException e) {
- // pass, we'll just ignore this value
- }
-
- }
- }
- } else if (mDepth == 4 && mCurrentAttr != null) {
- // get the enum/flag name
- String name = attributes.getValue(ATTR_NAME);
- String value = attributes.getValue(ATTR_VALUE);
-
- try {
- // Integer.decode/parseInt can't deal with hex value > 0x7FFFFFFF so we
- // use Long.decode instead.
- mCurrentAttr.addValue(name, (int)(long)Long.decode(value));
- } catch (NumberFormatException e) {
- // pass, we'll just ignore this value
- }
- }
- } finally {
- super.startElement(uri, localName, qName, attributes);
- }
- }
-
- private ResourceType getType(String qName, Attributes attributes) {
- String typeValue;
-
- // if the node is <item>, we get the type from the attribute "type"
- if (NODE_ITEM.equals(qName)) {
- typeValue = attributes.getValue(ATTR_TYPE);
- } else {
- // the type is the name of the node.
- typeValue = qName;
- }
-
- ResourceType type = ResourceType.getEnum(typeValue);
- return type;
- }
-
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- if (mCurrentValue != null) {
- String value = mCurrentValue.getValue();
- if (value == null) {
- mCurrentValue.setValue(new String(ch, start, length));
- } else {
- mCurrentValue.setValue(value + new String(ch, start, length));
- }
- }
- }
-
- /**
- * Replaces escapes in an XML resource string with the actual characters,
- * performing unicode substitutions (replacing any {@code \\uNNNN} references in the
- * given string with the corresponding unicode characters), etc.
- *
- *
- *
- * @param s the string to unescape
- * @param escapeEntities XML entities
- * @param trim whether surrounding space and quotes should be trimmed
- * @return the string with the escape characters removed and expanded
- */
- @Nullable
- public static String unescapeResourceString(
- @Nullable String s,
- boolean escapeEntities, boolean trim) {
- if (s == null) {
- return null;
- }
-
- // Trim space surrounding optional quotes
- int i = 0;
- int n = s.length();
- if (trim) {
- while (i < n) {
- char c = s.charAt(i);
- if (!Character.isWhitespace(c)) {
- break;
- }
- i++;
- }
- while (n > i) {
- char c = s.charAt(n - 1);
- if (!Character.isWhitespace(c)) {
- //See if this was a \, and if so, see whether it was escaped
- if (n < s.length() && isEscaped(s, n)) {
- n++;
- }
- break;
- }
- n--;
- }
-
- // Trim surrounding quotes. Note that there can be *any* number of these, and
- // the left side and right side do not have to match; e.g. you can have
- // """"f"" => f
- int quoteStart = i;
- int quoteEnd = n;
- while (i < n) {
- char c = s.charAt(i);
- if (c != '"') {
- break;
- }
- i++;
- }
- // Searching backwards is slightly more complicated; make sure we don't trim
- // quotes that have been escaped.
- while (n > i) {
- char c = s.charAt(n - 1);
- if (c != '"') {
- if (n < s.length() && isEscaped(s, n)) {
- n++;
- }
- break;
- }
- n--;
- }
- if (n == i) {
- return ""; //$NON-NLS-1$
- }
-
- // Only trim leading spaces if we didn't already process a leading quote:
- if (i == quoteStart) {
- while (i < n) {
- char c = s.charAt(i);
- if (!Character.isWhitespace(c)) {
- break;
- }
- i++;
- }
- }
- // Only trim trailing spaces if we didn't already process a trailing quote:
- if (n == quoteEnd) {
- while (n > i) {
- char c = s.charAt(n - 1);
- if (!Character.isWhitespace(c)) {
- //See if this was a \, and if so, see whether it was escaped
- if (n < s.length() && isEscaped(s, n)) {
- n++;
- }
- break;
- }
- n--;
- }
- }
- if (n == i) {
- return ""; //$NON-NLS-1$
- }
- }
-
- // If no surrounding whitespace and no escape characters, no need to do any
- // more work
- if (i == 0 && n == s.length() && s.indexOf('\\') == -1
- && (!escapeEntities || s.indexOf('&') == -1)) {
- return s;
- }
-
- StringBuilder sb = new StringBuilder(n - i);
- for (; i < n; i++) {
- char c = s.charAt(i);
- if (c == '\\' && i < n - 1) {
- char next = s.charAt(i + 1);
- // Unicode escapes
- if (next == 'u' && i < n - 5) { // case sensitive
- String hex = s.substring(i + 2, i + 6);
- try {
- int unicodeValue = Integer.parseInt(hex, 16);
- sb.append((char) unicodeValue);
- i += 5;
- continue;
- } catch (NumberFormatException e) {
- // Invalid escape: Just proceed to literally transcribe it
- sb.append(c);
- }
- } else if (next == 'n') {
- sb.append('\n');
- i++;
- } else if (next == 't') {
- sb.append('\t');
- i++;
- } else {
- sb.append(next);
- i++;
- continue;
- }
- } else {
- if (c == '&' && escapeEntities) {
- if (s.regionMatches(true, i, LT_ENTITY, 0, LT_ENTITY.length())) {
- sb.append('<');
- i += LT_ENTITY.length() - 1;
- continue;
- } else if (s.regionMatches(true, i, AMP_ENTITY, 0, AMP_ENTITY.length())) {
- sb.append('&');
- i += AMP_ENTITY.length() - 1;
- continue;
- }
- }
- sb.append(c);
- }
- }
- s = sb.toString();
-
- return s;
- }
-
- /**
- * Returns true if the character at the given offset in the string is escaped
- * (the previous character is a \, and that character isn't itself an escaped \)
- *
- * @param s the string
- * @param index the index of the character in the string to check
- * @return true if the character is escaped
- */
- @VisibleForTesting
- static boolean isEscaped(String s, int index) {
- if (index == 0 || index == s.length()) {
- return false;
- }
- int prevPos = index - 1;
- char prev = s.charAt(prevPos);
- if (prev != '\\') {
- return false;
- }
- // The character *may* be escaped; not sure if the \ we ran into is
- // an escape character, or an escaped backslash; we have to search backwards
- // to be certain.
- int j = prevPos - 1;
- while (j >= 0) {
- if (s.charAt(j) != '\\') {
- break;
- }
- j--;
- }
- // If we passed an odd number of \'s, the space is escaped
- return (prevPos - j) % 2 == 1;
- }
-
- /**
- * Escape a string value to be placed in a string resource file such that it complies with
- * the escaping rules described here:
- * http://developer.android.com/guide/topics/resources/string-resource.html
- * More examples of the escaping rules can be found here:
- * http://androidcookbook.com/Recipe.seam?recipeId=2219&recipeFrom=ViewTOC
- * This method assumes that the String is not escaped already.
- *
- * Rules:
- * <ul>
- * <li>Double quotes are needed if string starts or ends with at least one space.
- * <li>{@code @, ?} at beginning of string have to be escaped with a backslash.
- * <li>{@code ', ", \} have to be escaped with a backslash.
- * <li>{@code <, >, &} have to be replaced by their predefined xml entity.
- * <li>{@code \n, \t} have to be replaced by a backslash and the appropriate character.
- * </ul>
- * @param s the string to be escaped
- * @return the escaped string as it would appear in the XML text in a values file
- */
- public static String escapeResourceString(String s) {
- int n = s.length();
- if (n == 0) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder(s.length() * 2);
- boolean hasSpace = s.charAt(0) == ' ' || s.charAt(n - 1) == ' ';
-
- if (hasSpace) {
- sb.append('"');
- } else if (s.charAt(0) == '@' || s.charAt(0) == '?') {
- sb.append('\\');
- }
-
- for (int i = 0; i < n; ++i) {
- char c = s.charAt(i);
- switch (c) {
- case '\'':
- if (!hasSpace) {
- sb.append('\\');
- }
- sb.append(c);
- break;
- case '"':
- case '\\':
- sb.append('\\');
- sb.append(c);
- break;
- case '<':
- sb.append(LT_ENTITY);
- break;
- case '&':
- sb.append(AMP_ENTITY);
- break;
- case '\n':
- sb.append("\\n"); //$NON-NLS-1$
- break;
- case '\t':
- sb.append("\\t"); //$NON-NLS-1$
- break;
- default:
- sb.append(c);
- break;
- }
- }
-
- if (hasSpace) {
- sb.append('"');
- }
-
- return sb.toString();
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/Configurable.java b/sdk_common/src/com/android/ide/common/resources/configuration/Configurable.java
deleted file mode 100644
index 5e7f910..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/Configurable.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-
-/**
- * An object that is associated with a {@link FolderConfiguration}.
- */
-public interface Configurable {
- /**
- * Returns the {@link FolderConfiguration} for this object.
- */
- public FolderConfiguration getConfiguration();
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/CountryCodeQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/CountryCodeQualifier.java
deleted file mode 100644
index eb7cc0d..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/CountryCodeQualifier.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Mobile Country Code.
- */
-public final class CountryCodeQualifier extends ResourceQualifier {
- /** Default pixel density value. This means the property is not set. */
- private final static int DEFAULT_CODE = -1;
-
- private final static Pattern sCountryCodePattern = Pattern.compile("^mcc(\\d{3})$");//$NON-NLS-1$
-
- private final int mCode;
-
- public static final String NAME = "Mobile Country Code";
-
- /**
- * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
- * <code>null</code> is returned.
- * @param segment the folder segment from which to create a qualifier.
- * @return a new {@link CountryCodeQualifier} object or <code>null</code>
- */
- public static CountryCodeQualifier getQualifier(String segment) {
- Matcher m = sCountryCodePattern.matcher(segment);
- if (m.matches()) {
- String v = m.group(1);
-
- int code = -1;
- try {
- code = Integer.parseInt(v);
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number.
- return null;
- }
-
- CountryCodeQualifier qualifier = new CountryCodeQualifier(code);
- return qualifier;
- }
-
- return null;
- }
-
- /**
- * Returns the folder name segment for the given value. This is equivalent to calling
- * {@link #toString()} on a {@link CountryCodeQualifier} object.
- * @param code the value of the qualifier, as returned by {@link #getCode()}.
- */
- public static String getFolderSegment(int code) {
- if (code != DEFAULT_CODE && code >= 100 && code <=999) { // code is 3 digit.) {
- return String.format("mcc%1$d", code); //$NON-NLS-1$
- }
-
- return ""; //$NON-NLS-1$
- }
-
- public CountryCodeQualifier() {
- this(DEFAULT_CODE);
- }
-
- public CountryCodeQualifier(int code) {
- mCode = code;
- }
-
- public int getCode() {
- return mCode;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Country Code";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean isValid() {
- return mCode != DEFAULT_CODE;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- CountryCodeQualifier qualifier = getQualifier(value);
- if (qualifier != null) {
- config.setCountryCodeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof CountryCodeQualifier) {
- return mCode == ((CountryCodeQualifier)qualifier).mCode;
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return mCode;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- return getFolderSegment(mCode);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (mCode != DEFAULT_CODE) {
- return String.format("MCC %1$d", mCode);
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- return getShortDisplayValue();
- }
-
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/DensityQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/DensityQualifier.java
deleted file mode 100644
index a9e4a01..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/DensityQualifier.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Density;
-import com.android.resources.ResourceEnum;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Screen Pixel Density.
- */
-public final class DensityQualifier extends EnumBasedResourceQualifier {
- private final static Pattern sDensityLegacyPattern = Pattern.compile("^(\\d+)dpi$");//$NON-NLS-1$
-
- public static final String NAME = "Density";
-
- private Density mValue = Density.MEDIUM;
-
- public DensityQualifier() {
- // pass
- }
-
- public DensityQualifier(Density value) {
- mValue = value;
- }
-
- public Density getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 4;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Density density = Density.getEnum(value);
- if (density == null) {
-
- // attempt to read a legacy value.
- Matcher m = sDensityLegacyPattern.matcher(value);
- if (m.matches()) {
- String v = m.group(1);
-
- try {
- density = Density.getEnum(Integer.parseInt(v));
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number
- // which really shouldn't happen since the regexp would have failed.
- }
- }
- }
-
- if (density != null) {
- DensityQualifier qualifier = new DensityQualifier();
- qualifier.mValue = density;
- config.setDensityQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- if (qualifier instanceof DensityQualifier) {
- // as long as there's a density qualifier, it's always a match.
- // The best match will be found later.
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- DensityQualifier compareQ = (DensityQualifier)compareTo;
- DensityQualifier referenceQ = (DensityQualifier)reference;
-
- if (compareQ.mValue == referenceQ.mValue) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mValue == referenceQ.mValue) {
- // got new exact value, this is the best!
- return true;
- } else {
- // in all case we're going to prefer the higher dpi.
- // if reference is high, we want highest dpi.
- // if reference is medium, we'll prefer to scale down high dpi, than scale up low dpi
- // if reference if low, we'll prefer to scale down high than medium (2:1 over 4:3)
- return mValue.getDpiValue() > compareQ.mValue.getDpiValue();
- }
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/DeviceConfigHelper.java b/sdk_common/src/com/android/ide/common/resources/configuration/DeviceConfigHelper.java
deleted file mode 100644
index 27eaa01..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/DeviceConfigHelper.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.annotations.Nullable;
-import com.android.resources.NightMode;
-import com.android.resources.UiMode;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.Hardware;
-import com.android.sdklib.devices.Screen;
-import com.android.sdklib.devices.State;
-
-public class DeviceConfigHelper {
- /**
- * Returns a {@link FolderConfiguration} based on the given state
- *
- * @param state
- * The {@link State} of the {@link Device} to base the
- * {@link FolderConfiguration} on. Can be null.
- * @return A {@link FolderConfiguration} based on the given {@link State}.
- * If the given {@link State} is null, the result is also null;
- */
- @Nullable
- public static FolderConfiguration getFolderConfig(@Nullable State state) {
- if (state == null) {
- return null;
- }
-
- Hardware hw = state.getHardware();
-
- FolderConfiguration config = new FolderConfiguration();
- config.createDefault();
- Screen screen = hw.getScreen();
- config.setDensityQualifier(new DensityQualifier(screen.getPixelDensity()));
- config.setNavigationMethodQualifier(new NavigationMethodQualifier(hw.getNav()));
- ScreenDimensionQualifier sdq;
- if (screen.getXDimension() > screen.getYDimension()) {
- sdq = new ScreenDimensionQualifier(screen.getXDimension(), screen.getYDimension());
- } else {
- sdq = new ScreenDimensionQualifier(screen.getYDimension(), screen.getXDimension());
- }
- config.setScreenDimensionQualifier(sdq);
- config.setScreenRatioQualifier(new ScreenRatioQualifier(screen.getRatio()));
- config.setScreenSizeQualifier(new ScreenSizeQualifier(screen.getSize()));
- config.setTextInputMethodQualifier(new TextInputMethodQualifier(hw.getKeyboard()));
- config.setTouchTypeQualifier(new TouchScreenQualifier(screen.getMechanism()));
-
- config.setKeyboardStateQualifier(new KeyboardStateQualifier(state.getKeyState()));
- config.setNavigationStateQualifier(new NavigationStateQualifier(state.getNavState()));
- config.setScreenOrientationQualifier(
- new ScreenOrientationQualifier(state.getOrientation()));
-
- config.updateScreenWidthAndHeight();
-
- // Setup some default qualifiers
- config.setUiModeQualifier(new UiModeQualifier(UiMode.NORMAL));
- config.setNightModeQualifier(new NightModeQualifier(NightMode.NOTNIGHT));
- config.setCountryCodeQualifier(new CountryCodeQualifier());
- config.setLanguageQualifier(new LanguageQualifier());
- config.setNetworkCodeQualifier(new NetworkCodeQualifier());
- config.setRegionQualifier(new RegionQualifier());
- config.setVersionQualifier(new VersionQualifier());
-
- return config;
- }
-
- /**
- * Returns a {@link FolderConfiguration} based on the {@link State} given by
- * the {@link Device} and the state name.
- *
- * @param d
- * The {@link Device} to base the {@link FolderConfiguration} on.
- * @param stateName
- * The name of the state to base the {@link FolderConfiguration}
- * on.
- * @return The {@link FolderConfiguration} based on the determined
- * {@link State}. If there is no {@link State} with the given state
- * name for the given device, null is returned.
- */
- @Nullable
- public static FolderConfiguration getFolderConfig(Device d, String stateName) {
- return getFolderConfig(d.getState(stateName));
- }
-
- /**
- * Returns a {@link FolderConfiguration} based on the default {@link State}
- * for the given {@link Device}.
- *
- * @param d
- * The {@link Device} to generate the {@link FolderConfiguration}
- * from.
- * @return A {@link FolderConfiguration} based on the default {@link State}
- * for the given {@link Device}
- */
- public static FolderConfiguration getFolderConfig(Device d) {
- return getFolderConfig(d.getDefaultState());
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/EnumBasedResourceQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/EnumBasedResourceQualifier.java
deleted file mode 100644
index 7bfda2d..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/EnumBasedResourceQualifier.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-
-/**
- * Base class for {@link ResourceQualifier} whose value is an {@link ResourceEnum}.
- *
- */
-abstract class EnumBasedResourceQualifier extends ResourceQualifier {
-
- abstract ResourceEnum getEnumValue();
-
- @Override
- public boolean isValid() {
- return getEnumValue() != null;
- }
-
- @Override
- public boolean hasFakeValue() {
- return getEnumValue().isFakeValue();
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof EnumBasedResourceQualifier) {
- return getEnumValue() == ((EnumBasedResourceQualifier)qualifier).getEnumValue();
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- ResourceEnum value = getEnumValue();
- if (value != null) {
- return value.hashCode();
- }
-
- return 0;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public final String getFolderSegment() {
- ResourceEnum value = getEnumValue();
- if (value != null) {
- return value.getResourceValue();
- }
-
- return ""; //$NON-NLS-1$
- }
-
-
- @Override
- public String getShortDisplayValue() {
- ResourceEnum value = getEnumValue();
- if (value != null) {
- return value.getShortDisplayValue();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- ResourceEnum value = getEnumValue();
- if (value != null) {
- return value.getLongDisplayValue();
- }
-
- return ""; //$NON-NLS-1$
- }
-
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/FolderConfiguration.java b/sdk_common/src/com/android/ide/common/resources/configuration/FolderConfiguration.java
deleted file mode 100644
index fc83359..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/FolderConfiguration.java
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.SdkConstants;
-import com.android.resources.Density;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ScreenOrientation;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-
-/**
- * Represents the configuration for Resource Folders. All the properties have a default
- * value which means that the property is not set.
- */
-public final class FolderConfiguration implements Comparable<FolderConfiguration> {
-
- private final static ResourceQualifier[] DEFAULT_QUALIFIERS;
-
- static {
- // get the default qualifiers.
- FolderConfiguration defaultConfig = new FolderConfiguration();
- defaultConfig.createDefault();
- DEFAULT_QUALIFIERS = defaultConfig.getQualifiers();
- }
-
-
- private final ResourceQualifier[] mQualifiers = new ResourceQualifier[INDEX_COUNT];
-
- private final static int INDEX_COUNTRY_CODE = 0;
- private final static int INDEX_NETWORK_CODE = 1;
- private final static int INDEX_LANGUAGE = 2;
- private final static int INDEX_REGION = 3;
- private final static int INDEX_LAYOUTDIR = 4;
- private final static int INDEX_SMALLEST_SCREEN_WIDTH = 5;
- private final static int INDEX_SCREEN_WIDTH = 6;
- private final static int INDEX_SCREEN_HEIGHT = 7;
- private final static int INDEX_SCREEN_LAYOUT_SIZE = 8;
- private final static int INDEX_SCREEN_RATIO = 9;
- private final static int INDEX_SCREEN_ORIENTATION = 10;
- private final static int INDEX_UI_MODE = 11;
- private final static int INDEX_NIGHT_MODE = 12;
- private final static int INDEX_PIXEL_DENSITY = 13;
- private final static int INDEX_TOUCH_TYPE = 14;
- private final static int INDEX_KEYBOARD_STATE = 15;
- private final static int INDEX_TEXT_INPUT_METHOD = 16;
- private final static int INDEX_NAVIGATION_STATE = 17;
- private final static int INDEX_NAVIGATION_METHOD = 18;
- private final static int INDEX_SCREEN_DIMENSION = 19;
- private final static int INDEX_VERSION = 20;
- private final static int INDEX_COUNT = 21;
-
- /**
- * Creates a {@link FolderConfiguration} matching the folder segments.
- * @param folderSegments The segments of the folder name. The first segments should contain
- * the name of the folder
- * @return a FolderConfiguration object, or null if the folder name isn't valid..
- */
- public static FolderConfiguration getConfig(String[] folderSegments) {
- FolderConfiguration config = new FolderConfiguration();
-
- // we are going to loop through the segments, and match them with the first
- // available qualifier. If the segment doesn't match we try with the next qualifier.
- // Because the order of the qualifier is fixed, we do not reset the first qualifier
- // after each successful segment.
- // If we run out of qualifier before processing all the segments, we fail.
-
- int qualifierIndex = 0;
- int qualifierCount = DEFAULT_QUALIFIERS.length;
-
- for (int i = 1 ; i < folderSegments.length; i++) {
- String seg = folderSegments[i];
- if (seg.length() > 0) {
- while (qualifierIndex < qualifierCount &&
- DEFAULT_QUALIFIERS[qualifierIndex].checkAndSet(seg, config) == false) {
- qualifierIndex++;
- }
-
- // if we reached the end of the qualifier we didn't find a matching qualifier.
- if (qualifierIndex == qualifierCount) {
- return null;
- }
-
- } else {
- return null;
- }
- }
-
- return config;
- }
-
- /**
- * Creates a {@link FolderConfiguration} matching the folder segments.
- * @param folderSegments The segments of the folder name. The first segments should contain
- * the name of the folder
- * @return a FolderConfiguration object, or null if the folder name isn't valid..
- * @see FolderConfiguration#getConfig(String[])
- */
- public static FolderConfiguration getConfig(Iterable<String>folderSegments) {
- FolderConfiguration config = new FolderConfiguration();
-
- // we are going to loop through the segments, and match them with the first
- // available qualifier. If the segment doesn't match we try with the next qualifier.
- // Because the order of the qualifier is fixed, we do not reset the first qualifier
- // after each successful segment.
- // If we run out of qualifier before processing all the segments, we fail.
-
- int qualifierIndex = 0;
- int qualifierCount = DEFAULT_QUALIFIERS.length;
-
- Iterator<String> iterator = folderSegments.iterator();
- if (iterator.hasNext()) {
- // Skip the first segment: it should be just the base folder, such as "values" or
- // "layout"
- iterator.next();
- }
- while (iterator.hasNext()) {
- String seg = iterator.next();
- if (seg.length() > 0) {
- while (qualifierIndex < qualifierCount &&
- DEFAULT_QUALIFIERS[qualifierIndex].checkAndSet(seg, config) == false) {
- qualifierIndex++;
- }
-
- // if we reached the end of the qualifier we didn't find a matching qualifier.
- if (qualifierIndex == qualifierCount) {
- return null;
- }
-
- } else {
- return null;
- }
- }
-
- return config;
- }
-
- /**
- * Returns the number of {@link ResourceQualifier} that make up a Folder configuration.
- */
- public static int getQualifierCount() {
- return INDEX_COUNT;
- }
-
- /**
- * Sets the config from the qualifiers of a given <var>config</var>.
- * <p/>This is equivalent to <code>set(config, false)</code>
- * @param config the configuration to set
- *
- * @see #set(FolderConfiguration, boolean)
- */
- public void set(FolderConfiguration config) {
- set(config, false /*nonFakeValuesOnly*/);
- }
-
- /**
- * Sets the config from the qualifiers of a given <var>config</var>.
- * @param config the configuration to set
- * @param nonFakeValuesOnly if set to true this ignore qualifiers for which the
- * current value is a fake value.
- *
- * @see ResourceQualifier#hasFakeValue()
- */
- public void set(FolderConfiguration config, boolean nonFakeValuesOnly) {
- if (config != null) {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- ResourceQualifier q = config.mQualifiers[i];
- if (nonFakeValuesOnly == false || q == null || q.hasFakeValue() == false) {
- mQualifiers[i] = q;
- }
- }
- }
- }
-
- /**
- * Reset the config.
- * <p/>This makes qualifiers at all indices <code>null</code>.
- */
- public void reset() {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- mQualifiers[i] = null;
- }
- }
-
- /**
- * Removes the qualifiers from the receiver if they are present (and valid)
- * in the given configuration.
- */
- public void substract(FolderConfiguration config) {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (config.mQualifiers[i] != null && config.mQualifiers[i].isValid()) {
- mQualifiers[i] = null;
- }
- }
- }
-
- /**
- * Adds the non-qualifiers from the given config.
- * Qualifiers that are null in the given config do not change in the receiver.
- */
- public void add(FolderConfiguration config) {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (config.mQualifiers[i] != null) {
- mQualifiers[i] = config.mQualifiers[i];
- }
- }
- }
-
- /**
- * Returns the first invalid qualifier, or <code>null<code> if they are all valid (or if none
- * exists).
- */
- public ResourceQualifier getInvalidQualifier() {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (mQualifiers[i] != null && mQualifiers[i].isValid() == false) {
- return mQualifiers[i];
- }
- }
-
- // all allocated qualifiers are valid, we return null.
- return null;
- }
-
- /**
- * Returns whether the Region qualifier is valid. Region qualifier can only be present if a
- * Language qualifier is present as well.
- * @return true if the Region qualifier is valid.
- */
- public boolean checkRegion() {
- if (mQualifiers[INDEX_LANGUAGE] == null && mQualifiers[INDEX_REGION] != null) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Adds a qualifier to the {@link FolderConfiguration}
- * @param qualifier the {@link ResourceQualifier} to add.
- */
- public void addQualifier(ResourceQualifier qualifier) {
- if (qualifier instanceof CountryCodeQualifier) {
- mQualifiers[INDEX_COUNTRY_CODE] = qualifier;
-
- } else if (qualifier instanceof NetworkCodeQualifier) {
- mQualifiers[INDEX_NETWORK_CODE] = qualifier;
-
- } else if (qualifier instanceof LanguageQualifier) {
- mQualifiers[INDEX_LANGUAGE] = qualifier;
-
- } else if (qualifier instanceof RegionQualifier) {
- mQualifiers[INDEX_REGION] = qualifier;
-
- } else if (qualifier instanceof LayoutDirectionQualifier) {
- mQualifiers[INDEX_LAYOUTDIR] = qualifier;
-
- } else if (qualifier instanceof SmallestScreenWidthQualifier) {
- mQualifiers[INDEX_SMALLEST_SCREEN_WIDTH] = qualifier;
-
- } else if (qualifier instanceof ScreenWidthQualifier) {
- mQualifiers[INDEX_SCREEN_WIDTH] = qualifier;
-
- } else if (qualifier instanceof ScreenHeightQualifier) {
- mQualifiers[INDEX_SCREEN_HEIGHT] = qualifier;
-
- } else if (qualifier instanceof ScreenSizeQualifier) {
- mQualifiers[INDEX_SCREEN_LAYOUT_SIZE] = qualifier;
-
- } else if (qualifier instanceof ScreenRatioQualifier) {
- mQualifiers[INDEX_SCREEN_RATIO] = qualifier;
-
- } else if (qualifier instanceof ScreenOrientationQualifier) {
- mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier;
-
- } else if (qualifier instanceof UiModeQualifier) {
- mQualifiers[INDEX_UI_MODE] = qualifier;
-
- } else if (qualifier instanceof NightModeQualifier) {
- mQualifiers[INDEX_NIGHT_MODE] = qualifier;
-
- } else if (qualifier instanceof DensityQualifier) {
- mQualifiers[INDEX_PIXEL_DENSITY] = qualifier;
-
- } else if (qualifier instanceof TouchScreenQualifier) {
- mQualifiers[INDEX_TOUCH_TYPE] = qualifier;
-
- } else if (qualifier instanceof KeyboardStateQualifier) {
- mQualifiers[INDEX_KEYBOARD_STATE] = qualifier;
-
- } else if (qualifier instanceof TextInputMethodQualifier) {
- mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier;
-
- } else if (qualifier instanceof NavigationStateQualifier) {
- mQualifiers[INDEX_NAVIGATION_STATE] = qualifier;
-
- } else if (qualifier instanceof NavigationMethodQualifier) {
- mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier;
-
- } else if (qualifier instanceof ScreenDimensionQualifier) {
- mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier;
-
- } else if (qualifier instanceof VersionQualifier) {
- mQualifiers[INDEX_VERSION] = qualifier;
-
- }
- }
-
- /**
- * Removes a given qualifier from the {@link FolderConfiguration}.
- * @param qualifier the {@link ResourceQualifier} to remove.
- */
- public void removeQualifier(ResourceQualifier qualifier) {
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (mQualifiers[i] == qualifier) {
- mQualifiers[i] = null;
- return;
- }
- }
- }
-
- /**
- * Returns a qualifier by its index. The total number of qualifiers can be accessed by
- * {@link #getQualifierCount()}.
- * @param index the index of the qualifier to return.
- * @return the qualifier or null if there are none at the index.
- */
- public ResourceQualifier getQualifier(int index) {
- return mQualifiers[index];
- }
-
- public void setCountryCodeQualifier(CountryCodeQualifier qualifier) {
- mQualifiers[INDEX_COUNTRY_CODE] = qualifier;
- }
-
- public CountryCodeQualifier getCountryCodeQualifier() {
- return (CountryCodeQualifier)mQualifiers[INDEX_COUNTRY_CODE];
- }
-
- public void setNetworkCodeQualifier(NetworkCodeQualifier qualifier) {
- mQualifiers[INDEX_NETWORK_CODE] = qualifier;
- }
-
- public NetworkCodeQualifier getNetworkCodeQualifier() {
- return (NetworkCodeQualifier)mQualifiers[INDEX_NETWORK_CODE];
- }
-
- public void setLanguageQualifier(LanguageQualifier qualifier) {
- mQualifiers[INDEX_LANGUAGE] = qualifier;
- }
-
- public LanguageQualifier getLanguageQualifier() {
- return (LanguageQualifier)mQualifiers[INDEX_LANGUAGE];
- }
-
- public void setRegionQualifier(RegionQualifier qualifier) {
- mQualifiers[INDEX_REGION] = qualifier;
- }
-
- public RegionQualifier getRegionQualifier() {
- return (RegionQualifier)mQualifiers[INDEX_REGION];
- }
-
- public void setLayoutDirectionQualifier(LayoutDirectionQualifier qualifier) {
- mQualifiers[INDEX_LAYOUTDIR] = qualifier;
- }
-
- public LayoutDirectionQualifier getLayoutDirectionQualifier() {
- return (LayoutDirectionQualifier)mQualifiers[INDEX_LAYOUTDIR];
- }
-
- public void setSmallestScreenWidthQualifier(SmallestScreenWidthQualifier qualifier) {
- mQualifiers[INDEX_SMALLEST_SCREEN_WIDTH] = qualifier;
- }
-
- public SmallestScreenWidthQualifier getSmallestScreenWidthQualifier() {
- return (SmallestScreenWidthQualifier) mQualifiers[INDEX_SMALLEST_SCREEN_WIDTH];
- }
-
- public void setScreenWidthQualifier(ScreenWidthQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_WIDTH] = qualifier;
- }
-
- public ScreenWidthQualifier getScreenWidthQualifier() {
- return (ScreenWidthQualifier) mQualifiers[INDEX_SCREEN_WIDTH];
- }
-
- public void setScreenHeightQualifier(ScreenHeightQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_HEIGHT] = qualifier;
- }
-
- public ScreenHeightQualifier getScreenHeightQualifier() {
- return (ScreenHeightQualifier) mQualifiers[INDEX_SCREEN_HEIGHT];
- }
-
- public void setScreenSizeQualifier(ScreenSizeQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_LAYOUT_SIZE] = qualifier;
- }
-
- public ScreenSizeQualifier getScreenSizeQualifier() {
- return (ScreenSizeQualifier)mQualifiers[INDEX_SCREEN_LAYOUT_SIZE];
- }
-
- public void setScreenRatioQualifier(ScreenRatioQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_RATIO] = qualifier;
- }
-
- public ScreenRatioQualifier getScreenRatioQualifier() {
- return (ScreenRatioQualifier)mQualifiers[INDEX_SCREEN_RATIO];
- }
-
- public void setScreenOrientationQualifier(ScreenOrientationQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_ORIENTATION] = qualifier;
- }
-
- public ScreenOrientationQualifier getScreenOrientationQualifier() {
- return (ScreenOrientationQualifier)mQualifiers[INDEX_SCREEN_ORIENTATION];
- }
-
- public void setUiModeQualifier(UiModeQualifier qualifier) {
- mQualifiers[INDEX_UI_MODE] = qualifier;
- }
-
- public UiModeQualifier getUiModeQualifier() {
- return (UiModeQualifier)mQualifiers[INDEX_UI_MODE];
- }
-
- public void setNightModeQualifier(NightModeQualifier qualifier) {
- mQualifiers[INDEX_NIGHT_MODE] = qualifier;
- }
-
- public NightModeQualifier getNightModeQualifier() {
- return (NightModeQualifier)mQualifiers[INDEX_NIGHT_MODE];
- }
-
- public void setDensityQualifier(DensityQualifier qualifier) {
- mQualifiers[INDEX_PIXEL_DENSITY] = qualifier;
- }
-
- public DensityQualifier getDensityQualifier() {
- return (DensityQualifier)mQualifiers[INDEX_PIXEL_DENSITY];
- }
-
- public void setTouchTypeQualifier(TouchScreenQualifier qualifier) {
- mQualifiers[INDEX_TOUCH_TYPE] = qualifier;
- }
-
- public TouchScreenQualifier getTouchTypeQualifier() {
- return (TouchScreenQualifier)mQualifiers[INDEX_TOUCH_TYPE];
- }
-
- public void setKeyboardStateQualifier(KeyboardStateQualifier qualifier) {
- mQualifiers[INDEX_KEYBOARD_STATE] = qualifier;
- }
-
- public KeyboardStateQualifier getKeyboardStateQualifier() {
- return (KeyboardStateQualifier)mQualifiers[INDEX_KEYBOARD_STATE];
- }
-
- public void setTextInputMethodQualifier(TextInputMethodQualifier qualifier) {
- mQualifiers[INDEX_TEXT_INPUT_METHOD] = qualifier;
- }
-
- public TextInputMethodQualifier getTextInputMethodQualifier() {
- return (TextInputMethodQualifier)mQualifiers[INDEX_TEXT_INPUT_METHOD];
- }
-
- public void setNavigationStateQualifier(NavigationStateQualifier qualifier) {
- mQualifiers[INDEX_NAVIGATION_STATE] = qualifier;
- }
-
- public NavigationStateQualifier getNavigationStateQualifier() {
- return (NavigationStateQualifier)mQualifiers[INDEX_NAVIGATION_STATE];
- }
-
- public void setNavigationMethodQualifier(NavigationMethodQualifier qualifier) {
- mQualifiers[INDEX_NAVIGATION_METHOD] = qualifier;
- }
-
- public NavigationMethodQualifier getNavigationMethodQualifier() {
- return (NavigationMethodQualifier)mQualifiers[INDEX_NAVIGATION_METHOD];
- }
-
- public void setScreenDimensionQualifier(ScreenDimensionQualifier qualifier) {
- mQualifiers[INDEX_SCREEN_DIMENSION] = qualifier;
- }
-
- public ScreenDimensionQualifier getScreenDimensionQualifier() {
- return (ScreenDimensionQualifier)mQualifiers[INDEX_SCREEN_DIMENSION];
- }
-
- public void setVersionQualifier(VersionQualifier qualifier) {
- mQualifiers[INDEX_VERSION] = qualifier;
- }
-
- public VersionQualifier getVersionQualifier() {
- return (VersionQualifier)mQualifiers[INDEX_VERSION];
- }
-
- /**
- * Updates the {@link SmallestScreenWidthQualifier}, {@link ScreenWidthQualifier}, and
- * {@link ScreenHeightQualifier} based on the (required) values of
- * {@link ScreenDimensionQualifier} {@link DensityQualifier}, and
- * {@link ScreenOrientationQualifier}.
- *
- * Also the density cannot be {@link Density#NODPI} as it's not valid on a device.
- */
- public void updateScreenWidthAndHeight() {
-
- ResourceQualifier sizeQ = mQualifiers[INDEX_SCREEN_DIMENSION];
- ResourceQualifier densityQ = mQualifiers[INDEX_PIXEL_DENSITY];
- ResourceQualifier orientQ = mQualifiers[INDEX_SCREEN_ORIENTATION];
-
- if (sizeQ != null && densityQ != null && orientQ != null) {
- Density density = ((DensityQualifier) densityQ).getValue();
- if (density == Density.NODPI) {
- return;
- }
-
- ScreenOrientation orientation = ((ScreenOrientationQualifier) orientQ).getValue();
-
- int size1 = ((ScreenDimensionQualifier) sizeQ).getValue1();
- int size2 = ((ScreenDimensionQualifier) sizeQ).getValue2();
-
- // make sure size1 is the biggest (should be the case, but make sure)
- if (size1 < size2) {
- int a = size1;
- size1 = size2;
- size2 = a;
- }
-
- // compute the dp. round them up since we want -w480dp to match a 480.5dp screen
- int dp1 = (int) Math.ceil(size1 * Density.DEFAULT_DENSITY / density.getDpiValue());
- int dp2 = (int) Math.ceil(size2 * Density.DEFAULT_DENSITY / density.getDpiValue());
-
- setSmallestScreenWidthQualifier(new SmallestScreenWidthQualifier(dp2));
-
- switch (orientation) {
- case PORTRAIT:
- setScreenWidthQualifier(new ScreenWidthQualifier(dp2));
- setScreenHeightQualifier(new ScreenHeightQualifier(dp1));
- break;
- case LANDSCAPE:
- setScreenWidthQualifier(new ScreenWidthQualifier(dp1));
- setScreenHeightQualifier(new ScreenHeightQualifier(dp2));
- break;
- case SQUARE:
- setScreenWidthQualifier(new ScreenWidthQualifier(dp2));
- setScreenHeightQualifier(new ScreenHeightQualifier(dp2));
- break;
- }
- }
- }
-
- /**
- * Returns whether an object is equals to the receiver.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (obj instanceof FolderConfiguration) {
- FolderConfiguration fc = (FolderConfiguration)obj;
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- ResourceQualifier qualifier = mQualifiers[i];
- ResourceQualifier fcQualifier = fc.mQualifiers[i];
- if (qualifier != null) {
- if (qualifier.equals(fcQualifier) == false) {
- return false;
- }
- } else if (fcQualifier != null) {
- return false;
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
-
- /**
- * Returns whether the Configuration has only default values.
- */
- public boolean isDefault() {
- for (ResourceQualifier irq : mQualifiers) {
- if (irq != null) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the name of a folder with the configuration.
- */
- public String getFolderName(ResourceFolderType folder) {
- StringBuilder result = new StringBuilder(folder.getName());
-
- for (ResourceQualifier qualifier : mQualifiers) {
- if (qualifier != null) {
- String segment = qualifier.getFolderSegment();
- if (segment != null && segment.length() > 0) {
- result.append(SdkConstants.RES_QUALIFIER_SEP);
- result.append(segment);
- }
- }
- }
-
- return result.toString();
- }
-
- /**
- * Returns {@link #toDisplayString()}.
- */
- @Override
- public String toString() {
- return toDisplayString();
- }
-
- /**
- * Returns a string valid for display purpose.
- */
- public String toDisplayString() {
- if (isDefault()) {
- return "default";
- }
-
- StringBuilder result = null;
- int index = 0;
- ResourceQualifier qualifier = null;
-
- // pre- language/region qualifiers
- while (index < INDEX_LANGUAGE) {
- qualifier = mQualifiers[index++];
- if (qualifier != null) {
- if (result == null) {
- result = new StringBuilder();
- } else {
- result.append(", "); //$NON-NLS-1$
- }
- result.append(qualifier.getLongDisplayValue());
-
- }
- }
-
- // process the language/region qualifier in a custom way, if there are both non null.
- if (mQualifiers[INDEX_LANGUAGE] != null && mQualifiers[INDEX_REGION] != null) {
- String language = mQualifiers[INDEX_LANGUAGE].getLongDisplayValue();
- String region = mQualifiers[INDEX_REGION].getLongDisplayValue();
-
- if (result == null) {
- result = new StringBuilder();
- } else {
- result.append(", "); //$NON-NLS-1$
- }
- result.append(String.format("Locale %s_%s", language, region)); //$NON-NLS-1$
-
- index += 2;
- }
-
- // post language/region qualifiers.
- while (index < INDEX_COUNT) {
- qualifier = mQualifiers[index++];
- if (qualifier != null) {
- if (result == null) {
- result = new StringBuilder();
- } else {
- result.append(", "); //$NON-NLS-1$
- }
- result.append(qualifier.getLongDisplayValue());
-
- }
- }
-
- return result == null ? null : result.toString();
- }
-
- @Override
- public int compareTo(FolderConfiguration folderConfig) {
- // default are always at the top.
- if (isDefault()) {
- if (folderConfig.isDefault()) {
- return 0;
- }
- return -1;
- }
-
- // now we compare the qualifiers
- for (int i = 0 ; i < INDEX_COUNT; i++) {
- ResourceQualifier qualifier1 = mQualifiers[i];
- ResourceQualifier qualifier2 = folderConfig.mQualifiers[i];
-
- if (qualifier1 == null) {
- if (qualifier2 == null) {
- continue;
- } else {
- return -1;
- }
- } else {
- if (qualifier2 == null) {
- return 1;
- } else {
- int result = qualifier1.compareTo(qualifier2);
-
- if (result == 0) {
- continue;
- }
-
- return result;
- }
- }
- }
-
- // if we arrive here, all the qualifier matches
- return 0;
- }
-
- /**
- * Returns the best matching {@link Configurable} for this configuration.
- *
- * @param configurables the list of {@link Configurable} to choose from.
- *
- * @return an item from the given list of {@link Configurable} or null.
- *
- * @see http://d.android.com/guide/topics/resources/resources-i18n.html#best-match
- */
- public Configurable findMatchingConfigurable(List<? extends Configurable> configurables) {
- //
- // 1: eliminate resources that contradict the reference configuration
- // 2: pick next qualifier type
- // 3: check if any resources use this qualifier, if no, back to 2, else move on to 4.
- // 4: eliminate resources that don't use this qualifier.
- // 5: if more than one resource left, go back to 2.
- //
- // The precedence of the qualifiers is more important than the number of qualifiers that
- // exactly match the device.
-
- // 1: eliminate resources that contradict
- ArrayList<Configurable> matchingConfigurables = new ArrayList<Configurable>();
- for (int i = 0 ; i < configurables.size(); i++) {
- Configurable res = configurables.get(i);
-
- if (res.getConfiguration().isMatchFor(this)) {
- matchingConfigurables.add(res);
- }
- }
-
- // if there is only one match, just take it
- if (matchingConfigurables.size() == 1) {
- return matchingConfigurables.get(0);
- } else if (matchingConfigurables.size() == 0) {
- return null;
- }
-
- // 2. Loop on the qualifiers, and eliminate matches
- final int count = FolderConfiguration.getQualifierCount();
- for (int q = 0 ; q < count ; q++) {
- // look to see if one configurable has this qualifier.
- // At the same time also record the best match value for the qualifier (if applicable).
-
- // The reference value, to find the best match.
- // Note that this qualifier could be null. In which case any qualifier found in the
- // possible match, will all be considered best match.
- ResourceQualifier referenceQualifier = getQualifier(q);
-
- boolean found = false;
- ResourceQualifier bestMatch = null; // this is to store the best match.
- for (Configurable configurable : matchingConfigurables) {
- ResourceQualifier qualifier = configurable.getConfiguration().getQualifier(q);
- if (qualifier != null) {
- // set the flag.
- found = true;
-
- // Now check for a best match. If the reference qualifier is null ,
- // any qualifier is a "best" match (we don't need to record all of them.
- // Instead the non compatible ones are removed below)
- if (referenceQualifier != null) {
- if (qualifier.isBetterMatchThan(bestMatch, referenceQualifier)) {
- bestMatch = qualifier;
- }
- }
- }
- }
-
- // 4. If a configurable has a qualifier at the current index, remove all the ones that
- // do not have one, or whose qualifier value does not equal the best match found above
- // unless there's no reference qualifier, in which case they are all considered
- // "best" match.
- if (found) {
- for (int i = 0 ; i < matchingConfigurables.size(); ) {
- Configurable configurable = matchingConfigurables.get(i);
- ResourceQualifier qualifier = configurable.getConfiguration().getQualifier(q);
-
- if (qualifier == null) {
- // this resources has no qualifier of this type: rejected.
- matchingConfigurables.remove(configurable);
- } else if (referenceQualifier != null && bestMatch != null &&
- bestMatch.equals(qualifier) == false) {
- // there's a reference qualifier and there is a better match for it than
- // this resource, so we reject it.
- matchingConfigurables.remove(configurable);
- } else {
- // looks like we keep this resource, move on to the next one.
- i++;
- }
- }
-
- // at this point we may have run out of matching resources before going
- // through all the qualifiers.
- if (matchingConfigurables.size() < 2) {
- break;
- }
- }
- }
-
- // Because we accept resources whose configuration have qualifiers where the reference
- // configuration doesn't, we can end up with more than one match. In this case, we just
- // take the first one.
- if (matchingConfigurables.size() == 0) {
- return null;
- }
- return matchingConfigurables.get(0);
- }
-
-
- /**
- * Returns whether the configuration is a match for the given reference config.
- * <p/>A match means that, for each qualifier of this config
- * <ul>
- * <li>The reference config has no value set
- * <li>or, the qualifier of the reference config is a match. Depending on the qualifier type
- * this does not mean the same exact value.</li>
- * </ul>
- * @param referenceConfig The reference configuration to test against.
- * @return true if the configuration matches.
- */
- public boolean isMatchFor(FolderConfiguration referenceConfig) {
- if (referenceConfig == null) {
- return false;
- }
-
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- ResourceQualifier testQualifier = mQualifiers[i];
- ResourceQualifier referenceQualifier = referenceConfig.mQualifiers[i];
-
- // it's only a non match if both qualifiers are non-null, and they don't match.
- if (testQualifier != null && referenceQualifier != null &&
- testQualifier.isMatchFor(referenceQualifier) == false) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the index of the first non null {@link ResourceQualifier} starting at index
- * <var>startIndex</var>
- * @param startIndex
- * @return -1 if no qualifier was found.
- */
- public int getHighestPriorityQualifier(int startIndex) {
- for (int i = startIndex ; i < INDEX_COUNT ; i++) {
- if (mQualifiers[i] != null) {
- return i;
- }
- }
-
- return -1;
- }
-
- /**
- * Create default qualifiers.
- * <p/>This creates qualifiers with no values for all indices.
- */
- public void createDefault() {
- mQualifiers[INDEX_COUNTRY_CODE] = new CountryCodeQualifier();
- mQualifiers[INDEX_NETWORK_CODE] = new NetworkCodeQualifier();
- mQualifiers[INDEX_LANGUAGE] = new LanguageQualifier();
- mQualifiers[INDEX_REGION] = new RegionQualifier();
- mQualifiers[INDEX_LAYOUTDIR] = new LayoutDirectionQualifier();
- mQualifiers[INDEX_SMALLEST_SCREEN_WIDTH] = new SmallestScreenWidthQualifier();
- mQualifiers[INDEX_SCREEN_WIDTH] = new ScreenWidthQualifier();
- mQualifiers[INDEX_SCREEN_HEIGHT] = new ScreenHeightQualifier();
- mQualifiers[INDEX_SCREEN_LAYOUT_SIZE] = new ScreenSizeQualifier();
- mQualifiers[INDEX_SCREEN_RATIO] = new ScreenRatioQualifier();
- mQualifiers[INDEX_SCREEN_ORIENTATION] = new ScreenOrientationQualifier();
- mQualifiers[INDEX_UI_MODE] = new UiModeQualifier();
- mQualifiers[INDEX_NIGHT_MODE] = new NightModeQualifier();
- mQualifiers[INDEX_PIXEL_DENSITY] = new DensityQualifier();
- mQualifiers[INDEX_TOUCH_TYPE] = new TouchScreenQualifier();
- mQualifiers[INDEX_KEYBOARD_STATE] = new KeyboardStateQualifier();
- mQualifiers[INDEX_TEXT_INPUT_METHOD] = new TextInputMethodQualifier();
- mQualifiers[INDEX_NAVIGATION_STATE] = new NavigationStateQualifier();
- mQualifiers[INDEX_NAVIGATION_METHOD] = new NavigationMethodQualifier();
- mQualifiers[INDEX_SCREEN_DIMENSION] = new ScreenDimensionQualifier();
- mQualifiers[INDEX_VERSION] = new VersionQualifier();
- }
-
- /**
- * Returns an array of all the non null qualifiers.
- */
- public ResourceQualifier[] getQualifiers() {
- int count = 0;
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (mQualifiers[i] != null) {
- count++;
- }
- }
-
- ResourceQualifier[] array = new ResourceQualifier[count];
- int index = 0;
- for (int i = 0 ; i < INDEX_COUNT ; i++) {
- if (mQualifiers[i] != null) {
- array[index++] = mQualifiers[i];
- }
- }
-
- return array;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/KeyboardStateQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/KeyboardStateQualifier.java
deleted file mode 100644
index 1397808..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/KeyboardStateQualifier.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.KeyboardState;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for keyboard state.
- */
-public final class KeyboardStateQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Keyboard State";
-
- private KeyboardState mValue = null;
-
- public KeyboardStateQualifier() {
- // pass
- }
-
- public KeyboardStateQualifier(KeyboardState value) {
- mValue = value;
- }
-
- public KeyboardState getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Keyboard";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- KeyboardState orientation = KeyboardState.getEnum(value);
- if (orientation != null) {
- KeyboardStateQualifier qualifier = new KeyboardStateQualifier();
- qualifier.mValue = orientation;
- config.setKeyboardStateQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- if (qualifier instanceof KeyboardStateQualifier) {
- KeyboardStateQualifier referenceQualifier = (KeyboardStateQualifier)qualifier;
-
- // special case where EXPOSED can be used for SOFT
- if (referenceQualifier.mValue == KeyboardState.SOFT &&
- mValue == KeyboardState.EXPOSED) {
- return true;
- }
-
- return referenceQualifier.mValue == mValue;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- KeyboardStateQualifier compareQualifier = (KeyboardStateQualifier)compareTo;
- KeyboardStateQualifier referenceQualifier = (KeyboardStateQualifier)reference;
-
- if (referenceQualifier.mValue == KeyboardState.SOFT) { // only case where there could be a
- // better qualifier
- // only return true if it's a better value.
- if (compareQualifier.mValue == KeyboardState.EXPOSED && mValue == KeyboardState.SOFT) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/LanguageQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/LanguageQualifier.java
deleted file mode 100644
index 76514e2..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/LanguageQualifier.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Language.
- */
-public final class LanguageQualifier extends ResourceQualifier {
- private final static Pattern sLanguagePattern = Pattern.compile("^[a-z]{2}$"); //$NON-NLS-1$
-
- public static final String FAKE_LANG_VALUE = "__"; //$NON-NLS-1$
- public static final String NAME = "Language";
-
- private String mValue;
-
- /**
- * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
- * <code>null</code> is returned.
- * @param segment the folder segment from which to create a qualifier.
- * @return a new {@link LanguageQualifier} object or <code>null</code>
- */
- public static LanguageQualifier getQualifier(String segment) {
- if (sLanguagePattern.matcher(segment).matches()) {
- LanguageQualifier qualifier = new LanguageQualifier();
- qualifier.mValue = segment;
-
- return qualifier;
- }
- return null;
- }
-
- /**
- * Returns the folder name segment for the given value. This is equivalent to calling
- * {@link #toString()} on a {@link LanguageQualifier} object.
- * @param value the value of the qualifier, as returned by {@link #getValue()}.
- */
- public static String getFolderSegment(String value) {
- String segment = value.toLowerCase(Locale.US);
- if (sLanguagePattern.matcher(segment).matches()) {
- return segment;
- }
-
- return null;
- }
-
- public LanguageQualifier() {
-
- }
-
- public LanguageQualifier(String value) {
- mValue = value;
- }
-
- public String getValue() {
- if (mValue != null) {
- return mValue;
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean isValid() {
- return mValue != null;
- }
-
- @Override
- public boolean hasFakeValue() {
- return FAKE_LANG_VALUE.equals(mValue);
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- LanguageQualifier qualifier = getQualifier(value);
- if (qualifier != null) {
- config.setLanguageQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof LanguageQualifier) {
- if (mValue == null) {
- return ((LanguageQualifier)qualifier).mValue == null;
- }
- return mValue.equals(((LanguageQualifier)qualifier).mValue);
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- if (mValue != null) {
- return mValue.hashCode();
- }
-
- return 0;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- if (mValue != null) {
- return getFolderSegment(mValue);
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getShortDisplayValue() {
- if (mValue != null) {
- return mValue;
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (mValue != null) {
- return String.format("Language %s", mValue);
- }
-
- return ""; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/LayoutDirectionQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/LayoutDirectionQualifier.java
deleted file mode 100644
index 48498f0..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/LayoutDirectionQualifier.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.LayoutDirection;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for layout direction. values can be "ltr", or "rtl"
- */
-public class LayoutDirectionQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Layout Direction";
-
- private LayoutDirection mValue = null;
-
-
- public LayoutDirectionQualifier() {
- }
-
- public LayoutDirectionQualifier(LayoutDirection value) {
- mValue = value;
- }
-
- public LayoutDirection getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 17;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- LayoutDirection ld = LayoutDirection.getEnum(value);
- if (ld != null) {
- LayoutDirectionQualifier qualifier = new LayoutDirectionQualifier(ld);
- config.setLayoutDirectionQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/NavigationMethodQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/NavigationMethodQualifier.java
deleted file mode 100644
index f40bc6c..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/NavigationMethodQualifier.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Navigation;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for Navigation Method.
- */
-public final class NavigationMethodQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Navigation Method";
-
- private Navigation mValue;
-
- public NavigationMethodQualifier() {
- // pass
- }
-
- public NavigationMethodQualifier(Navigation value) {
- mValue = value;
- }
-
- public Navigation getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Navigation method = Navigation.getEnum(value);
- if (method != null) {
- NavigationMethodQualifier qualifier = new NavigationMethodQualifier(method);
- config.setNavigationMethodQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/NavigationStateQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/NavigationStateQualifier.java
deleted file mode 100644
index 91b81df..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/NavigationStateQualifier.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.NavigationState;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for navigation state.
- */
-public final class NavigationStateQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Navigation State";
-
- private NavigationState mValue = null;
-
- public NavigationStateQualifier() {
- // pass
- }
-
- public NavigationStateQualifier(NavigationState value) {
- mValue = value;
- }
-
- public NavigationState getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- NavigationState state = NavigationState.getEnum(value);
- if (state != null) {
- NavigationStateQualifier qualifier = new NavigationStateQualifier();
- qualifier.mValue = state;
- config.setNavigationStateQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/NetworkCodeQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/NetworkCodeQualifier.java
deleted file mode 100644
index 1ef2015..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/NetworkCodeQualifier.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Mobile Network Code Pixel Density.
- */
-public final class NetworkCodeQualifier extends ResourceQualifier {
- /** Default pixel density value. This means the property is not set. */
- private final static int DEFAULT_CODE = -1;
-
- private final static Pattern sNetworkCodePattern = Pattern.compile("^mnc(\\d{1,3})$"); //$NON-NLS-1$
-
- private final int mCode;
-
- public final static String NAME = "Mobile Network Code";
-
- /**
- * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
- * <code>null</code> is returned.
- * @param segment the folder segment from which to create a qualifier.
- * @return a new {@link CountryCodeQualifier} object or <code>null</code>
- */
- public static NetworkCodeQualifier getQualifier(String segment) {
- Matcher m = sNetworkCodePattern.matcher(segment);
- if (m.matches()) {
- String v = m.group(1);
-
- int code = -1;
- try {
- code = Integer.parseInt(v);
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number.
- return null;
- }
-
- NetworkCodeQualifier qualifier = new NetworkCodeQualifier(code);
- return qualifier;
- }
-
- return null;
- }
-
- /**
- * Returns the folder name segment for the given value. This is equivalent to calling
- * {@link #toString()} on a {@link NetworkCodeQualifier} object.
- * @param code the value of the qualifier, as returned by {@link #getCode()}.
- */
- public static String getFolderSegment(int code) {
- if (code != DEFAULT_CODE && code >= 1 && code <= 999) { // code is 1-3 digit.
- return String.format("mnc%1$d", code); //$NON-NLS-1$
- }
-
- return ""; //$NON-NLS-1$
- }
-
- public NetworkCodeQualifier() {
- this(DEFAULT_CODE);
- }
-
- public NetworkCodeQualifier(int code) {
- mCode = code;
- }
-
- public int getCode() {
- return mCode;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Network Code";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean isValid() {
- return mCode != DEFAULT_CODE;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Matcher m = sNetworkCodePattern.matcher(value);
- if (m.matches()) {
- String v = m.group(1);
-
- int code = -1;
- try {
- code = Integer.parseInt(v);
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number.
- return false;
- }
-
- NetworkCodeQualifier qualifier = new NetworkCodeQualifier(code);
- config.setNetworkCodeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof NetworkCodeQualifier) {
- return mCode == ((NetworkCodeQualifier)qualifier).mCode;
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return mCode;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- return getFolderSegment(mCode);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (mCode != DEFAULT_CODE) {
- return String.format("MNC %1$d", mCode);
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- return getShortDisplayValue();
- }
-
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/NightModeQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/NightModeQualifier.java
deleted file mode 100644
index d3b6760..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/NightModeQualifier.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.NightMode;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for Navigation Method.
- */
-public final class NightModeQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Night Mode";
-
- private NightMode mValue;
-
- public NightModeQualifier() {
- // pass
- }
-
- public NightModeQualifier(NightMode value) {
- mValue = value;
- }
-
- public NightMode getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Night Mode";
- }
-
- @Override
- public int since() {
- return 8;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- NightMode mode = NightMode.getEnum(value);
- if (mode != null) {
- NightModeQualifier qualifier = new NightModeQualifier(mode);
- config.setNightModeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/RegionQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/RegionQualifier.java
deleted file mode 100644
index bd033bd..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/RegionQualifier.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Region.
- */
-public final class RegionQualifier extends ResourceQualifier {
- private final static Pattern sRegionPattern = Pattern.compile("^r([A-Z]{2})$"); //$NON-NLS-1$
-
- public static final String FAKE_REGION_VALUE = "__"; //$NON-NLS-1$
- public static final String NAME = "Region";
-
- private String mValue;
-
- /**
- * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
- * <code>null</code> is returned.
- * @param segment the folder segment from which to create a qualifier.
- * @return a new {@link RegionQualifier} object or <code>null</code>
- */
- public static RegionQualifier getQualifier(String segment) {
- Matcher m = sRegionPattern.matcher(segment);
- if (m.matches()) {
- RegionQualifier qualifier = new RegionQualifier();
- qualifier.mValue = m.group(1);
-
- return qualifier;
- }
- return null;
- }
-
- /**
- * Returns the folder name segment for the given value. This is equivalent to calling
- * {@link #toString()} on a {@link RegionQualifier} object.
- * @param value the value of the qualifier, as returned by {@link #getValue()}.
- */
- public static String getFolderSegment(String value) {
- if (value != null) {
- // See http://developer.android.com/reference/java/util/Locale.html#default_locale
- String segment = "r" + value.toUpperCase(Locale.US); //$NON-NLS-1$
- if (sRegionPattern.matcher(segment).matches()) {
- return segment;
- }
- }
-
- return ""; //$NON-NLS-1$
- }
-
- public RegionQualifier() {
-
- }
-
- public RegionQualifier(String value) {
- mValue = value;
- }
-
- public String getValue() {
- if (mValue != null) {
- return mValue;
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean isValid() {
- return mValue != null;
- }
-
- @Override
- public boolean hasFakeValue() {
- return FAKE_REGION_VALUE.equals(mValue);
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- RegionQualifier qualifier = getQualifier(value);
- if (qualifier != null) {
- config.setRegionQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof RegionQualifier) {
- if (mValue == null) {
- return ((RegionQualifier)qualifier).mValue == null;
- }
- return mValue.equals(((RegionQualifier)qualifier).mValue);
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- if (mValue != null) {
- return mValue.hashCode();
- }
-
- return 0;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- return getFolderSegment(mValue);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (mValue != null) {
- return mValue;
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (mValue != null) {
- return String.format("Region %s", mValue);
- }
-
- return ""; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ResourceQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ResourceQualifier.java
deleted file mode 100644
index 2997c8f..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ResourceQualifier.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-
-/**
- * Base class for resource qualifiers.
- * <p/>The resource qualifier classes are designed as immutable.
- */
-public abstract class ResourceQualifier implements Comparable<ResourceQualifier> {
-
- /**
- * Returns the human readable name of the qualifier.
- */
- public abstract String getName();
-
- /**
- * Returns a shorter human readable name for the qualifier.
- * @see #getName()
- */
- public abstract String getShortName();
-
- /**
- * Returns when this qualifier was added to Android.
- */
- public abstract int since();
-
- /**
- * Whether this qualifier is deprecated.
- */
- public boolean deprecated() {
- return false;
- }
-
- /**
- * Returns whether the qualifier has a valid filter value.
- */
- public abstract boolean isValid();
-
- /**
- * Returns whether the qualifier has a fake value.
- * <p/>Fake values are used internally and should not be used as real qualifier value.
- */
- public abstract boolean hasFakeValue();
-
- /**
- * Check if the value is valid for this qualifier, and if so sets the value
- * into a Folder Configuration.
- * @param value The value to check and set. Must not be null.
- * @param config The folder configuration to receive the value. Must not be null.
- * @return true if the value was valid and was set.
- */
- public abstract boolean checkAndSet(String value, FolderConfiguration config);
-
- /**
- * Returns a string formated to be used in a folder name.
- * <p/>This is declared as abstract to force children classes to implement it.
- */
- public abstract String getFolderSegment();
-
- /**
- * Returns whether the given qualifier is a match for the receiver.
- * <p/>The default implementation returns the result of {@link #equals(Object)}.
- * <p/>Children class that re-implements this must implement
- * {@link #isBetterMatchThan(ResourceQualifier, ResourceQualifier)} too.
- * @param qualifier the reference qualifier
- * @return true if the receiver is a match.
- */
- public boolean isMatchFor(ResourceQualifier qualifier) {
- return equals(qualifier);
- }
-
- /**
- * Returns true if the receiver is a better match for the given <var>reference</var> than
- * the given <var>compareTo</var> comparable.
- * @param compareTo The {@link ResourceQualifier} to compare to. Can be null, in which
- * case the method must return <code>true</code>.
- * @param reference The reference qualifier value for which the match is.
- * @return true if the receiver is a better match.
- */
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- // the default is to always return false. This gives less overhead than always returning
- // true, as it would only compare same values anyway.
- return false;
- }
-
- @Override
- public String toString() {
- return getFolderSegment();
- }
-
- /**
- * Returns a string formatted for display purpose.
- */
- public abstract String getShortDisplayValue();
-
- /**
- * Returns a string formatted for display purpose.
- */
- public abstract String getLongDisplayValue();
-
- /**
- * Returns <code>true</code> if both objects are equal.
- * <p/>This is declared as abstract to force children classes to implement it.
- */
- @Override
- public abstract boolean equals(Object object);
-
- /**
- * Returns a hash code value for the object.
- * <p/>This is declared as abstract to force children classes to implement it.
- */
- @Override
- public abstract int hashCode();
-
- @Override
- public final int compareTo(ResourceQualifier o) {
- return toString().compareTo(o.toString());
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifier.java
deleted file mode 100644
index dce6c68..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifier.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Screen Dimension.
- */
-public final class ScreenDimensionQualifier extends ResourceQualifier {
- /** Default screen size value. This means the property is not set */
- final static int DEFAULT_SIZE = -1;
-
- private final static Pattern sDimensionPattern = Pattern.compile(
- "^(\\d+)x(\\d+)$"); //$NON-NLS-1$
-
- public static final String NAME = "Screen Dimension";
-
- /** Screen size 1 value. This is not size X or Y because the folder name always
- * contains the biggest size first. So if the qualifier is 400x200, size 1 will always be
- * 400 but that'll be X in landscape and Y in portrait.
- * Default value is <code>DEFAULT_SIZE</code> */
- private int mValue1 = DEFAULT_SIZE;
-
- /** Screen size 2 value. This is not size X or Y because the folder name always
- * contains the biggest size first. So if the qualifier is 400x200, size 2 will always be
- * 200 but that'll be Y in landscape and X in portrait.
- * Default value is <code>DEFAULT_SIZE</code> */
- private int mValue2 = DEFAULT_SIZE;
-
- public ScreenDimensionQualifier() {
- // pass
- }
-
- public ScreenDimensionQualifier(int value1, int value2) {
- mValue1 = value1;
- mValue2 = value2;
- }
-
- public int getValue1() {
- return mValue1;
- }
-
- public int getValue2() {
- return mValue2;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Dimension";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean deprecated() {
- return true;
- }
-
- @Override
- public boolean isValid() {
- return mValue1 != DEFAULT_SIZE && mValue2 != DEFAULT_SIZE;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Matcher m = sDimensionPattern.matcher(value);
- if (m.matches()) {
- String d1 = m.group(1);
- String d2 = m.group(2);
-
- ScreenDimensionQualifier qualifier = getQualifier(d1, d2);
- if (qualifier != null) {
- config.setScreenDimensionQualifier(qualifier);
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof ScreenDimensionQualifier) {
- ScreenDimensionQualifier q = (ScreenDimensionQualifier)qualifier;
- return (mValue1 == q.mValue1 && mValue2 == q.mValue2);
- }
-
- return false;
- }
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
-
- public static ScreenDimensionQualifier getQualifier(String size1, String size2) {
- try {
- int s1 = Integer.parseInt(size1);
- int s2 = Integer.parseInt(size2);
-
- ScreenDimensionQualifier qualifier = new ScreenDimensionQualifier();
-
- if (s1 > s2) {
- qualifier.mValue1 = s1;
- qualifier.mValue2 = s2;
- } else {
- qualifier.mValue1 = s2;
- qualifier.mValue2 = s1;
- }
-
- return qualifier;
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number.
- }
-
- return null;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- return String.format("%1$dx%2$d", mValue1, mValue2); //$NON-NLS-1$
- }
-
- @Override
- public String getShortDisplayValue() {
- if (isValid()) {
- return String.format("%1$dx%2$d", mValue1, mValue2);
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (isValid()) {
- return String.format("Screen resolution %1$dx%2$d", mValue1, mValue2);
- }
-
- return ""; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenHeightQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenHeightQualifier.java
deleted file mode 100644
index 08bba61..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenHeightQualifier.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Screen Pixel Density.
- */
-public final class ScreenHeightQualifier extends ResourceQualifier {
- /** Default screen size value. This means the property is not set */
- final static int DEFAULT_SIZE = -1;
-
- private final static Pattern sParsePattern = Pattern.compile("^h(\\d+)dp$");//$NON-NLS-1$
- private final static String sPrintPattern = "h%1$ddp";
-
- public static final String NAME = "Screen Height";
-
- private int mValue = DEFAULT_SIZE;
-
- public ScreenHeightQualifier() {
- // pass
- }
-
- public ScreenHeightQualifier(int value) {
- mValue = value;
- }
-
- public int getValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 13;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValid() {
- return mValue != DEFAULT_SIZE;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Matcher m = sParsePattern.matcher(value);
- if (m.matches()) {
- String v = m.group(1);
-
- ScreenHeightQualifier qualifier = getQualifier(v);
- if (qualifier != null) {
- config.setScreenHeightQualifier(qualifier);
- return true;
- }
- }
-
- return false;
- }
-
- public static ScreenHeightQualifier getQualifier(String value) {
- try {
- int dp = Integer.parseInt(value);
-
- ScreenHeightQualifier qualifier = new ScreenHeightQualifier();
- qualifier.mValue = dp;
- return qualifier;
-
- } catch (NumberFormatException e) {
- }
-
- return null;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- // this is the match only of the current dp value is lower or equal to the
- if (qualifier instanceof ScreenHeightQualifier) {
- return mValue <= ((ScreenHeightQualifier) qualifier).mValue;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- ScreenHeightQualifier compareQ = (ScreenHeightQualifier)compareTo;
- ScreenHeightQualifier referenceQ = (ScreenHeightQualifier)reference;
-
- if (compareQ.mValue == referenceQ.mValue) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mValue == referenceQ.mValue) {
- // got new exact value, this is the best!
- return true;
- } else {
- // get the qualifier that has the width that is the closest to the reference, but not
- // above. (which is guaranteed when this is called as isMatchFor is called first.
- return mValue > compareQ.mValue;
- }
- }
-
- @Override
- public String getFolderSegment() {
- return String.format(sPrintPattern, mValue);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
-
- @Override
- public int hashCode() {
- return mValue;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- ScreenHeightQualifier other = (ScreenHeightQualifier) obj;
- if (mValue != other.mValue) {
- return false;
- }
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifier.java
deleted file mode 100644
index 732a078..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifier.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-import com.android.resources.ScreenOrientation;
-
-/**
- * Resource Qualifier for Screen Orientation.
- */
-public final class ScreenOrientationQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Screen Orientation";
-
- private ScreenOrientation mValue = null;
-
- public ScreenOrientationQualifier() {
- }
-
- public ScreenOrientationQualifier(ScreenOrientation value) {
- mValue = value;
- }
-
- public ScreenOrientation getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Orientation";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- ScreenOrientation orientation = ScreenOrientation.getEnum(value);
- if (orientation != null) {
- ScreenOrientationQualifier qualifier = new ScreenOrientationQualifier(orientation);
- config.setScreenOrientationQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenRatioQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenRatioQualifier.java
deleted file mode 100644
index b45946b..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenRatioQualifier.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-import com.android.resources.ScreenRatio;
-
-public class ScreenRatioQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Screen Ratio";
-
- private ScreenRatio mValue = null;
-
- public ScreenRatioQualifier() {
- }
-
- public ScreenRatioQualifier(ScreenRatio value) {
- mValue = value;
- }
-
- public ScreenRatio getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Ratio";
- }
-
- @Override
- public int since() {
- return 4;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- ScreenRatio size = ScreenRatio.getEnum(value);
- if (size != null) {
- ScreenRatioQualifier qualifier = new ScreenRatioQualifier(size);
- config.setScreenRatioQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenSizeQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenSizeQualifier.java
deleted file mode 100644
index 77193a2..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenSizeQualifier.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-import com.android.resources.ScreenSize;
-
-/**
- * Resource Qualifier for Screen Size. Size can be "small", "normal", "large" and "x-large"
- */
-public class ScreenSizeQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Screen Size";
-
- private ScreenSize mValue = null;
-
-
- public ScreenSizeQualifier() {
- }
-
- public ScreenSizeQualifier(ScreenSize value) {
- mValue = value;
- }
-
- public ScreenSize getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Size";
- }
-
- @Override
- public int since() {
- return 4;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- ScreenSize size = ScreenSize.getEnum(value);
- if (size != null) {
- ScreenSizeQualifier qualifier = new ScreenSizeQualifier(size);
- config.setScreenSizeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenWidthQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/ScreenWidthQualifier.java
deleted file mode 100644
index ab9134b..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/ScreenWidthQualifier.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Screen Pixel Density.
- */
-public final class ScreenWidthQualifier extends ResourceQualifier {
- /** Default screen size value. This means the property is not set */
- final static int DEFAULT_SIZE = -1;
-
- private final static Pattern sParsePattern = Pattern.compile("^w(\\d+)dp$"); //$NON-NLS-1$
- private final static String sPrintPattern = "w%1$ddp"; //$NON-NLS-1$
-
- public static final String NAME = "Screen Width";
-
- private int mValue = DEFAULT_SIZE;
-
- public ScreenWidthQualifier() {
- // pass
- }
-
- public ScreenWidthQualifier(int value) {
- mValue = value;
- }
-
- public int getValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 13;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValid() {
- return mValue != DEFAULT_SIZE;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Matcher m = sParsePattern.matcher(value);
- if (m.matches()) {
- String v = m.group(1);
-
- ScreenWidthQualifier qualifier = getQualifier(v);
- if (qualifier != null) {
- config.setScreenWidthQualifier(qualifier);
- return true;
- }
- }
-
- return false;
- }
-
- public static ScreenWidthQualifier getQualifier(String value) {
- try {
- int dp = Integer.parseInt(value);
-
- ScreenWidthQualifier qualifier = new ScreenWidthQualifier();
- qualifier.mValue = dp;
- return qualifier;
-
- } catch (NumberFormatException e) {
- }
-
- return null;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- // this is the match only of the current dp value is lower or equal to the
- if (qualifier instanceof ScreenWidthQualifier) {
- return mValue <= ((ScreenWidthQualifier) qualifier).mValue;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- ScreenWidthQualifier compareQ = (ScreenWidthQualifier)compareTo;
- ScreenWidthQualifier referenceQ = (ScreenWidthQualifier)reference;
-
- if (compareQ.mValue == referenceQ.mValue) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mValue == referenceQ.mValue) {
- // got new exact value, this is the best!
- return true;
- } else {
- // get the qualifier that has the width that is the closest to the reference, but not
- // above. (which is guaranteed when this is called as isMatchFor is called first.
- return mValue > compareQ.mValue;
- }
- }
-
- @Override
- public String getFolderSegment() {
- return String.format(sPrintPattern, mValue);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public int hashCode() {
- return mValue;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- ScreenWidthQualifier other = (ScreenWidthQualifier) obj;
- if (mValue != other.mValue) {
- return false;
- }
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/SmallestScreenWidthQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/SmallestScreenWidthQualifier.java
deleted file mode 100644
index 35d1ab1..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/SmallestScreenWidthQualifier.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Screen Pixel Density.
- */
-public final class SmallestScreenWidthQualifier extends ResourceQualifier {
- /** Default screen size value. This means the property is not set */
- final static int DEFAULT_SIZE = -1;
-
- private final static Pattern sParsePattern = Pattern.compile("^sw(\\d+)dp$"); //$NON-NLS-1$
- private final static String sPrintPattern = "sw%1$ddp"; //$NON-NLS-1$
-
- public static final String NAME = "Smallest Screen Width";
-
- private int mValue = DEFAULT_SIZE;
-
- public SmallestScreenWidthQualifier() {
- // pass
- }
-
- public SmallestScreenWidthQualifier(int value) {
- mValue = value;
- }
-
- public int getValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 13;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean isValid() {
- return mValue != DEFAULT_SIZE;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Matcher m = sParsePattern.matcher(value);
- if (m.matches()) {
- String v = m.group(1);
-
- SmallestScreenWidthQualifier qualifier = getQualifier(v);
- if (qualifier != null) {
- config.setSmallestScreenWidthQualifier(qualifier);
- return true;
- }
- }
-
- return false;
- }
-
- public static SmallestScreenWidthQualifier getQualifier(String value) {
- try {
- int dp = Integer.parseInt(value);
-
- SmallestScreenWidthQualifier qualifier = new SmallestScreenWidthQualifier();
- qualifier.mValue = dp;
- return qualifier;
-
- } catch (NumberFormatException e) {
- }
-
- return null;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- // this is the match only of the current dp value is lower or equal to the
- if (qualifier instanceof SmallestScreenWidthQualifier) {
- return mValue <= ((SmallestScreenWidthQualifier) qualifier).mValue;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- SmallestScreenWidthQualifier compareQ = (SmallestScreenWidthQualifier)compareTo;
- SmallestScreenWidthQualifier referenceQ = (SmallestScreenWidthQualifier)reference;
-
- if (compareQ.mValue == referenceQ.mValue) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mValue == referenceQ.mValue) {
- // got new exact value, this is the best!
- return true;
- } else {
- // get the qualifier that has the width that is the closest to the reference, but not
- // above. (which is guaranteed when this is called as isMatchFor is called first.
- return mValue > compareQ.mValue;
- }
- }
-
- @Override
- public String getFolderSegment() {
- return String.format(sPrintPattern, mValue);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (isValid()) {
- return getFolderSegment();
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public int hashCode() {
- return mValue;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- SmallestScreenWidthQualifier other = (SmallestScreenWidthQualifier) obj;
- if (mValue != other.mValue) {
- return false;
- }
- return true;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/TextInputMethodQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/TextInputMethodQualifier.java
deleted file mode 100644
index 784d43d..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/TextInputMethodQualifier.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Keyboard;
-import com.android.resources.ResourceEnum;
-
-/**
- * Resource Qualifier for Text Input Method.
- */
-public final class TextInputMethodQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Text Input Method";
-
- private Keyboard mValue;
-
-
- public TextInputMethodQualifier() {
- // pass
- }
-
- public TextInputMethodQualifier(Keyboard value) {
- mValue = value;
- }
-
- public Keyboard getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Text Input";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- Keyboard method = Keyboard.getEnum(value);
- if (method != null) {
- TextInputMethodQualifier qualifier = new TextInputMethodQualifier();
- qualifier.mValue = method;
- config.setTextInputMethodQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/TouchScreenQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/TouchScreenQualifier.java
deleted file mode 100644
index dce9f1d..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/TouchScreenQualifier.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-import com.android.resources.TouchScreen;
-
-
-/**
- * Resource Qualifier for Touch Screen type.
- */
-public final class TouchScreenQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "Touch Screen";
-
- private TouchScreen mValue;
-
- public TouchScreenQualifier() {
- // pass
- }
-
- public TouchScreenQualifier(TouchScreen touchValue) {
- mValue = touchValue;
- }
-
- public TouchScreen getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- TouchScreen type = TouchScreen.getEnum(value);
- if (type != null) {
- TouchScreenQualifier qualifier = new TouchScreenQualifier();
- qualifier.mValue = type;
- config.setTouchTypeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/UiModeQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/UiModeQualifier.java
deleted file mode 100644
index 1e302c5..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/UiModeQualifier.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ResourceEnum;
-import com.android.resources.UiMode;
-
-/**
- * Resource Qualifier for UI Mode.
- */
-public final class UiModeQualifier extends EnumBasedResourceQualifier {
-
- public static final String NAME = "UI Mode";
-
- private UiMode mValue;
-
- public UiModeQualifier() {
- // pass
- }
-
- public UiModeQualifier(UiMode value) {
- mValue = value;
- }
-
- public UiMode getValue() {
- return mValue;
- }
-
- @Override
- ResourceEnum getEnumValue() {
- return mValue;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return NAME;
- }
-
- @Override
- public int since() {
- return 8;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- UiMode mode = UiMode.getEnum(value);
- if (mode != null) {
- UiModeQualifier qualifier = new UiModeQualifier(mode);
- config.setUiModeQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- // only normal is a match for all UI mode, because it's not an actual mode.
- if (mValue == UiMode.NORMAL) {
- return true;
- }
-
- // others must be an exact match
- return ((UiModeQualifier)qualifier).mValue == mValue;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- UiModeQualifier compareQualifier = (UiModeQualifier)compareTo;
- UiModeQualifier referenceQualifier = (UiModeQualifier)reference;
-
- if (compareQualifier.getValue() == referenceQualifier.getValue()) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mValue == referenceQualifier.mValue) {
- // got new exact value, this is the best!
- return true;
- } else if (mValue == UiMode.NORMAL) {
- // else "normal" can be a match in case there's no exact match
- return true;
- }
-
- return false;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/resources/configuration/VersionQualifier.java b/sdk_common/src/com/android/ide/common/resources/configuration/VersionQualifier.java
deleted file mode 100644
index 078d4af..0000000
--- a/sdk_common/src/com/android/ide/common/resources/configuration/VersionQualifier.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Resource Qualifier for Platform Version.
- */
-public final class VersionQualifier extends ResourceQualifier {
- /** Default pixel density value. This means the property is not set. */
- private final static int DEFAULT_VERSION = -1;
-
- private final static Pattern sVersionPattern = Pattern.compile("^v(\\d+)$");//$NON-NLS-1$
-
- private int mVersion = DEFAULT_VERSION;
-
- public static final String NAME = "Platform Version";
-
- /**
- * Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
- * <code>null</code> is returned.
- * @param segment the folder segment from which to create a qualifier.
- * @return a new {@link VersionQualifier} object or <code>null</code>
- */
- public static VersionQualifier getQualifier(String segment) {
- Matcher m = sVersionPattern.matcher(segment);
- if (m.matches()) {
- String v = m.group(1);
-
- int code = -1;
- try {
- code = Integer.parseInt(v);
- } catch (NumberFormatException e) {
- // looks like the string we extracted wasn't a valid number.
- return null;
- }
-
- VersionQualifier qualifier = new VersionQualifier();
- qualifier.mVersion = code;
- return qualifier;
- }
-
- return null;
- }
-
- /**
- * Returns the folder name segment for the given value. This is equivalent to calling
- * {@link #toString()} on a {@link VersionQualifier} object.
- * @param version the value of the qualifier, as returned by {@link #getVersion()}.
- */
- public static String getFolderSegment(int version) {
- if (version != DEFAULT_VERSION) {
- return String.format("v%1$d", version); //$NON-NLS-1$
- }
-
- return ""; //$NON-NLS-1$
- }
-
- public VersionQualifier(int apiLevel) {
- mVersion = apiLevel;
- }
-
- public VersionQualifier() {
- //pass
- }
-
- public int getVersion() {
- return mVersion;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public String getShortName() {
- return "Version";
- }
-
- @Override
- public int since() {
- return 1;
- }
-
- @Override
- public boolean isValid() {
- return mVersion != DEFAULT_VERSION;
- }
-
- @Override
- public boolean hasFakeValue() {
- return false;
- }
-
- @Override
- public boolean checkAndSet(String value, FolderConfiguration config) {
- VersionQualifier qualifier = getQualifier(value);
- if (qualifier != null) {
- config.setVersionQualifier(qualifier);
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean equals(Object qualifier) {
- if (qualifier instanceof VersionQualifier) {
- return mVersion == ((VersionQualifier)qualifier).mVersion;
- }
-
- return false;
- }
-
- @Override
- public boolean isMatchFor(ResourceQualifier qualifier) {
- if (qualifier instanceof VersionQualifier) {
- // it is considered a match if the api level is equal or lower to the given qualifier
- return mVersion <= ((VersionQualifier) qualifier).mVersion;
- }
-
- return false;
- }
-
- @Override
- public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
- if (compareTo == null) {
- return true;
- }
-
- VersionQualifier compareQ = (VersionQualifier)compareTo;
- VersionQualifier referenceQ = (VersionQualifier)reference;
-
- if (compareQ.mVersion == referenceQ.mVersion) {
- // what we have is already the best possible match (exact match)
- return false;
- } else if (mVersion == referenceQ.mVersion) {
- // got new exact value, this is the best!
- return true;
- } else {
- // in all case we're going to prefer the higher version (since they have been filtered
- // to not be too high
- return mVersion > compareQ.mVersion;
- }
- }
-
- @Override
- public int hashCode() {
- return mVersion;
- }
-
- /**
- * Returns the string used to represent this qualifier in the folder name.
- */
- @Override
- public String getFolderSegment() {
- return getFolderSegment(mVersion);
- }
-
- @Override
- public String getShortDisplayValue() {
- if (mVersion != DEFAULT_VERSION) {
- return String.format("API %1$d", mVersion);
- }
-
- return ""; //$NON-NLS-1$
- }
-
- @Override
- public String getLongDisplayValue() {
- if (mVersion != DEFAULT_VERSION) {
- return String.format("API Level %1$d", mVersion);
- }
-
- return ""; //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/sdk/LoadStatus.java b/sdk_common/src/com/android/ide/common/sdk/LoadStatus.java
deleted file mode 100644
index babbd63..0000000
--- a/sdk_common/src/com/android/ide/common/sdk/LoadStatus.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.sdk;
-
-/**
- * Enum for loading status of various SDK parts.
- */
-public enum LoadStatus {
- LOADING, LOADED, FAILED;
-}
diff --git a/sdk_common/src/com/android/ide/common/xml/AndroidManifestParser.java b/sdk_common/src/com/android/ide/common/xml/AndroidManifestParser.java
deleted file mode 100644
index 7fde6ce..0000000
--- a/sdk_common/src/com/android/ide/common/xml/AndroidManifestParser.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.SdkConstants;
-import com.android.ide.common.xml.ManifestData.Activity;
-import com.android.ide.common.xml.ManifestData.Instrumentation;
-import com.android.ide.common.xml.ManifestData.SupportsScreens;
-import com.android.ide.common.xml.ManifestData.UsesConfiguration;
-import com.android.ide.common.xml.ManifestData.UsesFeature;
-import com.android.ide.common.xml.ManifestData.UsesLibrary;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.io.StreamException;
-import com.android.resources.Keyboard;
-import com.android.resources.Navigation;
-import com.android.resources.TouchScreen;
-import com.android.xml.AndroidManifest;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-public class AndroidManifestParser {
-
- private final static int LEVEL_TOP = 0;
- private final static int LEVEL_INSIDE_MANIFEST = 1;
- private final static int LEVEL_INSIDE_APPLICATION = 2;
- private final static int LEVEL_INSIDE_APP_COMPONENT = 3;
- private final static int LEVEL_INSIDE_INTENT_FILTER = 4;
-
- private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
- private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
-
- public interface ManifestErrorHandler extends ErrorHandler {
- /**
- * Handles a parsing error and an optional line number.
- */
- void handleError(Exception exception, int lineNumber);
-
- /**
- * Checks that a class is valid and can be used in the Android Manifest.
- * <p/>
- * Errors are put as {@code org.eclipse.core.resources.IMarker} on the manifest file.
- *
- * @param locator
- * @param className the fully qualified name of the class to test.
- * @param superClassName the fully qualified name of the class it is supposed to extend.
- * @param testVisibility if <code>true</code>, the method will check the visibility of
- * the class or of its constructors.
- */
- void checkClass(Locator locator, String className, String superClassName,
- boolean testVisibility);
- }
-
- /**
- * XML error & data handler used when parsing the AndroidManifest.xml file.
- * <p/>
- * During parsing this will fill up the {@link ManifestData} object given to the constructor
- * and call out errors to the given {@link ManifestErrorHandler}.
- */
- private static class ManifestHandler extends DefaultHandler {
-
- //--- temporary data/flags used during parsing
- private final ManifestData mManifestData;
- private final ManifestErrorHandler mErrorHandler;
- private int mCurrentLevel = 0;
- private int mValidLevel = 0;
- private Activity mCurrentActivity = null;
- private Locator mLocator;
-
- /**
- * Creates a new {@link ManifestHandler}.
- *
- * @param manifestFile The manifest file being parsed. Can be null.
- * @param manifestData Class containing the manifest info obtained during the parsing.
- * @param errorHandler An optional error handler.
- */
- ManifestHandler(IAbstractFile manifestFile, ManifestData manifestData,
- ManifestErrorHandler errorHandler) {
- super();
- mManifestData = manifestData;
- mErrorHandler = errorHandler;
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
- */
- @Override
- public void setDocumentLocator(Locator locator) {
- mLocator = locator;
- super.setDocumentLocator(locator);
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
- * java.lang.String, org.xml.sax.Attributes)
- */
- @Override
- public void startElement(String uri, String localName, String name, Attributes attributes)
- throws SAXException {
- try {
- if (mManifestData == null) {
- return;
- }
-
- // if we're at a valid level
- if (mValidLevel == mCurrentLevel) {
- String value;
- switch (mValidLevel) {
- case LEVEL_TOP:
- if (AndroidManifest.NODE_MANIFEST.equals(localName)) {
- // lets get the package name.
- mManifestData.mPackage = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_PACKAGE,
- false /* hasNamespace */);
-
- // and the versionCode
- String tmp = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_VERSIONCODE, true);
- if (tmp != null) {
- try {
- mManifestData.mVersionCode = Integer.valueOf(tmp);
- } catch (NumberFormatException e) {
- // keep null in the field.
- }
- }
- mValidLevel++;
- }
- break;
- case LEVEL_INSIDE_MANIFEST:
- if (AndroidManifest.NODE_APPLICATION.equals(localName)) {
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_PROCESS,
- true /* hasNamespace */);
- if (value != null) {
- mManifestData.addProcessName(value);
- }
-
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_DEBUGGABLE,
- true /* hasNamespace*/);
- if (value != null) {
- mManifestData.mDebuggable = Boolean.parseBoolean(value);
- }
-
- mValidLevel++;
- } else if (AndroidManifest.NODE_USES_SDK.equals(localName)) {
- mManifestData.setMinSdkVersionString(getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_MIN_SDK_VERSION,
- true /* hasNamespace */));
- mManifestData.setTargetSdkVersionString(getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_TARGET_SDK_VERSION,
- true /* hasNamespace */));
- } else if (AndroidManifest.NODE_INSTRUMENTATION.equals(localName)) {
- processInstrumentationNode(attributes);
-
- } else if (AndroidManifest.NODE_SUPPORTS_SCREENS.equals(localName)) {
- processSupportsScreensNode(attributes);
-
- } else if (AndroidManifest.NODE_USES_CONFIGURATION.equals(localName)) {
- processUsesConfiguration(attributes);
-
- } else if (AndroidManifest.NODE_USES_FEATURE.equals(localName)) {
- UsesFeature feature = new UsesFeature();
-
- // get the name
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (value != null) {
- feature.mName = value;
- }
-
- // read the required attribute
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_REQUIRED,
- true /*hasNamespace*/);
- if (value != null) {
- Boolean b = Boolean.valueOf(value);
- if (b != null) {
- feature.mRequired = b;
- }
- }
-
- // read the gl es attribute
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_GLESVERSION,
- true /*hasNamespace*/);
- if (value != null) {
- try {
- int version = Integer.decode(value);
- feature.mGlEsVersion = version;
- } catch (NumberFormatException e) {
- // ignore
- }
-
- }
-
- mManifestData.mFeatures.add(feature);
- }
- break;
- case LEVEL_INSIDE_APPLICATION:
- if (AndroidManifest.NODE_ACTIVITY.equals(localName)
- || AndroidManifest.NODE_ACTIVITY_ALIAS.equals(localName)) {
- processActivityNode(attributes);
- mValidLevel++;
- } else if (AndroidManifest.NODE_SERVICE.equals(localName)) {
- processNode(attributes, SdkConstants.CLASS_SERVICE);
- mValidLevel++;
- } else if (AndroidManifest.NODE_RECEIVER.equals(localName)) {
- processNode(attributes, SdkConstants.CLASS_BROADCASTRECEIVER);
- mValidLevel++;
- } else if (AndroidManifest.NODE_PROVIDER.equals(localName)) {
- processNode(attributes, SdkConstants.CLASS_CONTENTPROVIDER);
- mValidLevel++;
- } else if (AndroidManifest.NODE_USES_LIBRARY.equals(localName)) {
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (value != null) {
- UsesLibrary library = new UsesLibrary();
- library.mName = value;
-
- // read the required attribute
- value = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_REQUIRED,
- true /*hasNamespace*/);
- if (value != null) {
- Boolean b = Boolean.valueOf(value);
- if (b != null) {
- library.mRequired = b;
- }
- }
-
- mManifestData.mLibraries.add(library);
- }
- }
- break;
- case LEVEL_INSIDE_APP_COMPONENT:
- // only process this level if we are in an activity
- if (mCurrentActivity != null &&
- AndroidManifest.NODE_INTENT.equals(localName)) {
- mCurrentActivity.resetIntentFilter();
- mValidLevel++;
- }
- break;
- case LEVEL_INSIDE_INTENT_FILTER:
- if (mCurrentActivity != null) {
- if (AndroidManifest.NODE_ACTION.equals(localName)) {
- // get the name attribute
- String action = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (action != null) {
- mCurrentActivity.setHasAction(true);
- mCurrentActivity.setHasMainAction(
- ACTION_MAIN.equals(action));
- }
- } else if (AndroidManifest.NODE_CATEGORY.equals(localName)) {
- String category = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (CATEGORY_LAUNCHER.equals(category)) {
- mCurrentActivity.setHasLauncherCategory(true);
- }
- }
-
- // no need to increase mValidLevel as we don't process anything
- // below this level.
- }
- break;
- }
- }
-
- mCurrentLevel++;
- } finally {
- super.startElement(uri, localName, name, attributes);
- }
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
- * java.lang.String)
- */
- @Override
- public void endElement(String uri, String localName, String name) throws SAXException {
- try {
- if (mManifestData == null) {
- return;
- }
-
- // decrement the levels.
- if (mValidLevel == mCurrentLevel) {
- mValidLevel--;
- }
- mCurrentLevel--;
-
- // if we're at a valid level
- // process the end of the element
- if (mValidLevel == mCurrentLevel) {
- switch (mValidLevel) {
- case LEVEL_INSIDE_APPLICATION:
- mCurrentActivity = null;
- break;
- case LEVEL_INSIDE_APP_COMPONENT:
- // if we found both a main action and a launcher category, this is our
- // launcher activity!
- if (mManifestData.mLauncherActivity == null &&
- mCurrentActivity != null &&
- mCurrentActivity.isHomeActivity() &&
- mCurrentActivity.isExported()) {
- mManifestData.mLauncherActivity = mCurrentActivity;
- }
- break;
- default:
- break;
- }
-
- }
- } finally {
- super.endElement(uri, localName, name);
- }
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
- */
- @Override
- public void error(SAXParseException e) {
- if (mErrorHandler != null) {
- mErrorHandler.handleError(e, e.getLineNumber());
- }
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
- */
- @Override
- public void fatalError(SAXParseException e) {
- if (mErrorHandler != null) {
- mErrorHandler.handleError(e, e.getLineNumber());
- }
- }
-
- /* (non-Javadoc)
- * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException)
- */
- @Override
- public void warning(SAXParseException e) throws SAXException {
- if (mErrorHandler != null) {
- mErrorHandler.warning(e);
- }
- }
-
- /**
- * Processes the activity node.
- * @param attributes the attributes for the activity node.
- */
- private void processActivityNode(Attributes attributes) {
- // lets get the activity name, and add it to the list
- String activityName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (activityName != null) {
- activityName = AndroidManifest.combinePackageAndClassName(mManifestData.mPackage,
- activityName);
-
- // get the exported flag.
- String exportedStr = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_EXPORTED, true);
- boolean exported = exportedStr == null ||
- exportedStr.toLowerCase(Locale.US).equals("true"); //$NON-NLS-1$
- mCurrentActivity = new Activity(activityName, exported);
- mManifestData.mActivities.add(mCurrentActivity);
-
- if (mErrorHandler != null) {
- mErrorHandler.checkClass(mLocator, activityName, SdkConstants.CLASS_ACTIVITY,
- true /* testVisibility */);
- }
- } else {
- // no activity found! Aapt will output an error,
- // so we don't have to do anything
- mCurrentActivity = null;
- }
-
- String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
- true /* hasNamespace */);
- if (processName != null) {
- mManifestData.addProcessName(processName);
- }
- }
-
- /**
- * Processes the service/receiver/provider nodes.
- * @param attributes the attributes for the activity node.
- * @param superClassName the fully qualified name of the super class that this
- * node is representing
- */
- private void processNode(Attributes attributes, String superClassName) {
- // lets get the class name, and check it if required.
- String serviceName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (serviceName != null) {
- serviceName = AndroidManifest.combinePackageAndClassName(mManifestData.mPackage,
- serviceName);
-
- if (mErrorHandler != null) {
- mErrorHandler.checkClass(mLocator, serviceName, superClassName,
- false /* testVisibility */);
- }
- }
-
- String processName = getAttributeValue(attributes, AndroidManifest.ATTRIBUTE_PROCESS,
- true /* hasNamespace */);
- if (processName != null) {
- mManifestData.addProcessName(processName);
- }
- }
-
- /**
- * Processes the instrumentation node.
- * @param attributes the attributes for the instrumentation node.
- */
- private void processInstrumentationNode(Attributes attributes) {
- // lets get the class name, and check it if required.
- String instrumentationName = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_NAME,
- true /* hasNamespace */);
- if (instrumentationName != null) {
- String instrClassName = AndroidManifest.combinePackageAndClassName(
- mManifestData.mPackage, instrumentationName);
- String targetPackage = getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_TARGET_PACKAGE,
- true /* hasNamespace */);
- mManifestData.mInstrumentations.add(
- new Instrumentation(instrClassName, targetPackage));
- if (mErrorHandler != null) {
- mErrorHandler.checkClass(mLocator, instrClassName,
- SdkConstants.CLASS_INSTRUMENTATION, true /* testVisibility */);
- }
- }
- }
-
- /**
- * Processes the supports-screens node.
- * @param attributes the attributes for the supports-screens node.
- */
- private void processSupportsScreensNode(Attributes attributes) {
- mManifestData.mSupportsScreensFromManifest = new SupportsScreens();
-
- mManifestData.mSupportsScreensFromManifest.setResizeable(getAttributeBooleanValue(
- attributes, AndroidManifest.ATTRIBUTE_RESIZEABLE, true /*hasNamespace*/));
-
- mManifestData.mSupportsScreensFromManifest.setAnyDensity(getAttributeBooleanValue(
- attributes, AndroidManifest.ATTRIBUTE_ANYDENSITY, true /*hasNamespace*/));
-
- mManifestData.mSupportsScreensFromManifest.setSmallScreens(getAttributeBooleanValue(
- attributes, AndroidManifest.ATTRIBUTE_SMALLSCREENS, true /*hasNamespace*/));
-
- mManifestData.mSupportsScreensFromManifest.setNormalScreens(getAttributeBooleanValue(
- attributes, AndroidManifest.ATTRIBUTE_NORMALSCREENS, true /*hasNamespace*/));
-
- mManifestData.mSupportsScreensFromManifest.setLargeScreens(getAttributeBooleanValue(
- attributes, AndroidManifest.ATTRIBUTE_LARGESCREENS, true /*hasNamespace*/));
- }
-
- /**
- * Processes the supports-screens node.
- * @param attributes the attributes for the supports-screens node.
- */
- private void processUsesConfiguration(Attributes attributes) {
- mManifestData.mUsesConfiguration = new UsesConfiguration();
-
- mManifestData.mUsesConfiguration.mReqFiveWayNav = getAttributeBooleanValue(
- attributes,
- AndroidManifest.ATTRIBUTE_REQ_5WAYNAV, true /*hasNamespace*/);
- mManifestData.mUsesConfiguration.mReqNavigation = Navigation.getEnum(
- getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_REQ_NAVIGATION, true /*hasNamespace*/));
- mManifestData.mUsesConfiguration.mReqHardKeyboard = getAttributeBooleanValue(
- attributes,
- AndroidManifest.ATTRIBUTE_REQ_HARDKEYBOARD, true /*hasNamespace*/);
- mManifestData.mUsesConfiguration.mReqKeyboardType = Keyboard.getEnum(
- getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_REQ_KEYBOARDTYPE, true /*hasNamespace*/));
- mManifestData.mUsesConfiguration.mReqTouchScreen = TouchScreen.getEnum(
- getAttributeValue(attributes,
- AndroidManifest.ATTRIBUTE_REQ_TOUCHSCREEN, true /*hasNamespace*/));
- }
-
- /**
- * Searches through the attributes list for a particular one and returns its value.
- * @param attributes the attribute list to search through
- * @param attributeName the name of the attribute to look for.
- * @param hasNamespace Indicates whether the attribute has an android namespace.
- * @return a String with the value or null if the attribute was not found.
- * @see SdkConstants#NS_RESOURCES
- */
- private String getAttributeValue(Attributes attributes, String attributeName,
- boolean hasNamespace) {
- int count = attributes.getLength();
- for (int i = 0 ; i < count ; i++) {
- if (attributeName.equals(attributes.getLocalName(i)) &&
- ((hasNamespace &&
- SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) ||
- (hasNamespace == false && attributes.getURI(i).length() == 0))) {
- return attributes.getValue(i);
- }
- }
-
- return null;
- }
-
- /**
- * Searches through the attributes list for a particular one and returns its value as a
- * Boolean. If the attribute is not present, this will return null.
- * @param attributes the attribute list to search through
- * @param attributeName the name of the attribute to look for.
- * @param hasNamespace Indicates whether the attribute has an android namespace.
- * @return a String with the value or null if the attribute was not found.
- * @see SdkConstants#NS_RESOURCES
- */
- private Boolean getAttributeBooleanValue(Attributes attributes, String attributeName,
- boolean hasNamespace) {
- int count = attributes.getLength();
- for (int i = 0 ; i < count ; i++) {
- if (attributeName.equals(attributes.getLocalName(i)) &&
- ((hasNamespace &&
- SdkConstants.NS_RESOURCES.equals(attributes.getURI(i))) ||
- (hasNamespace == false && attributes.getURI(i).length() == 0))) {
- String attr = attributes.getValue(i);
- if (attr != null) {
- return Boolean.valueOf(attr);
- } else {
- return null;
- }
- }
- }
-
- return null;
- }
-
- }
-
- private final static SAXParserFactory sParserFactory;
-
- static {
- sParserFactory = SAXParserFactory.newInstance();
- sParserFactory.setNamespaceAware(true);
- }
-
- /**
- * Parses the Android Manifest, and returns a {@link ManifestData} object containing the
- * result of the parsing.
- *
- * @param manifestFile the {@link IAbstractFile} representing the manifest file.
- * @param gatherData indicates whether the parsing will extract data from the manifest. If false
- * the method will always return null.
- * @param errorHandler an optional errorHandler.
- * @return A class containing the manifest info obtained during the parsing, or null on error.
- *
- * @throws StreamException
- * @throws IOException
- * @throws SAXException
- * @throws ParserConfigurationException
- */
- public static ManifestData parse(
- IAbstractFile manifestFile,
- boolean gatherData,
- ManifestErrorHandler errorHandler)
- throws SAXException, IOException, StreamException, ParserConfigurationException {
- if (manifestFile != null) {
- SAXParser parser = sParserFactory.newSAXParser();
-
- ManifestData data = null;
- if (gatherData) {
- data = new ManifestData();
- }
-
- ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
- data, errorHandler);
- parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
-
- return data;
- }
-
- return null;
- }
-
- /**
- * Parses the Android Manifest, and returns an object containing the result of the parsing.
- *
- * <p/>
- * This is the equivalent of calling <pre>parse(manifestFile, true, null)</pre>
- *
- * @param manifestFile the manifest file to parse.
- *
- * @throws ParserConfigurationException
- * @throws StreamException
- * @throws IOException
- * @throws SAXException
- */
- public static ManifestData parse(IAbstractFile manifestFile)
- throws SAXException, IOException, StreamException, ParserConfigurationException {
- return parse(manifestFile, true, null);
- }
-
- public static ManifestData parse(IAbstractFolder projectFolder)
- throws SAXException, IOException, StreamException, ParserConfigurationException {
- IAbstractFile manifestFile = AndroidManifest.getManifest(projectFolder);
- if (manifestFile == null) {
- throw new FileNotFoundException();
- }
-
- return parse(manifestFile, true, null);
- }
-
- /**
- * Parses the Android Manifest from an {@link InputStream}, and returns a {@link ManifestData}
- * object containing the result of the parsing.
- *
- * @param manifestFileStream the {@link InputStream} representing the manifest file.
- * @return A class containing the manifest info obtained during the parsing or null on error.
- *
- * @throws StreamException
- * @throws IOException
- * @throws SAXException
- * @throws ParserConfigurationException
- */
- public static ManifestData parse(InputStream manifestFileStream)
- throws SAXException, IOException, StreamException, ParserConfigurationException {
- if (manifestFileStream != null) {
- SAXParser parser = sParserFactory.newSAXParser();
-
- ManifestData data = new ManifestData();
-
- ManifestHandler manifestHandler = new ManifestHandler(null, data, null);
- parser.parse(new InputSource(manifestFileStream), manifestHandler);
-
- return data;
- }
-
- return null;
- }
-}
diff --git a/sdk_common/src/com/android/ide/common/xml/ManifestData.java b/sdk_common/src/com/android/ide/common/xml/ManifestData.java
deleted file mode 100644
index 9b68d60..0000000
--- a/sdk_common/src/com/android/ide/common/xml/ManifestData.java
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.resources.Keyboard;
-import com.android.resources.Navigation;
-import com.android.resources.TouchScreen;
-
-import java.util.ArrayList;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * Class containing the manifest info obtained during the parsing.
- */
-public final class ManifestData {
-
- /**
- * Value returned by {@link #getMinSdkVersion()} when the value of the minSdkVersion attribute
- * in the manifest is a codename and not an integer value.
- */
- public final static int MIN_SDK_CODENAME = 0;
-
- /**
- * Value returned by {@link #getGlEsVersion()} when there are no <uses-feature> node with the
- * attribute glEsVersion set.
- */
- public final static int GL_ES_VERSION_NOT_SET = -1;
-
- /** Application package */
- String mPackage;
- /** Application version Code, null if the attribute is not present. */
- Integer mVersionCode = null;
- /** List of all activities */
- final ArrayList<Activity> mActivities = new ArrayList<Activity>();
- /** Launcher activity */
- Activity mLauncherActivity = null;
- /** list of process names declared by the manifest */
- Set<String> mProcesses = null;
- /** debuggable attribute value. If null, the attribute is not present. */
- Boolean mDebuggable = null;
- /** API level requirement. if null the attribute was not present. */
- private String mMinSdkVersionString = null;
- /** API level requirement. Default is 1 even if missing. If value is a codename, then it'll be
- * 0 instead. */
- private int mMinSdkVersion = 1;
- private int mTargetSdkVersion = 0;
- /** List of all instrumentations declared by the manifest */
- final ArrayList<Instrumentation> mInstrumentations =
- new ArrayList<Instrumentation>();
- /** List of all libraries in use declared by the manifest */
- final ArrayList<UsesLibrary> mLibraries = new ArrayList<UsesLibrary>();
- /** List of all feature in use declared by the manifest */
- final ArrayList<UsesFeature> mFeatures = new ArrayList<UsesFeature>();
-
- SupportsScreens mSupportsScreensFromManifest;
- SupportsScreens mSupportsScreensValues;
- UsesConfiguration mUsesConfiguration;
-
- /**
- * Instrumentation info obtained from manifest
- */
- public final static class Instrumentation {
- private final String mName;
- private final String mTargetPackage;
-
- Instrumentation(String name, String targetPackage) {
- mName = name;
- mTargetPackage = targetPackage;
- }
-
- /**
- * Returns the fully qualified instrumentation class name
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the Android app package that is the target of this instrumentation
- */
- public String getTargetPackage() {
- return mTargetPackage;
- }
- }
-
- /**
- * Activity info obtained from the manifest.
- */
- public final static class Activity {
- private final String mName;
- private final boolean mIsExported;
- private boolean mHasAction = false;
- private boolean mHasMainAction = false;
- private boolean mHasLauncherCategory = false;
-
- public Activity(String name, boolean exported) {
- mName = name;
- mIsExported = exported;
- }
-
- public String getName() {
- return mName;
- }
-
- public boolean isExported() {
- return mIsExported;
- }
-
- public boolean hasAction() {
- return mHasAction;
- }
-
- public boolean isHomeActivity() {
- return mHasMainAction && mHasLauncherCategory;
- }
-
- void setHasAction(boolean hasAction) {
- mHasAction = hasAction;
- }
-
- /** If the activity doesn't yet have a filter set for the launcher, this resets both
- * flags. This is to handle multiple intent-filters where one could have the valid
- * action, and another one of the valid category.
- */
- void resetIntentFilter() {
- if (isHomeActivity() == false) {
- mHasMainAction = mHasLauncherCategory = false;
- }
- }
-
- void setHasMainAction(boolean hasMainAction) {
- mHasMainAction = hasMainAction;
- }
-
- void setHasLauncherCategory(boolean hasLauncherCategory) {
- mHasLauncherCategory = hasLauncherCategory;
- }
- }
-
- /**
- * Class representing the <code>supports-screens</code> node in the manifest.
- * By default, all the getters will return null if there was no value defined in the manifest.
- *
- * To get an instance with all the actual values, use {@link #resolveSupportsScreensValues(int)}
- */
- public final static class SupportsScreens {
- private Boolean mResizeable;
- private Boolean mAnyDensity;
- private Boolean mSmallScreens;
- private Boolean mNormalScreens;
- private Boolean mLargeScreens;
-
- public SupportsScreens() {
- }
-
- /**
- * Instantiate an instance from a string. The string must have been created with
- * {@link #getEncodedValues()}.
- * @param value the string.
- */
- public SupportsScreens(String value) {
- String[] values = value.split("\\|");
-
- mAnyDensity = Boolean.valueOf(values[0]);
- mResizeable = Boolean.valueOf(values[1]);
- mSmallScreens = Boolean.valueOf(values[2]);
- mNormalScreens = Boolean.valueOf(values[3]);
- mLargeScreens = Boolean.valueOf(values[4]);
- }
-
- /**
- * Returns an instance of {@link SupportsScreens} initialized with the default values
- * based on the given targetSdkVersion.
- * @param targetSdkVersion
- */
- public static SupportsScreens getDefaultValues(int targetSdkVersion) {
- SupportsScreens result = new SupportsScreens();
-
- result.mNormalScreens = Boolean.TRUE;
- // Screen size and density became available in Android 1.5/API3, so before that
- // non normal screens were not supported by default. After they are considered
- // supported.
- result.mResizeable = result.mAnyDensity = result.mSmallScreens = result.mLargeScreens =
- targetSdkVersion <= 3 ? Boolean.FALSE : Boolean.TRUE;
-
- return result;
- }
-
- /**
- * Returns a version of the receiver for which all values have been set, even if they
- * were not present in the manifest.
- * @param targetSdkVersion the target api level of the app, since this has an effect
- * on default values.
- */
- public SupportsScreens resolveSupportsScreensValues(int targetSdkVersion) {
- SupportsScreens result = getDefaultValues(targetSdkVersion);
-
- // Override the default with the existing values:
- if (mResizeable != null) result.mResizeable = mResizeable;
- if (mAnyDensity != null) result.mAnyDensity = mAnyDensity;
- if (mSmallScreens != null) result.mSmallScreens = mSmallScreens;
- if (mNormalScreens != null) result.mNormalScreens = mNormalScreens;
- if (mLargeScreens != null) result.mLargeScreens = mLargeScreens;
-
- return result;
- }
-
- /**
- * returns the value of the <code>resizeable</code> attribute or null if not present.
- */
- public Boolean getResizeable() {
- return mResizeable;
- }
-
- void setResizeable(Boolean resizeable) {
- mResizeable = getConstantBoolean(resizeable);
- }
-
- /**
- * returns the value of the <code>anyDensity</code> attribute or null if not present.
- */
- public Boolean getAnyDensity() {
- return mAnyDensity;
- }
-
- void setAnyDensity(Boolean anyDensity) {
- mAnyDensity = getConstantBoolean(anyDensity);
- }
-
- /**
- * returns the value of the <code>smallScreens</code> attribute or null if not present.
- */
- public Boolean getSmallScreens() {
- return mSmallScreens;
- }
-
- void setSmallScreens(Boolean smallScreens) {
- mSmallScreens = getConstantBoolean(smallScreens);
- }
-
- /**
- * returns the value of the <code>normalScreens</code> attribute or null if not present.
- */
- public Boolean getNormalScreens() {
- return mNormalScreens;
- }
-
- void setNormalScreens(Boolean normalScreens) {
- mNormalScreens = getConstantBoolean(normalScreens);
- }
-
- /**
- * returns the value of the <code>largeScreens</code> attribute or null if not present.
- */
- public Boolean getLargeScreens() {
- return mLargeScreens;
- }
-
- void setLargeScreens(Boolean largeScreens) {
- mLargeScreens = getConstantBoolean(largeScreens);
- }
-
- /**
- * Returns either {@link Boolean#TRUE} or {@link Boolean#FALSE} based on the value of
- * the given Boolean object.
- */
- private Boolean getConstantBoolean(Boolean v) {
- if (v != null) {
- if (v.equals(Boolean.TRUE)) {
- return Boolean.TRUE;
- } else {
- return Boolean.FALSE;
- }
- }
-
- return null;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof SupportsScreens) {
- SupportsScreens support = (SupportsScreens) obj;
- // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
- // (or null), we can simply check they are identical and not bother with
- // calling equals (which would require to check != null.
- // see #getConstanntBoolean(Boolean)
- return mResizeable == support.mResizeable &&
- mAnyDensity == support.mAnyDensity &&
- mSmallScreens == support.mSmallScreens &&
- mNormalScreens == support.mNormalScreens &&
- mLargeScreens == support.mLargeScreens;
- }
-
- return false;
- }
-
- /* Override hashCode, mostly to make Eclipse happy and not warn about it.
- * And if you ever put this in a Map or Set, it will avoid surprises. */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mAnyDensity == null) ? 0 : mAnyDensity.hashCode());
- result = prime * result + ((mLargeScreens == null) ? 0 : mLargeScreens.hashCode());
- result = prime * result + ((mNormalScreens == null) ? 0 : mNormalScreens.hashCode());
- result = prime * result + ((mResizeable == null) ? 0 : mResizeable.hashCode());
- result = prime * result + ((mSmallScreens == null) ? 0 : mSmallScreens.hashCode());
- return result;
- }
-
- /**
- * Returns true if the two instances support the same screen sizes.
- * This is similar to {@link #equals(Object)} except that it ignores the values of
- * {@link #getAnyDensity()} and {@link #getResizeable()}.
- * @param support the other instance to compare to.
- * @return true if the two instances support the same screen sizes.
- */
- public boolean hasSameScreenSupportAs(SupportsScreens support) {
- // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
- // (or null), we can simply check they are identical and not bother with
- // calling equals (which would require to check != null.
- // see #getConstanntBoolean(Boolean)
-
- // This only checks that matter here are the screen sizes. resizeable and anyDensity
- // are not checked.
- return mSmallScreens == support.mSmallScreens &&
- mNormalScreens == support.mNormalScreens &&
- mLargeScreens == support.mLargeScreens;
- }
-
- /**
- * Returns true if the two instances have strictly different screen size support.
- * This means that there is no screen size that they both support.
- * @param support the other instance to compare to.
- * @return true if they are stricly different.
- */
- public boolean hasStrictlyDifferentScreenSupportAs(SupportsScreens support) {
- // since all the fields are guaranteed to be either Boolean.TRUE or Boolean.FALSE
- // (or null), we can simply check they are identical and not bother with
- // calling equals (which would require to check != null.
- // see #getConstanntBoolean(Boolean)
-
- // This only checks that matter here are the screen sizes. resizeable and anyDensity
- // are not checked.
- return (mSmallScreens != Boolean.TRUE || support.mSmallScreens != Boolean.TRUE) &&
- (mNormalScreens != Boolean.TRUE || support.mNormalScreens != Boolean.TRUE) &&
- (mLargeScreens != Boolean.TRUE || support.mLargeScreens != Boolean.TRUE);
- }
-
- /**
- * Comparison of 2 Supports-screens. This only uses screen sizes (ignores resizeable and
- * anyDensity), and considers that
- * {@link #hasStrictlyDifferentScreenSupportAs(SupportsScreens)} returns true and
- * {@link #overlapWith(SupportsScreens)} returns false.
- * @throws IllegalArgumentException if the two instanced are not strictly different or
- * overlap each other
- * @see #hasStrictlyDifferentScreenSupportAs(SupportsScreens)
- * @see #overlapWith(SupportsScreens)
- */
- public int compareScreenSizesWith(SupportsScreens o) {
- if (hasStrictlyDifferentScreenSupportAs(o) == false) {
- throw new IllegalArgumentException("The two instances are not strictly different.");
- }
- if (overlapWith(o)) {
- throw new IllegalArgumentException("The two instances overlap each other.");
- }
-
- int comp = mLargeScreens.compareTo(o.mLargeScreens);
- if (comp != 0) return comp;
-
- comp = mNormalScreens.compareTo(o.mNormalScreens);
- if (comp != 0) return comp;
-
- comp = mSmallScreens.compareTo(o.mSmallScreens);
- if (comp != 0) return comp;
-
- return 0;
- }
-
- /**
- * Returns a string encoding of the content of the instance. This string can be used to
- * instantiate a {@link SupportsScreens} object through
- * {@link #SupportsScreens(String)}.
- */
- public String getEncodedValues() {
- return String.format("%1$s|%2$s|%3$s|%4$s|%5$s",
- mAnyDensity, mResizeable, mSmallScreens, mNormalScreens, mLargeScreens);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- boolean alreadyOutputSomething = false;
-
- if (Boolean.TRUE.equals(mSmallScreens)) {
- alreadyOutputSomething = true;
- sb.append("small");
- }
-
- if (Boolean.TRUE.equals(mNormalScreens)) {
- if (alreadyOutputSomething) {
- sb.append(", ");
- }
- alreadyOutputSomething = true;
- sb.append("normal");
- }
-
- if (Boolean.TRUE.equals(mLargeScreens)) {
- if (alreadyOutputSomething) {
- sb.append(", ");
- }
- alreadyOutputSomething = true;
- sb.append("large");
- }
-
- if (alreadyOutputSomething == false) {
- sb.append("<none>");
- }
-
- return sb.toString();
- }
-
- /**
- * Returns true if the two instance overlap with each other.
- * This can happen if one instances supports a size, when the other instance doesn't while
- * supporting a size above and a size below.
- * @param otherSS the other supports-screens to compare to.
- */
- public boolean overlapWith(SupportsScreens otherSS) {
- if (mSmallScreens == null || mNormalScreens == null || mLargeScreens == null ||
- otherSS.mSmallScreens == null || otherSS.mNormalScreens == null ||
- otherSS.mLargeScreens == null) {
- throw new IllegalArgumentException("Some screen sizes Boolean are not initialized");
- }
-
- if (mSmallScreens == Boolean.TRUE && mNormalScreens == Boolean.FALSE &&
- mLargeScreens == Boolean.TRUE) {
- return otherSS.mNormalScreens == Boolean.TRUE;
- }
-
- if (otherSS.mSmallScreens == Boolean.TRUE && otherSS.mNormalScreens == Boolean.FALSE &&
- otherSS.mLargeScreens == Boolean.TRUE) {
- return mNormalScreens == Boolean.TRUE;
- }
-
- return false;
- }
- }
-
- /**
- * Class representing a <code>uses-library</code> node in the manifest.
- */
- public final static class UsesLibrary {
- String mName;
- Boolean mRequired = Boolean.TRUE; // default is true even if missing
-
- public String getName() {
- return mName;
- }
-
- public Boolean getRequired() {
- return mRequired;
- }
- }
-
- /**
- * Class representing a <code>uses-feature</code> node in the manifest.
- */
- public final static class UsesFeature {
- String mName;
- int mGlEsVersion = 0;
- Boolean mRequired = Boolean.TRUE; // default is true even if missing
-
- public String getName() {
- return mName;
- }
-
- /**
- * Returns the value of the glEsVersion attribute, or 0 if the attribute was not present.
- */
- public int getGlEsVersion() {
- return mGlEsVersion;
- }
-
- public Boolean getRequired() {
- return mRequired;
- }
- }
-
- /**
- * Class representing the <code>uses-configuration</code> node in the manifest.
- */
- public final static class UsesConfiguration {
- Boolean mReqFiveWayNav;
- Boolean mReqHardKeyboard;
- Keyboard mReqKeyboardType;
- TouchScreen mReqTouchScreen;
- Navigation mReqNavigation;
-
- /**
- * returns the value of the <code>reqFiveWayNav</code> attribute or null if not present.
- */
- public Boolean getReqFiveWayNav() {
- return mReqFiveWayNav;
- }
-
- /**
- * returns the value of the <code>reqNavigation</code> attribute or null if not present.
- */
- public Navigation getReqNavigation() {
- return mReqNavigation;
- }
-
- /**
- * returns the value of the <code>reqHardKeyboard</code> attribute or null if not present.
- */
- public Boolean getReqHardKeyboard() {
- return mReqHardKeyboard;
- }
-
- /**
- * returns the value of the <code>reqKeyboardType</code> attribute or null if not present.
- */
- public Keyboard getReqKeyboardType() {
- return mReqKeyboardType;
- }
-
- /**
- * returns the value of the <code>reqTouchScreen</code> attribute or null if not present.
- */
- public TouchScreen getReqTouchScreen() {
- return mReqTouchScreen;
- }
- }
-
- /**
- * Returns the package defined in the manifest, if found.
- * @return The package name or null if not found.
- */
- public String getPackage() {
- return mPackage;
- }
-
- /**
- * Returns the versionCode value defined in the manifest, if found, null otherwise.
- * @return the versionCode or null if not found.
- */
- public Integer getVersionCode() {
- return mVersionCode;
- }
-
- /**
- * Returns the list of activities found in the manifest.
- * @return An array of fully qualified class names, or empty if no activity were found.
- */
- public Activity[] getActivities() {
- return mActivities.toArray(new Activity[mActivities.size()]);
- }
-
- /**
- * Returns the name of one activity found in the manifest, that is configured to show
- * up in the HOME screen.
- * @return the fully qualified name of a HOME activity or null if none were found.
- */
- public Activity getLauncherActivity() {
- return mLauncherActivity;
- }
-
- /**
- * Returns the list of process names declared by the manifest.
- */
- public String[] getProcesses() {
- if (mProcesses != null) {
- return mProcesses.toArray(new String[mProcesses.size()]);
- }
-
- return new String[0];
- }
-
- /**
- * Returns the <code>debuggable</code> attribute value or null if it is not set.
- */
- public Boolean getDebuggable() {
- return mDebuggable;
- }
-
- /**
- * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
- */
- public String getMinSdkVersionString() {
- return mMinSdkVersionString;
- }
-
- /**
- * Sets the value of the <code>minSdkVersion</code> attribute.
- * @param minSdkVersion the string value of the attribute in the manifest.
- */
- public void setMinSdkVersionString(String minSdkVersion) {
- mMinSdkVersionString = minSdkVersion;
- if (mMinSdkVersionString != null) {
- try {
- mMinSdkVersion = Integer.parseInt(mMinSdkVersionString);
- } catch (NumberFormatException e) {
- mMinSdkVersion = MIN_SDK_CODENAME;
- }
- }
- }
-
- /**
- * Returns the <code>minSdkVersion</code> attribute, or 0 if it's not set or is a codename.
- * @see #getMinSdkVersionString()
- */
- public int getMinSdkVersion() {
- return mMinSdkVersion;
- }
-
-
- /**
- * Sets the value of the <code>minSdkVersion</code> attribute.
- * @param targetSdkVersion the string value of the attribute in the manifest.
- */
- public void setTargetSdkVersionString(String targetSdkVersion) {
- if (targetSdkVersion != null) {
- try {
- mTargetSdkVersion = Integer.parseInt(targetSdkVersion);
- } catch (NumberFormatException e) {
- // keep the value at 0.
- }
- }
- }
-
- /**
- * Returns the <code>targetSdkVersion</code> attribute, or the same value as
- * {@link #getMinSdkVersion()} if it was not set in the manifest.
- */
- public int getTargetSdkVersion() {
- if (mTargetSdkVersion == 0) {
- return getMinSdkVersion();
- }
-
- return mTargetSdkVersion;
- }
-
- /**
- * Returns the list of instrumentations found in the manifest.
- * @return An array of {@link Instrumentation}, or empty if no instrumentations were
- * found.
- */
- public Instrumentation[] getInstrumentations() {
- return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]);
- }
-
- /**
- * Returns the list of libraries in use found in the manifest.
- * @return An array of {@link UsesLibrary} objects, or empty if no libraries were found.
- */
- public UsesLibrary[] getUsesLibraries() {
- return mLibraries.toArray(new UsesLibrary[mLibraries.size()]);
- }
-
- /**
- * Returns the list of features in use found in the manifest.
- * @return An array of {@link UsesFeature} objects, or empty if no libraries were found.
- */
- public UsesFeature[] getUsesFeatures() {
- return mFeatures.toArray(new UsesFeature[mFeatures.size()]);
- }
-
- /**
- * Returns the glEsVersion from a <uses-feature> or {@link #GL_ES_VERSION_NOT_SET} if not set.
- */
- public int getGlEsVersion() {
- for (UsesFeature feature : mFeatures) {
- if (feature.mGlEsVersion > 0) {
- return feature.mGlEsVersion;
- }
- }
- return GL_ES_VERSION_NOT_SET;
- }
-
- /**
- * Returns the {@link SupportsScreens} object representing the <code>supports-screens</code>
- * node, or null if the node doesn't exist at all.
- * Some values in the {@link SupportsScreens} instance maybe null, indicating that they
- * were not present in the manifest. To get an instance that contains the values, as seen
- * by the Android platform when the app is running, use {@link #getSupportsScreensValues()}.
- */
- public SupportsScreens getSupportsScreensFromManifest() {
- return mSupportsScreensFromManifest;
- }
-
- /**
- * Returns an always non-null instance of {@link SupportsScreens} that's been initialized with
- * the default values, and the values from the manifest.
- * The default values depends on the manifest values for minSdkVersion and targetSdkVersion.
- */
- public synchronized SupportsScreens getSupportsScreensValues() {
- if (mSupportsScreensValues == null) {
- if (mSupportsScreensFromManifest == null) {
- mSupportsScreensValues = SupportsScreens.getDefaultValues(getTargetSdkVersion());
- } else {
- // get a SupportsScreen that replace the missing values with default values.
- mSupportsScreensValues = mSupportsScreensFromManifest.resolveSupportsScreensValues(
- getTargetSdkVersion());
- }
- }
-
- return mSupportsScreensValues;
- }
-
- /**
- * Returns the {@link UsesConfiguration} object representing the <code>uses-configuration</code>
- * node, or null if the node doesn't exist at all.
- */
- public UsesConfiguration getUsesConfiguration() {
- return mUsesConfiguration;
- }
-
- void addProcessName(String processName) {
- if (mProcesses == null) {
- mProcesses = new TreeSet<String>();
- }
-
- if (processName.startsWith(":")) {
- mProcesses.add(mPackage + processName);
- } else {
- mProcesses.add(processName);
- }
- }
-
-}
diff --git a/sdk_common/tests/.classpath b/sdk_common/tests/.classpath
deleted file mode 100644
index 1e45d8a..0000000
--- a/sdk_common/tests/.classpath
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry combineaccessrules="false" kind="src" path="/sdk_common"/>
- <classpathentry combineaccessrules="false" kind="src" path="/common"/>
- <classpathentry combineaccessrules="false" kind="src" path="/layoutlib_api"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/sdk_common/tests/.project b/sdk_common/tests/.project
deleted file mode 100644
index 86d2f15..0000000
--- a/sdk_common/tests/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>sdk_common-tests</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
diff --git a/sdk_common/tests/.settings/org.moreunit.prefs b/sdk_common/tests/.settings/org.moreunit.prefs
deleted file mode 100644
index 902b677..0000000
--- a/sdk_common/tests/.settings/org.moreunit.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-eclipse.preferences.version=1
-org.moreunit.prefixes=
-org.moreunit.unitsourcefolder=sdk_common-tests\:src\:sdk_common\:src
-org.moreunit.useprojectsettings=true
diff --git a/sdk_common/tests/Android.mk b/sdk_common/tests/Android.mk
deleted file mode 100644
index e7f8c8d..0000000
--- a/sdk_common/tests/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := sdk_common-tests
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_JAVA_LIBRARIES := common sdk_common junit
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/ResourceRepositoryTest.java b/sdk_common/tests/src/com/android/ide/common/resources/ResourceRepositoryTest.java
deleted file mode 100644
index a8b8b1e..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/ResourceRepositoryTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.resources.ResourceType.ATTR;
-import static com.android.resources.ResourceType.DIMEN;
-import static com.android.resources.ResourceType.LAYOUT;
-import junit.framework.TestCase;
-
-@SuppressWarnings("javadoc")
-public class ResourceRepositoryTest extends TestCase {
- public void testParseResource() {
- assertNull(ResourceRepository.parseResource(""));
- assertNull(ResourceRepository.parseResource("not_a_resource"));
-
- assertEquals(LAYOUT, ResourceRepository.parseResource("@layout/foo").getFirst());
- assertEquals(DIMEN, ResourceRepository.parseResource("@dimen/foo").getFirst());
- assertEquals(DIMEN, ResourceRepository.parseResource("@android:dimen/foo").getFirst());
- assertEquals("foo", ResourceRepository.parseResource("@layout/foo").getSecond());
- assertEquals("foo", ResourceRepository.parseResource("@dimen/foo").getSecond());
- assertEquals("foo", ResourceRepository.parseResource("@android:dimen/foo").getSecond());
-
- assertEquals(ATTR, ResourceRepository.parseResource("?attr/foo").getFirst());
- assertEquals("foo", ResourceRepository.parseResource("?attr/foo").getSecond());
-
- assertEquals(ATTR, ResourceRepository.parseResource("?foo").getFirst());
- assertEquals("foo", ResourceRepository.parseResource("?foo").getSecond());
-
- assertEquals(ATTR, ResourceRepository.parseResource("?android:foo").getFirst());
- assertEquals("foo", ResourceRepository.parseResource("?android:foo").getSecond());
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/ValueResourceParserTest.java b/sdk_common/tests/src/com/android/ide/common/resources/ValueResourceParserTest.java
deleted file mode 100644
index aed6060..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/ValueResourceParserTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources;
-
-import static com.android.ide.common.resources.ValueResourceParser.escapeResourceString;
-import static com.android.ide.common.resources.ValueResourceParser.isEscaped;
-import static com.android.ide.common.resources.ValueResourceParser.unescapeResourceString;
-
-import junit.framework.TestCase;
-
-public class ValueResourceParserTest extends TestCase {
-
- public void testEscapeStringShouldEscapeXmlSpecialCharacters() throws Exception {
- assertEquals("&lt;", escapeResourceString("<"));
- assertEquals("&amp;", escapeResourceString("&"));
- }
-
- public void testEscapeStringShouldEscapeQuotes() throws Exception {
- assertEquals("\\'", escapeResourceString("'"));
- assertEquals("\\\"", escapeResourceString("\""));
- assertEquals("\" ' \"", escapeResourceString(" ' "));
- }
-
- public void testEscapeStringShouldPreserveWhitespace() throws Exception {
- assertEquals("\"at end \"", escapeResourceString("at end "));
- assertEquals("\" at begin\"", escapeResourceString(" at begin"));
- }
-
- public void testEscapeStringShouldEscapeAtSignAndQuestionMarkOnlyAtBeginning()
- throws Exception {
- assertEquals("\\@text", escapeResourceString("@text"));
- assertEquals("a@text", escapeResourceString("a@text"));
- assertEquals("\\?text", escapeResourceString("?text"));
- assertEquals("a?text", escapeResourceString("a?text"));
- assertEquals("\" ?text\"", escapeResourceString(" ?text"));
- }
-
- public void testEscapeStringShouldEscapeJavaEscapeSequences() throws Exception {
- assertEquals("\\n", escapeResourceString("\n"));
- assertEquals("\\t", escapeResourceString("\t"));
- assertEquals("\\\\", escapeResourceString("\\"));
- }
-
- public void testTrim() throws Exception {
- assertEquals("", unescapeResourceString("", false, true));
- assertEquals("", unescapeResourceString(" \n ", false, true));
- assertEquals("test", unescapeResourceString(" test ", false, true));
- assertEquals(" test ", unescapeResourceString("\" test \"", false, true));
- assertEquals("test", unescapeResourceString("\n\t test \t\n ", false, true));
-
- assertEquals("test\n", unescapeResourceString(" test\\n ", false, true));
- assertEquals(" test\n ", unescapeResourceString("\" test\\n \"", false, true));
- assertEquals("te\\st", unescapeResourceString("\n\t te\\\\st \t\n ", false, true));
- assertEquals("te\\st", unescapeResourceString(" te\\\\st ", false, true));
- assertEquals("test", unescapeResourceString("\"\"\"test\"\" ", false, true));
- assertEquals("\"test\"", unescapeResourceString("\"\"\\\"test\\\"\" ", false, true));
- assertEquals("test ", unescapeResourceString("test\\ ", false, true));
- assertEquals("\\\\\\", unescapeResourceString("\\\\\\\\\\\\ ", false, true));
- assertEquals("\\\\\\ ", unescapeResourceString("\\\\\\\\\\\\\\ ", false, true));
- }
-
- public void testNoTrim() throws Exception {
- assertEquals("", unescapeResourceString("", false, false));
- assertEquals(" \n ", unescapeResourceString(" \n ", false, false));
- assertEquals(" test ", unescapeResourceString(" test ", false, false));
- assertEquals("\" test \"", unescapeResourceString("\" test \"", false, false));
- assertEquals("\n\t test \t\n ", unescapeResourceString("\n\t test \t\n ", false, false));
-
- assertEquals(" test\n ", unescapeResourceString(" test\\n ", false, false));
- assertEquals("\" test\n \"", unescapeResourceString("\" test\\n \"", false, false));
- assertEquals("\n\t te\\st \t\n ", unescapeResourceString("\n\t te\\\\st \t\n ", false, false));
- assertEquals(" te\\st ", unescapeResourceString(" te\\\\st ", false, false));
- assertEquals("\"\"\"test\"\" ", unescapeResourceString("\"\"\"test\"\" ", false, false));
- assertEquals("\"\"\"test\"\" ", unescapeResourceString("\"\"\\\"test\\\"\" ", false, false));
- assertEquals("test ", unescapeResourceString("test\\ ", false, false));
- assertEquals("\\\\\\ ", unescapeResourceString("\\\\\\\\\\\\ ", false, false));
- assertEquals("\\\\\\ ", unescapeResourceString("\\\\\\\\\\\\\\ ", false, false));
- }
-
- public void testUnescapeStringShouldUnescapeXmlSpecialCharacters() throws Exception {
- assertEquals("&lt;", unescapeResourceString("&lt;", false, true));
- assertEquals("<", unescapeResourceString("&lt;", true, true));
- assertEquals("<", unescapeResourceString(" &lt; ", true, true));
- assertEquals("&amp;", unescapeResourceString("&amp;", false, true));
- assertEquals("&", unescapeResourceString("&amp;", true, true));
- assertEquals("&", unescapeResourceString(" &amp; ", true, true));
- assertEquals("!<", unescapeResourceString("!&lt;", true, true));
- }
-
- public void testUnescapeStringShouldUnescapeQuotes() throws Exception {
- assertEquals("'", unescapeResourceString("\\'", false, true));
- assertEquals("\"", unescapeResourceString("\\\"", false, true));
- assertEquals(" ' ", unescapeResourceString("\" ' \"", false, true));
- }
-
- public void testUnescapeStringShouldPreserveWhitespace() throws Exception {
- assertEquals("at end ", unescapeResourceString("\"at end \"", false, true));
- assertEquals(" at begin", unescapeResourceString("\" at begin\"", false, true));
- }
-
- public void testUnescapeStringShouldUnescapeAtSignAndQuestionMarkOnlyAtBeginning()
- throws Exception {
- assertEquals("@text", unescapeResourceString("\\@text", false, true));
- assertEquals("a@text", unescapeResourceString("a@text", false, true));
- assertEquals("?text", unescapeResourceString("\\?text", false, true));
- assertEquals("a?text", unescapeResourceString("a?text", false, true));
- assertEquals(" ?text", unescapeResourceString("\" ?text\"", false, true));
- }
-
- public void testUnescapeStringShouldUnescapeJavaUnescapeSequences() throws Exception {
- assertEquals("\n", unescapeResourceString("\\n", false, true));
- assertEquals("\t", unescapeResourceString("\\t", false, true));
- assertEquals("\\", unescapeResourceString("\\\\", false, true));
- }
-
- public void testIsEscaped() throws Exception {
- assertFalse(isEscaped("", 0));
- assertFalse(isEscaped(" ", 0));
- assertFalse(isEscaped(" ", 1));
- assertFalse(isEscaped("x\\y ", 0));
- assertFalse(isEscaped("x\\y ", 1));
- assertTrue(isEscaped("x\\y ", 2));
- assertFalse(isEscaped("x\\y ", 3));
- assertFalse(isEscaped("x\\\\y ", 0));
- assertFalse(isEscaped("x\\\\y ", 1));
- assertTrue(isEscaped("x\\\\y ", 2));
- assertFalse(isEscaped("x\\\\y ", 3));
- assertFalse(isEscaped("\\\\\\\\y ", 0));
- assertTrue(isEscaped( "\\\\\\\\y ", 1));
- assertFalse(isEscaped("\\\\\\\\y ", 2));
- assertTrue(isEscaped( "\\\\\\\\y ", 3));
- assertFalse(isEscaped("\\\\\\\\y ", 4));
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/CountryCodeQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/CountryCodeQualifierTest.java
deleted file mode 100644
index eba8b8d..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/CountryCodeQualifierTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import junit.framework.TestCase;
-
-public class CountryCodeQualifierTest extends TestCase {
-
- private CountryCodeQualifier mccq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mccq = new CountryCodeQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- mccq = null;
- config = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, mccq.checkAndSet("mcc123", config));//$NON-NLS-1$
- assertTrue(config.getCountryCodeQualifier() != null);
- assertEquals(123, config.getCountryCodeQualifier().getCode());
- assertEquals("mcc123", config.getCountryCodeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, mccq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, mccq.checkAndSet("mcc", config));//$NON-NLS-1$
- assertEquals(false, mccq.checkAndSet("MCC123", config));//$NON-NLS-1$
- assertEquals(false, mccq.checkAndSet("123", config));//$NON-NLS-1$
- assertEquals(false, mccq.checkAndSet("mccsdf", config));//$NON-NLS-1$
- }
-
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/DockModeQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/DockModeQualifierTest.java
deleted file mode 100644
index 1653805..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/DockModeQualifierTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.UiMode;
-
-import junit.framework.TestCase;
-
-public class DockModeQualifierTest extends TestCase {
-
- private UiModeQualifier mCarQualifier;
- private UiModeQualifier mDeskQualifier;
- private UiModeQualifier mTVQualifier;
- private UiModeQualifier mNoneQualifier;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mCarQualifier = new UiModeQualifier(UiMode.CAR);
- mDeskQualifier = new UiModeQualifier(UiMode.DESK);
- mTVQualifier = new UiModeQualifier(UiMode.TELEVISION);
- mNoneQualifier = new UiModeQualifier(UiMode.NORMAL);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- mCarQualifier = null;
- mDeskQualifier = null;
- mTVQualifier = null;
- mNoneQualifier = null;
- }
-
- public void testIsBetterMatchThan() {
- assertTrue(mNoneQualifier.isBetterMatchThan(mCarQualifier, mDeskQualifier));
- assertTrue(mNoneQualifier.isBetterMatchThan(mCarQualifier, mDeskQualifier));
- assertFalse(mNoneQualifier.isBetterMatchThan(mDeskQualifier, mDeskQualifier));
- assertTrue(mNoneQualifier.isBetterMatchThan(mDeskQualifier, mCarQualifier));
- assertFalse(mNoneQualifier.isBetterMatchThan(mCarQualifier, mCarQualifier));
-
- assertTrue(mDeskQualifier.isBetterMatchThan(mCarQualifier, mDeskQualifier));
- assertFalse(mDeskQualifier.isBetterMatchThan(mCarQualifier, mCarQualifier));
-
- assertTrue(mCarQualifier.isBetterMatchThan(mDeskQualifier, mCarQualifier));
- assertFalse(mCarQualifier.isBetterMatchThan(mDeskQualifier, mDeskQualifier));
-
- assertTrue(mTVQualifier.isBetterMatchThan(mCarQualifier, mTVQualifier));
- assertFalse(mTVQualifier.isBetterMatchThan(mDeskQualifier, mDeskQualifier));
-
- }
-
- public void testIsMatchFor() {
- assertTrue(mNoneQualifier.isMatchFor(mCarQualifier));
- assertTrue(mNoneQualifier.isMatchFor(mDeskQualifier));
- assertTrue(mNoneQualifier.isMatchFor(mTVQualifier));
- assertTrue(mCarQualifier.isMatchFor(mCarQualifier));
- assertTrue(mDeskQualifier.isMatchFor(mDeskQualifier));
- assertTrue(mTVQualifier.isMatchFor(mTVQualifier));
-
- assertFalse(mCarQualifier.isMatchFor(mNoneQualifier));
- assertFalse(mCarQualifier.isMatchFor(mDeskQualifier));
-
- assertFalse(mDeskQualifier.isMatchFor(mCarQualifier));
- assertFalse(mDeskQualifier.isMatchFor(mNoneQualifier));
-
- assertFalse(mTVQualifier.isMatchFor(mCarQualifier));
- assertFalse(mTVQualifier.isMatchFor(mNoneQualifier));
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/FolderConfigurationTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/FolderConfigurationTest.java
deleted file mode 100644
index 5f29791..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/FolderConfigurationTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-public class FolderConfigurationTest extends TestCase {
-
- /*
- * Test createDefault creates all the qualifiers.
- */
- public void testCreateDefault() {
- FolderConfiguration defaultConfig = new FolderConfiguration();
- defaultConfig.createDefault();
-
- // this is always valid and up to date.
- final int count = FolderConfiguration.getQualifierCount();
-
- // make sure all the qualifiers were created.
- for (int i = 0 ; i < count ; i++) {
- assertNotNull(defaultConfig.getQualifier(i));
- }
- }
-
- public void testSimpleResMatch() {
- runConfigMatchTest(
- "en-rGB-port-hdpi-notouch-12key",
- 3,
- "",
- "en",
- "fr-rCA",
- "en-port",
- "en-notouch-12key",
- "port-ldpi",
- "port-notouch-12key");
- }
-
- public void testVersionResMatch() {
- runConfigMatchTest(
- "en-rUS-w600dp-h1024dp-large-port-mdpi-finger-nokeys-v12",
- 2,
- "",
- "large",
- "w540dp");
- }
-
- public void testAddQualifier() {
- FolderConfiguration defaultConfig = new FolderConfiguration();
- defaultConfig.createDefault();
-
- final int count = FolderConfiguration.getQualifierCount();
- for (int i = 0 ; i < count ; i++) {
- FolderConfiguration empty = new FolderConfiguration();
-
- ResourceQualifier q = defaultConfig.getQualifier(i);
-
- empty.addQualifier(q);
-
- // check it was added
- assertNotNull(
- "addQualifier failed for " + q.getClass().getName(), empty.getQualifier(i));
- }
- }
-
-
- // --- helper methods
-
- private final static class MockConfigurable implements Configurable {
-
- private final FolderConfiguration mConfig;
-
- MockConfigurable(String config) {
- mConfig = FolderConfiguration.getConfig(getFolderSegments(config));
- }
-
- @Override
- public FolderConfiguration getConfiguration() {
- return mConfig;
- }
-
- @Override
- public String toString() {
- return mConfig.toString();
- }
- }
-
- private void runConfigMatchTest(String refConfig, int resultIndex, String... configs) {
- FolderConfiguration reference = FolderConfiguration.getConfig(getFolderSegments(refConfig));
- assertNotNull(reference);
-
- List<? extends Configurable> list = getConfigurable(configs);
-
- Configurable match = reference.findMatchingConfigurable(list);
- assertEquals(resultIndex, list.indexOf(match));
- }
-
- private List<? extends Configurable> getConfigurable(String... configs) {
- ArrayList<MockConfigurable> list = new ArrayList<MockConfigurable>();
-
- for (String config : configs) {
- list.add(new MockConfigurable(config));
- }
-
- return list;
- }
-
- private static String[] getFolderSegments(String config) {
- return (config.length() > 0 ? "foo-" + config : "foo").split("-");
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/KeyboardStateQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/KeyboardStateQualifierTest.java
deleted file mode 100644
index cf52a38..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/KeyboardStateQualifierTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.KeyboardState;
-
-import junit.framework.TestCase;
-
-public class KeyboardStateQualifierTest extends TestCase {
-
- private KeyboardStateQualifier ksq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- ksq = new KeyboardStateQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- ksq = null;
- config = null;
- }
-
- public void testExposed() {
- assertEquals(true, ksq.checkAndSet("keysexposed", config)); //$NON-NLS-1$
- assertTrue(config.getKeyboardStateQualifier() != null);
- assertEquals(KeyboardState.EXPOSED, config.getKeyboardStateQualifier().getValue());
- assertEquals("keysexposed", config.getKeyboardStateQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testHidden() {
- assertEquals(true, ksq.checkAndSet("keyshidden", config)); //$NON-NLS-1$
- assertTrue(config.getKeyboardStateQualifier() != null);
- assertEquals(KeyboardState.HIDDEN, config.getKeyboardStateQualifier().getValue());
- assertEquals("keyshidden", config.getKeyboardStateQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, ksq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, ksq.checkAndSet("KEYSEXPOSED", config));//$NON-NLS-1$
- assertEquals(false, ksq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/LanguageQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/LanguageQualifierTest.java
deleted file mode 100644
index 2dfd65f..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/LanguageQualifierTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import junit.framework.TestCase;
-
-public class LanguageQualifierTest extends TestCase {
-
- private FolderConfiguration config;
- private LanguageQualifier lq;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- config = new FolderConfiguration();
- lq = new LanguageQualifier();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- config = null;
- lq = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, lq.checkAndSet("en", config)); //$NON-NLS-1$
- assertTrue(config.getLanguageQualifier() != null);
- assertEquals("en", config.getLanguageQualifier().toString()); //$NON-NLS-1$
-
- }
-
- public void testFailures() {
- assertEquals(false, lq.checkAndSet("", config)); //$NON-NLS-1$
- assertEquals(false, lq.checkAndSet("EN", config)); //$NON-NLS-1$
- assertEquals(false, lq.checkAndSet("abc", config)); //$NON-NLS-1$
- }
-}
-
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/NavigationMethodQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/NavigationMethodQualifierTest.java
deleted file mode 100644
index 4237dde..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/NavigationMethodQualifierTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Navigation;
-
-import junit.framework.TestCase;
-
-public class NavigationMethodQualifierTest extends TestCase {
-
- private FolderConfiguration config;
- private NavigationMethodQualifier nmq;
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- config = new FolderConfiguration();
- nmq = new NavigationMethodQualifier();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- config = null;
- nmq = null;
- }
-
- public void testDPad() {
- assertEquals(true, nmq.checkAndSet("dpad", config)); //$NON-NLS-1$
- assertTrue(config.getNavigationMethodQualifier() != null);
- assertEquals(Navigation.DPAD, config.getNavigationMethodQualifier().getValue());
- assertEquals("dpad", config.getNavigationMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testTrackball() {
- assertEquals(true, nmq.checkAndSet("trackball", config)); //$NON-NLS-1$
- assertTrue(config.getNavigationMethodQualifier() != null);
- assertEquals(Navigation.TRACKBALL, config.getNavigationMethodQualifier().getValue());
- assertEquals("trackball", config.getNavigationMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testWheel() {
- assertEquals(true, nmq.checkAndSet("wheel", config)); //$NON-NLS-1$
- assertTrue(config.getNavigationMethodQualifier() != null);
- assertEquals(Navigation.WHEEL, config.getNavigationMethodQualifier().getValue());
- assertEquals("wheel", config.getNavigationMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, nmq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, nmq.checkAndSet("WHEEL", config));//$NON-NLS-1$
- assertEquals(false, nmq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/NetworkCodeQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/NetworkCodeQualifierTest.java
deleted file mode 100644
index 6896316..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/NetworkCodeQualifierTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import junit.framework.TestCase;
-
-public class NetworkCodeQualifierTest extends TestCase {
-
- private NetworkCodeQualifier mncq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mncq = new NetworkCodeQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- mncq = null;
- config = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, mncq.checkAndSet("mnc123", config));//$NON-NLS-1$
- assertTrue(config.getNetworkCodeQualifier() != null);
- assertEquals(123, config.getNetworkCodeQualifier().getCode());
- assertEquals("mnc123", config.getNetworkCodeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, mncq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, mncq.checkAndSet("mnc", config));//$NON-NLS-1$
- assertEquals(false, mncq.checkAndSet("MNC123", config));//$NON-NLS-1$
- assertEquals(false, mncq.checkAndSet("123", config));//$NON-NLS-1$
- assertEquals(false, mncq.checkAndSet("mncsdf", config));//$NON-NLS-1$
- }
-
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/PixelDensityQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/PixelDensityQualifierTest.java
deleted file mode 100644
index 4ab493a..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/PixelDensityQualifierTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Density;
-
-import junit.framework.TestCase;
-
-public class PixelDensityQualifierTest extends TestCase {
-
- private DensityQualifier pdq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- pdq = new DensityQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- pdq = null;
- config = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, pdq.checkAndSet("ldpi", config));//$NON-NLS-1$
- assertTrue(config.getDensityQualifier() != null);
- assertEquals(Density.LOW, config.getDensityQualifier().getValue());
- assertEquals("ldpi", config.getDensityQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, pdq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, pdq.checkAndSet("dpi", config));//$NON-NLS-1$
- assertEquals(false, pdq.checkAndSet("123dpi", config));//$NON-NLS-1$
- assertEquals(false, pdq.checkAndSet("123", config));//$NON-NLS-1$
- assertEquals(false, pdq.checkAndSet("sdfdpi", config));//$NON-NLS-1$
- }
-
- public void testIsBetterMatchThan() {
- DensityQualifier ldpi = new DensityQualifier(Density.LOW);
- DensityQualifier mdpi = new DensityQualifier(Density.MEDIUM);
- DensityQualifier hdpi = new DensityQualifier(Density.HIGH);
- DensityQualifier xhdpi = new DensityQualifier(Density.XHIGH);
-
- // first test that each Q is a better match than all other Qs when the ref is the same Q.
- assertTrue(ldpi.isBetterMatchThan(mdpi, ldpi));
- assertTrue(ldpi.isBetterMatchThan(hdpi, ldpi));
- assertTrue(ldpi.isBetterMatchThan(xhdpi, ldpi));
-
- assertTrue(mdpi.isBetterMatchThan(ldpi, mdpi));
- assertTrue(mdpi.isBetterMatchThan(hdpi, mdpi));
- assertTrue(mdpi.isBetterMatchThan(xhdpi, mdpi));
-
- assertTrue(hdpi.isBetterMatchThan(ldpi, hdpi));
- assertTrue(hdpi.isBetterMatchThan(mdpi, hdpi));
- assertTrue(hdpi.isBetterMatchThan(xhdpi, hdpi));
-
- assertTrue(xhdpi.isBetterMatchThan(ldpi, xhdpi));
- assertTrue(xhdpi.isBetterMatchThan(mdpi, xhdpi));
- assertTrue(xhdpi.isBetterMatchThan(hdpi, xhdpi));
-
- // now test that the highest dpi is always preferable if there's no exact match
-
- // looking for ldpi:
- assertTrue(hdpi.isBetterMatchThan(mdpi, ldpi));
- assertTrue(xhdpi.isBetterMatchThan(mdpi, ldpi));
- assertTrue(xhdpi.isBetterMatchThan(hdpi, ldpi));
- // the other way around
- assertFalse(mdpi.isBetterMatchThan(hdpi, ldpi));
- assertFalse(mdpi.isBetterMatchThan(xhdpi, ldpi));
- assertFalse(hdpi.isBetterMatchThan(xhdpi, ldpi));
-
- // looking for mdpi
- assertTrue(hdpi.isBetterMatchThan(ldpi, mdpi));
- assertTrue(xhdpi.isBetterMatchThan(ldpi, mdpi));
- assertTrue(xhdpi.isBetterMatchThan(hdpi, mdpi));
- // the other way around
- assertFalse(ldpi.isBetterMatchThan(hdpi, mdpi));
- assertFalse(ldpi.isBetterMatchThan(xhdpi, mdpi));
- assertFalse(hdpi.isBetterMatchThan(xhdpi, mdpi));
-
- // looking for hdpi
- assertTrue(mdpi.isBetterMatchThan(ldpi, hdpi));
- assertTrue(xhdpi.isBetterMatchThan(ldpi, hdpi));
- assertTrue(xhdpi.isBetterMatchThan(mdpi, hdpi));
- // the other way around
- assertFalse(ldpi.isBetterMatchThan(mdpi, hdpi));
- assertFalse(ldpi.isBetterMatchThan(xhdpi, hdpi));
- assertFalse(mdpi.isBetterMatchThan(xhdpi, hdpi));
-
- // looking for xhdpi
- assertTrue(mdpi.isBetterMatchThan(ldpi, xhdpi));
- assertTrue(hdpi.isBetterMatchThan(ldpi, xhdpi));
- assertTrue(hdpi.isBetterMatchThan(mdpi, xhdpi));
- // the other way around
- assertFalse(ldpi.isBetterMatchThan(mdpi, xhdpi));
- assertFalse(ldpi.isBetterMatchThan(hdpi, xhdpi));
- assertFalse(mdpi.isBetterMatchThan(hdpi, xhdpi));
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/RegionQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/RegionQualifierTest.java
deleted file mode 100644
index fc0402c..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/RegionQualifierTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import junit.framework.TestCase;
-
-public class RegionQualifierTest extends TestCase {
-
- private RegionQualifier rq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- rq = new RegionQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- rq = null;
- config = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, rq.checkAndSet("rUS", config));//$NON-NLS-1$
- assertTrue(config.getRegionQualifier() != null);
- assertEquals("US", config.getRegionQualifier().getValue()); //$NON-NLS-1$
- assertEquals("rUS", config.getRegionQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, rq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, rq.checkAndSet("rus", config));//$NON-NLS-1$
- assertEquals(false, rq.checkAndSet("rUSA", config));//$NON-NLS-1$
- assertEquals(false, rq.checkAndSet("abc", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifierTest.java
deleted file mode 100644
index e57424f..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenDimensionQualifierTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import junit.framework.TestCase;
-
-public class ScreenDimensionQualifierTest extends TestCase {
-
- private ScreenDimensionQualifier sdq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- sdq = new ScreenDimensionQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- sdq = null;
- config = null;
- }
-
- public void testCheckAndSet() {
- assertEquals(true, sdq.checkAndSet("400x200", config));//$NON-NLS-1$
- assertTrue(config.getScreenDimensionQualifier() != null);
- assertEquals(400, config.getScreenDimensionQualifier().getValue1());
- assertEquals(200, config.getScreenDimensionQualifier().getValue2());
- assertEquals("400x200", config.getScreenDimensionQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, sdq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("400X200", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("x200", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("ax200", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("400x", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("400xa", config));//$NON-NLS-1$
- assertEquals(false, sdq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifierTest.java
deleted file mode 100644
index 3aac5f3..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenOrientationQualifierTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ScreenOrientation;
-
-import junit.framework.TestCase;
-
-public class ScreenOrientationQualifierTest extends TestCase {
-
- private ScreenOrientationQualifier soq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- soq = new ScreenOrientationQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- soq = null;
- config = null;
- }
-
- public void testPortrait() {
- assertEquals(true, soq.checkAndSet("port", config)); //$NON-NLS-1$
- assertTrue(config.getScreenOrientationQualifier() != null);
- assertEquals(ScreenOrientation.PORTRAIT, config.getScreenOrientationQualifier().getValue());
- assertEquals("port", config.getScreenOrientationQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testLanscape() {
- assertEquals(true, soq.checkAndSet("land", config)); //$NON-NLS-1$
- assertTrue(config.getScreenOrientationQualifier() != null);
- assertEquals(ScreenOrientation.LANDSCAPE,
- config.getScreenOrientationQualifier().getValue());
- assertEquals("land", config.getScreenOrientationQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testSquare() {
- assertEquals(true, soq.checkAndSet("square", config)); //$NON-NLS-1$
- assertTrue(config.getScreenOrientationQualifier() != null);
- assertEquals(ScreenOrientation.SQUARE,
- config.getScreenOrientationQualifier().getValue());
- assertEquals("square", config.getScreenOrientationQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, soq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, soq.checkAndSet("PORT", config));//$NON-NLS-1$
- assertEquals(false, soq.checkAndSet("landscape", config));//$NON-NLS-1$
- assertEquals(false, soq.checkAndSet("portrait", config));//$NON-NLS-1$
- assertEquals(false, soq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenSizeQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenSizeQualifierTest.java
deleted file mode 100644
index b19f125..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/ScreenSizeQualifierTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.ScreenSize;
-
-import junit.framework.TestCase;
-
-public class ScreenSizeQualifierTest extends TestCase {
-
- private ScreenSizeQualifier ssq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- ssq = new ScreenSizeQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- ssq = null;
- config = null;
- }
-
- public void testSmall() {
- assertEquals(true, ssq.checkAndSet("small", config)); //$NON-NLS-1$
- assertTrue(config.getScreenSizeQualifier() != null);
- assertEquals(ScreenSize.SMALL, config.getScreenSizeQualifier().getValue());
- assertEquals("small", config.getScreenSizeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testNormal() {
- assertEquals(true, ssq.checkAndSet("normal", config)); //$NON-NLS-1$
- assertTrue(config.getScreenSizeQualifier() != null);
- assertEquals(ScreenSize.NORMAL, config.getScreenSizeQualifier().getValue());
- assertEquals("normal", config.getScreenSizeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testLarge() {
- assertEquals(true, ssq.checkAndSet("large", config)); //$NON-NLS-1$
- assertTrue(config.getScreenSizeQualifier() != null);
- assertEquals(ScreenSize.LARGE, config.getScreenSizeQualifier().getValue());
- assertEquals("large", config.getScreenSizeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testXLarge() {
- assertEquals(true, ssq.checkAndSet("xlarge", config)); //$NON-NLS-1$
- assertTrue(config.getScreenSizeQualifier() != null);
- assertEquals(ScreenSize.XLARGE, config.getScreenSizeQualifier().getValue());
- assertEquals("xlarge", config.getScreenSizeQualifier().toString()); //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/TextInputMethodQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/TextInputMethodQualifierTest.java
deleted file mode 100644
index bc2c890..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/TextInputMethodQualifierTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.Keyboard;
-
-import junit.framework.TestCase;
-
-public class TextInputMethodQualifierTest extends TestCase {
-
- private TextInputMethodQualifier timq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- timq = new TextInputMethodQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- timq = null;
- config = null;
- }
-
- public void testQuerty() {
- assertEquals(true, timq.checkAndSet("qwerty", config)); //$NON-NLS-1$
- assertTrue(config.getTextInputMethodQualifier() != null);
- assertEquals(Keyboard.QWERTY, config.getTextInputMethodQualifier().getValue());
- assertEquals("qwerty", config.getTextInputMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void test12Key() {
- assertEquals(true, timq.checkAndSet("12key", config)); //$NON-NLS-1$
- assertTrue(config.getTextInputMethodQualifier() != null);
- assertEquals(Keyboard.TWELVEKEY, config.getTextInputMethodQualifier().getValue());
- assertEquals("12key", config.getTextInputMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testNoKey() {
- assertEquals(true, timq.checkAndSet("nokeys", config)); //$NON-NLS-1$
- assertTrue(config.getTextInputMethodQualifier() != null);
- assertEquals(Keyboard.NOKEY, config.getTextInputMethodQualifier().getValue());
- assertEquals("nokeys", config.getTextInputMethodQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, timq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, timq.checkAndSet("QWERTY", config));//$NON-NLS-1$
- assertEquals(false, timq.checkAndSet("12keys", config));//$NON-NLS-1$
- assertEquals(false, timq.checkAndSet("*12key", config));//$NON-NLS-1$
- assertEquals(false, timq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/resources/configuration/TouchScreenQualifierTest.java b/sdk_common/tests/src/com/android/ide/common/resources/configuration/TouchScreenQualifierTest.java
deleted file mode 100644
index 04f8a30..0000000
--- a/sdk_common/tests/src/com/android/ide/common/resources/configuration/TouchScreenQualifierTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.resources.configuration;
-
-import com.android.resources.TouchScreen;
-
-import junit.framework.TestCase;
-
-public class TouchScreenQualifierTest extends TestCase {
-
- private TouchScreenQualifier tsq;
- private FolderConfiguration config;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- tsq = new TouchScreenQualifier();
- config = new FolderConfiguration();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- tsq = null;
- config = null;
- }
-
- public void testNoTouch() {
- assertEquals(true, tsq.checkAndSet("notouch", config)); //$NON-NLS-1$
- assertTrue(config.getTouchTypeQualifier() != null);
- assertEquals(TouchScreen.NOTOUCH, config.getTouchTypeQualifier().getValue());
- assertEquals("notouch", config.getTouchTypeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFinger() {
- assertEquals(true, tsq.checkAndSet("finger", config)); //$NON-NLS-1$
- assertTrue(config.getTouchTypeQualifier() != null);
- assertEquals(TouchScreen.FINGER, config.getTouchTypeQualifier().getValue());
- assertEquals("finger", config.getTouchTypeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testStylus() {
- assertEquals(true, tsq.checkAndSet("stylus", config)); //$NON-NLS-1$
- assertTrue(config.getTouchTypeQualifier() != null);
- assertEquals(TouchScreen.STYLUS, config.getTouchTypeQualifier().getValue());
- assertEquals("stylus", config.getTouchTypeQualifier().toString()); //$NON-NLS-1$
- }
-
- public void testFailures() {
- assertEquals(false, tsq.checkAndSet("", config));//$NON-NLS-1$
- assertEquals(false, tsq.checkAndSet("STYLUS", config));//$NON-NLS-1$
- assertEquals(false, tsq.checkAndSet("other", config));//$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/xml/AndroidManifestParserTest.java b/sdk_common/tests/src/com/android/ide/common/xml/AndroidManifestParserTest.java
deleted file mode 100644
index fee6014..0000000
--- a/sdk_common/tests/src/com/android/ide/common/xml/AndroidManifestParserTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.ide.common.xml.ManifestData.UsesFeature;
-import com.android.ide.common.xml.ManifestData.UsesLibrary;
-import com.android.resources.Keyboard;
-import com.android.resources.Navigation;
-import com.android.resources.TouchScreen;
-
-import junit.framework.TestCase;
-
-import java.io.InputStream;
-
-/**
- * Tests for {@link AndroidManifestParser}
- */
-public class AndroidManifestParserTest extends TestCase {
- private ManifestData mManifestTestApp;
- private ManifestData mManifestInstrumentation;
-
- private static final String TESTDATA_PATH =
- "/com/android/sdklib/testdata/"; //$NON-NLS-1$
- private static final String INSTRUMENTATION_XML = TESTDATA_PATH +
- "AndroidManifest-instrumentation.xml"; //$NON-NLS-1$
- private static final String TESTAPP_XML = TESTDATA_PATH +
- "AndroidManifest-testapp.xml"; //$NON-NLS-1$
- private static final String ACTIVITY_ALIAS_XML = TESTDATA_PATH +
- "AndroidManifest-activityalias.xml"; //$NON-NLS-1$
- private static final String PACKAGE_NAME = "com.android.testapp"; //$NON-NLS-1$
- private static final Integer VERSION_CODE = 42;
- private static final String ACTIVITY_NAME = "com.android.testapp.MainActivity"; //$NON-NLS-1$
- private static final String LIBRARY_NAME = "android.test.runner"; //$NON-NLS-1$
- private static final String LIBRARY_NAME2 = "android.test.runner2"; //$NON-NLS-1$
- private static final String FEATURE_NAME = "com.foo.feature"; //$NON-NLS-1$
- private static final String INSTRUMENTATION_NAME = "android.test.InstrumentationTestRunner"; //$NON-NLS-1$
- private static final String INSTRUMENTATION_TARGET = "com.android.AndroidProject"; //$NON-NLS-1$
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- InputStream manifestStream = this.getClass().getResourceAsStream(TESTAPP_XML);
-
- mManifestTestApp = AndroidManifestParser.parse(manifestStream);
- assertNotNull(mManifestTestApp);
-
- manifestStream = this.getClass().getResourceAsStream(INSTRUMENTATION_XML);
- mManifestInstrumentation = AndroidManifestParser.parse(manifestStream);
- assertNotNull(mManifestInstrumentation);
- }
-
- public void testGetInstrumentationInformation() {
- assertEquals(1, mManifestInstrumentation.getInstrumentations().length);
- assertEquals(INSTRUMENTATION_NAME,
- mManifestInstrumentation.getInstrumentations()[0].getName());
- assertEquals(INSTRUMENTATION_TARGET,
- mManifestInstrumentation.getInstrumentations()[0].getTargetPackage());
- }
-
- public void testGetPackage() {
- assertEquals(PACKAGE_NAME, mManifestTestApp.getPackage());
- }
-
- public void testGetVersionCode() {
- assertEquals(VERSION_CODE, mManifestTestApp.getVersionCode());
- assertEquals(null, mManifestInstrumentation.getVersionCode());
- }
-
- public void testMinSdkVersion() {
- assertEquals(7, mManifestTestApp.getMinSdkVersion());
- assertEquals(8, mManifestTestApp.getTargetSdkVersion());
-
- assertEquals("foo", mManifestInstrumentation.getMinSdkVersionString());
- assertEquals(ManifestData.MIN_SDK_CODENAME, mManifestInstrumentation.getMinSdkVersion());
- }
-
- public void testGetActivities() {
- assertEquals(1, mManifestTestApp.getActivities().length);
- ManifestData.Activity activity = mManifestTestApp.getActivities()[0];
- assertEquals(ACTIVITY_NAME, activity.getName());
- assertTrue(activity.hasAction());
- assertTrue(activity.isHomeActivity());
- assertTrue(activity.hasAction());
- assertEquals(activity, mManifestTestApp.getActivities()[0]);
- }
-
- public void testGetLauncherActivity() {
- ManifestData.Activity activity = mManifestTestApp.getLauncherActivity();
- assertEquals(ACTIVITY_NAME, activity.getName());
- assertTrue(activity.hasAction());
- assertTrue(activity.isHomeActivity());
- }
-
- public void testSupportsScreen() {
- ManifestData.SupportsScreens supportsScreens =
- mManifestTestApp.getSupportsScreensFromManifest();
-
- assertNotNull(supportsScreens);
- assertEquals(Boolean.TRUE, supportsScreens.getAnyDensity());
- assertEquals(Boolean.TRUE, supportsScreens.getResizeable());
- assertEquals(Boolean.TRUE, supportsScreens.getSmallScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getNormalScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getLargeScreens());
- }
-
- public void testUsesConfiguration() {
- ManifestData.UsesConfiguration usesConfig = mManifestTestApp.getUsesConfiguration();
-
- assertNotNull(usesConfig);
- assertEquals(Boolean.TRUE, usesConfig.getReqFiveWayNav());
- assertEquals(Navigation.NONAV, usesConfig.getReqNavigation());
- assertEquals(Boolean.TRUE, usesConfig.getReqHardKeyboard());
- assertEquals(Keyboard.TWELVEKEY, usesConfig.getReqKeyboardType());
- assertEquals(TouchScreen.FINGER, usesConfig.getReqTouchScreen());
- }
-
- private void assertEquals(ManifestData.Activity lhs, ManifestData.Activity rhs) {
- assertTrue(lhs == rhs || (lhs != null && rhs != null));
- if (lhs != null && rhs != null) {
- assertEquals(lhs.getName(), rhs.getName());
- assertEquals(lhs.isExported(), rhs.isExported());
- assertEquals(lhs.hasAction(), rhs.hasAction());
- assertEquals(lhs.isHomeActivity(), rhs.isHomeActivity());
- }
- }
-
- public void testGetUsesLibraries() {
- UsesLibrary[] libraries = mManifestTestApp.getUsesLibraries();
-
- assertEquals(2, libraries.length);
- assertEquals(LIBRARY_NAME, libraries[0].getName());
- assertEquals(Boolean.FALSE, libraries[0].getRequired());
- assertEquals(LIBRARY_NAME2, libraries[1].getName());
- assertEquals(Boolean.TRUE, libraries[1].getRequired());
- }
-
- public void testGetUsesFeatures() {
- UsesFeature[] features = mManifestTestApp.getUsesFeatures();
-
- assertEquals(2, features.length);
- assertEquals(0x00020001, features[0].mGlEsVersion);
- assertEquals(Boolean.TRUE, features[0].getRequired());
- assertEquals(FEATURE_NAME, features[1].getName());
- assertEquals(Boolean.TRUE, features[1].getRequired());
- }
-
- public void testGetPackageName() {
- assertEquals(PACKAGE_NAME, mManifestTestApp.getPackage());
- }
-
- public void testActivityAlias() throws Exception {
- InputStream manifestStream = this.getClass().getResourceAsStream(ACTIVITY_ALIAS_XML);
-
- ManifestData manifest = AndroidManifestParser.parse(manifestStream);
- assertNotNull(manifest);
-
- assertEquals(manifest.getLauncherActivity().getName(),
- "com.android.testapp.AliasActivity"); //$NON-NLS-1$
- }
-}
diff --git a/sdk_common/tests/src/com/android/ide/common/xml/SupportsScreensTest.java b/sdk_common/tests/src/com/android/ide/common/xml/SupportsScreensTest.java
deleted file mode 100644
index aa88fc7..0000000
--- a/sdk_common/tests/src/com/android/ide/common/xml/SupportsScreensTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
- *
- * 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.xml;
-
-import com.android.ide.common.xml.AndroidManifestParser;
-import com.android.ide.common.xml.ManifestData;
-import com.android.ide.common.xml.ManifestData.SupportsScreens;
-
-import java.io.InputStream;
-
-import junit.framework.TestCase;
-
-public class SupportsScreensTest extends TestCase {
-
- private static final String TESTDATA_PATH =
- "/com/android/sdklib/testdata/"; //$NON-NLS-1$
- private static final String TESTAPP2_XML = TESTDATA_PATH +
- "AndroidManifest-testapp2.xml"; //$NON-NLS-1$
-
- public void testDefaultValuesApi3() {
- SupportsScreens supportsScreens = SupportsScreens.getDefaultValues(3);
-
- assertNotNull(supportsScreens);
- assertEquals(Boolean.FALSE, supportsScreens.getAnyDensity());
- assertEquals(Boolean.FALSE, supportsScreens.getResizeable());
- assertEquals(Boolean.FALSE, supportsScreens.getSmallScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getNormalScreens());
- assertEquals(Boolean.FALSE, supportsScreens.getLargeScreens());
- }
-
- public void testDefaultValuesApi4() {
- SupportsScreens supportsScreens = SupportsScreens.getDefaultValues(4);
-
- assertNotNull(supportsScreens);
- assertEquals(Boolean.TRUE, supportsScreens.getAnyDensity());
- assertEquals(Boolean.TRUE, supportsScreens.getResizeable());
- assertEquals(Boolean.TRUE, supportsScreens.getSmallScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getNormalScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getLargeScreens());
- }
-
- public void testManifestParsing() throws Exception {
- InputStream manifestStream = this.getClass().getResourceAsStream(TESTAPP2_XML);
-
- ManifestData data = AndroidManifestParser.parse(manifestStream);
- assertNotNull(data);
-
- SupportsScreens supportsScreens = data.getSupportsScreensFromManifest();
- assertNotNull(supportsScreens);
- assertEquals(null, supportsScreens.getAnyDensity());
- assertEquals(null, supportsScreens.getResizeable());
- assertEquals(null, supportsScreens.getSmallScreens());
- assertEquals(null, supportsScreens.getNormalScreens());
- assertEquals(Boolean.FALSE, supportsScreens.getLargeScreens());
-
- supportsScreens = data.getSupportsScreensValues();
- assertNotNull(supportsScreens);
- assertEquals(Boolean.TRUE, supportsScreens.getAnyDensity());
- assertEquals(Boolean.TRUE, supportsScreens.getResizeable());
- assertEquals(Boolean.TRUE, supportsScreens.getSmallScreens());
- assertEquals(Boolean.TRUE, supportsScreens.getNormalScreens());
- assertEquals(Boolean.FALSE, supportsScreens.getLargeScreens());
- }
-
- public void testOverlapWith() {
- SupportsScreens supportsN = new SupportsScreens("false|false|false|true|false");
- SupportsScreens supportsSL = new SupportsScreens("false|false|true|false|true");
-
- assertTrue(supportsN.overlapWith(supportsSL));
- assertTrue(supportsSL.overlapWith(supportsN));
- }
-
- public void testCompareScreenSizesWith() {
- // set instance that support all combo of the three sizes.
- SupportsScreens supportsS = new SupportsScreens("false|false|true|false|false");
- SupportsScreens supportsN = new SupportsScreens("false|false|false|true|false");
- SupportsScreens supportsL = new SupportsScreens("false|false|false|false|true");
- SupportsScreens supportsSL = new SupportsScreens("false|false|true|false|true");
-
- assertEquals(-1, supportsS.compareScreenSizesWith(supportsN));
- assertEquals( 1, supportsN.compareScreenSizesWith(supportsS));
- assertEquals(-1, supportsN.compareScreenSizesWith(supportsL));
- assertEquals(-1, supportsS.compareScreenSizesWith(supportsL));
-
- // test thrown exception for overlapWith == true
- try {
- supportsSL.compareScreenSizesWith(supportsN);
- fail("Should have thrown IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // success!
- }
-
- // test thrown exception for hasStrictlyDifferentScreenSupportAs == false
- try {
- supportsSL.compareScreenSizesWith(supportsS);
- fail("Should have thrown IllegalArgumentException");
- } catch (IllegalArgumentException e) {
- // success!
- }
-
- }
-
- public void testHasStrictlyDifferentScreenSupportAs() {
- SupportsScreens supportsS = new SupportsScreens("false|false|true|false|false");
- SupportsScreens supportsN = new SupportsScreens("false|false|false|true|false");
- SupportsScreens supportsL = new SupportsScreens("false|false|false|false|true");
-
- SupportsScreens supportsSN = new SupportsScreens("false|false|true|true|false");
- SupportsScreens supportsNL = new SupportsScreens("false|false|false|true|true");
- SupportsScreens supportsSL = new SupportsScreens("false|false|true|false|true");
- SupportsScreens supportsSNL = new SupportsScreens("false|false|true|true|true");
-
- assertTrue(supportsS.hasStrictlyDifferentScreenSupportAs(supportsN));
- assertTrue(supportsS.hasStrictlyDifferentScreenSupportAs(supportsL));
- assertTrue(supportsN.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertTrue(supportsN.hasStrictlyDifferentScreenSupportAs(supportsL));
- assertTrue(supportsL.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertTrue(supportsL.hasStrictlyDifferentScreenSupportAs(supportsN));
-
-
- assertFalse(supportsSN.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertFalse(supportsSN.hasStrictlyDifferentScreenSupportAs(supportsN));
- assertTrue(supportsSN.hasStrictlyDifferentScreenSupportAs(supportsL));
- assertFalse(supportsSL.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertTrue(supportsSL.hasStrictlyDifferentScreenSupportAs(supportsN));
- assertFalse(supportsSL.hasStrictlyDifferentScreenSupportAs(supportsL));
- assertTrue(supportsNL.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertFalse(supportsNL.hasStrictlyDifferentScreenSupportAs(supportsN));
- assertFalse(supportsNL.hasStrictlyDifferentScreenSupportAs(supportsL));
- assertFalse(supportsSNL.hasStrictlyDifferentScreenSupportAs(supportsS));
- assertFalse(supportsSNL.hasStrictlyDifferentScreenSupportAs(supportsN));
- assertFalse(supportsSNL.hasStrictlyDifferentScreenSupportAs(supportsL));
- }
-}
diff --git a/sdkmanager/app/.classpath b/sdkmanager/app/.classpath
index b06fd5a..98cdeb1 100644
--- a/sdkmanager/app/.classpath
+++ b/sdkmanager/app/.classpath
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry excluding="**/Android.mk" kind="src" path="src"/>
- <classpathentry excluding="**/Android.mk" kind="src" path="tests"/>
+ <classpathentry excluding="**/Android.mk" kind="src" path="src/main/java"/>
+ <classpathentry excluding="**/Android.mk" kind="src" path="src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/sdklib"/>
<classpathentry combineaccessrules="false" kind="src" path="/sdkuilib"/>
@@ -11,5 +11,6 @@
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/eclipse/org.eclipse.core.commands_3.6.0.I20100512-1500.jar"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/eclipse/org.eclipse.equinox.common_3.6.0.v20100503.jar"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/eclipse/org.eclipse.jface_3.6.2.M20110210-1200.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/guava-tools/guava-13.0.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/sdkmanager/app/Android.mk b/sdkmanager/app/Android.mk
index 82aad43..f72c401 100644
--- a/sdkmanager/app/Android.mk
+++ b/sdkmanager/app/Android.mk
@@ -1,10 +1,22 @@
# Copyright 2007 The Android Open Source Project
#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIRS := src
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+LOCAL_JAVA_RESOURCE_DIRS := src/main/java
LOCAL_JAR_MANIFEST := etc/manifest.txt
@@ -17,6 +29,7 @@ LOCAL_JAR_MANIFEST := etc/manifest.txt
# current VM is 32 or 64 bit.)
LOCAL_JAVA_LIBRARIES := \
common \
+ guava-tools \
sdklib \
sdkuilib \
swt \
@@ -25,10 +38,33 @@ LOCAL_JAVA_LIBRARIES := \
org.eclipse.core.commands_3.6.0.I20100512-1500
LOCAL_MODULE := sdkmanager
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_JAVA_LIBRARY)
# Build all sub-directories
include $(call all-makefiles-under,$(LOCAL_PATH))
+
+# ----- TESTS ------
+# Copyright (C) 2011 The Android Open Source Project
+
+include $(CLEAR_VARS)
+
+# Only compile source java files in this lib.
+LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java)
+
+LOCAL_MODULE := sdkmanager-tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := \
+ guava-tools \
+ httpclient-4.1.1 \
+ httpcore-4.1 \
+ httpmime-4.1.1 \
+ junit \
+ sdkmanager \
+ sdklib
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/sdkmanager/app/etc/Android.mk b/sdkmanager/app/etc/Android.mk
index 96ec4df..8e3786e 100644
--- a/sdkmanager/app/etc/Android.mk
+++ b/sdkmanager/app/etc/Android.mk
@@ -4,6 +4,6 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PREBUILT_EXECUTABLES := android
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_PREBUILT)
diff --git a/sdkmanager/app/etc/manifest.txt b/sdkmanager/app/etc/manifest.txt
index 50e1285..44be3b8 100644
--- a/sdkmanager/app/etc/manifest.txt
+++ b/sdkmanager/app/etc/manifest.txt
@@ -1,2 +1,2 @@
Main-Class: com.android.sdkmanager.Main
-Class-Path: common.jar sdklib.jar sdkuilib.jar swtmenubar.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.equinox.common_3.6.0.v20100503.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar
+Class-Path: common.jar sdklib.jar sdkuilib.jar swtmenubar.jar org.eclipse.jface_3.6.2.M20110210-1200.jar org.eclipse.equinox.common_3.6.0.v20100503.jar org.eclipse.core.commands_3.6.0.I20100512-1500.jar guava-tools.jar
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/main/java/com/android/sdkmanager/Main.java
index 8f58612..0ef18b8 100644
--- a/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/sdkmanager/app/src/main/java/com/android/sdkmanager/Main.java
@@ -40,9 +40,9 @@ import com.android.sdklib.internal.repository.DownloadCache;
import com.android.sdklib.internal.repository.DownloadCache.Strategy;
import com.android.sdklib.internal.repository.packages.PlatformToolPackage;
import com.android.sdklib.internal.repository.packages.ToolPackage;
+import com.android.sdklib.internal.repository.updater.SdkUpdaterNoWindow;
import com.android.sdklib.repository.SdkAddonConstants;
import com.android.sdklib.repository.SdkRepoConstants;
-import com.android.sdkuilib.internal.repository.SdkUpdaterNoWindow;
import com.android.sdkuilib.internal.widgets.MessageBoxLog;
import com.android.sdkuilib.repository.AvdManagerWindow;
import com.android.sdkuilib.repository.AvdManagerWindow.AvdInvocationContext;
@@ -1512,6 +1512,7 @@ public class Main {
/**
* Reads a line from the input stream, masking it as much as possible.
*/
+ @SuppressWarnings("unused")
private String promptPassword(String prompt) throws IOException {
// Setup a thread that tries to overwrite any input by
diff --git a/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java b/sdkmanager/app/src/main/java/com/android/sdkmanager/SdkCommandLine.java
index 6a74c29..6a74c29 100644
--- a/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java
+++ b/sdkmanager/app/src/main/java/com/android/sdkmanager/SdkCommandLine.java
diff --git a/sdkmanager/app/tests/com/android/sdklib/SdkManagerTestCase.java b/sdkmanager/app/src/test/java/com/android/sdklib/SdkManagerTestCase.java
index ab45785..ab45785 100755
--- a/sdkmanager/app/tests/com/android/sdklib/SdkManagerTestCase.java
+++ b/sdkmanager/app/src/test/java/com/android/sdklib/SdkManagerTestCase.java
diff --git a/sdkmanager/app/tests/com/android/sdklib/mock/MockLog.java b/sdkmanager/app/src/test/java/com/android/sdklib/mock/MockLog.java
index e64ed51..e64ed51 100644
--- a/sdkmanager/app/tests/com/android/sdklib/mock/MockLog.java
+++ b/sdkmanager/app/src/test/java/com/android/sdklib/mock/MockLog.java
diff --git a/sdkmanager/app/tests/com/android/sdkmanager/AvdManagerTest.java b/sdkmanager/app/src/test/java/com/android/sdkmanager/AvdManagerTest.java
index a376490..a376490 100644
--- a/sdkmanager/app/tests/com/android/sdkmanager/AvdManagerTest.java
+++ b/sdkmanager/app/src/test/java/com/android/sdkmanager/AvdManagerTest.java
diff --git a/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java b/sdkmanager/app/src/test/java/com/android/sdkmanager/MainTest.java
index 24a644b..24a644b 100644
--- a/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java
+++ b/sdkmanager/app/src/test/java/com/android/sdkmanager/MainTest.java
diff --git a/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java b/sdkmanager/app/src/test/java/com/android/sdkmanager/SdkCommandLineTest.java
index e88d892..e88d892 100644
--- a/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java
+++ b/sdkmanager/app/src/test/java/com/android/sdkmanager/SdkCommandLineTest.java
diff --git a/sdkmanager/app/tests/Android.mk b/sdkmanager/app/tests/Android.mk
deleted file mode 100644
index 7b88129..0000000
--- a/sdkmanager/app/tests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
-#
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-
-# Only compile source java files in this lib.
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE := sdkmanager-tests
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_JAVA_LIBRARIES := \
- httpclient-4.1.1 \
- httpcore-4.1 \
- httpmime-4.1.1 \
- junit \
- sdkmanager \
- sdklib
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/sdkmanager/libs/sdklib/Android.mk b/sdkmanager/libs/sdklib/Android.mk
index dfd3fcb..ef0362d 100644
--- a/sdkmanager/libs/sdklib/Android.mk
+++ b/sdkmanager/libs/sdklib/Android.mk
@@ -24,10 +24,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := sdklib
LOCAL_MODULE_TAGS := optional
-# IMPORTANT: if you add a new dependency here, please make sure
-# to also check the following files:
-# sdkmanager/sdklib/manifest.txt
-# sdkmanager/app/etc/android.bat
+
LOCAL_JAVA_LIBRARIES := \
common \
commons-codec-1.4 \
@@ -42,7 +39,7 @@ LOCAL_JAVA_LIBRARIES := \
layoutlib_api
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/sdkmanager/libs/sdkuilib/Android.mk b/sdkmanager/libs/sdkuilib/Android.mk
index b746632..df35432 100644
--- a/sdkmanager/libs/sdkuilib/Android.mk
+++ b/sdkmanager/libs/sdkuilib/Android.mk
@@ -24,10 +24,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := sdkuilib
LOCAL_MODULE_TAGS := optional
-# IMPORTANT: if you add a new dependency here, please make sure
-# to also check the following file:
-# sdkmanager/app/etc/android.bat
-# (Note: there is no manifest.txt for sdkuilib.)
+
LOCAL_JAVA_LIBRARIES := \
common \
commons-codec-1.4 \
@@ -45,7 +42,7 @@ LOCAL_JAVA_LIBRARIES := \
swtmenubar
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/swtmenubar/Android.mk b/swtmenubar/Android.mk
index 865c277..01e8645 100644
--- a/swtmenubar/Android.mk
+++ b/swtmenubar/Android.mk
@@ -26,7 +26,7 @@ LOCAL_JAVA_LIBRARIES := \
org.eclipse.jface_3.6.2.M20110210-1200
LOCAL_PREBUILT_JAVA_LIBRARIES := \
- ../../prebuilts/devtools/$(LOCAL_MODULE)/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
+ ../../prebuilts/devtools/$(LOCAL_MODULE)$(COMMON_JAVA_PACKAGE_SUFFIX)
include $(BUILD_HOST_PREBUILT)
diff --git a/traceview/etc/manifest.txt b/traceview/etc/manifest.txt
index 0c17bec..e145b4a 100644
--- a/traceview/etc/manifest.txt
+++ b/traceview/etc/manifest.txt
@@ -1,2 +1,2 @@
Main-Class: com.android.traceview.MainWindow
-Class-Path: common.jar swt.jar org.eclipse.equinox.common_3.2.0.v20060603.jar org.eclipse.jface_3.2.0.I20060605-1400.jar org.eclipse.core.commands_3.2.0.I20060605-1400.jar
+Class-Path: common.jar swt.jar org.eclipse.equinox.common_3.2.0.v20060603.jar org.eclipse.jface_3.2.0.I20060605-1400.jar org.eclipse.core.commands_3.2.0.I20060605-1400.jar guava-tools.jar