diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/acp/Android.mk | 3 | ||||
-rw-r--r-- | tools/atree/files.cpp | 9 | ||||
-rw-r--r-- | tools/atree/fs.cpp | 7 | ||||
-rwxr-xr-x | tools/buildinfo.sh | 7 | ||||
-rw-r--r-- | tools/droiddoc/templates-sac/head_tag.cs | 2 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt (renamed from tools/droiddoc/templates-sdk-dyn/assets/GPL-LICENSE.txt) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt (renamed from tools/droiddoc/templates-sdk-dyn/assets/LICENSE.txt) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css (renamed from tools/droiddoc/templates-sdk-dyn/assets/android-developer-docs.css) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/css/default.css (renamed from tools/droiddoc/templates-sdk-dyn/assets/css/default.css) | 1304 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css (renamed from tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css) | 3 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/design/default.js (renamed from tools/droiddoc/templates-sdk-dyn/assets/design/default.js) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/android-developers-logo.png) | bin | 3195 -> 3195 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/android.png | bin | 0 -> 4934 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/android_wrench.png) | bin | 3633 -> 3633 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left-develop.png) | bin | 3036 -> 3036 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left.png) | bin | 3144 -> 3144 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right-develop.png) | bin | 2960 -> 2960 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right.png) | bin | 2757 -> 2757 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_down.png) | bin | 180 -> 180 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_up.png) | bin | 181 -> 181 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_off.jpg) | bin | 592 -> 592 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_on.jpg) | bin | 692 -> 692 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_off.jpg) | bin | 592 -> 592 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_on.jpg) | bin | 692 -> 692 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrows-up-down.png) | bin | 162 -> 162 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_community_leftDiv.jpg) | bin | 10692 -> 10692 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_fade.jpg) | bin | 300 -> 300 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_gradient.jpg) | bin | 1376 -> 1376 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_images_sprite.png) | bin | 2008 -> 2008 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_logo.png) | bin | 1525 -> 1525 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/blog-default.png) | bin | 72570 -> 72570 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient-tab.png) | bin | 192 -> 192 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient.png) | bin | 146 -> 146 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png) | bin | 164 -> 164 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png | bin | 0 -> 379 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png | bin | 0 -> 830 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/close-white.png | bin | 0 -> 292 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png | bin | 0 -> 586 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/close.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/close.png) | bin | 312 -> 312 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo.png) | bin | 2170 -> 2170 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png) | bin | 2497 -> 2497 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/developers-logo.png) | bin | 10155 -> 10155 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/file-generic.png) | bin | 224 -> 224 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/file-image.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/file-image.png) | bin | 511 -> 511 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/file-java.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/file-java.png) | bin | 299 -> 299 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/file-manifest.png) | bin | 341 -> 341 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/file-xml.png) | bin | 301 -> 301 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/folder.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/folder.png) | bin | 311 -> 311 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/fullscreen.png) | bin | 1154 -> 1154 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/grad-rule-qv.png) | bin | 249 -> 249 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/Android_Dev_Lab_l.png) | bin | 16512 -> 16512 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/GDC2011.png) | bin | 15892 -> 15892 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_large.png) | bin | 7553 -> 7553 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_small.png) | bin | 3576 -> 3576 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo-2011.png) | bin | 11210 -> 11210 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo.png) | bin | 3673 -> 3673 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_l.png) | bin | 111790 -> 111790 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_s.png) | bin | 27250 -> 27250 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/android_adc.png) | bin | 1849 -> 1849 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_announcement.png) | bin | 2840 -> 2840 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_bottom.jpg) | bin | 2180 -> 2180 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel.png) | bin | 3654 -> 3654 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_board.png) | bin | 1902 -> 1902 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_wheel.png) | bin | 2041 -> 2041 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/carousel_buttons_sprite.png) | bin | 3413 -> 3413 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-large.png) | bin | 16630 -> 16630 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-small.png) | bin | 1944 -> 1944 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/donut-android.png) | bin | 9386 -> 9386 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/eclair-android.png) | bin | 11311 -> 11311 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/froyo-android.png) | bin | 17086 -> 17086 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/gdc-logo.png) | bin | 2739 -> 2739 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/gingerdroid.png) | bin | 11690 -> 11690 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus-small.png) | bin | 5042 -> 5042 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus.png) | bin | 21315 -> 21315 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/honeycomb-android.png) | bin | 13716 -> 13716 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-about.png) | bin | 5573 -> 5573 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-design.png) | bin | 5739 -> 5739 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-develop.png) | bin | 5364 -> 5364 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-distribute.png) | bin | 4588 -> 4588 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/ics-android.png) | bin | 15002 -> 15002 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/io-large.png) | bin | 5522 -> 5522 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/io-small.png) | bin | 1427 -> 1427 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-large.png) | bin | 39756 -> 39756 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-small.png) | bin | 3424 -> 3424 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/market-large.png) | bin | 5752 -> 5752 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/market-small.png) | bin | 3134 -> 3134 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-large.png) | bin | 1616 -> 1616 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-small.png) | bin | 2381 -> 2381 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_main.jpg) | bin | 378 -> 378 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_side.jpg) | bin | 344 -> 344 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_contribute.jpg) | bin | 1021 -> 1021 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_design.png) | bin | 697 -> 697 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_download.jpg) | bin | 1192 -> 1192 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_download2.jpg) | bin | 653 -> 653 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_guidelines_logo.png) | bin | 44163 -> 44163 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_market.jpg) | bin | 1022 -> 1022 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_more.png) | bin | 1098 -> 1098 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_play.png) | bin | 10201 -> 10201 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_robot.jpg) | bin | 638 -> 638 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_search.png) | bin | 1406 -> 1406 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_world.jpg) | bin | 511 -> 511 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/left_off.jpg) | bin | 592 -> 592 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/left_on.jpg) | bin | 692 -> 692 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/link-out.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png) | bin | 202 -> 202 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/locale.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/locale.png) | bin | 393 -> 393 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/logo_breadcrumbz.jpg) | bin | 3311 -> 3311 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/more_bottom.png) | bin | 1055 -> 1055 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/more_check.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/more_check.png) | bin | 1014 -> 1014 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/more_mid.png) | bin | 958 -> 958 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/more_top.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/more_top.png) | bin | 1447 -> 1447 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/open_source.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/open_source.png) | bin | 6340 -> 6340 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.png | bin | 0 -> 880 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.png | bin | 0 -> 2280 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.png | bin | 0 -> 670 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.png | bin | 0 -> 1733 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/preliminary.png) | bin | 2251 -> 2251 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/preview.png | bin | 0 -> 1664 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_arrow.png) | bin | 2951 -> 2951 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_btn_bg.png) | bin | 1024 -> 1024 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e.gif) | bin | 2713 -> 2713 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e2.gif) | bin | 2680 -> 2680 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-eg.gif) | bin | 3075 -> 3075 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s.gif) | bin | 2617 -> 2617 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.gif) | bin | 2618 -> 2618 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.png) | bin | 966 -> 966 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-sg.gif) | bin | 3057 -> 3057 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-article.png) | bin | 889 -> 889 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-article.png) | bin | 2095 -> 2095 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-sample.png) | bin | 2480 -> 2480 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-tutorial.png) | bin | 2544 -> 2544 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-video.png) | bin | 2155 -> 2155 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg) | bin | 15565 -> 15565 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-sample.png) | bin | 972 -> 972 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-tutorial.png) | bin | 1001 -> 1001 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resource-video.png) | bin | 835 -> 835 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/right_off.jpg) | bin | 592 -> 592 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/right_on.jpg) | bin | 692 -> 692 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/sidenav-rule.png) | bin | 258 -> 258 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_1.jpg) | bin | 3060 -> 3060 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_2.jpg) | bin | 3736 -> 3736 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_3.jpg) | bin | 3151 -> 3151 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_1.jpg) | bin | 19240 -> 19240 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_2.jpg) | bin | 20188 -> 20188 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_3.jpg) | bin | 20202 -> 20202 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_off.jpg) | bin | 676 -> 676 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_on.jpg) | bin | 733 -> 733 bytes | |||
-rwxr-xr-x | tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif) | bin | 96 -> 96 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png) | bin | 198 -> 198 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/callout.png) | bin | 1383 -> 1383 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span13.png) | bin | 64431 -> 64431 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span8.png) | bin | 30679 -> 30679 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span5.png) | bin | 39994 -> 39994 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span9.png) | bin | 75920 -> 75920 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus4_blank_port_432.png) | bin | 301931 -> 301931 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_land_span13.png) | bin | 57247 -> 57247 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_port_span5.png) | bin | 33589 -> 33589 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png | bin | 0 -> 13039 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png | bin | 0 -> 21525 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_down.png) | bin | 238 -> 238 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_left.png) | bin | 229 -> 229 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_right.png) | bin | 228 -> 228 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_up.png) | bin | 221 -> 221 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/gototop.png) | bin | 262 -> 262 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png | bin | 0 -> 1437 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png | bin | 0 -> 3315 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_action.png) | bin | 415 -> 415 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_good.png) | bin | 318 -> 318 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_movie_inline.png) | bin | 1040 -> 1040 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_phone_tablet.png) | bin | 302 -> 302 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_use.png) | bin | 437 -> 437 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_web.png) | bin | 1037 -> 1037 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_wrong.png) | bin | 286 -> 286 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material.png (renamed from tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material.png) | bin | 3208 -> 3208 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material@2x.png (renamed from tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material@2x.png) | bin | 5877 -> 5877 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video.png) | bin | 3338 -> 3338 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video@2x.png) | bin | 6019 -> 6019 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers.png) | bin | 3208 -> 3208 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers@2x.png) | bin | 5877 -> 5877 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video.png) | bin | 3219 -> 3219 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video@2x.png) | bin | 5738 -> 5738 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers.png) | bin | 3017 -> 3017 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers@2x.png) | bin | 5456 -> 5456 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/styles/open_new_page.png) | bin | 980 -> 980 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed-small.png) | bin | 166 -> 166 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed.png) | bin | 3565 -> 3565 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened-small.png) | bin | 170 -> 170 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened.png) | bin | 3567 -> 3567 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/uiguidelines1.png) | bin | 5258 -> 5258 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/video-droid.png) | bin | 1614 -> 1614 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js (renamed from tools/droiddoc/templates-sdk-dyn/assets/js/android_3p-bundle.js) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/js/docs.js (renamed from tools/droiddoc/templates-sdk-dyn/assets/js/docs.js) | 916 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/assets/js/prettify.js (renamed from tools/droiddoc/templates-sdk-dyn/assets/js/prettify.js) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/class.cs (renamed from tools/droiddoc/templates-sdk-dyn/class.cs) | 49 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/classes.cs (renamed from tools/droiddoc/templates-sdk-dyn/classes.cs) | 8 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/components/masthead.cs (renamed from tools/droiddoc/templates-sdk-dyn/components/masthead.cs) | 141 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/customizations.cs (renamed from tools/droiddoc/templates-sdk-dyn/customizations.cs) | 40 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/data.hdf (renamed from tools/droiddoc/templates-sdk-dyn/data.hdf) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/designpage.cs (renamed from tools/droiddoc/templates-sdk-dyn/designpage.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/docpage.cs (renamed from tools/droiddoc/templates-sdk-dyn/docpage.cs) | 66 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/footer.cs (renamed from tools/droiddoc/templates-sdk-dyn/footer.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs (renamed from tools/droiddoc/templates-sdk-dyn/gcm_navtree_data.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs (renamed from tools/droiddoc/templates-sdk-dyn/gms_navtree_data.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/head_tag.cs (renamed from tools/droiddoc/templates-sdk-dyn/head_tag.cs) | 36 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/header.cs (renamed from tools/droiddoc/templates-sdk-dyn/header.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/header_tabs.cs (renamed from tools/droiddoc/templates-sdk-dyn/header_tabs.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs (renamed from tools/droiddoc/templates-sdk-dyn/jd_lists_unified.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/macros_override.cs | 36 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/navtree_data.cs (renamed from tools/droiddoc/templates-sdk-dyn/navtree_data.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/nosidenavpage.cs (renamed from tools/droiddoc/templates-sdk-dyn/nosidenavpage.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/package.cs (renamed from tools/droiddoc/templates-sdk-dyn/package.cs) | 4 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/packages.cs (renamed from tools/droiddoc/templates-sdk-dyn/packages.cs) | 2 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/sample.cs (renamed from tools/droiddoc/templates-sdk-dyn/sample.cs) | 2 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/sampleindex.cs (renamed from tools/droiddoc/templates-sdk-dyn/sampleindex.cs) | 2 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs (renamed from tools/droiddoc/templates-sdk-dyn/samples_navtree_data.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/sdkpage.cs (renamed from tools/droiddoc/templates-sdk-dyn/sdkpage.cs) | 237 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/timestamp.cs (renamed from tools/droiddoc/templates-sdk-dyn/timestamp.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk-dev/trailer.cs (renamed from tools/droiddoc/templates-sdk-dyn/trailer.cs) | 0 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/css/default.css | 6706 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/css/fullscreen.css | 194 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/android_logo.png | bin | 0 -> 513 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png | bin | 0 -> 860 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png | bin | 0 -> 4712 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.png | bin | 0 -> 18596 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg | bin | 15565 -> 12042 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/sprite-2x.png | bin | 0 -> 7283 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/images/sprite.png | bin | 0 -> 3121 bytes | |||
-rw-r--r-- | tools/droiddoc/templates-sdk/assets/js/docs.js | 1352 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/class.cs | 23 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/classes.cs | 5 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/components/masthead.cs | 504 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/customizations.cs | 521 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/designpage.cs | 12 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/docpage.cs | 87 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/footer.cs | 187 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/head_tag.cs | 15 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/nosidenavpage.cs | 1 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/package.cs | 3 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/packages.cs | 3 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/sample.cs | 8 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/sampleindex.cs | 8 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/sdkpage.cs | 9 | ||||
-rw-r--r-- | tools/droiddoc/templates-sdk/trailer.cs | 1 | ||||
-rw-r--r-- | tools/fs_config/Android.mk | 66 | ||||
-rw-r--r-- | tools/fs_config/default/android_filesystem_config.h | 44 | ||||
-rw-r--r-- | tools/fs_config/fs_config_generate.c | 128 | ||||
-rw-r--r-- | tools/fs_get_stats/Android.mk | 2 | ||||
-rwxr-xr-x | tools/post_process_props.py | 19 | ||||
-rwxr-xr-x | tools/product_debug.py | 1 | ||||
-rwxr-xr-x | tools/releasetools/add_img_to_target_files.py | 85 | ||||
-rw-r--r-- | tools/releasetools/blockimgdiff.py | 138 | ||||
-rwxr-xr-x | tools/releasetools/build_image.py | 131 | ||||
l---------[-rwxr-xr-x] | tools/releasetools/check_target_files_signatures | 442 | ||||
-rwxr-xr-x | tools/releasetools/check_target_files_signatures.py | 442 | ||||
-rw-r--r-- | tools/releasetools/common.py | 400 | ||||
-rw-r--r-- | tools/releasetools/edify_generator.py | 91 | ||||
-rwxr-xr-x | tools/releasetools/img_from_target_files.py | 32 | ||||
l---------[-rwxr-xr-x] | tools/releasetools/make_recovery_patch | 54 | ||||
-rwxr-xr-x | tools/releasetools/make_recovery_patch.py | 53 | ||||
l---------[-rwxr-xr-x] | tools/releasetools/ota_from_target_files | 1577 | ||||
-rwxr-xr-x | tools/releasetools/ota_from_target_files.py | 1631 | ||||
-rw-r--r-- | tools/releasetools/pylintrc | 382 | ||||
-rw-r--r-- | tools/releasetools/rangelib.py | 3 | ||||
l---------[-rwxr-xr-x] | tools/releasetools/sign_target_files_apks | 499 | ||||
-rwxr-xr-x | tools/releasetools/sign_target_files_apks.py | 506 | ||||
-rw-r--r-- | tools/releasetools/sparse_img.py | 13 | ||||
-rw-r--r-- | tools/releasetools/test_common.py | 110 | ||||
-rw-r--r-- | tools/signapk/SignApk.java | 22 | ||||
-rw-r--r-- | tools/signtos/Android.mk | 25 | ||||
-rw-r--r-- | tools/signtos/SignTos.java | 314 | ||||
-rw-r--r-- | tools/signtos/SignTos.mf | 1 | ||||
-rw-r--r-- | tools/zipalign/Android.mk | 2 | ||||
-rw-r--r-- | tools/zipalign/README.txt | 5 | ||||
-rw-r--r-- | tools/zipalign/ZipAlign.cpp | 52 | ||||
-rw-r--r-- | tools/zipalign/ZipEntry.cpp | 4 |
274 files changed, 12509 insertions, 7278 deletions
diff --git a/tools/acp/Android.mk b/tools/acp/Android.mk index 33c5567..2b41bc1 100644 --- a/tools/acp/Android.mk +++ b/tools/acp/Android.mk @@ -4,6 +4,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES := \ acp.c @@ -21,5 +22,7 @@ LOCAL_STATIC_LIBRARIES := libhost LOCAL_C_INCLUDES := build/libs/host/include LOCAL_MODULE := acp LOCAL_ACP_UNAVAILABLE := true +LOCAL_CXX_STL := none +LOCAL_ADDRESS_SANITIZER := false include $(BUILD_HOST_EXECUTABLE) diff --git a/tools/atree/files.cpp b/tools/atree/files.cpp index df3e987..d945f58 100644 --- a/tools/atree/files.cpp +++ b/tools/atree/files.cpp @@ -447,14 +447,7 @@ list_dir(const string& path, const FileRecord& rec, continue; } string entry = path_append(path, ent->d_name); -#ifdef HAVE_DIRENT_D_TYPE - bool is_directory = (ent->d_type == DT_DIR); -#else - // If dirent.d_type is missing, then use stat instead - struct stat stat_buf; - stat(entry.c_str(), &stat_buf); - bool is_directory = S_ISDIR(stat_buf.st_mode); -#endif + bool is_directory = (ent->d_type == DT_DIR); add_more(entry, is_directory, rec, more); if (is_directory) { dirs.push_back(entry); diff --git a/tools/atree/fs.cpp b/tools/atree/fs.cpp index 9468cfd..6cd080e 100644 --- a/tools/atree/fs.cpp +++ b/tools/atree/fs.cpp @@ -63,14 +63,7 @@ remove_recursively(const string& path) string full = path; full += '/'; full += ent->d_name; -#ifdef HAVE_DIRENT_D_TYPE bool is_directory = (ent->d_type == DT_DIR); -#else - // If dirent.d_type is missing, then use stat instead - struct stat stat_buf; - stat(full.c_str(), &stat_buf); - bool is_directory = S_ISDIR(stat_buf.st_mode); -#endif if (is_directory) { dirs.push_back(full); } else { diff --git a/tools/buildinfo.sh b/tools/buildinfo.sh index a80b2db..dcd9ab5 100755 --- a/tools/buildinfo.sh +++ b/tools/buildinfo.sh @@ -36,11 +36,8 @@ echo "ro.product.cpu.abilist32=$TARGET_CPU_ABI_LIST_32_BIT" echo "ro.product.cpu.abilist64=$TARGET_CPU_ABI_LIST_64_BIT" echo "ro.product.manufacturer=$PRODUCT_MANUFACTURER" -if [ -n "$PRODUCT_DEFAULT_LANGUAGE" ] ; then - echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE" -fi -if [ -n "$PRODUCT_DEFAULT_REGION" ] ; then - echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION" +if [ -n "$PRODUCT_DEFAULT_LOCALE" ] ; then + echo "ro.product.locale=$PRODUCT_DEFAULT_LOCALE" fi echo "ro.wifi.channels=$PRODUCT_DEFAULT_WIFI_CHANNELS" echo "ro.board.platform=$TARGET_BOARD_PLATFORM" diff --git a/tools/droiddoc/templates-sac/head_tag.cs b/tools/droiddoc/templates-sac/head_tag.cs index 9fca488..5cee68c 100644 --- a/tools/droiddoc/templates-sac/head_tag.cs +++ b/tools/droiddoc/templates-sac/head_tag.cs @@ -7,7 +7,7 @@ <title><?cs if:page.title ?><?cs var:page.title ?> | <?cs - /if ?>Android Developers</title> + /if ?>Android Open Source Project</title> <!-- STYLESHEETS --> <link rel="stylesheet" diff --git a/tools/droiddoc/templates-sdk-dyn/assets/GPL-LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt index 66a0f18..66a0f18 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/GPL-LICENSE.txt +++ b/tools/droiddoc/templates-sdk-dev/assets/GPL-LICENSE.txt diff --git a/tools/droiddoc/templates-sdk-dyn/assets/LICENSE.txt b/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt index e84328b..e84328b 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/LICENSE.txt +++ b/tools/droiddoc/templates-sdk-dev/assets/LICENSE.txt diff --git a/tools/droiddoc/templates-sdk-dyn/assets/android-developer-docs.css b/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css index cd610f7..cd610f7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/android-developer-docs.css +++ b/tools/droiddoc/templates-sdk-dev/assets/android-developer-docs.css diff --git a/tools/droiddoc/templates-sdk-dyn/assets/css/default.css b/tools/droiddoc/templates-sdk-dev/assets/css/default.css index e26aec6..cc4dce7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/css/default.css +++ b/tools/droiddoc/templates-sdk-dev/assets/css/default.css @@ -158,12 +158,6 @@ video.with-shadow { .layout-content-row { display: inline-block; margin-bottom: 10px; } - .layout-content-row:after { - content: "."; - display: block; - height: 0; - clear: both; - visibility: hidden; } * html .layout-content-row { height: 1px; } @@ -430,20 +424,19 @@ video.with-shadow { /* content header */ .content-header { height: 30px; - margin:20px 0 25px; - padding:0 0 10px;} + margin:36px 0 23px; /* same as h1 */ + padding:0 0 10px;} /* same as h1 */ .content-header.just-links { margin-bottom:0; padding-bottom:0;} .content-header h1 { - color:#000; margin:0; - border-bottom:0; padding:0; + width: 700px; } .content-header > div:first-child { - height:55px; /* set fixed height for the header div to ensure the + height:1px; /* set fixed height for the header div to ensure the next/prev links align with toc on training classes */ } @@ -451,7 +444,7 @@ video.with-shadow { border-top: 1px solid #ccc; margin-top: 10px; padding-top:10px; - height: 30px; } + width:100%; } .content-footer .col-9 { margin-left:0; @@ -462,20 +455,33 @@ video.with-shadow { .content-footer.wrap { width:940px; } +.content-footer .plus-container { + margin:5px 0 0; + text-align:right; + float:right; +} + +a.back-link { + text-decoration: none; + text-transform: uppercase; +} +.content-header .paging-links { + margin-top:-25px; +} .paging-links { - position: relative; } + position: relative; + height:30px; } .paging-links a { position: absolute; } .paging-links a, .training-nav-top a { - font-size: 14px; - line-height: 30px; color: #555555; text-decoration: none; text-transform: uppercase; } .paging-links .prev-page-link:before, - .training-nav-top .prev-page-link:before { + .training-nav-top .prev-page-link:before, + a.back-link:before { content: ''; background: transparent url(../images/styles/disclosure_left.png) no-repeat scroll 50% 50%; width: 10px; @@ -489,7 +495,7 @@ video.with-shadow { .paging-links .prev-page-link { left: -15px; } .paging-links .next-page-link { - right: 0px; } + right: 0; } .next-page-link:after, .start-class-link:after, .start-course-link:after, @@ -506,6 +512,9 @@ video.with-shadow { .next-page-link.inline:after { content: none; } + .content-footer .paging-links .next-page-link { + left:0; + } .training-nav-top a { display:block; @@ -544,7 +553,6 @@ video.with-shadow { .paging-links a.start-class-link { width:100%; - text-align:right; } /* list of classes on course landing page */ @@ -623,19 +631,6 @@ video.with-shadow { display:none !important; } - .content-footer.next-class { - display:block; - border:0; - margin-top:0; - padding-top:0; - } - - .content-footer.next-class a.next-class-link { - display:block; - float:right; - text-transform:uppercase; - } - /* inner-doc tabs w/ title */ @@ -713,6 +708,7 @@ ul#title-tabs li a:active { color: #33b5e5; border-bottom-color: #33b5e5; } } +h1:target, h2:target, h3:target { -webkit-animation-name: glowheader; @@ -894,7 +890,7 @@ scroll top left; .framed-nexus4-port-216 img { width: 216px; height: 360px; } - + .framed-nexus5-port-span-5 { background: transparent url(../images/styles/device_nexus5_blank_port_span5.png) no-repeat scroll top left; @@ -929,6 +925,47 @@ scroll top left; height: 384px; } +/* wear device frames */ + +.framed-wear-square { + background: transparent url(../images/styles/device_wear_square.png) no-repeat scroll top left; + background-size: 302px 302px; + height:222px; + width:222px; + padding:40px; + overflow:hidden; +} + +.framed-wear-square-small { + background: transparent url(../images/styles/device_wear_square_small.png) no-repeat scroll top left; + background-size: 169px 200px; + height:147px; + width:147px; + padding:27px 11px; + overflow:hidden; +} + +#jd-content +.framed-wear-square img { + height:222px; + width: 222px; + padding:0; + margin:0; +} + +#jd-content +.framed-wear-square-small img { + height:147px; + width: 147px; + padding:0; + margin:0; +} + + + + + + /* landing page disclosures */ .landing-page-link { text-decoration: none; @@ -1102,12 +1139,13 @@ table, fieldset { } h1 { color:#333; - font-size: 22px; - margin: 20px 0 20px; + font-size: 34px; + margin: 36px 0 27px; padding:0 0 10px; + font-weight:300; } h1, h2 { - line-height: 32px; + line-height: 30px; } h1.short { margin-right:320px; @@ -1120,21 +1158,24 @@ h1.super { } h2 { color:#333; - font-size: 20px; - margin: 20px 0 20px; + font-size: 26px; + margin: 32px 0 20px; padding:0; + font-weight:300; } h3 { color:#333; - font-size: 18px; + font-size: 21px; + font-weight:400; + margin:21px 0 14px 0; } h3, h4 { - color:#333; - line-height: 20px; - margin: 10px 0; + line-height: 21px; } h4 { - font-size: 16px; + font-size: 18px; + margin: 12px 0; + font-weight:500; } h5 { font-size: 14px; @@ -1147,7 +1188,7 @@ h6 { } hr { /* applied to the bottom of h2 elements */ height: 1px; - margin: 5px 0 20px; + margin: 3px 0 12px; border: 0; background: #ccc; } @@ -1208,7 +1249,7 @@ code { legend { display: none; } -a:link, a:visited { +a:link, a:visited, .link-color { color: #258aaf; text-decoration: none; } @@ -1216,6 +1257,13 @@ a:focus, a:hover, a:active { color: #33B5E5; text-decoration: none; } +a.white { + color: #fff; + text-decoration:underline; +} +a.white:hover, a.white:active { + color: #ccc !important; +} strong, b { font-weight:bold; color: #222; @@ -1249,6 +1297,7 @@ th { tr:first-of-type th:first-of-type:empty { visibility: hidden; } + /* -------------------------------------------------------------------------- Footer */ @@ -1523,6 +1572,9 @@ Header, Login, Nav-X, Search color: #333; font-size: 16px; } +.about a.selected { + color: #9933CC; +} .design a.selected { color: #33b5e5; } @@ -1834,6 +1886,11 @@ EndColorStr='#ececec'); margin:0 0 0 20px; } +.training-nav-top { + position:relative; + top:73px; +} + .training-nav-bottom { padding:0 0 20px; } @@ -1842,12 +1899,12 @@ EndColorStr='#ececec'); #qv-wrapper { float:right; clear:right; - margin:0 0 0 30px; /* negative top-margin to counter the content-header bottom margin */ + margin:6px 0 0 30px; /* negative top-margin to counter the content-header bottom margin */ padding:0 0 30px; } #tb-wrapper { - margin:-29px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */ + margin:51px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */ } #tb, @@ -1931,6 +1988,10 @@ EndColorStr='#ececec'); margin:0 15px 10px 35px; } +#tb p { + margin:0 15px 10px; +} + #qv ol { list-style:none; margin:0 15px 15px; @@ -1959,28 +2020,12 @@ EndColorStr='#ececec'); /* related resources blocks in checklists */ -.rel-resources { - margin:10px 0px; - border:1px solid #ccc; - background-color:rgba(0, 0, 0, 0.027451); - border:1px solid #ccc; - font-size:13px; - color:#6f6f6f; -} +/* related resources sections that have dynamic content */ -.rel-resources ul { -padding: .5em 1em 0 1em; -} -.rel-resources a { -font-weight:500; -} -.rel-resources h3 { - margin:4px 15px 0px 15px; - font-size:13px; - font-weight:600; - text-transform:uppercase; +h3.rel-resources { +margin:1.25em auto; } /* -------------------------------------------------------------------------- @@ -2360,6 +2405,13 @@ a:visited, #doc-col { margin-right:0; } + +/* Uncomment this for preview release watermark +#doc-col { + background: url('../images/preview.png') repeat; +} +*/ + #doc-content-container { margin-left: 291px } @@ -2725,19 +2777,22 @@ Butterbar width:100%; } #butterbar { - width:940px; + width:100%; margin:0 auto; } #butterbar-message { - background-color:#f80; - float:right; - font-size:12px; - font-weight:bold; - padding:0 10px; - border-radius: 0 0 5px 5px; + background-color:rgba(255, 187, 51, .4); + font-size:13px; + padding: 5px 0; + text-align:center; +} +a#butterbar-message { + cursor:pointer; + display:block; +} +a#butterbar-message:hover { + text-decoration:underline; } -#butterbar-message a {color:#fff !important} -#butterbar-message a:hover {text-decoration:underline;} /* -------------------------------------------------------------------------- Misc @@ -2761,7 +2816,7 @@ table.blank th, table.blank td { .caption { margin: 0.5em 0 2em 0; color: #000; - font-size: 11.5px; + font-size: 11.5px; } .nolist, .nolist ul, .nolist ol { @@ -2910,7 +2965,8 @@ div.design-announce p { a.notice-developers-video, a.notice-developers, a.notice-designers-video, -a.notice-designers { +a.notice-designers, +a.notice-designers-material { float:right; clear:right; width:238px; @@ -2921,13 +2977,15 @@ a.notice-designers { a.notice-developers-video.wide, a.notice-developers.wide, a.notice-designers-video.wide, -a.notice-designers.wide { +a.notice-designers.wide, +a.notice-designers-material.wide { width:278px; } a.notice-developers-video div, a.notice-developers div, a.notice-designers-video div, -a.notice-designers div { +a.notice-designers div, +a.notice-designers-material div { min-height:40px; background:url('../images/styles/notice-developers@2x.png') no-repeat 10px 10px; background-size:40px 40px; @@ -2945,16 +3003,22 @@ a.notice-developers-video div { background:url('../images/styles/notice-developers-video@2x.png') no-repeat 10px 10px; background-size:40px 40px; } +a.notice-designers-material div { + background:url('../images/styles/notice-designers-material@2x.png') no-repeat 10px 10px; + background-size:40px 40px; +} a.notice-developers-video:hover, a.notice-developers:hover, a.notice-designers-video:hover, -a.notice-designers:hover { +a.notice-designers:hover, +a.notice-designers-material:hover { background:#eee; } a.notice-developers-video h3, a.notice-developers h3, a.notice-designers-video h3, -a.notice-designers h3 { +a.notice-designers h3, +a.notice-designers-material h3 { font-size:13px; line-height:18px; font-weight:bold; @@ -2965,14 +3029,16 @@ a.notice-designers h3 { a.notice-developers-video p, a.notice-developers p, a.notice-designers-video p, -a.notice-designers p { +a.notice-designers p, +a.notice-designers-material p { margin:0; line-height:14px; } a.notice-developers-video.left, a.notice-developers.left, a.notice-designers-video.left, -a.notice-designers.left { +a.notice-designers.left, +a.notice-designers-material.left { margin-left:0; float:left; } @@ -2994,6 +3060,34 @@ a.header-toggle { } +/* for IDE instruction toggle (Studio/Eclipse/Other) */ +select.ide { + background: transparent; + border: 1px solid #bbb; + border-left: 0; + border-right: 0; + margin: 10px 0; + padding: 10px 0; + color:#666; +} +select.ide, +select.ide option { + font-family: inherit; + font-size:16px; + font-weight:500; +} +/* hide all except studio by default */ +.select-ide.eclipse, +.select-ide.other { + display:none; +} +/* ... unless studio also includes one of the others */ +.select-ide.studio.eclipse, +.select-ide.studio.other { + display:none; +} + + /* ----------------------------------------------- good/bad example containers */ @@ -3072,6 +3166,7 @@ div#deprecatedSticker { -webkit-box-shadow:-5px 5px 10px #ccc; } +div#langMessage, div#naMessage { display:none; width:555px; @@ -3079,6 +3174,8 @@ div#naMessage { margin:0 auto; } + +div#langMessage>div, div#naMessage div { z-index:99; width:450px; @@ -3092,12 +3189,16 @@ div#naMessage div { -webkit-box-shadow:-10px 10px 40px #888; } /* IE6 can't position fixed */ +* html div#langMessage>div, * html div#naMessage div { position:absolute; } div#naMessage strong { font-size:1.1em; } +div#langMessage .lang { + display:none; +} /* -------------------------------------------------------------------------- Slideshow Controls & Next/Prev @@ -3346,28 +3447,37 @@ Page-Specific Styles } #jd-header { - padding: 0 0 5px; - margin: 20px 0 10px; - font-size:13px; + padding: 0 0 12px; + margin: 20px 0 12px; + font-size:12px; + padding-bottom:12px; border-bottom:solid 1px #ccc; } #jd-header h1 { margin:0; - padding:0; + padding:0 0 6px 0; } +/* not sure if this is needed in the ref docs, disabling for now +.jd-descr h2 { + margin:16px 0; +} +*/ + /* page-top-right container for reference pages (holds links to summary tables) */ #api-info-block { - font-size:13px; + font-size:12px; margin:20px 0 0; padding:0 10px 6px; font-weight:normal; float:right; text-align:right; color:#999; - max-width:70%; + max-width:80%; + font-size: 12px; + line-height:14px; } #api-info-block div.api-level { @@ -3384,7 +3494,8 @@ links to summary tables) */ border-spacing:0; margin:0; padding:0; - font-size:13px; + font-size:12px; + line-height:14px; background-color:transparent; } .jd-inheritance-table tr td { @@ -3966,7 +4077,7 @@ EndColorStr='#ececec'); height: 38px; } #header-wrapper #nav-x ul.nav-x li { - margin-right: 36px !important; + margin-right: 31px !important; margin-top: 5px; margin-bottom: 0px; height: 30px; @@ -4093,6 +4204,7 @@ EndColorStr='#ececec'); width: 26px; height: 25px; background: url(../images/dac_logo.png); + background-image: -webkit-image-set(url(../images/dac_logo.png) 1x, url(../images/dac_logo@2x.png) 2x); z-index: 52; position: relative; } @@ -4115,6 +4227,15 @@ EndColorStr='#ececec'); z-index: 52; } +/* offset the <a name=""> tags to account for sticky nav */ +body.reference a[name], +div.renderscript a[name] { + visibility: hidden; + display: block; + position: relative; + top: -56px; +} + } @@ -4168,13 +4289,13 @@ EndColorStr='#ececec'); } -#header-wrap .logo.wear-logo { +#header-wrap .logo.landing-logo { width:220px; margin:0; padding:0; margin-bottom:22px; } -#header-wrap .logo.wear-logo img { +#header-wrap .logo.landing-logo img { padding:0 0 0 10px; } @@ -4246,7 +4367,7 @@ EndColorStr='#ececec'); #quicknav { float:none; clear:both; - margin-left:180px; + margin-left:0; margin-top:-30px; display:none; overflow:hidden; @@ -4261,6 +4382,10 @@ EndColorStr='#ececec'); padding:0; } +#quicknav ul li.about { + border-top:1px solid #9933CC; +} + #quicknav ul li.design { border-top:1px solid #33b5e5; } @@ -4311,7 +4436,7 @@ EndColorStr='#ececec'); } #header-wrap.quicknav { - height:196px; + height:216px; } @@ -4590,7 +4715,9 @@ EndColorStr='#ececec'); } - +#landing h1 { + margin:17px 0 20px 0 !important; +} a.download-sdk { float:right; @@ -4761,14 +4888,14 @@ a.download-sdk { /* Slideshow */ .slideshow-develop { - height: 300px; + height: 316px; width: 940px; position: relative; overflow:hidden; } .slideshow-develop .frame { width: 940px; - height: 300px; + height: 316px; } .slideshow-develop img.play { max-width:350px; @@ -4800,6 +4927,7 @@ a.download-sdk { padding:0; margin-bottom:10px; border:none; + font-size:24px; } .slideshow-develop .item { height: 300px; @@ -4972,7 +5100,8 @@ a.download-sdk { margin-bottom:0; } .landing-banner h1 { - margin-top:0; + margin-top:16px; + padding-bottom:24px; } .landing-docs, .landing-banner { @@ -5127,22 +5256,6 @@ a.download-sdk { /************ DISTRIBUTE PAGES ******************/ -/* Article page header line fix */ -.headerLine { - overflow: hidden; -} -.headerLine h1 { - float: left; - padding-right: 20px; - margin-bottom: 0px; - font-size: 20px; - color: #363636; -} -.headerLine hr { - overflow: hidden; - margin: 42px 0 0 0; -} - .article-detail #body-content { padding-top: 10px; } @@ -5155,7 +5268,7 @@ a.download-sdk { text-transform:uppercase; border-bottom:1px solid #CCC; padding:8px 0 0 1px; - margin-bottom:10px; + margin-bottom:14px; clear:both; } @@ -5191,7 +5304,7 @@ a.download-sdk { /* Basic card-styling with shadow */ .resource-card { border-radius: 1px; - box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.14); + box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.12); background: #fefefe; } @@ -5220,6 +5333,9 @@ a.download-sdk { -o-transition: opacity 0.5s; transition: opacity 0.5s; } +.static .card-bg:after { + display:none; +} .card-bg .card-section-icon { position: absolute; top: 50%; @@ -5366,18 +5482,21 @@ a.download-sdk { content: "."; display: block; height: 0; + position:relative; clear: both; visibility: hidden; } - .resource-card:hover { cursor: pointer; } +.static .resource-card:hover { + cursor: auto; +} .resource-card:hover .card-bg:after { opacity: 0; } /* disabled to make way for fade/ellipsis truncation, - and the plusone moves up. + and the plusone moves up. .resource-card:hover .card-info .description .text { padding-right: 70px; } */ @@ -6289,6 +6408,17 @@ a.download-sdk { display: none; } + +/* Override to show the description instead of the content section */ +.no-section .resource-card-3x2 > .card-info .section, +.no-section .resource-card-6x2 > .card-info .section { + display: none; +} +.no-section .resource-card-3x2 > .card-info .description, +.no-section .resource-card-6x2 > .card-info .description { + display: block; +} + /* 1/2 row items */ .resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg { left: 0; @@ -6383,4 +6513,940 @@ height:30px; div.jd-descr > .resource-widget[data-section=distribute\/tools] .section-card-menu .card-info ul li { border-top-color: #7e3794 !important; -}
\ No newline at end of file +} + + + +/** + * UTILITIES + */ + + +.border-box { + box-sizing: border-box; +} + +.vertical-center-outer { + display: table; + height: 100%; + width: 100%; +} + +.vertical-center-inner { + display: table-cell; + vertical-align: middle; +} + +/** + * TYPE STYLES + */ + +.landing-h1 { + font-weight: 100; + font-size: 60px; + line-height: 78px; + text-align: center; + letter-spacing: -1px; +} + +.landing-pre-h1 { + font-weight: 400; + font-size: 28px; + color: #93B73F; + line-height: 36px; + text-align: center; + letter-spacing: -1px; + text-transform: uppercase; + +} + +.landing-h1.hero { + text-align: left; +} + +.landing-h2 { + font-weight: 300; + font-size: 42px; + line-height: 64px; + text-align: center; +} + +.landing-subhead { + color: #999999; + font-size: 20px; + line-height: 28px; + font-weight:300; + text-align: center; +} +.landing-subhead.hero { + text-align: left; + color: white; +} + +.landing-hero-description { + text-align: left; + margin: 1em 0; +} + +.landing-hero-description p { + font-weight: 300; + margin: 0; + font-size: 18px; + line-height: 24px; +} + +.landing-body .landing-small { + font-size: 14px; + line-height: 19px; +} + +.landing-body.landing-align-center { + text-align: center; +} + +.landing-align-left { + text-align: left; +} + +/** + * LAYOUT + */ + +#body-content, +.fullpage, +#jd-content, +.jd-descr, +.landing-body-content { + height: 100%; +} + +.landing-section { + padding: 80px 10px 80px; + width: 100%; + margin-left: -10px; + text-rendering: optimizeLegibility; +} + +#extending-android-to-wearables { + padding-top: 30px; +} + +.landing-short-section { + padding: 40px 10px 28px; +} + +.landing-gray-background { + background-color: #e9e9e9; +} + +.landing-white-background { + background-color: white; +} + +.landing-red-background { + color: white; + background-color: hsl(8, 70%, 54%); +} + +.landing-subhead-red { + color: hsl(8, 71%, 84%); + text-align: left; +} + +.landing-subhead-red p { + margin-top: 20px; +} + +.landing-hero-container { + height: 100%; +} + + +.preview-hero { + height: calc(100% - 110px); + min-height: 504px; + margin-top: -5px; + padding-top: 0; + padding-bottom: 0; + background-image: url(../../preview/images/hero.jpg); + background-size: cover; + background-position: right center; + color: white; + position: relative; + overflow: hidden; +} + +.wear-hero { + height: calc(100% - 110px); + min-height: 504px; + margin-top: -5px; + padding-top: 0; + padding-bottom: 0; + background-image: url(../../wear/images/hero.jpg); + background-size: cover; + background-position: top center; + color: white; + position: relative; + overflow: hidden; +} + +.tv-hero { + height: calc(100% - 110px); + min-height: 504px; + margin-top: -5px; + padding-top: 0; + padding-bottom: 0; + background-image: url(../../tv/images/hero.jpg); + background-size: cover; + background-position: right center; + color: white; + position: relative; + overflow: hidden; +} + +.auto-hero { + height: calc(100% - 110px); + min-height: 504px; + margin-top: -5px; + padding-top: 0; + padding-bottom: 0; + background-image: url(../../auto/images/hero.jpg); + background-size: cover; + background-position: right center; + color: white; + position: relative; + overflow: hidden; +} + +.landing-hero-scrim { + background: black; + opacity: .2; + position: absolute; + width: 100%; + height: 100%; + margin-left: -10px; +} + +.landing-hero-wrap { + margin: 0 auto; + width: 940px; + clear: both; + height: 100%; + position: relative; +} + +.landing-section-header { + margin-bottom: 40px; +} + +.landing-hero-wrap .landing-section-header { + margin-bottom: 16px; +} + +.landing-body { + font-size: 18px; + line-height: 24px; +} + +.landing-button { + white-space: nowrap; + display: inline-block; + padding: 16px 32px; + font-size: 18px; + font-weight: 500; + line-height: 24px; + cursor: pointer; + color: white; + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; + -webkit-transition: .2s background-color ease-in-out; + -moz-transition: .2s background-color ease-in-out; + -o-transition: .2s background-color ease-in-out; + transition: .2s background-color ease-in-out; +} + +.landing-primary { + background-color: hsl(8, 70%, 44%); + color: #f8f8f8; +} + +.landing-button.landing-primary:hover { + background-color: hsl(8, 70%, 36%); +} + +.landing-button.landing-primary:active { + background-color: hsl(8, 70%, 30%); +} + +.landing-button.landing-secondary { + background-color: #2faddb; +} + +.landing-button.landing-secondary:hover { + background-color: #09c; +} + +.landing-button.landing-secondary:active { + background-color: #3990ab; +} + +a.landing-button, +a.landing-button:hover, +a.landing-button:visited { + color: white !important; +} + +.landing-video-link { + white-space: nowrap; + display: inline-block; + padding: 16px 32px 16px 82px; + font-size: 18px; + font-weight: 400; + line-height: 24px; + cursor: pointer; + color: hsla(0, 0%, 100%, .8); + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; + -webkit-transition: .2s color ease-in-out; + -moz-transition: .2s color ease-in-out; + -o-transition: .2s color ease-in-out; + transition: .2s color ease-in-out; +} + +.landing-video-link:before { + height: 64px; + width: 64px; + display: inline-block; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=); + background-size: contain; + position: absolute; + content: ""; + opacity: .7; + margin-top: -19px; + margin-left: -64px; + -webkit-transition: .2s opacity ease-in-out; + -moz-transition: .2s opacity ease-in-out; + -o-transition: .2s opacity ease-in-out; + transition: .2s opacity ease-in-out; +} + +.landing-video-link:hover { + color: hsla(0, 0%, 100%, 1); +} + +.landing-video-link:hover:before { + opacity: 1; +} + +.landing-social-image { + float: left; + margin-right: 14px; + height: 64px; + width: 64px; +} + +.landing-social-copy { + padding-left: 78px; +} + +.landing-scroll-down-affordance { + position: absolute; + bottom: 0; + width: 100%; + text-align: center; + z-index: 10; +} + +.landing-down-arrow { + padding: 24px; + display: inline-block; + opacity: .5; + -webkit-transition: .2s opacity ease-in-out; + -moz-transition: .2s opacity ease-in-out; + -o-transition: .2s opacity ease-in-out; + transition: .2s opacity ease-in-out; + + -webkit-animation-name: pulse-opacity; + -webkit-animation-duration: 4s; +} + +.landing-down-arrow:hover { + opacity: 1; +} + +.landing-down-arrow img { + height: 28px; + width: 28px; + margin: 0 auto; + display: block; +} + +.landing-divider { + display: inline-block; + height: 2px; + background-color: white; + position: relative; + margin: 10px 0; +} + +/* 3 CLOLUMN LAYOUT */ + +.landing-breakout { + margin-top: 40px; + margin-bottom: 40px; +} + +.landing-breakout img { + margin-bottom: 20px; +} + +.landing-partners img { + margin-bottom: 20px; +} + +.landing-breakout p { + padding: 0 23px; +} + +.landing-breakout.landing-partners img { + margin-bottom: 20px; +} + +.col-3-wide { + display: inline; + float: left; + margin-left: 10px; + margin-right: 10px; +} + +.col-3-wide { + width: 302px; +} + +/** + * ANIMATION + */ + +@-webkit-keyframes pulse-opacity { + 0% { + opacity: .5; + } + 20% { + opacity: .5; + } + 40% { + opacity: 1; + } + 60% { + opacity: .5; + } + 80% { + opacity: 1; + } + 100% { + opacity: .5; + } +} + + + +/** + * VIDEO + */ + +#video-container { + display:none; + position:fixed; + top:0; + left:0; + width:100%; + height:100%; + background-color:rgba(0,0,0,0.8); + z-index:9999; +} + +#video-frame { + width:940px; + height:100%; + margin:72px auto; + display:none; + position:relative; +} + +.video-close { + cursor: pointer; + position: absolute; + right: -49px; + top: -49px; + pointer-events: all; +} + +#icon-video-close { + background-image: url("../images/close-white.png"); + background-image: -webkit-image-set(url(../images/close-white.png) 1x, url(../images/close-white_2x.png) 2x); + background-repeat: no-repeat; + background-position: 0 0; + background-size: 36px 36px; + height: 36px; + width: 36px; + display:block; +} + +#icon-video-close:hover { + background-image: url("../images/close-grey.png"); + background-image: -webkit-image-set(url(../images/close-grey.png) 1x, url(../images/close-grey_2x.png) 2x); +} + +/* Preload the hover images */ +a.video-shadowbox-button.white:after { + display:none; + content:url("../images/close-grey.png") url("../images/close-grey_2x.png"); +} + +a.video-shadowbox-button.white { + background-image: url("../images/play-circle-white.png"); + background-image: -webkit-image-set(url(../images/play-circle-white.png) 1x, url(../images/play-circle-white_2x.png) 2x); + background-size: 36px 36px; + background-repeat: no-repeat; + background-position: right; + padding: 16px 42px 16px 8px; + font-size: 18px; + font-weight: 500; + line-height: 24px; + color: #fff; + text-decoration:none; +} + +a.video-shadowbox-button.white:hover { + color:#bababa !important; + background-image: url("../images/play-circle-grey.png"); + background-image: -webkit-image-set(url(../images/play-circle-grey.png) 1x, url(../images/play-circle-grey_2x.png) 2x); +} + +/* Preload the hover images */ +a.video-shadowbox-button.white:after { + display:none; + content:url("../images/play-circle-grey.png") url("../images/play-circle-grey_2x.png"); +} + +/****************** +Styles for d.a.c/index: +*******************/ + + + +/* Generic full screen carousel styling to be used across pages. */ +.fullscreen-carousel { + margin: 0 -10px; + width: 100%; + overflow: hidden; + position: relative; +} + +.fullscreen-carousel-content { + width: 100%; + height: 100%; + position: relative; + display: table; /* For vertical centering */ +} + +.fullscreen-carousel .vcenter { + display: table-cell; + vertical-align: middle; + position: relative; +} + +.fullscreen-carousel .vcenter > div { + margin: 10px auto; +} + +/* Styles for the full-bleed hero image type. */ +.fullscreen-carousel .hero, .fullscreen-carousel .hero h1 { + color: #fff; +} + +.fullscreen-carousel .hero h1 { + font-weight: 300; + font-size: 60px; + line-height: 68px; + letter-spacing: -1px; + margin-top: 0; +} + +.fullscreen-carousel .hero p { + font-weight: 300; + font-size: 18px; + line-height: 24px; + -webkit-font-smoothing: antialiased; +} + +.fullscreen-carousel .hero .hero-bg { + background-size: cover; + width: 100%; + height: 100%; + position: absolute; + left: 0px; + top: 0px; +} + + +/* Full screen carousel styling for the resource flow layout type of content */ +.fullscreen-carousel .resource-flow-layout:after { + height: 0; /* Dont know why this is set at 10 in default.css */ +} + +.fullscreen-carousel .resource-flow-layout { + margin-bottom: 20px; +} + + + +/* Generic Tab carousel styling to be used across multiple pages. */ + +.tab-carousel .tab-nav { + list-style: none; + position: relative; + text-align: center; +} + +.tab-carousel .tab-nav li { + display: inline-block; + font-size: 22px; + font-weight: 400; + line-height: 50px; + list-style: none; + margin: 0; + padding: 0 25px; + position: relative; +} + +.tab-carousel .tab-nav li a, +.tab-carousel .tab-nav li a:hover { + color: #333 !important; + padding: 10px 10px 13px 10px; + position: relative; + z-index: 1000; +} + +.tab-carousel .tab-nav li:after { + background: #ddd; + bottom: 0; + content: ''; + height: 4px; + left: 0; + position: absolute; + width: 100%; + z-index: 0; +} + +.tab-carousel .tab-nav .highlight { + position: absolute; + height: 4px; + width: 100px; + bottom: 0; + background: #33b5e5; +} + +.tab-carousel .tab-carousel-content { + position: relative; + overflow: hidden; + white-space: nowrap; +} + +.tab-carousel .tab-carousel-content [data-tab] { + display: inline-block; + white-space: normal; +} + + + +/* + Resource styling for the tab carousel. The tab carousel contains either + a 3 column layout of resources or a single full-width resource. The + latter has the 18x12 class applied to it and can be styled differently + that way. +*/ + +.tab-carousel .resource .image { + width: 100%; + height: 250px; + background-repeat: no-repeat; + background-size: contain; + background-position: 50% 50%; +} + +.tab-carousel .resource .info .title { + font-size: 18px; + line-height: 24px; +} + +.tab-carousel .resource .info .summary, +.tab-carousel .resource .info .cta { + line-height: 24px; + font-size: 16px; +} + +.tab-carousel .resource-card-18x12 { + position: relative; + padding-left: 450px; + box-sizing: border-box; + display: table-cell; + vertical-align: middle; +} + +.tab-carousel .resource-card-18x12 .image { + position: absolute; + width: 420px; + height: 100%; + left: 0; + top: 0; +} + +.tab-carousel .resource-card-18x12 .info { + display: inline-block; +} + +.tab-carousel .resource-card-18x12 .info .title { + margin-bottom: 26px; +} + + + + + +/* + Styles for the entity link used in the actions bar and in the cta of + the resources that appear in the tab carousel. +*/ +.actions-bar a:after, +.resource .cta:after { + content: '›'; + font-weight: 400; + font-size: 22px; + left: 5px; + line-height: 1; + position: relative; + top: 1px; + transition: left 190ms ease-out; +} + +.actions-bar a:hover:after, +.resource .cta:hover:after { + left: 10px; +} + + + + +/* + Styles for the actions bar. +*/ +.actions-bar { + background: #9acd00; + margin: 0 -10px; + text-align: center; +} + +.actions-bar .actions { + padding: 30px 0 30px; + text-align: justify; + font-size: 0.1px; + line-height: 0.1px; + margin: 0 10px 0 0; +} + +.actions-bar .actions:after { + content: ''; + width: 100%; + display: inline-block; +} + +.actions-bar .actions > div { + display: inline-block; +} + +.actions-bar a { + font-size: 21px; + line-height: 27px; + color: #fff; + font-weight: 300; + -webkit-font-smoothing: antialiased; +} + +.actions-bar a:after { + top: 0px; + font-size: 22px; +} + +.actions-bar a:hover { + color: #fff !important; +} + + + + + +/* + Specific styles for new home page layout of the carousels. +*/ + +/* Big blue button */ +a.home-new-cta-btn, +.home-new-carousel-1 .resource-card-18x6 .cta { + white-space: nowrap; + display: inline-block; + padding: 14px 32px; + font-size: 18px; + font-weight: 500; + line-height: 24px; + cursor: pointer; + background: #33b5e6; + border-radius: 4px; + margin-top: 20px; + color: #fff; + transition: 0.2s background-color ease-in-out; +} + +.home-new-carousel-1 .resource-card-18x6 .cta:after { + display: none; /* Hide the entity for this button */ +} + +a.home-new-cta-btn:hover, +.home-new-carousel-1 .resource-card-18x6 .cta:hover { + color: #fff !important; + background: #2d9fca; +} + +.home-new-carousel-1 .resource-card-18x6 .cta { + position: absolute; + bottom: 20px; + left: 16px; +} + +/* Fullscreen carousel. */ +.home-new-carousel-1 { + max-height: 700px; /* Set max height so doesn't get too long */ +} + +.home-new-carousel-1 .fullscreen-carousel-content { + min-height: 450px; /* Set min height for all content */ +} + +.home-new-carousel-1 .hero { + background: #000; +} + +.home-new-carousel-1 .hero-bg { + background-image: url(/home-new/images/hero.jpg); + background-position: right center; + opacity: 0.85; +} + +/* + Styling for special top card of full screen layout resource layout. + We need to specifically style the 18x6 card to adjust its size and layout, + since it's not a standard card, not sure if this is unique to the home page + layout or should be namespaced within the fullscreen-carousel container. +*/ +.home-new-carousel-1 .resource-flow-layout.col-16 .resource-card-18x6 { + height: 320px; + background-color:#F9F9F9; + border-radius: 0px; + box-shadow: 0px 0px 0px rgba(0, 0, 0, 0); + +} + +.home-new-carousel-1 .resource-card-18x6 .card-bg { + width: 636px; + height: 100%; +} + +.home-new-carousel-1 .resource-card-18x6 .card-info { + right: 0px; + left: 636px; + height: 100%; + top: 0px; + padding: 15px 22px; +} + +.home-new-carousel-1 .resource-card-18x6 .card-info .util { + display: none; +} + +.home-new-carousel-1 .resource-card-18x6 .card-info .title { + font-size: 20px; + font-weight: 500; + margin-top: 15px; + margin-bottom: 15px; +} + +.home-new-carousel-1 .resource-card-18x6 .card-info .text { + font-size: 15px; + line-height: 21px; +} + + +/* Tabbed carousel. */ +.home-new-carousel-2 { + margin: 35px auto 100px auto; +} + +.home-new-carousel-2 h1 { + font-size: 47px; + font-weight: 100; + line-height: 54px; + text-align: center; +} + +.annotation-message { + display: block; + font-style: italic; + color: #F80; +} + + + +/* Helpouts widget */ +.resource-card-6x2.helpouts-card { + width: 255px; + height: 40px; + position:absolute; + z-index:999; + top:-8px; + right:1px; +} + +.resource-card-6x2.helpouts-card > .card-info { + left:35px; + height:35px; + padding:4px 8px 4px 0; +} + +.resource-card-6x2.helpouts-card > .card-info .helpouts-description { + display:block; + overflow:visible; + font-size:12px; + line-height:12px; + text-align:right; + color:#666; +} + +.helpouts-description .link-color { + text-transform: uppercase; +} + +.resource-card-6x2 > .card-bg.helpouts-card-bg { + width:35px; + height:35px; + margin:2px 0 0 0; + background-image: url(../images/styles/helpouts-logo-35_2x.png); + background-image: -webkit-image-set(url(../images/styles/helpouts-logo-35.png) 1x, url(../images/styles/helpouts-logo-35_2x.png) 2x); +} + +.resource-card-6x2 > .card-bg.helpouts-card-bg:after { + display:none; +} diff --git a/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css index 53d9a64..7912e34 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/css/fullscreen.css +++ b/tools/droiddoc/templates-sdk-dev/assets/css/fullscreen.css @@ -197,9 +197,6 @@ body { left:-20px; } - -} - .col-right { margin-right:0px; } diff --git a/tools/droiddoc/templates-sdk-dyn/assets/design/default.js b/tools/droiddoc/templates-sdk-dev/assets/design/default.js index 3ba8486..3ba8486 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/design/default.js +++ b/tools/droiddoc/templates-sdk-dev/assets/design/default.js diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/android-developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png Binary files differindex 30a8f62..30a8f62 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/android-developers-logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/android-developers-logo.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android.png b/tools/droiddoc/templates-sdk-dev/assets/images/android.png Binary files differnew file mode 100644 index 0000000..4040f3f --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/android_wrench.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png Binary files differindex 6390a2d..6390a2d 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/android_wrench.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png Binary files differindex 5fdfaa3..5fdfaa3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left-develop.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left-develop.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png Binary files differindex 43afec8..43afec8 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png Binary files differindex c86f1f3..c86f1f3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right-develop.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right-develop.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png Binary files differindex 6f7d6db..6f7d6db 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png Binary files differindex 58c248a..58c248a 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_down.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png Binary files differindex 7d0f38e..7d0f38e 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_up.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg Binary files differindex fd32a64..fd32a64 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_off.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg Binary files differindex 143184b..143184b 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_on.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg Binary files differindex 17d2efe..17d2efe 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_off.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg Binary files differindex baa2af1..baa2af1 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_on.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrows-up-down.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png Binary files differindex a2a91ed..a2a91ed 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/arrows-up-down.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/arrows-up-down.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_community_leftDiv.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg Binary files differindex a6d6f0e..a6d6f0e 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_community_leftDiv.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_fade.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg Binary files differindex c6c70b6..c6c70b6 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_fade.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_gradient.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg Binary files differindex 884f8f5..884f8f5 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_gradient.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_images_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png Binary files differindex 84437e7..84437e7 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_images_sprite.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png Binary files differindex 7cf0cb9..7cf0cb9 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/blog-default.png b/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png Binary files differindex f8ab6c3..f8ab6c3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/blog-default.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient-tab.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png Binary files differindex 5223ac3..5223ac3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient-tab.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient-tab.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png Binary files differindex 9d59855..9d59855 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png Binary files differindex 407a318..407a318 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png Binary files differnew file mode 100644 index 0000000..1b0d7f1 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png Binary files differnew file mode 100644 index 0000000..1355507 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png Binary files differnew file mode 100644 index 0000000..ef02018 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png Binary files differnew file mode 100644 index 0000000..9b9c41d --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/close.png b/tools/droiddoc/templates-sdk-dev/assets/images/close.png Binary files differindex 6ae3391..6ae3391 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/close.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/close.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png Binary files differindex 0f11044..0f11044 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png Binary files differindex 0f2784d..0f2784d 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png Binary files differindex 08122ee..08122ee 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/developers-logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-generic.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png Binary files differindex 1802457..1802457 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/file-generic.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-image.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png Binary files differindex d3aec46..d3aec46 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/file-image.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-java.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png Binary files differindex ec85e4b..ec85e4b 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/file-java.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-manifest.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png Binary files differindex 332d066..332d066 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/file-manifest.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-xml.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png Binary files differindex 3dd21b6..3dd21b6 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/file-xml.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/folder.png b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png Binary files differindex 44c6100..44c6100 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/folder.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/fullscreen.png b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png Binary files differindex 01f971c..01f971c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/fullscreen.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/grad-rule-qv.png b/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png Binary files differindex bae2d18..bae2d18 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/grad-rule-qv.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/grad-rule-qv.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/Android_Dev_Lab_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png Binary files differindex 3c04f24..3c04f24 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/Android_Dev_Lab_l.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/Android_Dev_Lab_l.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GDC2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png Binary files differindex 82ce918..82ce918 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GDC2011.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png Binary files differindex 72d54ad..72d54ad 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png Binary files differindex 3da1699..3da1699 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GTV_icon_small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/GTV_icon_small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo-2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png Binary files differindex 4a28447..4a28447 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo-2011.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo-2011.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png Binary files differindex 65334c8..65334c8 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/IO-logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/IO-logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_l.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png Binary files differindex 0b101a4..0b101a4 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_l.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_l.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_s.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png Binary files differindex 0d36bdb..0d36bdb 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/adc2_s.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/adc2_s.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/android_adc.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png Binary files differindex 9fe7f8f..9fe7f8f 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/android_adc.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/android_adc.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_announcement.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png Binary files differindex 91485ff..91485ff 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_announcement.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_announcement.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_bottom.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg Binary files differindex dacd401..dacd401 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_bottom.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_bottom.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png Binary files differindex 5ce5e30..5ce5e30 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_board.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png Binary files differindex c577e02..c577e02 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_board.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_board.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_wheel.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png Binary files differindex aa224ad..aa224ad 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/bg_home_carousel_wheel.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/bg_home_carousel_wheel.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/carousel_buttons_sprite.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png Binary files differindex e98c942..e98c942 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/carousel_buttons_sprite.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/carousel_buttons_sprite.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png Binary files differindex 0db0f6c..0db0f6c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png Binary files differindex e10bfa9..e10bfa9 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/devphone-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/devphone-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/donut-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png Binary files differindex 6aba06b..6aba06b 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/donut-android.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/eclair-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png Binary files differindex d476ce9..d476ce9 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/eclair-android.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/eclair-android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/froyo-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png Binary files differindex c63f7f0..c63f7f0 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/froyo-android.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/froyo-android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/gdc-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png Binary files differindex 5fb53fb..5fb53fb 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/gdc-logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/gdc-logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/gingerdroid.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png Binary files differindex 8399d84..8399d84 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/gingerdroid.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png Binary files differindex 5bb7d7a..5bb7d7a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png Binary files differindex 90871e1..90871e1 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/google-plus.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/google-plus.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/honeycomb-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png Binary files differindex 6cc5031..6cc5031 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/honeycomb-android.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/honeycomb-android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-about.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png Binary files differindex 8339762..8339762 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-about.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-about.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-design.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png Binary files differindex 0d31cdf..0d31cdf 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-design.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-design.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-develop.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png Binary files differindex e02b20f..e02b20f 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-develop.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-develop.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-distribute.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png Binary files differindex 4824072..4824072 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/icon-distribute.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/icon-distribute.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/ics-android.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png Binary files differindex be62ca8..be62ca8 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/ics-android.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/ics-android.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/io-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png Binary files differindex 986053c..986053c 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/io-large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/io-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png Binary files differindex 3a22549..3a22549 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/io-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png Binary files differindex b26f65a..b26f65a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png Binary files differindex cc5f1fa..cc5f1fa 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/maps-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/maps-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/market-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png Binary files differindex 069fee7..069fee7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/market-large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/market-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png Binary files differindex fa1201c..fa1201c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/market-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/market-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-large.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png Binary files differindex 315a1bf..315a1bf 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-large.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-large.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png Binary files differindex 0f1670d..0f1670d 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/home/sdk-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/home/sdk-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_main.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg Binary files differindex f7a0a2f..f7a0a2f 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_main.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_side.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg Binary files differindex 6667476..6667476 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_side.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_contribute.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg Binary files differindex 1aa12b6..1aa12b6 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_contribute.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_design.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png Binary files differindex c12907c..c12907c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_design.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg Binary files differindex f8c1165..f8c1165 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg Binary files differindex c0af7a2..c0af7a2 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download2.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_guidelines_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png Binary files differindex 9362c8f..9362c8f 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_guidelines_logo.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_guidelines_logo.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_market.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg Binary files differindex 0fbb197..0fbb197 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_market.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_more.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png Binary files differindex 6cd03a3..6cd03a3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_more.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_play.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png Binary files differindex 8bfdc7b..8bfdc7b 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_play.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_robot.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg Binary files differindex ca0fd39..ca0fd39 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_robot.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_search.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png Binary files differindex ee90a12..ee90a12 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_search.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_world.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg Binary files differindex 65b8fa6..65b8fa6 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_world.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg Binary files differindex fd32a64..fd32a64 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/left_off.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg Binary files differindex 143184b..143184b 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/left_on.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png b/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png Binary files differindex aa55f9a..aa55f9a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/locale.png b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png Binary files differindex de3aae7..de3aae7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/locale.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/logo_breadcrumbz.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg Binary files differindex e743f86..e743f86 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/logo_breadcrumbz.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_bottom.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png Binary files differindex 632546a..632546a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/more_bottom.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_check.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png Binary files differindex f2fcbfc..f2fcbfc 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/more_check.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_mid.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png Binary files differindex 99bc999..99bc999 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/more_mid.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_top.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png Binary files differindex 8ead1d3..8ead1d3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/more_top.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/open_source.png b/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png Binary files differindex 12bb1fb..12bb1fb 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/open_source.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.png b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.png Binary files differnew file mode 100644 index 0000000..5e7e7ba --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.png Binary files differnew file mode 100644 index 0000000..3e01635 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.png b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.png Binary files differnew file mode 100644 index 0000000..017d846 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.png Binary files differnew file mode 100644 index 0000000..e48c1fd --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/preliminary.png b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png Binary files differindex fe0da3d..fe0da3d 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/preliminary.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png Binary files differnew file mode 100644 index 0000000..e5856db --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_arrow.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png Binary files differindex 697ac82..697ac82 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_arrow.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_btn_bg.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png Binary files differindex b80c9a8..b80c9a8 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_btn_bg.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_btn_bg.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif Binary files differindex f748097..f748097 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif Binary files differindex e45d0c5..e45d0c5 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e2.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-eg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif Binary files differindex 6196616..6196616 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-eg.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif Binary files differindex 7f6a4eb..7f6a4eb 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif Binary files differindex 99e869c..99e869c 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.png b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png Binary files differindex f3a6d2d..f3a6d2d 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-sg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif Binary files differindex b4bea10..b4bea10 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-sg.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png Binary files differindex 416493f..416493f 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-article.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png Binary files differindex 7273275..7273275 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-article.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-article.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png Binary files differindex 59b6b68..59b6b68 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-sample.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-sample.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png Binary files differindex c32e89a..c32e89a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-tutorial.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-tutorial.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png Binary files differindex 59d46a0..59d46a0 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-big-video.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-big-video.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg Binary files differindex 8050744..8050744 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-card-default-android.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-card-default-android.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png Binary files differindex f7a411c..f7a411c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-sample.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png Binary files differindex 10a14fe..10a14fe 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-tutorial.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png Binary files differindex 8fd5cae..8fd5cae 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-video.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg Binary files differindex 17d2efe..17d2efe 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/right_off.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg Binary files differindex baa2af1..baa2af1 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/right_on.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/sidenav-rule.png b/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png Binary files differindex eab9920..eab9920 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/sidenav-rule.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg Binary files differindex 6d75be1..6d75be1 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_1.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg Binary files differindex aa994c2..aa994c2 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_2.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg Binary files differindex b04deb3..b04deb3 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_3.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg Binary files differindex a992e92..a992e92 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_1.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg Binary files differindex 9af63f4..9af63f4 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_2.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg Binary files differindex fcf236c..fcf236c 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_3.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg Binary files differindex 5971227..5971227 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_off.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg Binary files differindex 7ca3577..7ca3577 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_on.jpg +++ b/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif Binary files differindex f96b355..f96b355 100755 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif +++ b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png Binary files differindex 46d6a50..46d6a50 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/stack-arrow-right.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/stack-arrow-right.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/callout.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png Binary files differindex 5d49f34..5d49f34 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/callout.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png Binary files differindex bab6aca..bab6aca 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span13.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span13.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span8.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png Binary files differindex cb180bf..cb180bf 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_land_span8.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_land_span8.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png Binary files differindex bdccc2f..bdccc2f 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span5.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span5.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span9.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png Binary files differindex 5e0135b..5e0135b 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_galaxynexus_blank_port_span9.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_galaxynexus_blank_port_span9.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus4_blank_port_432.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png Binary files differindex 9d41aa3..9d41aa3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus4_blank_port_432.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus4_blank_port_432.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_land_span13.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png Binary files differindex 5d37121..5d37121 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_land_span13.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_land_span13.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_port_span5.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png Binary files differindex df35117..df35117 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/device_nexus5_blank_port_span5.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_nexus5_blank_port_span5.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png Binary files differnew file mode 100644 index 0000000..077a7e6 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png Binary files differnew file mode 100644 index 0000000..e7e1540 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_down.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png Binary files differindex 6a0a8ee..6a0a8ee 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_down.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_down.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_left.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png Binary files differindex e887b2a..e887b2a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_left.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_left.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_right.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png Binary files differindex ced7fa4..ced7fa4 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_right.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_right.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_up.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png Binary files differindex ddd4ec9..ddd4ec9 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/disclosure_up.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/disclosure_up.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/gototop.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png Binary files differindex 5f09a29..5f09a29 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/gototop.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png Binary files differnew file mode 100644 index 0000000..3c2dc1a --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png Binary files differnew file mode 100644 index 0000000..e34be2e --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_action.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png Binary files differindex 30e4cc7..30e4cc7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_action.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_action.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_good.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png Binary files differindex afebe1c..afebe1c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_good.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_good.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_movie_inline.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png Binary files differindex 7cfb5c5..7cfb5c5 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_movie_inline.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_movie_inline.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_phone_tablet.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png Binary files differindex 003b876..003b876 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_phone_tablet.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_phone_tablet.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_use.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png Binary files differindex 9d868b3..9d868b3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_use.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_use.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_web.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png Binary files differindex 0848e3c..0848e3c 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_web.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_web.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_wrong.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png Binary files differindex b7d04ce..b7d04ce 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/ico_wrong.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/ico_wrong.png diff --git a/tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material.png Binary files differindex 1fb22a2..1fb22a2 100644 --- a/tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material.png diff --git a/tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material@2x.png Binary files differindex bc2f74b..bc2f74b 100644 --- a/tools/droiddoc/templates-sdk/assets/images/styles/notice-designers-material@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-material@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png Binary files differindex eea3485..eea3485 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png Binary files differindex a5fdae3..a5fdae3 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers-video@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers-video@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png Binary files differindex 1fb22a2..1fb22a2 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png Binary files differindex bc2f74b..bc2f74b 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-designers@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-designers@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png Binary files differindex e9f8ed2..e9f8ed2 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png Binary files differindex c067ac1..c067ac1 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers-video@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers-video@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png Binary files differindex a29c31a..a29c31a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers@2x.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png Binary files differindex d42f537..d42f537 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/notice-developers@2x.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/notice-developers@2x.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/open_new_page.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png Binary files differindex 6197e3a..6197e3a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/open_new_page.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/open_new_page.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png Binary files differindex 002364a..002364a 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png Binary files differindex 40a68d9..40a68d9 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened-small.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png Binary files differindex e1eb784..e1eb784 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened-small.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened-small.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png Binary files differindex 789f5fa..789f5fa 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/uiguidelines1.png b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png Binary files differindex 5ce1611..5ce1611 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/uiguidelines1.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/video-droid.png b/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png Binary files differindex 25163b6..25163b6 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/images/video-droid.png +++ b/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png diff --git a/tools/droiddoc/templates-sdk-dyn/assets/js/android_3p-bundle.js b/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js index a67b5b0..a67b5b0 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/js/android_3p-bundle.js +++ b/tools/droiddoc/templates-sdk-dev/assets/js/android_3p-bundle.js diff --git a/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js b/tools/droiddoc/templates-sdk-dev/assets/js/docs.js index e6befe3..7f4be4e 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/js/docs.js +++ b/tools/droiddoc/templates-sdk-dev/assets/js/docs.js @@ -19,9 +19,19 @@ $.ajaxSetup({ /****** ON LOAD SET UP STUFF *********/ -var navBarIsFixed = false; $(document).ready(function() { + // show lang dialog if the URL includes /intl/ + //if (location.pathname.substring(0,6) == "/intl/") { + // var lang = location.pathname.split('/')[2]; + // if (lang != getLangPref()) { + // $("#langMessage a.yes").attr("onclick","changeLangPref('" + lang + // + "', true); $('#langMessage').hide(); return false;"); + // $("#langMessage .lang." + lang).show(); + // $("#langMessage").show(); + // } + //} + // load json file for JD doc search suggestions $.getScript(toRoot + 'jd_lists_unified.js'); // load json file for Android API search suggestions @@ -64,7 +74,12 @@ $(document).ready(function() { $('.scroll-pane').jScrollPane( {verticalGutter:0} ); // add HRs below all H2s (except for a few other h2 variants) - $('h2').not('#qv h2').not('#tb h2').not('.sidebox h2').not('#devdoc-nav h2').not('h2.norule').css({marginBottom:0}).after('<hr/>'); + $('h2').not('#qv h2') + .not('#tb h2') + .not('.sidebox h2') + .not('#devdoc-nav h2') + .not('h2.norule').css({marginBottom:0}) + .after('<hr/>'); // set up the search close button $('.search .close').click(function() { @@ -169,6 +184,18 @@ $(document).ready(function() { $("#header li.design a").addClass("selected"); $("#sticky-header").addClass("design"); + // highlight About tabs + } else if ($("body").hasClass("about")) { + var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1)); + if (rootDir == "about") { + $("#nav-x li.about a").addClass("selected"); + } else if (rootDir == "wear") { + $("#nav-x li.wear a").addClass("selected"); + } else if (rootDir == "tv") { + $("#nav-x li.tv a").addClass("selected"); + } else if (rootDir == "auto") { + $("#nav-x li.auto a").addClass("selected"); + } // highlight Develop tab } else if ($("body").hasClass("develop") || $("body").hasClass("google")) { $("#header li.develop a").addClass("selected"); @@ -207,6 +234,8 @@ $(document).ready(function() { $("#nav-x li.engage a").addClass("selected"); } else if (secondFrag == "monetize") { $("#nav-x li.monetize a").addClass("selected"); + } else if (secondFrag == "analyze") { + $("#nav-x li.analyze a").addClass("selected"); } else if (secondFrag == "tools") { $("#nav-x li.disttools a").addClass("selected"); } else if (secondFrag == "stories") { @@ -218,7 +247,7 @@ $(document).ready(function() { } } else if ($("body").hasClass("about")) { $("#sticky-header").addClass("about"); - } + } // set global variable so we can highlight the sidenav a bit later (such as for google reference) // and highlight the sidenav @@ -239,7 +268,7 @@ $(document).ready(function() { var crossBoundaries = ($("body.design").length > 0) || ($("body.guide").length > 0) ? true : false; // navigate across topic boundaries only in design docs if ($prevListItem.length) { - if ($prevListItem.hasClass('nav-section')) { + if ($prevListItem.hasClass('nav-section') || crossBoundaries) { // jump to last topic of previous section $prevLink = $prevListItem.find('a:last'); } else if (!$selListItem.hasClass('nav-section')) { @@ -262,7 +291,6 @@ false; // navigate across topic boundaries only in design docs // set up next links var $nextLink = []; var startClass = false; - var training = $(".next-class-link").length; // decides whether to provide "next class" link var isCrossingBoundary = false; if ($selListItem.hasClass('nav-section') && $selListItem.children('div.empty').length == 0) { @@ -289,13 +317,15 @@ false; // navigate across topic boundaries only in design docs if ($nextLink.length == 0) { isCrossingBoundary = true; // no more topics in this section, jump to the first topic in the next section - $nextLink = $selListItem.parents('li:eq(0)').next('li.nav-section').find('a:eq(0)'); + $nextLink = $selListItem.parents('li:eq(0)').next('li').find('a:eq(0)'); if (!$nextLink.length) { // Go up another layer to look for next page (lesson > class > course) $nextLink = $selListItem.parents('li:eq(1)').next('li.nav-section').find('a:eq(0)'); if ($nextLink.length == 0) { // if that doesn't work, we're at the end of the list, so disable NEXT link $('.next-page-link').attr('href','').addClass("disabled") .click(function() { return false; }); + // and completely hide the one in the footer + $('.content-footer .next-page-link').hide(); } } } @@ -314,13 +344,19 @@ false; // navigate across topic boundaries only in design docs $('.next-page-link').attr('href','') .removeClass("hide").addClass("disabled") .click(function() { return false; }); + // and completely hide the one in the footer + $('.content-footer .next-page-link').hide(); if ($nextLink.length) { $('.next-class-link').attr('href',$nextLink.attr('href')) - .removeClass("hide").append($nextLink.html()); + .removeClass("hide") + .append(": " + $nextLink.html()); $('.next-class-link').find('.new').empty(); } } else { - $('.next-page-link').attr('href', $nextLink.attr('href')).removeClass("hide"); + $('.next-page-link').attr('href', $nextLink.attr('href')) + .removeClass("hide"); + // for the footer link, also add the next page title + $('.content-footer .next-page-link').append(": " + $nextLink.html()); } if (!startClass && $prevLink.length) { @@ -332,14 +368,6 @@ false; // navigate across topic boundaries only in design docs } } - // If this is a training 'article', there should be no prev/next nav - // ... if the grandparent is the "nav" ... and it has no child list items... - if (training && $selListItem.parents('ul').eq(1).is('[id="nav"]') && - !$selListItem.find('li').length) { - $('.next-page-link,.prev-page-link').attr('href','').addClass("disabled") - .click(function() { return false; }); - } - } @@ -347,7 +375,20 @@ false; // navigate across topic boundaries only in design docs // Set up the course landing pages for Training with class names and descriptions if ($('body.trainingcourse').length) { var $classLinks = $selListItem.find('ul li a').not('#nav .nav-section .nav-section ul a'); - var $classDescriptions = $classLinks.attr('description'); + + // create an array for all the class descriptions + var $classDescriptions = new Array($classLinks.length); + var lang = getLangPref(); + $classLinks.each(function(index) { + var langDescr = $(this).attr(lang + "-description"); + if (typeof langDescr !== 'undefined' && langDescr !== false) { + // if there's a class description in the selected language, use that + $classDescriptions[index] = langDescr; + } else { + // otherwise, use the default english description + $classDescriptions[index] = $(this).attr("description"); + } + }); var $olClasses = $('<ol class="class-list"></ol>'); var $liClass; @@ -359,7 +400,7 @@ false; // navigate across topic boundaries only in design docs $classLinks.each(function(index) { $liClass = $('<li></li>'); $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>'); - $pSummary = $('<p class="description">' + $(this).attr('description') + '</p>'); + $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>'); $olLessons = $('<ol class="lesson-list"></ol>'); @@ -398,7 +439,7 @@ false; // navigate across topic boundaries only in design docs var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]'); setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed // make sidenav behave when resizing the window and side-scolling is a concern - if (navBarIsFixed) { + if (sticky) { if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) { updateSideNavPosition(); } else { @@ -482,7 +523,11 @@ false; // navigate across topic boundaries only in design docs } } + // Resize once loading is finished resizeNav(); + // Check if there's an anchor that we need to scroll into view. + // A delay is needed, because some browsers do not immediately scroll down to the anchor + window.setTimeout(offsetScrollForSticky, 100); /* init the language selector based on user cookie for lang */ loadLangPref(); @@ -515,10 +560,147 @@ false; // navigate across topic boundaries only in design docs cookiePath = "distribute_"; } + + /* setup shadowbox for any videos that want it */ + var $videoLinks = $("a.video-shadowbox-button, a.notice-developers-video"); + if ($videoLinks.length) { + // if there's at least one, add the shadowbox HTML to the body + $('body').prepend( +'<div id="video-container">'+ + '<div id="video-frame">'+ + '<div class="video-close">'+ + '<span id="icon-video-close" onclick="closeVideo()"> </span>'+ + '</div>'+ + '<div id="youTubePlayer"></div>'+ + '</div>'+ +'</div>'); + + // loads the IFrame Player API code asynchronously. + $.getScript("https://www.youtube.com/iframe_api"); + + $videoLinks.each(function() { + var videoId = $(this).attr('href').split('?v=')[1]; + $(this).click(function(event) { + event.preventDefault(); + startYouTubePlayer(videoId); + }); + }); + } }); // END of the onload event +var youTubePlayer; +function onYouTubeIframeAPIReady() { +} + +/* Returns the height the shadowbox video should be. It's based on the current + height of the "video-frame" element, which is 100% height for the window. + Then minus the margin so the video isn't actually the full window height. */ +function getVideoHeight() { + var frameHeight = $("#video-frame").height(); + var marginTop = $("#video-frame").css('margin-top').split('px')[0]; + return frameHeight - (marginTop * 2); +} + +var mPlayerPaused = false; + +function startYouTubePlayer(videoId) { + $("#video-container").show(); + $("#video-frame").show(); + mPlayerPaused = false; + + // compute the size of the player so it's centered in window + var maxWidth = 940; // the width of the web site content + var videoAspect = .5625; // based on 1280x720 resolution + var maxHeight = maxWidth * videoAspect; + var videoHeight = getVideoHeight(); + var videoWidth = videoHeight / videoAspect; + if (videoWidth > maxWidth) { + videoWidth = maxWidth; + videoHeight = maxHeight; + } + $("#video-frame").css('width', videoWidth); + + // check if we've already created this player + if (youTubePlayer == null) { + // check if there's a start time specified + var idAndHash = videoId.split("#"); + var startTime = 0; + if (idAndHash.length > 1) { + startTime = idAndHash[1].split("t=")[1] != undefined ? idAndHash[1].split("t=")[1] : 0; + } + // enable localized player + var lang = getLangPref(); + var captionsOn = lang == 'en' ? 0 : 1; + + youTubePlayer = new YT.Player('youTubePlayer', { + height: videoHeight, + width: videoWidth, + videoId: idAndHash[0], + playerVars: {start: startTime, hl: lang, cc_load_policy: captionsOn}, + events: { + 'onReady': onPlayerReady, + 'onStateChange': onPlayerStateChange + } + }); + } else { + // reset the size in case the user adjusted the window since last play + youTubePlayer.setSize(videoWidth, videoHeight); + // if a video different from the one already playing was requested, cue it up + if (videoId != youTubePlayer.getVideoUrl().split('?v=')[1].split('&')[0].split('%')[0]) { + youTubePlayer.cueVideoById(videoId); + } + youTubePlayer.playVideo(); + } +} + +function onPlayerReady(event) { + event.target.playVideo(); + mPlayerPaused = false; +} + +function closeVideo() { + try { + youTubePlayer.pauseVideo(); + } catch(e) { + } + $("#video-container").fadeOut(200); +} + +/* Track youtube playback for analytics */ +function onPlayerStateChange(event) { + // Video starts, send the video ID + if (event.data == YT.PlayerState.PLAYING) { + if (mPlayerPaused) { + ga('send', 'event', 'Videos', 'Resume', + youTubePlayer.getVideoUrl().split('?v=')[1].split('&')[0].split('%')[0]); + } else { + // track the start playing event so we know from which page the video was selected + ga('send', 'event', 'Videos', 'Start: ' + + youTubePlayer.getVideoUrl().split('?v=')[1].split('&')[0].split('%')[0], + 'on: ' + document.location.href); + } + mPlayerPaused = false; + } + // Video paused, send video ID and video elapsed time + if (event.data == YT.PlayerState.PAUSED) { + ga('send', 'event', 'Videos', 'Paused', + youTubePlayer.getVideoUrl().split('?v=')[1].split('&')[0].split('%')[0], + youTubePlayer.getCurrentTime()); + mPlayerPaused = true; + } + // Video finished, send video ID and video elapsed time + if (event.data == YT.PlayerState.ENDED) { + ga('send', 'event', 'Videos', 'Finished', + youTubePlayer.getVideoUrl().split('?v=')[1].split('&')[0].split('%')[0], + youTubePlayer.getCurrentTime()); + mPlayerPaused = true; + } +} + + + function initExpandableNavItems(rootTag) { $(rootTag + ' li.nav-section .nav-section-header').click(function() { var section = $(this).closest('li.nav-section'); @@ -626,7 +808,7 @@ function toggleFullscreen(enable) { setTimeout(updateSidenavFixedWidth,delay); // need to wait a moment for css to switch enabled = false; } - writeCookie("fullscreen", enabled, null, null); + writeCookie("fullscreen", enabled, null); setNavBarLeftPos(); resizeNav(delay); updateSideNavPosition(); @@ -787,7 +969,7 @@ function reInitScrollbars() { function saveNavPanels() { var basePath = getBaseUri(location.pathname); var section = basePath.substring(1,basePath.indexOf("/",1)); - writeCookie("height", resizePackagesNav.css("height"), section, null); + writeCookie("height", resizePackagesNav.css("height"), section); } @@ -868,118 +1050,110 @@ function readCookie(cookie) { return 0; } -function writeCookie(cookie, val, section, expiration) { +function writeCookie(cookie, val, section) { if (val==undefined) return; section = section == null ? "_" : "_"+section+"_"; - if (expiration == null) { - var date = new Date(); - date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week - expiration = date.toGMTString(); - } + var age = 2*365*24*60*60; // set max-age to 2 years var cookieValue = cookie_namespace + section + cookie + "=" + val - + "; expires=" + expiration+"; path=/"; + + "; max-age=" + age +"; path=/"; document.cookie = cookieValue; } /* ######### END COOKIES! ########## */ - - +var sticky = false; var stickyTop; +var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll /* Sets the vertical scoll position at which the sticky bar should appear. This method is called to reset the position when search results appear or hide */ function setStickyTop() { stickyTop = $('#header-wrapper').outerHeight() - $('#sticky-header').outerHeight(); } - -/* - * Displays sticky nav bar on pages when dac header scrolls out of view +/* + * Displays sticky nav bar on pages when dac header scrolls out of view */ -(function() { - $(document).ready(function() { - - setStickyTop(); - var sticky = false; - var hiding = false; - var $stickyEl = $('#sticky-header'); - var $menuEl = $('.menu-container'); - - var prevScrollLeft = 0; // used to compare current position to previous position of horiz scroll - - $(window).scroll(function() { - // Exit if there's no sidenav - if ($('#side-nav').length == 0) return; - // Exit if the mouse target is a DIV, because that means the event is coming - // from a scrollable div and so there's no need to make adjustments to our layout - if (event.target.nodeName == "DIV") { - return; - } - - - var top = $(window).scrollTop(); - // we set the navbar fixed when the scroll position is beyond the height of the site header... - var shouldBeSticky = top >= stickyTop; - // ... except if the document content is shorter than the sidenav height. - // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing) - if ($("#doc-col").height() < $("#side-nav").height()) { - shouldBeSticky = false; - } - - // Don't continue if the header is sufficently far away - // (to avoid intensive resizing that slows scrolling) - if (sticky && shouldBeSticky) { - return; - } +$(window).scroll(function(event) { + + setStickyTop(); + var hiding = false; + var $stickyEl = $('#sticky-header'); + var $menuEl = $('.menu-container'); + // Exit if there's no sidenav + if ($('#side-nav').length == 0) return; + // Exit if the mouse target is a DIV, because that means the event is coming + // from a scrollable div and so there's no need to make adjustments to our layout + if ($(event.target).nodeName == "DIV") { + return; + } - // Account for horizontal scroll - var scrollLeft = $(window).scrollLeft(); - // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match - if (navBarIsFixed && (scrollLeft != prevScrollLeft)) { - updateSideNavPosition(); - prevScrollLeft = scrollLeft; - } + var top = $(window).scrollTop(); + // we set the navbar fixed when the scroll position is beyond the height of the site header... + var shouldBeSticky = top >= stickyTop; + // ... except if the document content is shorter than the sidenav height. + // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing) + if ($("#doc-col").height() < $("#side-nav").height()) { + shouldBeSticky = false; + } + // Account for horizontal scroll + var scrollLeft = $(window).scrollLeft(); + // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match + if (sticky && (scrollLeft != prevScrollLeft)) { + updateSideNavPosition(); + prevScrollLeft = scrollLeft; + } - // If sticky header visible and position is now near top, hide sticky - if (sticky && !shouldBeSticky) { - sticky = false; - hiding = true; - // make the sidenav static again - $('#devdoc-nav') - .removeClass('fixed') - .css({'width':'auto','margin':''}) - .prependTo('#side-nav'); - // delay hide the sticky - $menuEl.removeClass('sticky-menu'); - $stickyEl.fadeOut(250); - hiding = false; - - // update the sidenaav position for side scrolling - updateSideNavPosition(); - } else if (!sticky && shouldBeSticky) { - sticky = true; - $stickyEl.fadeIn(10); - $menuEl.addClass('sticky-menu'); - - // make the sidenav fixed - var width = $('#devdoc-nav').width(); - $('#devdoc-nav') - .addClass('fixed') - .css({'width':width+'px'}) - .prependTo('#body-content'); - - // update the sidenaav position for side scrolling - updateSideNavPosition(); + // Don't continue if the header is sufficently far away + // (to avoid intensive resizing that slows scrolling) + if (sticky == shouldBeSticky) { + return; + } - } else if (hiding && top < 15) { - $menuEl.removeClass('sticky-menu'); - $stickyEl.hide(); - hiding = false; - } + // If sticky header visible and position is now near top, hide sticky + if (sticky && !shouldBeSticky) { + sticky = false; + hiding = true; + // make the sidenav static again + $('#devdoc-nav') + .removeClass('fixed') + .css({'width':'auto','margin':''}) + .prependTo('#side-nav'); + // delay hide the sticky + $menuEl.removeClass('sticky-menu'); + $stickyEl.fadeOut(250); + hiding = false; + + // update the sidenaav position for side scrolling + updateSideNavPosition(); + } else if (!sticky && shouldBeSticky) { + sticky = true; + $stickyEl.fadeIn(10); + $menuEl.addClass('sticky-menu'); + + // make the sidenav fixed + var width = $('#devdoc-nav').width(); + $('#devdoc-nav') + .addClass('fixed') + .css({'width':width+'px'}) + .prependTo('#body-content'); + + // update the sidenaav position for side scrolling + updateSideNavPosition(); + + } else if (hiding && top < 15) { + $menuEl.removeClass('sticky-menu'); + $stickyEl.hide(); + hiding = false; + } + resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance +}); - resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance - }); +/* + * Manages secion card states and nav resize to conclude loading + */ +(function() { + $(document).ready(function() { // Stack hover states $('.section-card-menu').each(function(index, el) { @@ -990,7 +1164,6 @@ function setStickyTop() { $cardInfo.css({position: 'absolute', bottom:'0px', left:'0px', right:'0px', overflow:'visible'}); }); - resizeNav(); // must resize once loading is finished }); })(); @@ -1060,8 +1233,16 @@ function hideNestedItems(list, toggle) { } +/* Call this to add listeners to a <select> element for Studio/Eclipse/Other docs */ +function setupIdeDocToggle() { + $( "select.ide" ).change(function() { + var selected = $(this).find("option:selected").attr("value"); + $(".select-ide").hide(); + $(".select-ide."+selected).show(); - + $("select.ide").val(selected); + }); +} @@ -1114,9 +1295,7 @@ function swapNav() { nav_pref = NAV_PREF_TREE; init_default_navtree(toRoot); } - var date = new Date(); - date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years - writeCookie("nav", nav_pref, "reference", date.toGMTString()); + writeCookie("nav", nav_pref, "reference"); $("#nav-panels").toggle(); $("#panel-link").toggle(); @@ -1184,11 +1363,7 @@ function changeNavLang(lang) { } function changeLangPref(lang, submit) { - var date = new Date(); - expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); - // keep this for 50 years - //alert("expires: " + expires) - writeCookie("pref_lang", lang, null, expires); + writeCookie("pref_lang", lang, null); // ####### TODO: Remove this condition once we're stable on devsite ####### // This condition is only needed if we still need to support legacy GAE server @@ -1607,8 +1782,8 @@ var gDocsListLength = 0; function onSuggestionClick(link) { // When user clicks a suggested document, track it - _gaq.push(['_trackEvent', 'Suggestion Click', 'clicked: ' + $(link).text(), - 'from: ' + $("#search_autocomplete").val()]); + ga('send', 'event', 'Suggestion Click', 'clicked: ' + $(link).attr('href'), + 'query: ' + $("#search_autocomplete").val().toLowerCase()); } function set_item_selected($li, selected) @@ -1825,8 +2000,12 @@ function search_changed(e, kd, toroot) return false; } } - // Stop here if Google results are showing + // If Google results are showing, return true to allow ajax search to execute else if ($("#searchResults").is(":visible")) { + // Also, if search_results is scrolled out of view, scroll to top to make results visible + if ((sticky ) && (search.value != "")) { + $('body,html').animate({scrollTop:0}, '500', 'swing'); + } return true; } // 38 UP ARROW @@ -1949,7 +2128,7 @@ function search_changed(e, kd, toroot) // Search for matching JD docs - if (text.length >= 3) { + if (text.length >= 2) { // Regex to match only the beginning of a word var textRegex = new RegExp("\\b" + text.toLowerCase(), "g"); @@ -2496,8 +2675,29 @@ google.setOnLoadCallback(function(){ } }, true); +/* Adjust the scroll position to account for sticky header, only if the hash matches an id. + This does not handle <a name=""> tags. Some CSS fixes those, but only for reference docs. */ +function offsetScrollForSticky() { + // Ignore if there's no search bar (some special pages have no header) + if ($("#search-container").length < 1) return; + + var hash = escape(location.hash.substr(1)); + var $matchingElement = $("#"+hash); + // Sanity check that there's an element with that ID on the page + if ($matchingElement.length) { + // If the position of the target element is near the top of the page (<20px, where we expect it + // to be because we need to move it down 60px to become in view), then move it down 60px + if (Math.abs($matchingElement.offset().top - $(window).scrollTop()) < 20) { + $(window).scrollTop($(window).scrollTop() - 60); + } + } +} + // when an event on the browser history occurs (back, forward, load) requery hash and do search $(window).hashchange( function(){ + // Ignore if there's no search bar (some special pages have no header) + if ($("#search-container").length < 1) return; + // If the hash isn't a search query or there's an error in the query, // then adjust the scroll position to account for sticky header, then exit. if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) { @@ -2505,8 +2705,7 @@ $(window).hashchange( function(){ if (!$("#searchResults").is(":hidden")) { hideResults(); } - // Adjust the scroll position to account for sticky header - $(window).scrollTop($(window).scrollTop() - 60); + offsetScrollForSticky(); return; } @@ -2557,8 +2756,8 @@ function addResultClickListeners() { $("#searchResults a.gs-title").each(function(index, link) { // When user clicks enter for Google search results, track it $(link).click(function() { - _gaq.push(['_trackEvent', 'Google Click', 'clicked: ' + $(this).text(), - 'from: ' + $("#search_autocomplete").val()]); + ga('send', 'event', 'Google Click', 'clicked: ' + $(this).attr('href'), + 'query: ' + $("#search_autocomplete").val().toLowerCase()); }); }); } @@ -2621,7 +2820,7 @@ var maxLevel = 1; } function updateSidenavFixedWidth() { - if (!navBarIsFixed) return; + if (!sticky) return; $('#devdoc-nav').css({ 'width' : $('#side-nav').css('width'), 'margin' : $('#side-nav').css('margin') @@ -2632,7 +2831,7 @@ function updateSidenavFixedWidth() { } function updateSidenavFullscreenWidth() { - if (!navBarIsFixed) return; + if (!sticky) return; $('#devdoc-nav').css({ 'width' : $('#side-nav').css('width'), 'margin' : $('#side-nav').css('margin') @@ -2673,10 +2872,7 @@ function changeApiLevel() { selectedLevel = parseInt($("#apiLevelSelector option:selected").val()); toggleVisisbleApis(selectedLevel, "body"); - var date = new Date(); - date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years - var expiration = date.toGMTString(); - writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration); + writeCookie(API_LEVEL_COOKIE, selectedLevel, null); if (selectedLevel < minLevel) { var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class"; @@ -3349,7 +3545,7 @@ function showSamples() { showing lines that are cut off. This works with the css ellipsis classes to fade last text line and apply an ellipsis char. */ - //card text currently uses 15px line height. + //card text currently uses 15px line height. var lineHeight = 15; $('.card-info .text').ellipsisfade(lineHeight); }); @@ -3380,7 +3576,10 @@ function showSamples() { sortOrder: $widget.data('sortorder'), query: $widget.data('query'), section: $widget.data('section'), - sizeCols: sizeCols + sizeCols: sizeCols, + /* Added by LFL 6/6/14 */ + resourceStyle: $widget.data('resourcestyle') || 'card', + stackSort: $widget.data('stacksort') || 'true' }; // run the search for the set of resources to show @@ -3392,9 +3591,13 @@ function showSamples() { } else if (isCarousel) { drawResourcesCarouselWidget($widget, opts, resources); } else if (isStack) { - var sections = buildSectionList(opts); + /* Looks like this got removed and is not used, so repurposing for the + homepage style layout. + Modified by LFL 6/6/14 + */ + //var sections = buildSectionList(opts); opts['numStacks'] = $widget.data('numstacks'); - drawResourcesStackWidget($widget, opts, resources, sections); + drawResourcesStackWidget($widget, opts, resources/*, sections*/); } } @@ -3413,10 +3616,8 @@ function showSamples() { var $ul = $('<ul>'); for (var i = 0; i < resources.length; ++i) { - //keep url clean for matching and offline mode handling - var urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot; var $card = $('<a>') - .attr('href', urlPrefix + resources[i].url) + .attr('href', cleanUrl(resources[i].url)) .decorateResourceCard(resources[i],plusone); $('<li>').css(css) @@ -3435,7 +3636,9 @@ function showSamples() { }); }; - /* Initializes a Resource Card Stack Widget (column-based layout) */ + /* Initializes a Resource Card Stack Widget (column-based layout) + Modified by LFL 6/6/14 + */ function drawResourcesStackWidget($widget, opts, resources, sections) { // Don't empty widget, grab all items inside since they will be the first // items stacked, followed by the resource query @@ -3453,60 +3656,88 @@ function showSamples() { var sectionResources = []; // Extract any subsections that are actually resource cards - for (var i = 0; i < sections.length; ++i) { - if (!sections[i].sections || !sections[i].sections.length) { - //keep url clean for matching and offline mode handling - urlPrefix = sections[i].url.indexOf("//") > -1 ? "" : toRoot; - // Render it as a resource card - - sectionResources.push( - $('<a>') - .addClass('resource-card section-card') - .attr('href', urlPrefix + sections[i].resource.url) - .decorateResourceCard(sections[i].resource,plusone)[0] - ); + if (sections) { + for (var i = 0; i < sections.length; ++i) { + if (!sections[i].sections || !sections[i].sections.length) { + // Render it as a resource card + sectionResources.push( + $('<a>') + .addClass('resource-card section-card') + .attr('href', cleanUrl(sections[i].resource.url)) + .decorateResourceCard(sections[i].resource,plusone)[0] + ); - } else { - cards.push( - $('<div>') - .addClass('resource-card section-card-menu') - .decorateResourceSection(sections[i],plusone)[0] - ); + } else { + cards.push( + $('<div>') + .addClass('resource-card section-card-menu') + .decorateResourceSection(sections[i],plusone)[0] + ); + } } } cards = cards.concat(sectionResources); for (var i = 0; i < resources.length; ++i) { - //keep url clean for matching and offline mode handling - urlPrefix = resources[i].url.indexOf("//") > -1 ? "" : toRoot; - var $card = $('<a>') - .addClass('resource-card related-card') - .attr('href', urlPrefix + resources[i].url) - .decorateResourceCard(resources[i],plusone); + var $card = createResourceElement(resources[i], opts); + + if (opts.resourceStyle.indexOf('related') > -1) { + $card.addClass('related-card'); + } cards.push($card[0]); } - for (var i = 0; i < cards.length; ++i) { - // Find the stack with the shortest height, but give preference to - // left to right order. - var minHeight = $stacks[0].height(); - var minIndex = 0; - - for (var j = 1; j < numStacks; ++j) { - var height = $stacks[j].height(); - if (height < minHeight - 45) { - minHeight = height; - minIndex = j; + if (opts.stackSort != 'false') { + for (var i = 0; i < cards.length; ++i) { + // Find the stack with the shortest height, but give preference to + // left to right order. + var minHeight = $stacks[0].height(); + var minIndex = 0; + + for (var j = 1; j < numStacks; ++j) { + var height = $stacks[j].height(); + if (height < minHeight - 45) { + minHeight = height; + minIndex = j; + } } - } - $stacks[minIndex].append($(cards[i])); + $stacks[minIndex].append($(cards[i])); + } } }; + /* + Create a resource card using the given resource object and a list of html + configured options. Returns a jquery object containing the element. + */ + function createResourceElement(resource, opts, plusone) { + var $el; + + // The difference here is that generic cards are not entirely clickable + // so its a div instead of an a tag, also the generic one is not given + // the resource-card class so it appears with a transparent background + // and can be styled in whatever way the css setup. + if (opts.resourceStyle == 'generic') { + $el = $('<div>') + .addClass('resource') + .attr('href', cleanUrl(resource.url)) + .decorateResource(resource, opts); + } else { + var cls = 'resource resource-card'; + + $el = $('<a>') + .addClass(cls) + .attr('href', cleanUrl(resource.url)) + .decorateResourceCard(resource, plusone); + } + + return $el; + } + /* Initializes a flow widget, see distribute.scss for generating accompanying css */ function drawResourcesFlowWidget($widget, opts, resources) { $widget.empty(); @@ -3517,7 +3748,6 @@ function showSamples() { while (i < resources.length) { var cardSize = cardSizes[j++ % cardSizes.length]; cardSize = cardSize.replace(/^\s+|\s+$/,''); - console.log("cardsize is " + cardSize); // Some card sizes do not get a plusone button, such as where space is constrained // or for cards commonly embedded in docs (to improve overall page speed). plusone = !((cardSize == "6x2") || (cardSize == "6x3") || @@ -3539,11 +3769,11 @@ function showSamples() { // Build each stack item or just a single item do { var resource = resources[i]; - //keep url clean for matching and offline mode handling - urlPrefix = resource.url.indexOf("//") > -1 ? "" : toRoot; - var $card = $('<a>') - .addClass('resource-card resource-card-' + cardSize + ' resource-card-' + resource.type) - .attr('href', urlPrefix + resource.url); + + var $card = createResourceElement(resources[i], opts, plusone); + + $card.addClass('resource-card-' + cardSize + + ' resource-card-' + resource.type); if (isStack) { $card.addClass('resource-card-' + isStack[1] + 'x' + isStack[2]); @@ -3555,8 +3785,7 @@ function showSamples() { stackCount = 0; } - $card.decorateResourceCard(resource,plusone) - .appendTo($stackDiv || $widget); + $card.appendTo($stackDiv || $widget); } while (++i < resources.length && stackCount > 0); } @@ -3696,6 +3925,15 @@ function showSamples() { return true; } + function cleanUrl(url) + { + if (url && url.indexOf('//') === -1) { + url = toRoot + url; + } + + return url; + } + function parseResourceQuery(query) { // Parse query into array of expressions (expression e.g. 'tag:foo + type:video') @@ -3743,42 +3981,56 @@ function showSamples() { })(); (function($) { + + /* + Utility method for creating dom for the description area of a card. + Used in decorateResourceCard and decorateResource. + */ + function buildResourceCardDescription(resource, plusone) { + var $description = $('<div>').addClass('description ellipsis'); + + $description.append($('<div>').addClass('text').html(resource.summary)); + + if (resource.cta) { + $description.append($('<a>').addClass('cta').html(resource.cta)); + } + + if (plusone) { + var plusurl = resource.url.indexOf("//") > -1 ? resource.url : + "//developer.android.com/" + resource.url; + + $description.append($('<div>').addClass('util') + .append($('<div>').addClass('g-plusone') + .attr('data-size', 'small') + .attr('data-align', 'right') + .attr('data-href', plusurl))); + } + + return $description; + } + + /* Simple jquery function to create dom for a standard resource card */ $.fn.decorateResourceCard = function(resource,plusone) { var section = resource.group || resource.type; - var imgUrl; - if (resource.image) { - //keep url clean for matching and offline mode handling - var urlPrefix = resource.image.indexOf("//") > -1 ? "" : toRoot; - imgUrl = urlPrefix + resource.image; - } - //add linkout logic here. check url or type, assign a class, map to css :after - $('<div>') - .addClass('card-bg') - .css('background-image', 'url(' + (imgUrl || toRoot + 'assets/images/resource-card-default-android.jpg') + ')') - .appendTo(this); - if (!plusone) { - $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : '')) - .append($('<div>').addClass('section').text(section)) - .append($('<div>').addClass('title').html(resource.title)) - .append($('<div>').addClass('description ellipsis') - .append($('<div>').addClass('text').html(resource.summary)) - .append($('<div>').addClass('util'))) - .appendTo(this); - } else { - $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : '')) - .append($('<div>').addClass('section').text(section)) - .append($('<div>').addClass('title').html(resource.title)) - .append($('<div>').addClass('description ellipsis') - .append($('<div>').addClass('text').html(resource.summary)) - .append($('<div>').addClass('util') - .append($('<div>').addClass('g-plusone') - .attr('data-size', 'small') - .attr('data-align', 'right') - .attr('data-href', resource.url)))) - .appendTo(this); + var imgUrl = resource.image || + 'assets/images/resource-card-default-android.jpg'; + + if (imgUrl.indexOf('//') === -1) { + imgUrl = toRoot + imgUrl; } + $('<div>').addClass('card-bg') + .css('background-image', 'url(' + (imgUrl || toRoot + + 'assets/images/resource-card-default-android.jpg') + ')') + .appendTo(this); + + $('<div>').addClass('card-info' + (!resource.summary ? ' empty-desc' : '')) + .append($('<div>').addClass('section').text(section)) + .append($('<div>').addClass('title').html(resource.title)) + .append(buildResourceCardDescription(resource, plusone)) + .appendTo(this); + return this; }; @@ -3860,7 +4112,39 @@ function showSamples() { return this; }; + + + + + /* Render other types of resource styles that are not cards. */ + $.fn.decorateResource = function(resource, opts) { + var imgUrl = resource.image || + 'assets/images/resource-card-default-android.jpg'; + var linkUrl = resource.url; + + if (imgUrl.indexOf('//') === -1) { + imgUrl = toRoot + imgUrl; + } + + if (linkUrl && linkUrl.indexOf('//') === -1) { + linkUrl = toRoot + linkUrl; + } + + $(this).append( + $('<div>').addClass('image') + .css('background-image', 'url(' + imgUrl + ')'), + $('<div>').addClass('info').append( + $('<h4>').addClass('title').html(resource.title), + $('<p>').addClass('summary').html(resource.summary), + $('<a>').attr('href', linkUrl).addClass('cta').html('Learn More') + ) + ); + + return this; + }; })(jQuery); + + /* Calculate the vertical area remaining */ (function($) { $.fn.ellipsisfade= function(lineHeight) { @@ -3870,8 +4154,10 @@ function showSamples() { var remainingHeight = $this.parent().parent().height(); $this.parent().siblings().each(function () { - var h = $(this).height(); - remainingHeight = remainingHeight - h; + if ($(this).is(":visible")) { + var h = $(this).height(); + remainingHeight = remainingHeight - h; + } }); adjustedRemainingHeight = ((remainingHeight)/lineHeight>>0)*lineHeight @@ -3882,3 +4168,189 @@ function showSamples() { return this; }; }) (jQuery); + +/* + Fullscreen Carousel + + The following allows for an area at the top of the page that takes over the + entire browser height except for its top offset and an optional bottom + padding specified as a data attribute. + + HTML: + + <div class="fullscreen-carousel"> + <div class="fullscreen-carousel-content"> + <!-- content here --> + </div> + <div class="fullscreen-carousel-content"> + <!-- content here --> + </div> + + etc ... + + </div> + + Control over how the carousel takes over the screen can mostly be defined in + a css file. Setting min-height on the .fullscreen-carousel-content elements + will prevent them from shrinking to far vertically when the browser is very + short, and setting max-height on the .fullscreen-carousel itself will prevent + the area from becoming to long in the case that the browser is stretched very + tall. + + There is limited functionality for having multiple sections since that request + was removed, but it is possible to add .next-arrow and .prev-arrow elements to + scroll between multiple content areas. +*/ + +(function() { + $(document).ready(function() { + $('.fullscreen-carousel').each(function() { + initWidget(this); + }); + }); + + function initWidget(widget) { + var $widget = $(widget); + + var topOffset = $widget.offset().top; + var padBottom = parseInt($widget.data('paddingbottom')) || 0; + var maxHeight = 0; + var minHeight = 0; + var $content = $widget.find('.fullscreen-carousel-content'); + var $nextArrow = $widget.find('.next-arrow'); + var $prevArrow = $widget.find('.prev-arrow'); + var $curSection = $($content[0]); + + if ($content.length <= 1) { + $nextArrow.hide(); + $prevArrow.hide(); + } else { + $nextArrow.click(function() { + var index = ($content.index($curSection) + 1); + $curSection.hide(); + $curSection = $($content[index >= $content.length ? 0 : index]); + $curSection.show(); + }); + + $prevArrow.click(function() { + var index = ($content.index($curSection) - 1); + $curSection.hide(); + $curSection = $($content[index < 0 ? $content.length - 1 : 0]); + $curSection.show(); + }); + } + + // Just hide all content sections except first. + $content.each(function(index) { + if ($(this).height() > minHeight) minHeight = $(this).height(); + $(this).css({position: 'absolute', display: index > 0 ? 'none' : ''}); + }); + + // Register for changes to window size, and trigger. + $(window).resize(resizeWidget); + resizeWidget(); + + function resizeWidget() { + var height = $(window).height() - topOffset - padBottom; + $widget.width($(window).width()); + $widget.height(height < minHeight ? minHeight : + (maxHeight && height > maxHeight ? maxHeight : height)); + } + } +})(); + + + + + +/* + Tab Carousel + + The following allows tab widgets to be installed via the html below. Each + tab content section should have a data-tab attribute matching one of the + nav items'. Also each tab content section should have a width matching the + tab carousel. + + HTML: + + <div class="tab-carousel"> + <ul class="tab-nav"> + <li><a href="#" data-tab="handsets">Handsets</a> + <li><a href="#" data-tab="wearable">Wearable</a> + <li><a href="#" data-tab="tv">TV</a> + </ul> + + <div class="tab-carousel-content"> + <div data-tab="handsets"> + <!--Full width content here--> + </div> + + <div data-tab="wearable"> + <!--Full width content here--> + </div> + + <div data-tab="tv"> + <!--Full width content here--> + </div> + </div> + </div> + +*/ +(function() { + $(document).ready(function() { + $('.tab-carousel').each(function() { + initWidget(this); + }); + }); + + function initWidget(widget) { + var $widget = $(widget); + var $nav = $widget.find('.tab-nav'); + var $anchors = $nav.find('[data-tab]'); + var $li = $nav.find('li'); + var $contentContainer = $widget.find('.tab-carousel-content'); + var $tabs = $contentContainer.find('[data-tab]'); + var $curTab = $($tabs[0]); // Current tab is first tab. + var width = $widget.width(); + + // Setup nav interactivity. + $anchors.click(function(evt) { + evt.preventDefault(); + var query = '[data-tab=' + $(this).data('tab') + ']'; + transitionWidget($tabs.filter(query)); + }); + + // Add highlight for navigation on first item. + var $highlight = $('<div>').addClass('highlight') + .css({left:$li.position().left + 'px', width:$li.outerWidth() + 'px'}) + .appendTo($nav); + + // Store height since we will change contents to absolute. + $contentContainer.height($contentContainer.height()); + + // Absolutely position tabs so they're ready for transition. + $tabs.each(function(index) { + $(this).css({position: 'absolute', left: index > 0 ? width + 'px' : '0'}); + }); + + function transitionWidget($toTab) { + if (!$curTab.is($toTab)) { + var curIndex = $tabs.index($curTab[0]); + var toIndex = $tabs.index($toTab[0]); + var dir = toIndex > curIndex ? 1 : -1; + + // Animate content sections. + $toTab.css({left:(width * dir) + 'px'}); + $curTab.animate({left:(width * -dir) + 'px'}); + $toTab.animate({left:'0'}); + + // Animate navigation highlight. + $highlight.animate({left:$($li[toIndex]).position().left + 'px', + width:$($li[toIndex]).outerWidth() + 'px'}) + + // Store new current section. + $curTab = $toTab; + } + } + } +})(); diff --git a/tools/droiddoc/templates-sdk-dyn/assets/js/prettify.js b/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js index eef5ad7..eef5ad7 100644 --- a/tools/droiddoc/templates-sdk-dyn/assets/js/prettify.js +++ b/tools/droiddoc/templates-sdk-dev/assets/js/prettify.js diff --git a/tools/droiddoc/templates-sdk-dyn/class.cs b/tools/droiddoc/templates-sdk-dev/class.cs index 0461af6..693eaed 100644 --- a/tools/droiddoc/templates-sdk-dyn/class.cs +++ b/tools/droiddoc/templates-sdk-dev/class.cs @@ -1,9 +1,12 @@ <?cs include:"doctype.cs" ?> <?cs include:"macros.cs" ?> +<?cs include:"macros_override.cs" ?> <html<?cs if:devsite ?> devsite<?cs /if ?>> <?cs include:"head_tag.cs" ?> <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?> <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs + if:reference ?> reference<?cs + /if ?><?cs elif:design ?>design<?cs elif:distribute ?>distribute<?cs /if ?>" itemscope itemtype="http://schema.org/Article"> @@ -123,6 +126,7 @@ Summary: <?cs /if ?> <?cs set:colspan = colspan-1 ?> <?cs /each ?> +<?cs call:show_annotations_list(class) ?> </div><!-- end header --> @@ -165,13 +169,15 @@ Summary: <div class="jd-descr"> <?cs call:deprecated_warning(class) ?> -<?cs if:subcount(class.descr) ?> +<?cs if:subcount(class.descr) || subcount(class.annotationdocumentation) ?> <h2>Class Overview</h2> -<p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p> +<?cs if:subcount(class.descr) ?><p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p><?cs /if ?> +<?cs if:subcount(class.annotationdocumentation) ?><?cs each:annodoc = class.annotationdocumentation?> +<p><?cs var:annodoc.text ?></p> +<?cs /each?><?cs /if?> <?cs /if ?> <?cs call:see_also_tags(class.seeAlso) ?> - </div><!-- jd-descr --> @@ -192,9 +198,12 @@ Summary: </td> <td class="jd-linkcol" width="100%"><nobr> <span class="sympad"><?cs call:cond_link(method.name, toroot, method.href, included) ?></span>(<?cs call:parameter_list(method.params) ?>)</nobr> - <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?> - <div class="jd-descrdiv"><?cs call:short_descr(method) ?></div> - <?cs /if ?> + <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) || subcount(method.showAnnotations) ?> + <div class="jd-descrdiv"> + <?cs if:subcount(method.shortDescr) || subcount(method.annotationdocumentation) ?><?cs call:short_descr(method)?><?cs /if?> + <?cs call:show_annotations_list(method) ?> + </div> + <?cs /if ?> </td></tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -210,7 +219,10 @@ Summary: <?cs var:field.final ?> <?cs call:type_link(field.type) ?></nobr></td> <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(field) ?> + <?cs call:show_annotations_list(field) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -222,7 +234,10 @@ Summary: <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" > <td class="jd-typecol"><?cs call:type_link(field.type) ?></td> <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, included) ?></td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?></td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(field) ?> + <?cs call:show_annotations_list(field) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -242,7 +257,10 @@ Summary: <?cs call:cond_link(m.name, toroot, m.href, included) ?> <?cs /each ?> </td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(attr) ?> </td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(attr) ?> + <?cs call:show_annotations_list(attr) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -259,7 +277,10 @@ Summary: <?cs var:cl.abstract ?> <?cs var:cl.kind ?></nobr></td> <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?> </td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(cl) ?> + <?cs call:show_annotations_list(cl) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -335,7 +356,10 @@ Summary: <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:field.since ?>" > <td class="jd-descrcol"><?cs call:type_link(field.type) ?> </td> <td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?> </td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?> </td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(field) ?> + <?cs call:show_annotations_list(field) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -504,6 +528,7 @@ From <?cs var:cl.kind ?> <?cs call:federated_refs(field) ?> </div> <div class="jd-details-descr"> + <?cs call:show_annotations_list(field) ?> <?cs call:description(field) ?> <?cs if:subcount(field.constantValue) ?> <div class="jd-tagdata"> @@ -546,6 +571,7 @@ From <?cs var:cl.kind ?> <?cs call:federated_refs(method) ?> </div> <div class="jd-details-descr"> + <?cs call:show_annotations_list(method) ?> <?cs call:description(method) ?> </div> </div> @@ -560,6 +586,7 @@ From <?cs var:cl.kind ?> <h4 class="jd-details-title"><?cs var:attr.name ?> </h4> <div class="jd-details-descr"> + <?cs call:show_annotations_list(attr) ?> <?cs call:description(attr) ?> <div class="jd-tagdata"> diff --git a/tools/droiddoc/templates-sdk-dyn/classes.cs b/tools/droiddoc/templates-sdk-dev/classes.cs index 6769f47..405892d 100644 --- a/tools/droiddoc/templates-sdk-dyn/classes.cs +++ b/tools/droiddoc/templates-sdk-dev/classes.cs @@ -1,9 +1,12 @@ <?cs include:"doctype.cs" ?> <?cs include:"macros.cs" ?> +<?cs include:"macros_override.cs" ?> <html<?cs if:devsite ?> devsite<?cs /if ?>> <?cs include:"head_tag.cs" ?> <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?> <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs + if:reference ?> reference<?cs + /if ?><?cs elif:design ?>design<?cs elif:distribute ?>distribute<?cs /if ?>" itemscope itemtype="http://schema.org/Article"> @@ -30,7 +33,10 @@ <?cs each:cl = letter ?> <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.since ?>" > <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td> - <td class="jd-descrcol" width="100%"><?cs call:short_descr(cl) ?> </td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(cl) ?> + <?cs call:show_annotations_list(cl) ?> + </td> </tr> <?cs set:count = count + #1 ?> <?cs /each ?> diff --git a/tools/droiddoc/templates-sdk-dyn/components/masthead.cs b/tools/droiddoc/templates-sdk-dev/components/masthead.cs index d0ff64d..d48ea29 100644 --- a/tools/droiddoc/templates-sdk-dyn/components/masthead.cs +++ b/tools/droiddoc/templates-sdk-dev/components/masthead.cs @@ -1,12 +1,58 @@ <?cs def:custom_masthead() ?> -<?cs if:wear ?> - <?cs call:wear_masthead() ?> +<?cs if:preview ?> + <?cs call:preview_masthead() ?> <?cs else ?> <a name="top"></a> + +<!-- dialog to prompt lang pref change when loaded from hardcoded URL +<div id="langMessage" style="display:none"> + <div> + <div class="lang en"> + <p>You requested a page in English, would you like to proceed with this language setting?</p> + </div> + <div class="lang es"> + <p>You requested a page in Spanish (Español), would you like to proceed with this language setting?</p> + </div> + <div class="lang ja"> + <p>You requested a page in Japanese (日本語), would you like to proceed with this language setting?</p> + </div> + <div class="lang ko"> + <p>You requested a page in Korean (한국어), would you like to proceed with this language setting?</p> + </div> + <div class="lang ru"> + <p>You requested a page in Russian (Русский), would you like to proceed with this language setting?</p> + </div> + <div class="lang zh-cn"> + <p>You requested a page in Simplified Chinese (简体中文), would you like to proceed with this language setting?</p> + </div> + <div class="lang zh-tw"> + <p>You requested a page in Traditional Chinese (繁體中文), would you like to proceed with this language setting?</p> + </div> + <a href="#" class="button yes" onclick="return false;"> + <span class="lang en">Yes</span> + <span class="lang es">Sí</span> + <span class="lang ja">Yes</span> + <span class="lang ko">Yes</span> + <span class="lang ru">Yes</span> + <span class="lang zh-cn">是的</span> + <span class="lang zh-tw">没有</span> + </a> + <a href="#" class="button" onclick="$('#langMessage').hide();return false;"> + <span class="lang en">No</span> + <span class="lang es">No</span> + <span class="lang ja">No</span> + <span class="lang ko">No</span> + <span class="lang ru">No</span> + <span class="lang zh-cn">没有</span> + <span class="lang zh-tw">没有</span> + </a> + </div> +</div> --> + <?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?> <!-- Header --> <div id="header-wrapper"> - <div id="header"> + <div id="header"><?cs call:butter_bar() ?> <div class="wrap" id="header-wrap"> <div class="col-3 logo"> <a href="<?cs var:toroot ?>index.html"> @@ -54,11 +100,20 @@ <!-- Expanded quicknav --> - <div id="quicknav" class="col-9"> + <div id="quicknav" class="col-13"> <ul> + <li class="about"> + <ul> + <li><a href="<?cs var:toroot ?>about/index.html">About</a></li> + <li><a href="<?cs var:toroot ?>wear/index.html">Wear</a></li> + <li><a href="<?cs var:toroot ?>tv/index.html">TV</a></li> + <li><a href="<?cs var:toroot ?>auto/index.html">Auto</a></li> + </ul> + </li> <li class="design"> <ul> <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li> + <li><a href="<?cs var:toroot ?>design/devices.html">Devices</a></li> <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li> <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li> <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li> @@ -92,7 +147,7 @@ ja-lang="リファレンス" es-lang="Referencia" >Reference</a></li> - <li><a href="<?cs var:toroot ?>tools/index.html" + <li><a href="<?cs var:toroot ?>sdk/index.html" zh-tw-lang="相關工具" zh-cn-lang="工具" ru-lang="Инструменты" @@ -100,7 +155,6 @@ ja-lang="ツール" es-lang="Herramientas" >Tools</a> - <ul><li><a href="<?cs var:toroot ?>sdk/index.html">Get the SDK</a></li></ul> </li> <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a> </li> @@ -117,6 +171,7 @@ <li><a href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li> <li><a href="<?cs var:toroot ?>distribute/engage/index.html">Engage & Retain</a></li> <li><a href="<?cs var:toroot ?>distribute/monetize/index.html">Monetize</a></li> + <li><a href="<?cs var:toroot ?>distribute/analyze/index.html">Analyze</a></li> <li><a href="<?cs var:toroot ?>distribute/tools/index.html">Tools & Reference</a></li> <li><a href="<?cs var:toroot ?>distribute/stories/index.html">Developer Stories</a></li> </ul> @@ -126,10 +181,35 @@ </div><!-- end header-wrap.wrap --> </div><!-- end header --> - <?cs if:training || guide || reference || tools || develop || google || samples ?> + <?cs if:about || wear || tv || auto ?> <!-- Secondary x-nav --> <div id="nav-x"> <div class="wrap"> + <ul class="nav-x col-9 about" style="width:100%"> + <li class="about"><a href="<?cs var:toroot ?>about/index.html" + >About</a></li> + <li class="wear"><a href="<?cs var:toroot ?>wear/index.html" + >Wear</a></li> + <li class="tv"><a href="<?cs var:toroot ?>tv/index.html" + >TV</a></li> + <li class="auto"><a href="<?cs var:toroot ?>auto/index.html" + >Auto</a></li> + </ul> + </div> + </div> + <!-- /Sendondary x-nav ABOUT --> + + + + <?cs elif:training || guide || reference || tools || develop || google || samples ?> + <!-- Secondary x-nav --> + <div id="nav-x"> + <div class="wrap" style="position:relative;z-index:1"> + + <?cs if:reference ?> + + <?cs /if ?> + <ul class="nav-x col-9 develop" style="width:100%"> <li class="training"><a href="<?cs var:toroot ?>training/index.html" zh-tw-lang="訓練課程" @@ -155,7 +235,7 @@ ja-lang="リファレンス" es-lang="Referencia" >Reference</a></li> - <li class="tools"><a href="<?cs var:toroot ?>tools/index.html" + <li class="tools"><a href="<?cs var:toroot ?>sdk/index.html" zh-tw-lang="相關工具" zh-cn-lang="工具" ru-lang="Инструменты" @@ -174,9 +254,9 @@ </ul> </div> </div> - <!-- /Sendondary x-nav --> + <!-- /Sendondary x-nav DEVELOP --> - <?cs elif:distribute || googleplay || essentials || users || engage || monetize || disttools || stories ?> + <?cs elif:distribute || googleplay || essentials || users || engage || monetize || analyze || disttools || stories ?> <!-- Secondary distribute x-nav --> <div id="nav-x"> <div class="wrap"> @@ -192,6 +272,9 @@ <li class="monetize"><a href="<?cs var:toroot ?>distribute/monetize/index.html" >Monetize</a> </li> + <li class="analyze"><a href="<?cs var:toroot ?>distribute/analyze/index.html" + >Analyze</a> + </li> <li class="disttools"><a href="<?cs var:toroot ?>distribute/tools/index.html" >Tools</a> </li> @@ -202,6 +285,7 @@ <a href="https://play.google.com/apps/publish/" class="developer-console-btn">Developer Console</a> </div> <!-- /Secondary distribute x-nav --> </div> + <!-- /Sendondary x-nav DISTRIBUTE --> <?cs /if ?> <div id="searchResults" class="wrap" style="display:none;"> @@ -223,23 +307,25 @@ </div> <?cs /if ?><?cs # end if/else !devsite ?> -<?cs /if ?><?cs # end if/else wear ?><?cs +<?cs /if ?><?cs # end if/else preview ?><?cs /def ?> -<?cs def:wear_masthead() ?> +<?cs def:preview_masthead() ?> <a name="top"></a> + <!-- Header --> <div id="header-wrapper"> - <div id="header"> + <div id="header"><?cs call:butter_bar() ?> <div class="wrap" id="header-wrap"> - <div class="col_3 logo wear-logo"> - <a href="<?cs var:toroot ?>wear/index.html"> - <img src="<?cs var:toroot ?>wear/images/android-wear.png" height="16" alt="Android Wear" /> + <div class="col_3 logo landing-logo" style="width:240px"> + <a href="<?cs var:toroot ?>preview/index.html"> + <img src="<?cs var:toroot ?>assets/images/android.png" height="25" alt="Android" + style="margin:-3px 0 0" /> </a> </div> - <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px; -color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div> + <div class="col-8" style="margin:0"><h1 style="margin: 4px 0 0 0px;padding:0;line-height:16px; +color:#666;font-weight:100;font-size:27px;">M Developer Preview</h1></div> <?cs # ADD SEARCH AND MENU ?> <?cs call:header_search_widget() ?> @@ -268,3 +354,22 @@ color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div> <?cs /def ?> + + +<?cs # (UN)COMMENT THE INSIDE OF THIS METHOD TO TOGGLE VISIBILITY ?> +<?cs def:butter_bar() ?> + +<?cs # HIDE THE BUTTER BAR + + <div style="height:20px"><!-- spacer to bump header down --></div> + <div id="butterbar-wrapper"> + <div id="butterbar"> + <a href="http://googleblog.blogspot.com/" id="butterbar-message"> + The Android {version_number} SDK will be available on {Month} {Day}! + </a> + </div> + </div> + +?> + +<?cs /def ?> diff --git a/tools/droiddoc/templates-sdk-dyn/customizations.cs b/tools/droiddoc/templates-sdk-dev/customizations.cs index 27822d5..c8c88cc 100644 --- a/tools/droiddoc/templates-sdk-dyn/customizations.cs +++ b/tools/droiddoc/templates-sdk-dev/customizations.cs @@ -112,6 +112,20 @@ def:engage_nav() ?> </script> <?cs /def ?><?cs +def:analyze_nav() ?> + <div class="wrap clearfix" id="body-content"> + <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div id="devdoc-nav" class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/distribute/analyze/analyze_toc.cs" ?> + </div> + </div> <!-- end side-nav --> + <script> + $(document).ready(function() { + scrollIntoView("devdoc-nav"); + }); + </script> +<?cs /def ?><?cs + def:monetize_nav() ?> <div class="wrap clearfix" id="body-content"> <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> @@ -290,6 +304,22 @@ def:wear_nav() ?> </script> <?cs /def ?> +<?cs +def:preview_nav() ?> + <div class="wrap clearfix" id="body-content"> + <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div id="devdoc-nav" class="scroll-pane"> + <?cs + include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?> + </div> + </div> <!-- end side-nav --> + <script> + $(document).ready(function() { + scrollIntoView("devdoc-nav"); + }); + </script> +<?cs /def ?> + <?cs # The default side navigation for the reference docs ?><?cs def:default_left_nav() ?> <?cs if:reference.gcm || reference.gms ?> @@ -337,6 +367,7 @@ def:default_left_nav() ?> <?cs if:subcount(class.package) ?> <ul> + <?cs call:list("Annotations", class.package.annotations) ?> <?cs call:list("Interfaces", class.package.interfaces) ?> <?cs call:list("Classes", class.package.classes) ?> <?cs call:list("Enums", class.package.enums) ?> @@ -345,6 +376,7 @@ def:default_left_nav() ?> </ul><?cs elif:subcount(package) ?> <ul> + <?cs call:class_link_list("Annotations", package.annotations) ?> <?cs call:class_link_list("Interfaces", package.interfaces) ?> <?cs call:class_link_list("Classes", package.classes) ?> <?cs call:class_link_list("Enums", package.enums) ?> @@ -431,8 +463,8 @@ def:header_search_widget() ?> <option value="ja">日本語</option> <option value="ko">한국어</option> <option value="ru">Русский</option> - <option value="zh-cn">中文 (中国)</option> - <option value="zh-tw">中文 (台灣)</option> + <option value="zh-cn">中文(简体)</option> + <option value="zh-tw">中文(繁體)</option> </select> </div> <script type="text/javascript"> @@ -526,6 +558,8 @@ def:custom_left_nav() ?><?cs call:engage_nav() ?><?cs elif:monetize ?><?cs call:monetize_nav() ?><?cs + elif:analyze ?><?cs + call:analyze_nav() ?><?cs elif:disttools ?><?cs call:disttools_nav() ?><?cs elif:stories ?><?cs @@ -537,6 +571,8 @@ def:custom_left_nav() ?><?cs call:distribute_nav() ?><?cs elif:wear ?><?cs call:wear_nav() ?><?cs + elif:preview ?><?cs + call:preview_nav() ?><?cs else ?><?cs call:default_left_nav() ?> <?cs /if ?><?cs diff --git a/tools/droiddoc/templates-sdk-dyn/data.hdf b/tools/droiddoc/templates-sdk-dev/data.hdf index 9411b78..9411b78 100644 --- a/tools/droiddoc/templates-sdk-dyn/data.hdf +++ b/tools/droiddoc/templates-sdk-dev/data.hdf diff --git a/tools/droiddoc/templates-sdk-dyn/designpage.cs b/tools/droiddoc/templates-sdk-dev/designpage.cs index 2be179d..2be179d 100644 --- a/tools/droiddoc/templates-sdk-dyn/designpage.cs +++ b/tools/droiddoc/templates-sdk-dev/designpage.cs diff --git a/tools/droiddoc/templates-sdk-dyn/docpage.cs b/tools/droiddoc/templates-sdk-dev/docpage.cs index 7eae405..83b1199 100644 --- a/tools/droiddoc/templates-sdk-dyn/docpage.cs +++ b/tools/droiddoc/templates-sdk-dev/docpage.cs @@ -2,7 +2,7 @@ <?cs include:"macros.cs" ?> <html<?cs if:devsite ?> devsite<?cs /if ?>> <?cs include:"head_tag.cs" ?> -<body class="gc-documentation +<body class="gc-documentation <?cs if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?><?cs @@ -18,7 +18,7 @@ if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?><?cs if:monetize ?> monetize<?cs /if ?><?cs if:disttools ?> disttools<?cs /if ?><?cs if:stories ?> stories<?cs /if ?><?cs - elif:about ?>about<?cs + elif:(about||wear||tv||auto) ?>about<?cs elif:design ?>design<?cs /if ?><?cs if:page.trainingcourse ?> trainingcourse<?cs @@ -90,7 +90,7 @@ include:"header.cs" ?> </div> <?cs /if ?><?cs # end if training ?> </div> - <?cs /if ?> + <?cs /if ?><?cs # end if header.hide ?> <?cs elif:samplesProjectIndex ?> <div id="api-info-block"> @@ -103,7 +103,14 @@ include:"header.cs" ?> <h1 itemprop="name"><?cs var:projectDir ?></h1> <?cs else ?> - + <?cs if:training ?> +<?cs # horrible horrible hack to move TOC up when the next/prev links are not there ?> +<style> + #tb-wrapper { + margin-top:6px; + } +</style> + <?cs /if ?> <?cs if:(!fullpage && !header.hide) ?> <?cs if:page.landing ?><?cs # header logic for docs that are landing pages ?> @@ -150,25 +157,9 @@ include:"header.cs" ?> if:fullpage ?>wrap<?cs else ?>layout-content-row<?cs /if ?>" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div class="layout-content-col <?cs - if:fullpage ?>col-16<?cs - elif:training||guide ?>col-8<?cs - else ?>col-9<?cs /if ?>" style="padding-top:4px"> - <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?> - <div class="g-plusone" data-size="medium"></div> - <?cs /if ?> - </div> <?cs if:!fullscreen ?> - <div class="paging-links layout-content-col col-4"> + <div class="paging-links layout-content-col col-10"> <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?> - <a href="#" class="prev-page-link hide" - zh-tw-lang="上一堂課" - zh-cn-lang="上一课" - ru-lang="Предыдущий" - ko-lang="이전" - ja-lang="前へ" - es-lang="Anterior" - >Previous</a> <a href="#" class="next-page-link hide" zh-tw-lang="下一堂課" zh-cn-lang="下一课" @@ -185,41 +176,28 @@ include:"header.cs" ?> ja-lang="開始する" es-lang="Empezar" >Get started</a> + <a href="#" class="next-class-link hide">Next class</a> + <?cs /if ?> + </div> + <div class="layout-content-col plus-container col-2" > + <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?> + <div class="g-plusone" data-size="medium"></div> <?cs /if ?> </div> <?cs /if ?> </div> - <?cs # for training classes, provide a different kind of link when the next page is a different class ?> - <?cs if:training && !page.article ?> - <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <a href="#" class="next-class-link hide">Next class: </a> - </div> - <?cs /if ?> - </div> <!-- end jd-content --> <?cs include:"footer.cs" ?> </div><!-- end doc-content --> -<!-- Start of Tag --> -<script type="text/javascript"> -var axel = Math.random() + ""; -var a = axel * 10000000000000; -document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>'); -</script> -<noscript> -<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe> -</noscript> -<!-- End of Tag --> - - <?cs include:"trailer.cs" ?> <script src="https://developer.android.com/ytblogger_lists_unified.js" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_lists_unified.js" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_extras.js" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_collections.js" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_tag_helpers.js" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_lists_unified.js?v=9" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_extras.js?v=11" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_collections.js?v=12" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_tag_helpers.js?v=5" type="text/javascript"></script> </body> </html> diff --git a/tools/droiddoc/templates-sdk-dyn/footer.cs b/tools/droiddoc/templates-sdk-dev/footer.cs index b609d3b..b609d3b 100644 --- a/tools/droiddoc/templates-sdk-dyn/footer.cs +++ b/tools/droiddoc/templates-sdk-dev/footer.cs diff --git a/tools/droiddoc/templates-sdk-dyn/gcm_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs index 6f33d88..6f33d88 100644 --- a/tools/droiddoc/templates-sdk-dyn/gcm_navtree_data.cs +++ b/tools/droiddoc/templates-sdk-dev/gcm_navtree_data.cs diff --git a/tools/droiddoc/templates-sdk-dyn/gms_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs index 66b7d55..66b7d55 100644 --- a/tools/droiddoc/templates-sdk-dyn/gms_navtree_data.cs +++ b/tools/droiddoc/templates-sdk-dev/gms_navtree_data.cs diff --git a/tools/droiddoc/templates-sdk-dyn/head_tag.cs b/tools/droiddoc/templates-sdk-dev/head_tag.cs index 732118f..9f79f54 100644 --- a/tools/droiddoc/templates-sdk-dyn/head_tag.cs +++ b/tools/droiddoc/templates-sdk-dev/head_tag.cs @@ -24,8 +24,8 @@ <meta name="Description" content="<?cs var:page.metaDescription ?>"><?cs /if ?> <link rel="shortcut icon" type="image/x-icon" href="<?cs var:toroot ?>favicon.ico" /> -<title><?cs - if:page.title ?><?cs +<title><?cs + if:page.title ?><?cs var:page.title ?> | <?cs /if ?>Android Developers</title> @@ -38,9 +38,9 @@ if:android.whichdoc != 'online' ?>http:<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto"> -<link href="<?cs var:toroot ?>assets/css/default.css" rel="stylesheet" type="text/css"> +<link href="<?cs var:toroot ?>assets/css/default.css?v=5" rel="stylesheet" type="text/css"> -<?cs if:reference && !(reference.gms || reference.gcm || wear) ?> +<?cs if:reference && !(reference.gms || reference.gcm || preview) ?> <!-- FULLSCREEN STYLESHEET --> <link href="<?cs var:toroot ?>assets/css/fullscreen.css" rel="stylesheet" class="fullscreen" type="text/css"> @@ -62,17 +62,25 @@ else var metaTags = [<?cs var:meta.tags ?>]; var devsite = <?cs if:devsite ?>true<?cs else ?>false<?cs /if ?>; </script> -<script src="<?cs var:toroot ?>assets/js/docs.js" type="text/javascript"></script> +<script src="<?cs var:toroot ?>assets/js/docs.js?v=3" type="text/javascript"></script> -<script type="text/javascript"> - var _gaq = _gaq || []; - _gaq.push(['_setAccount', 'UA-5831155-1']); - _gaq.push(['_trackPageview']); +<?cs if:helpoutsWidget ?> +<script type="text/javascript" src="https://helpouts.google.com/ps/res/embed.js" defer async + data-helpouts-embed data-helpouts-vertical="programming" + data-helpouts-tags="<?cs var:page.tags ?>" data-helpouts-prefix="android" + data-helpouts-standalone="true"></script> +<?cs /if ?> - (function() { - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); - })(); +<script> + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-5831155-1', 'android.com'); + ga('create', 'UA-49880327-2', 'android.com', {'name': 'universal'}); // New tracker); + ga('send', 'pageview'); + ga('universal.send', 'pageview'); // Send page view for new tracker. </script> + </head> diff --git a/tools/droiddoc/templates-sdk-dyn/header.cs b/tools/droiddoc/templates-sdk-dev/header.cs index e8301be..e8301be 100644 --- a/tools/droiddoc/templates-sdk-dyn/header.cs +++ b/tools/droiddoc/templates-sdk-dev/header.cs diff --git a/tools/droiddoc/templates-sdk-dyn/header_tabs.cs b/tools/droiddoc/templates-sdk-dev/header_tabs.cs index 38c9da8..38c9da8 100644 --- a/tools/droiddoc/templates-sdk-dyn/header_tabs.cs +++ b/tools/droiddoc/templates-sdk-dev/header_tabs.cs diff --git a/tools/droiddoc/templates-sdk-dyn/jd_lists_unified.cs b/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs index 417a5c1..417a5c1 100644 --- a/tools/droiddoc/templates-sdk-dyn/jd_lists_unified.cs +++ b/tools/droiddoc/templates-sdk-dev/jd_lists_unified.cs diff --git a/tools/droiddoc/templates-sdk-dev/macros_override.cs b/tools/droiddoc/templates-sdk-dev/macros_override.cs new file mode 100644 index 0000000..0a94598 --- /dev/null +++ b/tools/droiddoc/templates-sdk-dev/macros_override.cs @@ -0,0 +1,36 @@ +<?cs # Create a comma separated list of annotations on obj that were in showAnnotations in Doclava ?> +<?cs # pre is an HTML string to start the list, post is an HTML string to close the list ?> +<?cs # for example call:show_annotations_list(cl, "<td>Annotations: ", "</td>") ?> +<?cs # if obj has nothing on obj.showAnnotations, nothing will be output ?> +<?cs def:show_annotations_list(obj) ?> + <?cs each:anno = obj.showAnnotations ?> + <?cs if:first(anno) ?> + <span class='annotation-message'> + Included in documentation by the annotations: + <?cs /if ?> + @<?cs var:anno.type.label ?> + <?cs if:last(anno) == 0 ?> + , + <?cs /if ?> + <?cs if:last(anno)?> + </span> + <?cs /if ?> + <?cs /each ?> +<?cs /def ?> + +<?cs # Override default class_link_table to display annotations ?> +<?cs def:class_link_table(classes) ?> + <?cs set:count = #1 ?> + <table class="jd-sumtable-expando"> + <?cs each:cl=classes ?> + <tr class="<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since ?>" > + <td class="jd-linkcol"><?cs call:type_link(cl.type) ?></td> + <td class="jd-descrcol" width="100%"> + <?cs call:short_descr(cl) ?> + <?cs call:show_annotations_list(cl) ?> + </td> + </tr> + <?cs set:count = count + #1 ?> + <?cs /each ?> + </table> +<?cs /def ?>
\ No newline at end of file diff --git a/tools/droiddoc/templates-sdk-dyn/navtree_data.cs b/tools/droiddoc/templates-sdk-dev/navtree_data.cs index 73aa199..73aa199 100644 --- a/tools/droiddoc/templates-sdk-dyn/navtree_data.cs +++ b/tools/droiddoc/templates-sdk-dev/navtree_data.cs diff --git a/tools/droiddoc/templates-sdk-dyn/nosidenavpage.cs b/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs index 8e59693..8e59693 100644 --- a/tools/droiddoc/templates-sdk-dyn/nosidenavpage.cs +++ b/tools/droiddoc/templates-sdk-dev/nosidenavpage.cs diff --git a/tools/droiddoc/templates-sdk-dyn/package.cs b/tools/droiddoc/templates-sdk-dev/package.cs index 99eaff2..2225565 100644 --- a/tools/droiddoc/templates-sdk-dyn/package.cs +++ b/tools/droiddoc/templates-sdk-dev/package.cs @@ -1,10 +1,13 @@ <?cs include:"doctype.cs" ?> <?cs include:"macros.cs" ?> +<?cs include:"macros_override.cs" ?> <html<?cs if:devsite ?> devsite<?cs /if ?>> <?cs include:"head_tag.cs" ?> <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?> <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs + if:reference ?> reference<?cs + /if ?><?cs elif:design ?>design<?cs elif:distribute ?>distribute<?cs /if ?>"> @@ -45,6 +48,7 @@ <?cs /if ?> <?cs /def ?> +<?cs call:class_table("Annotations", package.annotations) ?> <?cs call:class_table("Interfaces", package.interfaces) ?> <?cs call:class_table("Classes", package.classes) ?> <?cs call:class_table("Enums", package.enums) ?> diff --git a/tools/droiddoc/templates-sdk-dyn/packages.cs b/tools/droiddoc/templates-sdk-dev/packages.cs index 44680c3..5056d3a 100644 --- a/tools/droiddoc/templates-sdk-dyn/packages.cs +++ b/tools/droiddoc/templates-sdk-dev/packages.cs @@ -4,6 +4,8 @@ <?cs include:"head_tag.cs" ?> <body class="gc-documentation <?cs if:(reference.gms || reference.gcm) ?>google<?cs /if ?> <?cs if:(guide||develop||training||reference||tools||sdk) ?>develop<?cs + if:reference ?> reference<?cs + /if ?><?cs elif:design ?>design<?cs elif:distribute ?>distribute<?cs /if ?>"> diff --git a/tools/droiddoc/templates-sdk-dyn/sample.cs b/tools/droiddoc/templates-sdk-dev/sample.cs index c6f28f8..32a0788 100644 --- a/tools/droiddoc/templates-sdk-dyn/sample.cs +++ b/tools/droiddoc/templates-sdk-dev/sample.cs @@ -18,7 +18,7 @@ <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/index.html">Overview</a> | <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a> | <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip" - onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);" + onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);" >Download</a> </div><!-- end sum-details-links --> diff --git a/tools/droiddoc/templates-sdk-dyn/sampleindex.cs b/tools/droiddoc/templates-sdk-dev/sampleindex.cs index 98767b1..1bacb53 100644 --- a/tools/droiddoc/templates-sdk-dyn/sampleindex.cs +++ b/tools/droiddoc/templates-sdk-dev/sampleindex.cs @@ -21,7 +21,7 @@ | <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a> <?cs /if ?> | <a href="<?cs var:toroot ?>downloads/samples/<?cs var:projectDir ?>.zip" - onclick="_gaq.push(['_trackEvent', 'Samples', 'Download', <?cs var:projectDir ?>]);" + onclick="ga('send', 'event', 'Samples', 'Download', <?cs var:projectDir ?>);" >Download</a> </div><!-- end sum-details-links --> diff --git a/tools/droiddoc/templates-sdk-dyn/samples_navtree_data.cs b/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs index 24ac7b7..24ac7b7 100644 --- a/tools/droiddoc/templates-sdk-dyn/samples_navtree_data.cs +++ b/tools/droiddoc/templates-sdk-dev/samples_navtree_data.cs diff --git a/tools/droiddoc/templates-sdk-dyn/sdkpage.cs b/tools/droiddoc/templates-sdk-dev/sdkpage.cs index 95f6596..817ac47 100644 --- a/tools/droiddoc/templates-sdk-dyn/sdkpage.cs +++ b/tools/droiddoc/templates-sdk-dev/sdkpage.cs @@ -183,21 +183,7 @@ <td><?cs var:ndk.linux64.legacy_bytes ?></td> <td><?cs var:ndk.linux64.legacy_checksum ?></td> </tr> --> - <tr> - <th>Additional Download</th> - <th>Package</th> - <th style="white-space:nowrap">Size (Bytes)</th> - <th>MD5 Checksum</th> - </tr> - <tr> - <td>STL debug info</td> - <td> - <a onClick="return onDownload(this)" - href="http://dl.google.com/android/ndk/<?cs var:ndk.debug_info_download ?>"><?cs var:ndk.debug_info_download ?></a> - </td> - <td><?cs var:ndk.debug_info_bytes ?></td> - <td><?cs var:ndk.debug_info_checksum ?></td> - </tr> + </table> <?cs ######## HERE IS THE JD DOC CONTENT ######### ?> @@ -278,119 +264,137 @@ -<h4><a href='' class="expandable" - onclick="toggleExpandable(this,'.pax');hideExpandable('.myide,.reqs');return false;" - >DOWNLOAD FOR OTHER PLATFORMS</a></h4> +<div class="pax col-13 online" style="margin:0;"> -<div class="pax col-13 online" style="display:none;margin:0;"> +<h3>SDK Tools Only</h3> +<p>If you prefer to use a different IDE or run the tools from the +command line or with build scripts, you can instead download the stand-alone Android SDK Tools. +These packages provide the basic SDK tools for app development, without an IDE. +Also see the <a href="<?cs var:toroot ?>tools/sdk/tools-notes.html">SDK tools release notes</a>.</p> -<p class="table-caption"><strong>ADT Bundle</strong></p> <table class="download"> <tr> <th>Platform</th> <th>Package</th> <th>Size</th> - <th>MD5 Checksum</th> - </tr> - <tr> - <td>Windows 32-bit</td> - <td> - <a onClick="return onDownload(this)" id="win-bundle32" - href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win32_bundle_download ?>"><?cs var:sdk.win32_bundle_download ?></a> - </td> - <td><?cs var:sdk.win32_bundle_bytes ?> bytes</td> - <td><?cs var:sdk.win32_bundle_checksum ?></td> + <th>SHA-1 Checksum</th> </tr> <tr> - <td>Windows 64-bit</td> + <td rowspan="2">Windows</td> <td> - <a onClick="return onDownload(this)" id="win-bundle64" - href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.win64_bundle_download ?>"><?cs var:sdk.win64_bundle_download ?></a> + <a onclick="return onDownload(this)" id="win-tools" href="http://dl.google.com/android/<?cs +var:sdk.win_installer +?>"><?cs var:sdk.win_installer ?></a> (Recommended) </td> - <td><?cs var:sdk.win64_bundle_bytes ?> bytes</td> - <td><?cs var:sdk.win64_bundle_checksum ?></td> + <td><?cs var:sdk.win_installer_bytes ?> bytes</td> + <td><?cs var:sdk.win_installer_checksum ?></td> </tr> <tr> - <td><nobr>Mac OS X 64-bit</nobr></td> + <!-- blank TD from Windows rowspan --> <td> - <a onClick="return onDownload(this)" id="mac-bundle64" - href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.mac64_bundle_download ?>"><?cs var:sdk.mac64_bundle_download ?></a> + <a onclick="return onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.win_download +?>"><?cs var:sdk.win_download ?></a> </td> - <td><?cs var:sdk.mac64_bundle_bytes ?> bytes</td> - <td><?cs var:sdk.mac64_bundle_checksum ?></td> + <td><?cs var:sdk.win_bytes ?> bytes</td> + <td><?cs var:sdk.win_checksum ?></td> </tr> <tr> - <td>Linux 32-bit</td> + <td><nobr>Mac OS X</nobr></td> <td> - <a onClick="return onDownload(this)" id="linux-bundle32" - href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux32_bundle_download ?>"><?cs var:sdk.linux32_bundle_download ?></a> + <a onclick="return onDownload(this)" id="mac-tools" href="http://dl.google.com/android/<?cs +var:sdk.mac_download +?>"><?cs var:sdk.mac_download ?></a> </td> - <td><?cs var:sdk.linux32_bundle_bytes ?> bytes</td> - <td><?cs var:sdk.linux32_bundle_checksum ?></td> + <td><?cs var:sdk.mac_bytes ?> bytes</td> + <td><?cs var:sdk.mac_checksum ?></td> </tr> <tr> - <td>Linux 64-bit</td> + <td>Linux</td> <td> - <a onClick="return onDownload(this)" id="linux-bundle64" - href="http://dl.google.com/android/adt/<?cs var:sdk.version ?>/<?cs var:sdk.linux64_bundle_download ?>"><?cs var:sdk.linux64_bundle_download ?></a> + <a onclick="return onDownload(this)" id="linux-tools" href="http://dl.google.com/android/<?cs +var:sdk.linux_download +?>"><?cs var:sdk.linux_download ?></a> </td> - <td><?cs var:sdk.linux64_bundle_bytes ?> bytes</td> - <td><?cs var:sdk.linux64_bundle_checksum ?></td> + <td><?cs var:sdk.linux_bytes ?> bytes</td> + <td><?cs var:sdk.linux_checksum ?></td> </tr> </table> -<p class="table-caption"><strong>SDK Tools Only</strong></p> + +<h3>All Android Studio Packages</h3> + +<p>Select a specific Android Studio package for your platform. Also see the +<a href="<?cs var:toroot ?>tools/revisions/studio.html">Android Studio release notes</a>.</p> + <table class="download"> <tr> <th>Platform</th> <th>Package</th> <th>Size</th> - <th>MD5 Checksum</th> + <th>SHA-1 Checksum</th> </tr> + <tr> - <td rowspan="2">Windows<br>32 & 64-bit</td> + <td rowspan="3">Windows</td> <td> - <a onclick="return onDownload(this)" href="http://dl.google.com/android/<?cs var:sdk.win_download -?>"><?cs var:sdk.win_download ?></a> + <a onclick="return onDownload(this)" id="win-bundle" + href="https://dl.google.com/dl/android/studio/install/<?cs var:studio.version ?>/<?cs var:studio.win_bundle_exe_download ?>" + ><?cs var:studio.win_bundle_exe_download ?></a><br>(Recommended) </td> - <td><?cs var:sdk.win_bytes ?> bytes</td> - <td><?cs var:sdk.win_checksum ?></td> + <td><?cs var:studio.win_bundle_exe_bytes ?> bytes</td> + <td><?cs var:studio.win_bundle_exe_checksum ?></td> </tr> + <tr> <!-- blank TD from Windows rowspan --> <td> - <a onclick="return onDownload(this)" id="win-tools" href="http://dl.google.com/android/<?cs -var:sdk.win_installer -?>"><?cs var:sdk.win_installer ?></a> (Recommended) + <a onclick="return onDownload(this)" + href="https://dl.google.com/dl/android/studio/install/<?cs var:studio.version ?>/<?cs var:studio.win_notools_exe_download ?>" + ><?cs var:studio.win_notools_exe_download ?></a><br>(No SDK tools included) </td> - <td><?cs var:sdk.win_installer_bytes ?> bytes</td> - <td><?cs var:sdk.win_installer_checksum ?></td> + <td><?cs var:studio.win_notools_exe_bytes ?> bytes</td> + <td><?cs var:studio.win_notools_exe_checksum ?></td> </tr> + <tr> - <td><nobr>Mac OS X</nobr><br>32 & 64-bit</td> + <!-- blank TD from Windows rowspan --> <td> - <a onclick="return onDownload(this)" id="mac-tools" href="http://dl.google.com/android/<?cs -var:sdk.mac_download -?>"><?cs var:sdk.mac_download ?></a> + <a onclick="return onDownload(this)" + href="https://dl.google.com/dl/android/studio/ide-zips/<?cs var:studio.version ?>/<?cs var:studio.win_bundle_download ?>" + ><?cs var:studio.win_bundle_download ?></a> </td> - <td><?cs var:sdk.mac_bytes ?> bytes</td> - <td><?cs var:sdk.mac_checksum ?></td> + <td><?cs var:studio.win_bundle_bytes ?> bytes</td> + <td><?cs var:studio.win_bundle_checksum ?></td> </tr> + <tr> - <td>Linux<br>32 & 64-bit</td> + <td><nobr>Mac OS X</nobr></td> <td> - <a onclick="return onDownload(this)" id="linux-tools" href="http://dl.google.com/android/<?cs -var:sdk.linux_download -?>"><?cs var:sdk.linux_download ?></a> + <a onclick="return onDownload(this)" id="mac-bundle" + href="https://dl.google.com/dl/android/studio/install/<?cs var:studio.version ?>/<?cs var:studio.mac_bundle_download ?>" + ><?cs var:studio.mac_bundle_download ?></a> </td> - <td><?cs var:sdk.linux_bytes ?> bytes</td> - <td><?cs var:sdk.linux_checksum ?></td> + <td><?cs var:studio.mac_bundle_bytes ?> bytes</td> + <td><?cs var:studio.mac_bundle_checksum ?></td> + </tr> + + <tr> + <td>Linux</td> + <td> + <a onclick="return onDownload(this)" id="linux-bundle" + href="https://dl.google.com/dl/android/studio/ide-zips/<?cs var:studio.version ?>/<?cs var:studio.linux_bundle_download ?>" + ><?cs var:studio.linux_bundle_download ?></a> + </td> + <td><?cs var:studio.linux_bundle_bytes ?> bytes</td> + <td><?cs var:studio.linux_bundle_checksum ?></td> </tr> </table> + + </div><!-- end pax --> @@ -411,7 +415,9 @@ var:sdk.linux_download var bundlename; var $toolslink; - if (navigator.appVersion.indexOf("Win")!=-1) { + if (navigator.appVersion.indexOf("Mobile")!=-1) { + // Do nothing for any "mobile" user agent + } else if (navigator.appVersion.indexOf("Win")!=-1) { os = "Windows"; bundlename = '#win-bundle'; $toolslink = $('#win-tools'); @@ -419,26 +425,18 @@ var:sdk.linux_download os = "Mac"; bundlename = '#mac-bundle'; $toolslink = $('#mac-tools'); - } else if (navigator.appVersion.indexOf("Linux")!=-1) { + } else if (navigator.appVersion.indexOf("Linux")!=-1 && navigator.appVersion.indexOf("Android")==-1) { os = "Linux"; bundlename = '#linux-bundle'; $toolslink = $('#linux-tools'); } - if (os) { + if (os != undefined) { $('#not-supported').hide(); - /* set up primary adt download button */ - $('#download-bundle-button').show(); - $('#download-bundle-button').append("Download the SDK <br/><span class='small'>ADT Bundle for " + os + "</span>"); - $('#download-bundle-button').click(function() {return onDownload(this,true,true);}).attr('href', bundlename); - - /* set up sdk tools only button */ - $('#download-tools-button').show(); - $('#download-tools-button').append("Download the SDK Tools for " + os); - $('#download-tools-button').click(function() {return onDownload(this,true);}).attr('href', $toolslink.attr('href')); - } else { - $('.pax').show(); + /* set up primary Android Studio download button */ + $('.download-bundle-button').append(" <br/><span class='small'>for " + os + "</span>"); + $('.download-bundle-button').click(function() {return onDownload(this,true,true);}).attr('href', bundlename); } @@ -451,44 +449,29 @@ var:sdk.linux_download $("#downloadForRealz").html("Download " + $(link).text()); } - /* if it's a bundle, show the 32/64-bit picker */ - if (bundle) { - $("#downloadForRealz").attr('bundle','true'); - if ($("#downloadForRealz").text().indexOf("Mac") == -1) { - $("p#bitpicker").show(); - } else { - /* mac is always 64 bit, so set it checked */ - $("p#bitpicker input[value=64]").attr('checked', true); - } - /* save link name until the bit version is chosen */ - $("#downloadForRealz").attr('name',$(link).attr('href')); - } else { - /* if not using bundle, set download button to ignore bitpicker and set url */ - $("#downloadForRealz").attr('bundle','false'); - $("#downloadForRealz").attr('href',$(link).attr('href')); - /* set picker checked as a fake default */ - $("p#bitpicker input[value=64]").attr('checked', true); - $("a#next-link").html("Setting Up an Existing IDE").attr('href',toRoot + 'sdk/installing/index.html'); - } + $("#downloadForRealz").attr('bundle', bundle); + $("a#downloadForRealz").attr("name", $(link).attr('href')); - $("#tos").fadeIn('fast'); - $("#landing").fadeOut('fast'); + $("#tos").show(); + $("#landing").hide(); - location.hash = "download"; + location.hash = "top"; return false; } function onAgreeChecked() { - /* verify that the TOS is agreed and a bit version is chosen */ - if ($("input#agree").is(":checked") && $("#bitpicker input:checked").length) { + /* verify that the TOS is agreed */ + if ($("input#agree").is(":checked")) { /* if downloading the bundle */ if ($("#downloadForRealz").attr('bundle')) { - /* construct the name of the link we want based on the bit version */ - linkId = $("a#downloadForRealz").attr("name") + $("#bitpicker input:checked").val(); + /* construct the name of the link we want */ + linkId = $("a#downloadForRealz").attr("name"); /* set the real url for download */ $("a#downloadForRealz").attr("href", $(linkId).attr("href")); + } else { + $("a#downloadForRealz").attr("href", $("a#downloadForRealz").attr("name")); } /* reveal the download button */ @@ -499,16 +482,28 @@ var:sdk.linux_download } function onDownloadForRealz(link) { - if ($("input#agree").is(':checked') && $("#bitpicker input:checked").length) { + if ($("input#agree").is(':checked')) { + location.hash = ""; + location.hash = "top"; $("div.sdk-terms").slideUp(); - $("#sdk-terms-form,.sdk-terms-intro").fadeOut('slow'); - $("#next-steps").fadeIn('slow'); - $("h1#tos-header").text('Get Ready to Code!'); - _gaq.push(['_trackEvent', 'SDK', 'ADT and Tools', $("#downloadForRealz").html()]); + $("h1#tos-header").text('Now downloading...'); + $(".sdk-terms-intro").text('You\'ll be redirected to the install instructions in a moment.'); + $("#sdk-terms-form").fadeOut('slow', function() { + setTimeout(function() { + if ($("#downloadForRealz").attr('bundle') == 'true') { + // User downloaded the studio Bundle + window.location = "/sdk/installing/index.html?pkg=studio"; + } else { + // User downloaded the SDK Tools + window.location = "/sdk/installing/index.html?pkg=tools"; + } + }, 3000); + }); + ga('send', 'event', 'SDK', 'IDE and Tools', $("#downloadForRealz").html()); return true; } else { - $("label#agreeLabel,#bitpicker input").parent().stop().animate({color: "#258AAF"}, 200, - function() {$("label#agreeLabel,#bitpicker input").parent().stop().animate({color: "#222"}, 200)} + $("label#agreeLabel").parent().stop().animate({color: "#258AAF"}, 200, + function() {$("label#agreeLabel").parent().stop().animate({color: "#222"}, 200)} ); return false; } diff --git a/tools/droiddoc/templates-sdk-dyn/timestamp.cs b/tools/droiddoc/templates-sdk-dev/timestamp.cs index 4bf502a..4bf502a 100644 --- a/tools/droiddoc/templates-sdk-dyn/timestamp.cs +++ b/tools/droiddoc/templates-sdk-dev/timestamp.cs diff --git a/tools/droiddoc/templates-sdk-dyn/trailer.cs b/tools/droiddoc/templates-sdk-dev/trailer.cs index 337f8d3..337f8d3 100644 --- a/tools/droiddoc/templates-sdk-dyn/trailer.cs +++ b/tools/droiddoc/templates-sdk-dev/trailer.cs diff --git a/tools/droiddoc/templates-sdk/assets/css/default.css b/tools/droiddoc/templates-sdk/assets/css/default.css index 2e01559..693027a 100644 --- a/tools/droiddoc/templates-sdk/assets/css/default.css +++ b/tools/droiddoc/templates-sdk/assets/css/default.css @@ -17,18 +17,32 @@ html, body { height: 100%; margin: 0; padding: 0; - background-color:#F9F9F9; + background-color: #fff; -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; /* prevent subpixel antialiasing, which thickens the text */ /* text-rendering: optimizeLegibility; */ /* turned off ligatures due to bug 5945455 */ } body { - color: #222; - font: 14px/19px Roboto, sans-serif; + color: #515151; + color: rgba(0, 0, 0, .68); + font: 14px/24px Roboto, sans-serif; font-weight: 400; letter-spacing:.1; - padding:0 10px; } + padding:0 20px; +} + +@media (max-width: 719px) { + html { + /* Disable accidental horizontal overflow. */ + overflow-x: hidden; + } + + body { + padding: 0 10px; + } +} #page-container { width: 940px; @@ -83,13 +97,8 @@ body { } #side-nav { - min-height:5px; /* silly way to avoid doc floating left when nav goes fixed */ - margin-bottom:1px; + padding-top: 20px; } -#devdoc-nav { - outline:none; - width:auto; - margin: 20px 0 0; } #devdoc-nav h2 { border:0; @@ -98,44 +107,251 @@ body { #devdoc-nav.fixed { position: fixed; margin:0; - top: 65px; /* sticky-header height + 20px gutter */ + top: 84px; /* sticky-header height + 20px gutter */ } -#devdoc-nav span.small { - font-size:12px; - font-weight:normal; +.dac-devdoc-toggle { + cursor: pointer; + padding: 8px 0; +} + +.scroll-pane { + /* Match height of fixed parent. */ + height: 100%; } #content { width: 760px; float: left; } -a:hover, -acronym:hover { - color: #7aa1b0 !important; } -a:focus, -a:active { - color: #33b5e5 !important; } +/***** PREVIOUSLY style.css ******************/ +/* This should be close to the top, so it is easier to override. */ +[dir='rtl'] { + direction: rtl; +} +html { + line-height: 20px; +} +pre, table, input, textarea, code { + font-size: 1em; +} +address, abbr, cite { + font-style: normal; +} +[dir='rtl'] th { + text-align: right; +} +html[lang^=ja] blockquote, html[lang^=ja] q, html[lang^=ko] blockquote, html[lang^=ko] q, +html[lang^=zh] blockquote, html[lang^=zh] q { + font-style: normal; +} +q { + font-style: italic; +} +fieldset, iframe, img { + border: 0; +} +img { + border: none; + -ms-interpolation-mode: bicubic; + max-width: 100%; + vertical-align: middle; +} +video { + max-width: 100%; + object-fit: cover; +} +q { + quotes: none; +} +sup, sub { + font-size: 11px; + line-height: 0; +} + +table, fieldset { + margin: 0; +} +/* Biggest type */ +.display-1 { + font-size: 56px; + line-height: 68px; +} +@media (max-width: 719px) { + .display-1 { + font-size: 44px; + line-height: 56px; + } +} +h1, h2, h3 { + color: #212121; + color: rgba(0, 0, 0, .87); +} +h1 { + font-size: 44px; + line-height: 56px; + margin: 24px 0 12px; + font-weight: 300; +} +h1.short { + margin-right:320px; +} +@media (max-width: 719px) { + h1 { + font-size: 36px; + line-height: 48px; + } +} +h2 { + clear: left; + font-size: 28px; + font-weight: 400; + line-height: 32px; + margin: 24px 0 16px; +} +h3 { + font-size: 24px; + line-height: 32px; + font-weight: 400; + margin: 16px 0; +} +h4 { + font-size: 18px; + line-height: 24px; + margin: 12px 0; + font-weight: 500; +} +h5, h6 { + font-size: 16px; + line-height: 24px; + margin: 8px 0; +} +hr { /* applied to the bottom of h2 elements */ + height: 1px; + margin: 7px 0 12px; + border: 0; + background: #e5e5e5; +} +p, pre, table, form { + margin: 0 0 12px; +} +small { + font-size: 11.5px; + color: #000; +} +ul, ol { + margin: 0 0 15px 20px; + padding: 0; +} +[dir='rtl'] ul, [dir='rtl'] ol { + margin: 10px 30px 10px 10px; +} +ul ul, ul ol, ol ul, ol ol { + margin-bottom: 0; + margin-top: 0; +} +li { + margin: 0 0 12px; +} +dt { + margin: 24px 0 12px; +} +dd { + margin:0 0 10px 40px; +} +dd p, +dd pre, +dd ul, +dd ol, +dd dl { + margin-top:10px; +} +li p, +li pre, +li ul, +li ol, +li dl { + margin-top: 6px; + margin-bottom: 6px; +} +dl dd dl:first-child { + margin-top: 0; +} +pre strong, pre b, a strong, a b, a code { + color: inherit; +} +pre, code { + color: #060; + font: 13px/18px Consolas, "Liberation Mono", Menlo, Courier, monospace; + -webkit-font-smoothing: subpixel-antialiased; + -moz-osx-font-smoothing: auto; +} +code { + background-color: #f7f7f7; + padding: 3px 5px; +} + +legend { + display: none; +} +a, .link-color { + color: #039BE5; + text-decoration: none; +} +a:focus, a:hover { + color: rgba(3, 155, 229, .7); + text-decoration: none; +} +a.white { + color: #fff; + text-decoration:underline; +} +a.white:hover, a.white:active { + color: #ccc; +} +strong, b { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; + border:0; + margin: .5em 1em 1em 0; + width:100%; /* consistent table widths; within IE's quirks */ + background-color:#f7f7f7; +} +th, td { + padding: 4px 12px; + vertical-align: top; + text-align: left; +} +td { + background-color:inherit; + border:solid 1px #DDD; +} +td *:last-child { + margin-bottom:0; +} +th { + background-color: #999; + color: #fff; + border:solid 1px #DDD; + font-weight: normal; +} +tr:first-of-type th:first-of-type:empty { + visibility: hidden; +} a.external-link { background:url('../images/styles/open_new_page.png') no-repeat 100% 50%; padding-right:16px; } -img { - border: none; } #jd-content img { margin-bottom:15px; } -ul { - margin: 0; - padding: 0; } - -strong { - font-weight: 500; } - em { font-style: italic; } @@ -155,6 +371,7 @@ video.with-shadow { /* disclosures mixin */ /* content layout */ +/* This grid is deprecated in favor of .cols and .col-X */ .layout-content-row { display: inline-block; margin-bottom: 10px; } @@ -264,33 +481,32 @@ video.with-shadow { /* sublinks */ } #nav li { list-style-type: none; - font-size: 14px; + font-size: 12px; margin:0; padding:0; - line-height: 15px; } + line-height: 18px; } #nav a { - color: #555555; + color: #505050; text-decoration: none; word-wrap:break-word; } #nav .nav-section-header { position: relative; margin-bottom: 1px; padding: 0 30px 0 0; } - #nav li.selected a, #nav li.selected > .nav-section-header > a { - color: #09C; + #nav li.selected a { + color: #039BE5; } #nav li.selected ul li a { /* don't highlight child items */ - color: #555555; } + color: #505050; } #nav .nav-section .nav-section .nav-section-header { /* no white line between second level sections */ margin-bottom: 0; } /* section header links */ #nav > li > div > a { display: block; - color: #333333; - font-weight: 500; - padding: 10px 0 10px 10px; } + font-weight: 700; + padding: 13px 0 12px 10px; } #nav .nav-section-header:after { content: ''; background: transparent url(../images/styles/disclosure_down.png) no-repeat scroll 50% 50%; @@ -298,7 +514,7 @@ video.with-shadow { height: 34px; display: block; position: absolute; - top: 0; + top: 6px; right: 0; } #nav .nav-section-header.empty { padding:0; } @@ -312,22 +528,24 @@ video.with-shadow { #nav .nav-section li a { /* first gen child (2nd level li) */ display:block; - font-weight: normal; + font-weight: 700; text-transform: none; - padding: 7px 5px 7px 10px; + padding: 13px 5px 13px 10px; } #nav .nav-section li li a { /* second gen child (3rd level li) */ - padding: 5px 5px 5px 10px; + font-weight: 400; + padding: 7px 5px 7px 10px; } #nav li.expanded .nav-section-header { - background:#e9e9e9; - background: rgba(0, 0, 0, 0.05); } + background: #f0f0f0; } + #nav li.expanded .nav-section-header.empty { + background: none; } #nav li.expanded li .nav-section-header { - background: transparent; } + background: none; } #nav li.expanded li ul { /* 3rd level ul */ - padding:0 0 0 10px; + padding:6px 0 1px 20px; } #nav li.expanded > .nav-section-header:after { content: ''; @@ -394,16 +612,12 @@ video.with-shadow { padding-bottom:0; } #nav li.expanded ul > li { - background:#efefef; - background: rgba(0, 0, 0, 0.03); } + background:#f7f7f7; } #nav li.expanded ul > li li { background:inherit; } #nav li ul.tree-list-children ul { display:block; } -#nav.samples-nav li li li { - font-size:13px; -} #nav.samples-nav li li li a { padding-top:3px; padding-bottom:3px; @@ -423,25 +637,19 @@ video.with-shadow { /* content header */ .content-header { - height: 30px; - margin:36px 0 23px; /* same as h1 */ - padding:0 0 10px;} /* same as h1 */ + position: relative; +} +.content-header:before, +.content-header:after { + content: ''; + display: table; + /* Clear heading margins, to make absolutely positioned nav a bit more predictable. */ +} .content-header.just-links { margin-bottom:0; padding-bottom:0;} -.content-header h1 { - margin:0; - padding:0; - width: 700px; -} -.content-header > div:first-child { - height:1px; /* set fixed height for the header div to ensure the - next/prev links align with toc on training classes */ -} - .content-footer { - border-top: 1px solid #ccc; margin-top: 10px; padding-top:10px; width:100%; } @@ -453,7 +661,7 @@ video.with-shadow { margin-right:0; } .content-footer.wrap { - width:940px; + max-width:940px; } .content-footer .plus-container { margin:5px 0 0; @@ -467,7 +675,10 @@ a.back-link { } .content-header .paging-links { - margin-top:-25px; + position: absolute; + right: 0; + top: 8px; + width: 220px; } .paging-links { position: relative; @@ -476,9 +687,7 @@ a.back-link { position: absolute; } .paging-links a, .training-nav-top a { - color: #555555; - text-decoration: none; - text-transform: uppercase; } + text-decoration: none; } .paging-links .prev-page-link:before, .training-nav-top .prev-page-link:before, a.back-link:before { @@ -488,10 +697,6 @@ a.back-link { height: 10px; display: inline-block; margin-right: 5px; } - .training-nav-top .next-page-link, - .training-nav-top .start-class-link, - .training-nav-top .start-course-link { - right: 10px; } .paging-links .prev-page-link { left: -15px; } .paging-links .next-page-link { @@ -517,20 +722,25 @@ a.back-link { } .training-nav-top a { + border-bottom:0; + box-sizing: border-box; + color: inherit; display:block; float:left; - width:122px; - height:28px; - padding: 8px; - line-height:28px; + padding:10px 0; + line-height:30px; text-align:center; - border:1px solid #DADADA; - border-bottom:0; + width: 50%; + } + + .training-nav-top a.prev-page-link { + padding-left: 15px; + text-align: left; } .training-nav-top a.next-page-link { - border-left:0; - width:123px; + padding-right: 15px; + text-align: right; } .paging-links a.disabled, @@ -547,41 +757,57 @@ a.back-link { } .training-nav-top a.start-class-link, - .training-nav-top a.start-course-link { - width:262px; - } - + .training-nav-top a.start-course-link, .paging-links a.start-class-link { width:100%; } /* list of classes on course landing page */ ol.class-list { - list-style:none; - margin-left:0; + counter-reset: class; + list-style: none; + margin: 60px 0 0; } ol.class-list>li { - margin:0 0 15px; - padding:5px 0 0; - overflow:hidden; - border-top:1px solid #ccc; + box-shadow: 0px 2px 5px 0 rgba(0, 0, 0, 0.26); + margin: 0 0 20px; + overflow: hidden; } - ol.class-list li a.title { - font-size:16px; - margin:0; - clear:left; - display:block; - height:32px; - padding:0 4px; + ol.class-list .title { + background: #00bcd4; + color: #fff; + display: block; + font-size: 20px; + font-weight: 500; + height: 32px; + margin: 0; + padding: 52px 16px 12px; + position: relative; + } + ol.class-list .title:before { + border-bottom: 1px solid white; + box-sizing: border-box; + /* Disable the numbers for now, since vert few classes need to be taken in order. */ + /* content: counter(class); */ + counter-increment: class; + height: 40px; + left: 0; + padding: 10px 1px 0 5px; + position: absolute; + top: 0; + text-align: right; + min-width: 30px; } - ol.class-list li a.title h2 { - color:inherit; + ol.class-list .title h2 { + color: currentColor; + font-size: inherit; + font-weight: inherit; margin:0 0 10px; display:block; float:left; width:675px; } - ol.class-list li a.title span { + ol.class-list .title span { display:none; float:left; font-size:18px; @@ -590,40 +816,71 @@ a.back-link { width: 10px; height: 32px; } - ol.class-list li a.title:hover { - background:#ddd; - color:#258AAF !important; - } - ol.class-list li a.title:hover span { - display:block; - } - #jd-content - ol.class-list li img { - float:left; - clear:left; - width:64px; - margin:0 20px 0 0; - } - ol.class-list li p.description { + ol.class-list .description { + box-sizing: border-box; float:left; display:block; - width:250px; margin:0; + padding: 16px 10px 16px 16px; + width: 50%; } - ol.class-list li p.description.article { + ol.class-list .description.article { width: 550px; } ol.class-list ol { - float:left; - width:320px; - margin:0 0 0 30px; - list-style:none; - margin:0 0 0 20px; + box-sizing: border-box; + float: left; + list-style: none; + margin: 0; + padding: 16px 16px 16px 10px; + width: 50%; + } + ol.class-list .lessons li { + margin: 0 0 6px; + line-height: 16px; + } + + /* Class colors */ + ol.class-list li:nth-child(10n+1) .title { + background: #00bcd4; + } + ol.class-list li:nth-child(10n+2) .title { + background: #4db6ac; + } + ol.class-list li:nth-child(10n+3) .title { + background: #66bb6a; + } + ol.class-list li:nth-child(10n+4) .title { + background: #7cb342; + } + ol.class-list li:nth-child(10n+5) .title { + background: #afb42b; + } + ol.class-list li:nth-child(10n+6) .title { + background: #ffb300; } - ol.class-list div.lessons li { - margin:0 0 6px; - line-height:16px; + ol.class-list li:nth-child(10n+7) .title { + background: #ff7043; + } + ol.class-list li:nth-child(10n+8) .title { + background: #ec407a; + } + ol.class-list li:nth-child(10n+9) .title { + background: #ab47bc; + } + ol.class-list li:nth-child(10n+10) .title { + background: #7e57c2; + } + + @media (max-width: 719px) { + ol.class-list ol, + ol.class-list .description { + float: none; + margin: 16px; + padding: 0; + width: auto; + } } @@ -669,7 +926,7 @@ ul#title-tabs li a { } ul#title-tabs li a:hover, ul#title-tabs li a:active { - color:#93C !important; + color:#039BE5 !important; } @@ -798,46 +1055,6 @@ li.no-bullet *{ .design li.with-icon.use:before { background-image: url(../images/styles/ico_use.png); } -/* figures and callouts */ -.figure { - position: relative; } - .figure.pad-below { - margin-bottom: 20px; } - .figure .figure-callout { - position: absolute; - color: #fff; - font-weight: 500; - font-size: 16px; - line-height: 23px; - text-align: center; - background: transparent url(../images/styles/callout.png) no-repeat scroll 50% 50%; - padding-right: 2px; - width: 30px; - height: 29px; - z-index: 1000; } - .figure .figure-callout.top { - top: -9px; } - .figure .figure-callout.right { - right: -5px; } - -.figure-caption { - margin: 0 10px 20px 0; - font-size: 14px; - line-height: 20px; - font-style: italic; } - -/* rows of figures */ -.figure-row { - font-size: 0; - line-height: 0; - /* to prevent space between figures */ } - .figure-row .figure { - display: inline-block; - vertical-align: top; } - .figure-row .figure + .figure { - margin-left: 10px; - /* reintroduce space between figures */ } - /* video containers */ .framed-galaxynexus-land-span-13 { background: transparent url(../images/styles/device_galaxynexus_blank_land_span13.png) no-repeat @@ -1031,6 +1248,15 @@ scroll top left; .download-button:active { background-color: #006699; } +.button.disabled, +.button.disabled:hover, +.button.disabled:active { + background:#ebebeb; + color:#999 !important; + border-color:#999; + cursor:default; +} + /* UI tables and other things found in Writing style and Settings pattern */ .ui-table { width: 100%; @@ -1071,233 +1297,6 @@ scroll top left; - - - - - - - - - - - - - - - -/***** PREVIOUSLY style.css ******************/ - - - - - -@media screen, projection, print { -[dir='rtl'] { - direction: rtl; -} -html { - line-height: 20px; -} -pre, table, input, textarea, code { - font-size: 1em; -} -address, abbr, cite { - font-style: normal; -} -[dir='rtl'] th { - text-align: right; -} -html[lang^=ja] blockquote, html[lang^=ja] q, html[lang^=ko] blockquote, html[lang^=ko] q, -html[lang^=zh] blockquote, html[lang^=zh] q { - font-style: normal; -} -q { - font-style: italic; -} -fieldset, iframe, img { - border: 0; -} -img { - -ms-interpolation-mode: bicubic; - vertical-align: middle; - max-width: 100%; -} -q { - quotes: none; -} -sup, sub { - font-size: 11px; - line-height: 0; -} -} - -@media screen, projection { - -table, fieldset { - margin: 0; -} -h1 { - color:#333; - font-size: 34px; - margin: 36px 0 27px; - padding:0 0 10px; - font-weight:300; -} -h1, h2 { - line-height: 30px; -} -h1.short { - margin-right:320px; -} -h1.short { - margin-right:320px; -} -h1.super { - font-size: 37px; -} -h2 { - color:#333; - font-size: 26px; - margin: 32px 0 20px; - padding:0; - font-weight:300; -} -h3 { - color:#333; - font-size: 21px; - font-weight:400; - margin:21px 0 14px 0; -} -h3, h4 { - line-height: 21px; -} -h4 { - font-size: 18px; - margin: 12px 0; - font-weight:500; -} -h5 { - font-size: 14px; -} -h5, h6 { - margin: 5px 0; -} -h6 { - font-size: 12px; -} -hr { /* applied to the bottom of h2 elements */ - height: 1px; - margin: 3px 0 12px; - border: 0; - background: #ccc; -} -p, pre, table, form { - margin: 0 0 15px; -} -small { - font-size: 11.5px; - color: #000; -} -ul, ol { - margin: 0 0 15px 18px; - padding: 0; -} -[dir='rtl'] ul, [dir='rtl'] ol { - margin: 10px 30px 10px 10px; -} -ul ul, ul ol, ol ul, ol ol { - margin-bottom: 0; - margin-top: 0; -} -li { - margin:0 0 5px; -} -dd { - margin:0 0 10px 30px; -} -dd p, -dd pre, -dd ul, -dd ol, -dd dl { - margin-top:10px; -} -li p, -li pre, -li ul, -li ol, -li dl { - margin-top:5px; - margin-bottom:5px; -} -dl dd dl:first-child { - margin-top:0; -} -pre strong, pre b, a strong, a b, a code { - color: inherit; -} -pre, code { - color: #060; - font: 13px/1.5 monospace; -} -code { - font-weight:bold; - font: 13px/14px monospace; -} - -legend { - display: none; -} -a:link, a:visited, .link-color { - color: #258aaf; - text-decoration: none; -} -a:focus, a:hover, a:active { - color: #33B5E5; - text-decoration: none; -} -a.white { - color: #fff; - text-decoration:underline; -} -a.white:hover, a.white:active { - color: #ccc !important; -} -strong, b { - font-weight:bold; - color: #222; -} -table { - border-collapse: collapse; - border-spacing: 0; - border:0; - margin: .5em 1em 1em 0; - width:100%; /* consistent table widths; within IE's quirks */ - background-color:#f7f7f7; -} -th, td { - padding: 4px 12px; - vertical-align: top; - text-align: left; -} -td { - background-color:inherit; - border:solid 1px #DDD; -} -td *:last-child { - margin-bottom:0; -} -th { - background-color: #999; - color: #fff; - border:solid 1px #DDD; - font-weight: normal; -} -tr:first-of-type th:first-of-type:empty { - visibility: hidden; -} - /* -------------------------------------------------------------------------- Footer */ @@ -1468,430 +1467,23 @@ color-stop(50%, #acbc00), color-stop(50%, #bdde00), color-stop(100%, #bdde00)); } /* ============================================================================= - Columns - ========================================================================== */ - -@media screen, projection, print { -.full { - padding: 2.5em 0; - border-top: solid 1px #ddd; - border-bottom: solid 1px #ddd; - background: #f7f7f7; -} -.wrap { - margin: 0 auto; - width: 940px; - clear: both; -} -.cols { - height: 1%; - margin: 0 -1.533742331288343558282%; - width: 103.06748466257669%} -*+html .cols { - margin-bottom: 20px; -} -.cols:after { - clear: both; - content: ' '; - display: block; - height: 0; - visibility: hidden; -} -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, -.col-13, .col-14, .col-15, .col-16 { - display: inline; - float: left; - margin-left: 10px; - margin-right: 10px; -} -/* -* html .col-1, * html .col-2, * html .col-3, * html .col-4, * html .col-5, * html .col-6, * html -.col-7, * html .col-8, * html .col-9, * html .col-10, * html .col-11, * html .col-12 { - margin: 0; - padding: 0 1.4% 20px; -} -[dir='rtl'] .col-1, [dir='rtl'] .col-2, [dir='rtl'] .col-3, [dir='rtl'] .col-4, [dir='rtl'] .col-5, -[dir='rtl'] .col-6, [dir='rtl'] .col-7, [dir='rtl'] .col-8, [dir='rtl'] .col-9, [dir='rtl'] .col-10, -[dir='rtl'] .col-11, [dir='rtl'] .col-12 { - float: right; -} -*/ -.col-1 { width: 40px } -.col-2 { width: 100px } -.col-3 { width: 160px } -.col-4 { width: 220px } -.col-5 { width: 280px } -.col-6 { width: 340px } -.col-7 { width: 400px } -.col-8 { width: 460px } -.col-9 { width: 520px } -.col-10 { width: 580px } -.col-11 { width: 640px } -.col-12 { width: 700px } -.col-13 { width: 760px } -.col-14 { width: 820px } -.col-15 { width: 880px } -.col-16 { width: 940px } -} - -.col-right { - margin-right:0px; -} - -@media screen and (max-width:772px) { -.col-5, .col-6, .col-7 { - clear: both; - width: 97.0238096%} -} - -/* ============================================================================= Layout ========================================================================== */ @media screen, projection, print { -/* -------------------------------------------------------------------------- -Header, Login, Nav-X, Search -*/ -#header { - margin: 0; - padding: 0; -} -#header:before, #header:after { - content: ""; - display: table; - clear: both -} -.logo, .nav-x { - float: left; -} -.nav-x { - margin-top: -2px; - list-style-type: none; -} -.nav-x a { - color: #333; - font-size: 16px; -} -.about a.selected { - color: #9933CC; -} -.design a.selected { - color: #33b5e5; -} -.develop a.selected { - color: #F80; -} -.distribute a.selected { - color: #9C0; -} - - - -.nav-x li { - display: inline; - margin-right: 45px; -} -.search { - float: right; - position: relative; - width: 220px -} -.search .bottom, .search .left, .search .right { - position: absolute; - background-color: #a3a3a3; -} -.search .bottom { - width: 220px; - height: 1px; - top: 24px; - left: 0 -} -.search .left, .search .right { - height: 5px; - width: 1px -} -.search .left { top: 19px; left: 0 } -.search .right { top: 19px; right: 0 } -.search form { - float: left; - margin-top: 2px; - width: inherit; -} -.search .close, -#player-frame .close { - position: absolute; - right: 8px; - bottom: 4px; - width: 16px; - height: 16px; - margin: 0; - text-indent: -1000em; - background: url(../images/close.png) no-repeat 0 0; - z-index:9999; -} -.search .close:hover, .search .close:focus, -#player-frame .close:hover, #player-frame .close:focus { - background-position: -16px 0; - cursor:pointer; -} -#player-frame .close { - top: 6px; -} -.search form input { - color: #999; - font-size: 1em; - width: inherit; - border: none; - margin: 0; - padding:0 0 0 6px; - z-index: 1500; - background-color: transparent -} -.search:hover .bottom, .search:hover .left, .search:hover .right { - background-color: #33b5e5; -} -.search:hover .icon { - background-position: -8px 0 -} -.search form input:focus { - color: #222; - font-weight: bold; - outline:0; -} -/* Search Dropdown */ -.search-dropdown { - padding: 15px; - width: 192px; - border: solid 1px #c5c5c5; - background: #fff; +.training-nav-top { + border:1px solid #e5e5e5; + border-width: 1px 1px 0; + bottom: -56px; + box-sizing: border-box; position: absolute; - top: 35px; - left: 0; - -moz-box-shadow: 0 0 10px rgba(0,0,0,0.2); - -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.2); - box-shadow: 0 0 10px rgba(0,0,0,0.2) -} -.search-dropdown ul, .search-dropdown ul li { - list-style-type: none; - margin: 0; - padding: 0 -} -.search-dropdown ul li { - clear: both -} -.search-dropdown img { - float: left; - margin: 0 10px 10px 0 -} -.search-dropdown h6 { - color: #222; - margin: 0; - line-height: normal -} -.search-dropdown .desc { - color: #999; - font-size: 11.5px; - line-height: normal; - margin: 0; -} -.search-dropdown li a:hover h6, .search-dropdown li a:hover .desc { - color: #33b5e5 -} -/* -------------------------------------------------------------------------- -Buttons -*/ -.button, a.button, .button-secondary, a.button-secondary { - border-image: initial; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - cursor: pointer; -} -.button, a.button { - display:inline-block; - background-color: #09c; - background-image: -webkit-gradient(linear, left top, left bottom, from(#2faddb), to(#09c)); - background-image: -webkit-linear-gradient(top, #2faddb, #09c); - background-image: -moz-linear-gradient(top, #2faddb, #09c); - background-image: -ms-linear-gradient(top, #2faddb, #09c); - background-image: -o-linear-gradient(top, #2faddb, #09c); - background-image: linear-gradient(top, #2faddb, #09c); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#2faddb', EndColorStr='#0099cc',GradientType=0); - border: 1px solid #3990ab; - color: #fff; -} -.button-secondary, a.button-secondary { - background-color: #f3f3f3; - border: 1px solid #dcdcdc; - color: #444; -} -a.button, a.button:visited, a.button-secondary, a.button-secondary:visited { - margin-right: 16px; - font-weight: 400; - min-width: 54px; - outline: 0; - padding: 8px 15px; - text-align: center; -} -.button, .button-secondary { - margin-right: 16px; - font-weight: 400; - min-width: 54px; - outline: 0; - padding: 0 15px; - text-align: center; -} -.button:hover, a.button:hover { - border-color: #09c; - background-color: #4cadcb; - background-image: -webkit-gradient(linear, left top, left bottom, from(#5dbcd9), to(#4cadcb)); - background-image: -webkit-linear-gradient(top, #5dbcd9, #4cadcb); - background-image: -moz-linear-gradient(top, #5dbcd9, #4cadcb); - background-image: -ms-linear-gradient(top, #5dbcd9, #4cadcb); - background-image: -o-linear-gradient(top, #5dbcd9, #4cadcb); - background-image: linear-gradient(top, #5dbcd9, #4cadcb); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#5dbcd9', -EndColorStr='#4cadcb',GradientType=0); - color: #fff !important; -} -.button:active, a.button:active { - background-color: #1e799a; - background-image: none; - border-color: #30b7e6; -} -a.button.big.subtitle { - line-height:18px; -} -.button-secondary:hover, a.button-secondary:hover { - border-color: #dbdbdb; - background-color: #f3f3f3; - background-image: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#ececec)); - background-image: -webkit-linear-gradient(top, #f9f9f9, #ececec); - background-image: -moz-linear-gradient(top, #f9f9f9, #ececec); - background-image: -ms-linear-gradient(top, #f9f9f9, #ececec); - background-image: -o-linear-gradient(top, #f9f9f9, #ececec); - background-image: linear-gradient(top, #f9f9f9, #ececec); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f9f9f9', -EndColorStr='#ececec'); - color: #33B5E5 !important; -} -.button-secondary:active, a.button-secondary:active { - border-color: #dadada; - background: #ebebeb; /* Old browsers */ - /* IE9 SVG, needs conditional override of 'filter' to 'none' */ - background: -url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/ -Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0Jv -eD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+ -CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIg -eDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ViZWJl -YiIgc3RvcC1vcGFjaXR5PSIxIi8+ -CiAgICA8c3RvcCBvZmZzZXQ9IjEwJSIgc3RvcC1jb2xvcj0iI2Y5ZjlmOSIgc3RvcC1vcGFjaXR5PSIxIi8+ -CiAgICA8c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iI2ZhZmFmYSIgc3RvcC1vcGFjaXR5PSIxIi8+ -CiAgICA8c3RvcCBvZmZzZXQ9IjkwJSIgc3RvcC1jb2xvcj0iI2Y5ZjlmOSIgc3RvcC1vcGFjaXR5PSIxIi8+ -CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmNmY2ZjYiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFy -R3JhZGllbnQ+ -CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIg -Lz4KPC9zdmc+); - background: -moz-linear-gradient(top, #ebebeb 0%, #f9f9f9 5%, #fafafa 50%, #f9f9f9 90%, -#ffffff 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ebebeb), -color-stop(5%,#f9f9f9), color-stop(50%,#fafafa), color-stop(90%,#f9f9f9), color-stop(100%,#ffffff)); -/* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #ebebeb 0%,#f9f9f9 5%,#fafafa 50%,#f9f9f9 -90%,#ffffff 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #ebebeb 0%,#f9f9f9 5%,#fafafa 50%,#f9f9f9 90%,#ffffff -100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, #ebebeb 0%,#f9f9f9 5%,#fafafa 50%,#f9f9f9 90%,#ffffff -100%); /* IE10+ */ - background: linear-gradient(top, #ebebeb 0%,#f9f9f9 5%,#fafafa 50%,#f9f9f9 90%,#ffffff -100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebebeb', -endColorstr='#ffffff',GradientType=0 ); /* IE6-8 */ - -webkit-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); - -moz-box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); - box-shadow: inset 0px 0px 5px 2px rgba(0, 0, 0, .05); - color: #258AAF !important; -} -.button.big { - font-size:20px; - display:inline-block; -} -.button.big span.small { - font-size:14px; -} -.button-caption { - margin-top:10px; - font-size:12px; - font-style:italic; -} - -.button.disabled, -.button.disabled:hover, -.button.disabled:active { - background:#ebebeb; - color:#999 !important; - border-color:#999; - cursor:default; -} - -.training-nav-top a.button-secondary, -.training-nav-bottom a.button-secondary { - display:block; - float:left; - margin:0; - width:130px; - text-transform:uppercase; - font-weight:bold; - - background-color: #f3f3f3; - background-image: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#ececec)); - background-image: -webkit-linear-gradient(top, #f9f9f9, #ececec); - background-image: -moz-linear-gradient(top, #f9f9f9, #ececec); - background-image: -ms-linear-gradient(top, #f9f9f9, #ececec); - background-image: -o-linear-gradient(top, #f9f9f9, #ececec); - background-image: linear-gradient(top, #f9f9f9, #ececec); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f9f9f9', -EndColorStr='#ececec'); - color: #33B5E5; -} - -.training-nav-top a.button-secondary:hover, -.training-nav-bottom a.button-secondary:hover { - background-color: #09c; - background-image: -webkit-gradient(linear, left top, left bottom, from(#2faddb), to(#09c)); - background-image: -webkit-linear-gradient(top, #2faddb, #09c); - background-image: -moz-linear-gradient(top, #2faddb, #09c); - background-image: -ms-linear-gradient(top, #2faddb, #09c); - background-image: -o-linear-gradient(top, #2faddb, #09c); - background-image: linear-gradient(top, #2faddb, #09c); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#2faddb', EndColorStr='#09c'); - border: 1px solid #3990ab; - color: #fff !important; -} - -.training-nav-top a.button-secondary.last, -.training-nav-bottom a.button-secondary.last { - border-left:0; -} - -.training-nav-top a.button-secondary.double-size, -.training-nav-bottom a.button-secondary.double-size { - width:291px; + right: 0; + width: 280px; } -.training-nav-top, .training-nav-bottom { float:right; margin:0 0 0 20px; -} - -.training-nav-top { - position:relative; - top:73px; -} - -.training-nav-bottom { padding:0 0 20px; } @@ -1904,33 +1496,38 @@ EndColorStr='#ececec'); } #tb-wrapper { - margin:51px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */ + margin:56px 0 0 20px; /* negative top-margin to counter the content-header bottom margin */ } #tb, #qv { - font-size:13px; - line-height:18px; - width:238px; - border:1px solid #ccc; - float:right; + border: 1px solid #e5e5e5; + box-sizing: border-box; + float: right; + line-height: 16px; + padding: 5px 0; + width: 240px; } #tb { - width:278px; + width:280px; } #tb h2, #qv h2 { - margin:10px 15px; - padding:0; - text-transform:uppercase; - border-bottom:1px solid gainsboro; + border-top: 1px solid #e5e5e5; + color: inherit; + font-size: 16px; + line-height: 24px; + margin: 15px 0 4px; + padding: 10px 15px 0; } -#tb *, -#qv * { - font-size:inherit; +#tb h2:first-child, +#qv h2:first-child { + border-top: 0; + padding-top: 0; + margin-top: 10px; } #tb .download-box, @@ -1942,7 +1539,28 @@ EndColorStr='#ececec'); #qv .download-box .filename { font-size:11px; margin:4px 4px 10px; - color:#666; +} + +@media (max-width: 719px) { + .training-nav-top { + left: 0; + width: auto; + } + + #tb-wrapper { + clear: none; + float: none; + margin-left: 0; + } + + #tb { + float: none; + width: auto; + } + + #qv-wrapper { + display: none; + } } @@ -1959,9 +1577,9 @@ EndColorStr='#ececec'); width:226px; font-size:13px; line-height:18px; - border-left:4px solid #99CC00; + border-left:3px solid #a9e27d; float:right; - padding:0 0 0 10px; + padding:0 0 0 20px; margin:0 0 1em 20px; } @@ -1985,7 +1603,15 @@ EndColorStr='#ececec'); #tb ol, #tb ul, #qv ul { - margin:0 15px 10px 35px; + list-style-type: none; + margin:0 15px 10px 15px; +} + +#tb li, +#qv li { + margin: 8px 0; + padding: 0 0 0 16px; + position: relative; } #tb p { @@ -2005,11 +1631,7 @@ EndColorStr='#ececec'); #qv ul ul, .sidebox ol ol, .sidebox ul ul { - margin-bottom:0; -} - -#qv ol ol { - margin:3px 0 3px 15px; + margin: 8px 0; } .sidebox p, @@ -2145,7 +1767,6 @@ form .form-error input[type='text'], form .form-error textarea { border-radius: 2px; margin: 10px 0; padding: 20px; - color: #666; position: relative; background: #f9f9f9; } @@ -2332,16 +1953,11 @@ a:visited, /* nav tree */ -#side-nav, #swapper, -#nav-tree, #tree-list { +#swapper, #nav-tree, #tree-list { overflow:hidden; margin-left:0; } -#devdoc-nav { - overflow:visible !important; /* To keep the "to top" button visible */ -} - #nav-tree ul { list-style:none; padding:0; @@ -2443,7 +2059,7 @@ a:visited, border-bottom: 1px solid #CCC; background:#e9e9e9; background: rgba(0, 0, 0, 0.05); /* matches #nav li.expanded */ - + line-height: 19px; /* Fix regression after page line-height is bumped to 24px */ } #api-nav-title { padding:0 5px; @@ -2795,7 +2411,7 @@ a#butterbar-message:hover { } /* -------------------------------------------------------------------------- -Misc +Misc and article typography */ @@ -2842,27 +2458,121 @@ pre.classic { p.img-caption { margin: -10px 0 20px; - font-size:13px; - color:#666; + font-size: 13px; } -div.figure, -div.figure-right { - float:right; - clear:right; - margin:10px 0 0 0; - padding:0 0 0 20px; +/* figures and callouts */ +.figure { + position: relative; +} + +.figure.pad-below { + margin-bottom: 20px; +} + +.figure .figure-callout { + position: absolute; + color: #fff; + font-weight: 500; + font-size: 16px; + line-height: 23px; + text-align: center; + background: transparent url(../images/styles/callout.png) no-repeat scroll 50% 50%; + padding-right: 2px; + width: 30px; + height: 29px; + z-index: 1000; +} + +.figure .figure-callout.top { + top: -9px; +} + +.figure .figure-callout.right { + right: -5px; +} + +.figure-caption { + margin: 0 10px 20px 0; + font-size: 14px; + line-height: 20px; + font-style: italic; +} + +/* rows of figures */ +.figure-row { + font-size: 0; + line-height: 0; + /* to prevent space between figures */ +} + +.figure-row .figure { + display: inline-block; + vertical-align: top; +} + +.figure-row .figure + .figure { + margin-left: 10px; + /* reintroduce space between figures */ +} + +.border-img { + border: 1px solid #CCC; +} + +.center-img { + margin: auto; + text-align: center; +} +.center-img img { + margin-bottom: 15px; +} + +.figure img, +.figure-right img, +.figure-left img, +.figure-center img, +.border-img { + margin-bottom: 15px; +} + +.figure-center { + margin: 32px auto 24px; + max-width: 100%; +} + +.figure, +.figure-right { + clear: right; + float: right; + margin: 10px 0 0 0; + padding: 0 0 0 20px; + max-width: 50%; /* width must be defined w/ an inline style matching the image width */ } -div.figure-left { - float:left; - clear:left; - margin:10px 0 0 0; - padding:0 20px 0 0; +.figure-left { + clear: left; + float: left; + margin: 10px 0 0 0; + padding: 0 20px 0 0; + max-width: 50%; /* width must be defined w/ an inline style matching the image width */ } +@media (max-width: 719px) { + /* Collapse on mobile. */ + .figure, + .figure-right, + .figure-left { + float: none; + clear: none; + padding: 0; + margin: 32px auto 24px; + max-width: 100%; + } +} + img.frame { border:1px solid #DDD; padding:4px; @@ -2871,38 +2581,31 @@ img.frame { p.table-caption { margin: 0 0 4px 0; font-size:13px; - color:#666; } p.code-caption { margin-bottom: 4px; font: 12px/1.5 monospace; - color:#666; -} - -div.note, -div.caution, -div.warning { - margin: 0 0 15px; } p.note, div.note, p.caution, div.caution, p.warning, div.warning { - padding: 0 0 0 10px; - border-left: 4px solid; + padding: 0 0 0 20px; + border-left: 3px solid; + margin: 16px 0; } p.note, div.note { - border-color: #258AAF; + border-color: #66c2ff; } p.caution, div.caution { - border-color: #FF8800; + border-color: #f81; } p.warning, div.warning { - border-color: #ff4443; + border-color: #f55; } div.note.design { @@ -2965,8 +2668,7 @@ div.design-announce p { a.notice-developers-video, a.notice-developers, a.notice-designers-video, -a.notice-designers, -a.notice-designers-material { +a.notice-designers { float:right; clear:right; width:238px; @@ -2977,15 +2679,13 @@ a.notice-designers-material { a.notice-developers-video.wide, a.notice-developers.wide, a.notice-designers-video.wide, -a.notice-designers.wide, -a.notice-designers-material.wide { +a.notice-designers.wide { width:278px; } a.notice-developers-video div, a.notice-developers div, a.notice-designers-video div, -a.notice-designers div, -a.notice-designers-material div { +a.notice-designers div { min-height:40px; background:url('../images/styles/notice-developers@2x.png') no-repeat 10px 10px; background-size:40px 40px; @@ -3003,22 +2703,16 @@ a.notice-developers-video div { background:url('../images/styles/notice-developers-video@2x.png') no-repeat 10px 10px; background-size:40px 40px; } -a.notice-designers-material div { - background:url('../images/styles/notice-designers-material@2x.png') no-repeat 10px 10px; - background-size:40px 40px; -} a.notice-developers-video:hover, a.notice-developers:hover, a.notice-designers-video:hover, -a.notice-designers:hover, -a.notice-designers-material:hover { +a.notice-designers:hover { background:#eee; } a.notice-developers-video h3, a.notice-developers h3, a.notice-designers-video h3, -a.notice-designers h3, -a.notice-designers-material h3 { +a.notice-designers h3 { font-size:13px; line-height:18px; font-weight:bold; @@ -3029,16 +2723,14 @@ a.notice-designers-material h3 { a.notice-developers-video p, a.notice-developers p, a.notice-designers-video p, -a.notice-designers p, -a.notice-designers-material p { +a.notice-designers p { margin:0; line-height:14px; } a.notice-developers-video.left, a.notice-developers.left, a.notice-designers-video.left, -a.notice-designers.left, -a.notice-designers-material.left { +a.notice-designers.left { margin-left:0; float:left; } @@ -3465,6 +3157,15 @@ Page-Specific Styles } */ +/* First paragraph of a content pages is a bit larger + - note the very specific selector. */ +.jd-descr > p:first-child, +.jd-descr > #tb-wrapper + p, +.jd-descr > #qv-wrapper + p { + font-size: 16px; + margin-bottom: 16px; +} + /* page-top-right container for reference pages (holds links to summary tables) */ #api-info-block { @@ -3676,6 +3377,7 @@ h5.jd-tagtitle { font-style:italic; } + /* Inline api level indicator for methods */ div.api-level { font-size:.8em; @@ -3696,27 +3398,6 @@ table.jd-tagtable th { } - - - - - - - - - - - - - - - - - - - - - /* SEARCH FILTER */ .menu-container { @@ -3726,53 +3407,38 @@ table.jd-tagtable th { font-weight:normal; } -.search_filtered_wrapper.reference { - width: 193px; - float: right; -} -.search_filtered_wrapper.docs { - width:875px; - float: left; - position:absolute; - top:26px; - right:66px; +.search_filtered_wrapper { + position: absolute; + right: 18px; + top: 64px; } .suggest-card { + float:right; position:relative; width:170px; min-height:90px; - padding:5px; border: solid 1px #C5C5C5; background: white; - top: 15px; margin-right:-5px; -moz-box-shadow: 0 0 10px rgba(0,0,0,0.2); -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); } .suggest-card.reference { - position:absolute; - z-index:999; - min-width:171px; /* +padding and border makes this match input width */ - min-height:93px; /* add 3px because this has 1 not 4px top border */ - width:auto; - top:41px; - margin:0; + z-index: 998; + width: auto; } .suggest-card.develop { z-index:997; - border-top: solid 4px #F80; - float:right; + border-top: solid 4px #ff7043; } .suggest-card.design { z-index:996; - border-top: solid 4px #33b5e5; - float:right; + border-top: solid 4px #00bcd4; } .suggest-card.distribute { z-index:995; - border-top: solid 4px #9C0; - float:right; + border-top: solid 4px #afb42b; } .child-card { width:100%; @@ -3790,7 +3456,7 @@ table.jd-tagtable th { ul.search_filtered { min-width:100%; list-style: none; - margin: 0 0 5px; + margin: 5px 0; padding: 0; } .search_filtered .jd-selected { @@ -3799,7 +3465,7 @@ ul.search_filtered { } .search_filtered .jd-selected, .search_filtered .jd-selected a { - color:#09C !important; + color:#039BE5 !important; } .no-display { @@ -3809,13 +3475,13 @@ ul.search_filtered { .search_filtered li.jd-autocomplete { font-size: 0.81em; border: none; - margin: 0 0 2px; + margin: 0; padding: 0; line-height:1.5em; } .search_filtered li a { - padding:0 5px; + padding: 2px 10px; color:#222 !important; display:inline-block; line-height:12px; @@ -3825,8 +3491,8 @@ ul.search_filtered { font-weight:bold; color:#444; border: none; - margin: 8px 0 2px; - padding:1px 5px; + margin: 0; + padding: 2px 10px; line-height:1.5em; } .search_filtered li.header.small { @@ -3843,6 +3509,51 @@ ul.search_filtered { margin: 0 0 2px; } +@media (max-width: 719px) { + .search_filtered_wrapper { + left: 24px; + right: 24px; + top: 44px; + } + + .suggest-card { + box-shadow: 0 2px 1px rgba(0, 0, 0, 0.1), 0 0 1px rgba(0, 0, 0, 0.1); + float: none; + margin-right: 0; + min-height: 0; + max-height: 204px; + overflow: hidden; + } + + .suggest-card.develop, + .suggest-card.design, + .suggest-card.distribute { + display: none !important; + } + + ul.search_filtered { + margin: 0; + } + + .search_filtered li.jd-autocomplete { + border-top: solid 1px #C5C5C5; + font-size: inherit; + text-align: left; + } + + .search_filtered li.jd-autocomplete:first-child { + border-top: 0; + } + + .search_filtered li a { + display: block; + overflow: hidden; + padding: 14px 10px; + text-overflow: ellipsis; + white-space: nowrap; + } +} + .show-item { display: table-row; } @@ -3852,8 +3563,6 @@ ul.search_filtered { - - /* SEARCH RESULTS */ @@ -3950,10 +3659,10 @@ td.gsc-search-button { } #searchResults .gsc-tabsArea { - position:relative; - white-space:nowrap; - float:left; - width:200px; + position: relative; + white-space: nowrap; + float: left; + width: 25%; } #searchResults .gsc-above-wrapper-area { @@ -3961,12 +3670,26 @@ td.gsc-search-button { } #searchResults .gsc-resultsbox-visible { - float:left; - width:720px; - margin-left:20px; + box-sizing: border-box; + float: left; + padding-left:20px; + width: 75%; +} + +@media (max-width: 719px) { + #searchResults .gsc-tabsArea { + display: none; + } + + #searchResults .gsc-resultsbox-visible { + float: none; + padding-left: 0; + width: auto; + } } #searchResults .gsc-tabHeader { + margin-top: 4px; padding: 3px 6px; position:relative; width:auto; @@ -3975,7 +3698,7 @@ td.gsc-search-button { #searchResults h2#searchTitle { padding:0; - margin:5px 0; + margin:30px 0 5px; border:none; } @@ -4023,98 +3746,25 @@ td.gsc-search-button { #searchResults .gsc-tabHeader.gsc-tabhInactive, #searchResults .gsc-cursor-page { - text-decoration:none; - color:#258AAF; - border: solid 1px #DADADA; -} - -#searchResults .gsc-tabHeader.gsc-tabhInactive:hover, -#searchResults .gsc-cursor-page:hover { - border-color: #DBDBDB; - background-color: #F3F3F3; - background-image: -webkit-gradient(linear, left top, left bottom, from(#F9F9F9), to(#ECECEC)); - background-image: -webkit-linear-gradient(top, #F9F9F9, #ECECEC); - background-image: -moz-linear-gradient(top, #F9F9F9, #ECECEC); - background-image: -ms-linear-gradient(top, #F9F9F9, #ECECEC); - background-image: -o-linear-gradient(top, #F9F9F9, #ECECEC); - background-image: linear-gradient(top, #F9F9F9, #ECECEC); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f9f9f9', -EndColorStr='#ececec'); - color: #33B5E5; + background: #F0F0F0; + border: 0; + color: #039BE5; } #searchResults .gsc-tabHeader.gsc-tabhActive, #searchResults .gsc-tabHeader.gsc-tabhActive:hover, #searchResults .gsc-cursor-page.gsc-cursor-current-page, #searchResults .gsc-cursor-page.gsc-cursor-current-page:hover { - color:#fff; - background-color: #09C; - background-image: -webkit-gradient(linear, left top, left bottom, from(#2FADDB), to(#09C)); - background-image: -webkit-linear-gradient(top, #2FADDB, #09C); - background-image: -moz-linear-gradient(top, #2FADDB, #09C); - background-image: -ms-linear-gradient(top, #2FADDB, #09C); - background-image: -o-linear-gradient(top, #2FADDB, #09C); - background-image: linear-gradient(top, #2FADDB, #09C); - filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#2faddb', EndColorStr='#09c'); - border: 1px solid #3990AB; - z-index:100; + background-color: #039BE5; + border: 0; + color: #fff; } - /************ STICKY NAV BAR ******************/ -#header-wrapper { - background: #f9f9f9; - margin: 0 -10px 0 -10px; - padding: 31px 10px 0px 10px; - position: relative; -} -#header-wrapper #nav-x div.wrap { - max-width: 940px; - height: 38px; -} -#header-wrapper #nav-x ul.nav-x li { - margin-right: 31px !important; - margin-top: 5px; - margin-bottom: 0px; - height: 30px; -} -#header-wrapper #nav-x > div.wrap ul.nav-x li.active { - color: #669900; - border-bottom: 3px solid #669900; -} -#header-wrapper #nav-x > div.wrap ul.nav-x li.active a { - color: #669900; -} -#header-wrapper #nav-x > div.wrap ul.nav-x a { - font-size: 14.5px; -} -#header-wrapper .developer-console-btn { - float: right; - background: #fefefe; - border-radius: 4px; - padding: 8px 14px; - box-shadow: 1px 1px 0px #7a7a7a; - font-size: 14px; - margin-top: -6px; - cursor: pointer; - color: #464646; - margin-right: 20px; -} -/* not currently used */ -#header-wrapper .shadow { - width: 1034px; - height: 4px; - position: absolute; - left: 50%; - margin-left: -517px; - bottom: -4px; - background-image: url(../images/header-shadow.png); -} - #context { clear: both; padding-top: 14px; @@ -4158,75 +3808,6 @@ EndColorStr='#ececec'); display: none; } -/* Sticky Nav overrides */ -.sticky-menu { - position: fixed; - width: 940px; - height: 0px; - z-index: 51; - top: 12px; -} -#sticky-header { - display: none; - padding: 0 10px; - position: fixed; - background: #f9f9f9; - top: 0px; - left: 0px; - right: 0px; - height: 45px; - box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.1); - border-bottom: 1px solid #a5c43a; - z-index: 50; -} -#sticky-header.design { - border-bottom: 1px solid #33b5e5; -} -#sticky-header.develop { - border-bottom: 1px solid #F80; -} -#sticky-header.distribute { - border-bottom: 1px solid #9C0; -} -#sticky-header.about { - border-bottom: 1px solid #9933CC; -} -#sticky-header > div { - overflow: hidden; - *zoom: 1; - width: 940px; - margin: 0 auto; - clear: both; - padding-top: 9px; -} -#sticky-header > div .logo { - float: left; - width: 26px; - height: 25px; - background: url(../images/dac_logo.png); - background-image: -webkit-image-set(url(../images/dac_logo.png) 1x, url(../images/dac_logo@2x.png) 2x); - z-index: 52; - position: relative; -} -#sticky-header > div .top { - float: left; - width: 38px; - height: 38px; - position: relative; - background: url(../images/styles/gototop.png); - z-index: 52; -} -#sticky-header > div .breadcrumb { - float: left; - padding: 0 0 0 10px; - border-left: 1px solid #d2d2d2; - line-height: 24px; - font-size: 14px; - position: relative; - top: 0px; - z-index: 52; -} - /* offset the <a name=""> tags to account for sticky nav */ body.reference a[name] { visibility: hidden; @@ -4236,76 +3817,6 @@ body.reference a[name] { } -} - - - - - - - -/*********** PREVIOUSLY dac-styles.css ***************/ - - -#header { - border-bottom:0; -} - -#header .wrap { - max-width:940px; - height:41px; - border-bottom:1px solid; - border-color: #ccc; - position:relative; -} - -.about #header .wrap { - border-color: #9933CC; -} - -.design #header .wrap { - border-color: #33b5e5; -} - -.develop #header .wrap { - border-color: #F80; -} - -.distribute #header .wrap { - border-color: #9C0; -} - -.logo a { - float:left; -} - -#header .logo { - margin-top: -6px; - margin-left: 0px; - margin-bottom:0px; - width: 160px; - padding-right:10px; -} - - -#header-wrap .logo.landing-logo { - width:220px; - margin:0; - padding:0; - margin-bottom:22px; -} -#header-wrap .logo.landing-logo img { - padding:0 0 0 10px; -} - -.search { - height:25px; - margin-top: -3px; - margin-bottom: 0px; -} - - - /* Quicknav */ .btn-quicknav { width:20px; @@ -4343,17 +3854,6 @@ body.reference a[name] { display:block; } -.nav-x li { - display:block; - float:left; - margin-right:45px; - -webkit-transition: all 0.25s linear; - -moz-transition: all 0.25s linear; - -ms-transition: all 0.25s linear; - -o-transition: all 0.25s linear; - transition: all 0.25s linear; -} - #header-wrap.quicknav .nav-x li { min-width:160px; margin-right:20px; @@ -4439,105 +3939,6 @@ body.reference a[name] { } -/* SEARCH AND MORE */ -.search { - position: absolute; - width: 50px; - height:28px; - display: block; - margin-top:-3px; - margin-bottom:7px; - overflow:hidden; - z-index:100; - right:54px; - -webkit-transition: width 0.4s ease; - -moz-transition: width 0.4s ease; - -o-transition: width 0.4s ease; - transition: width 0.4s ease; -} - -.search #search-btn { - width:50px; - height:28px; - background:url(../images/icon_search.png) no-repeat; - float:left; -} - -.search-inner { - width:245px; -} - -.search:hover, .search.active { - width:245px; -} - -.search .bottom, .search .left, .search .right { - position: absolute; - background-color: #a2a2a2 -} - -.search .bottom { - width: 214px; - height: 1px; - top: 24px; - left: 0 -} - -.search .left, .search .right { - height: 5px; - width: 1px -} - -.search .left { - top: 22px; - left: 56px; - background-color:#CCC; -} - -.search .right { - top: 22px; - left: 238px; - background-color:#CCC; -} - -.search form { - margin-top: 2px; - width: 162px; - float:left; -} - -.search form input { - color: #2f2f2f; - font-size: 0.95em; - width: 178px; - border: none; - margin-left: 6px; - z-index: 1500; - position: relative; - background-color: transparent; - border-bottom:1px solid #CCC; - padding:0 0 0 4px; - outline:none; - height:24px; -} - -.search:hover form input { - border-bottom:1px solid #33B5E5; -} - -.search:hover .bottom, .search:hover .left, .search:hover .right { - background-color: #33b5e5; -} - -.search:hover #search-btn { - background-position: 0 -28px -} - -.search form input:focus { - color: #222; - font-weight: bold -} - .moremenu { float: right; position: relative; @@ -4690,9 +4091,9 @@ body.reference a[name] { height:12px; text-indent:-8000px; list-style:none; - margin: 0 2px; + margin: 0 3px; border-radius:6px; - background-color:#ccc; + background-color:#ddd; cursor:pointer; -webkit-transition:color .5s ease-in; -moz-transition:color .5s ease-in; @@ -4700,13 +4101,13 @@ body.reference a[name] { transition:color .5s ease-in; } .slideshow-container .pagination ul li:hover { - background-color:#999; + background-color:#bbb; } .slideshow-container .pagination ul li.active { - background-color:#33b5e5; + background-color:#6ab344; } .slideshow-container .pagination ul li.active:hover { - background-color:#33b5e5; + background-color:#6ab344; } .slideshow-container ul li { display:inline; @@ -4726,27 +4127,14 @@ a.download-sdk { padding-bottom:0px; } -#nav-x { - padding-top: 13px; -} - -#nav-x .wrap { - min-height:32px; -} - -#nav-x .wrap, #searchResults.wrap { max-width:940px; - border-bottom:1px solid #CCC; + border-bottom:1px solid #e5e5e5; } #searchResults.wrap #leftSearchControl { min-height:700px } -.nav-x { - margin-left:0; - margin-bottom:0; -} @@ -4816,7 +4204,7 @@ a.download-sdk { } .jspDrag { - background: #bbb; + background: #ccc; position: relative; top: 0; left: 0; @@ -5059,7 +4447,7 @@ a.download-sdk { display:none; margin: -1px auto 0; position: relative; - width: 940px; + max-width: 940px; height: 0px; } #player-frame { @@ -5071,6 +4459,22 @@ a.download-sdk { height: 330px; position: relative; } +#player-frame .close { + position: absolute; + right: 8px; + bottom: 4px; + width: 16px; + height: 16px; + margin: 0; + text-indent: -1000em; + top: 6px; + background: url(../images/close.png) no-repeat 0 0; + z-index:9999; +} +#player-frame .close:hover, #player-frame .close:focus { + background-position: -16px 0; + cursor:pointer; +} @@ -5125,7 +4529,7 @@ a.download-sdk { } .landing-docs .normal-links a { - color:#258aaf !important; + color:#039BE5 !important; } .plusone { @@ -5232,7 +4636,7 @@ a.download-sdk { float: left; width: 100%; text-align: center; - color: #09c !important; + color: #039BE5 !important; } .home-sections ul li a { font-weight: bold; @@ -5249,9 +4653,6 @@ a.download-sdk { .home-sections ul li.last { margin-right: 0px; } -.fullpage #footer { - margin-top: -40px; -} /************ DISTRIBUTE PAGES ******************/ @@ -5280,1241 +4681,6 @@ a.download-sdk { clear: both; } -.border-img { - border: 1px solid #CCC; -} - -.center-img { - margin: auto; - text-align: center; -} -.center-img img { - margin-bottom: 15px; -} - -.figure img, .border-img { - margin-bottom: 15px; -} - -/************ RESOURCE CARDS ******************/ - -/* Resource cards, 12, 13, 16-col */ - -/* Basic card-styling with shadow */ -.resource-card { - border-radius: 1px; - box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.12); - background: #fefefe; -} - -/* Styling for background image including tinting and section icons in stacks */ -.card-bg { - display: block; - position: absolute; - vertical-align: top; - width: 100%; - left: 0; - top: 0; - background-size: cover; - background-repeat: no-repeat; - background-position: center; - background-image: url(../images/resource-card-default-android.jpg); -} -.card-bg:after { - content: ""; - display: block; - height: 100%; - width: 100%; - opacity: 1; - background: rgba(0, 0, 0, 0.2); - -webkit-transition: opacity 0.5s; - -moz-transition: opacity 0.5s; - -o-transition: opacity 0.5s; - transition: opacity 0.5s; -} -.static .card-bg:after { - display:none; -} -.card-bg .card-section-icon { - position: absolute; - top: 50%; - width: 100%; - margin-top: -35px; - text-align: center; - padding-top: 65px; - z-index: 100; -} -.card-bg .card-section-icon .icon { - position: absolute; - left: 50%; - margin-left: -28px; - top: 0px; - width: 56px; - height: 56px; - background-repeat: no-repeat; - background-position: 50% 50%; - background-image: url(../images/stack-icon.png); -} -.card-bg .card-section-icon .section { - text-transform: uppercase; - color: white; - font-size: 14px; -} - -.card-info { - position: absolute; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - top: 0; - right: 0; - bottom: 0; - left: 0; - overflow: hidden; - background: #fefefe; - padding: 4px 12px 6px 12px; -} -.card-info .section { - text-transform: uppercase; - color: #898989; - font-size: 12px; - margin-bottom: 1px; -} -.card-info .title { - color: #363636; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding-bottom: 5px; - margin-bottom: -2px; - font-size: 16px; -} -.card-info .description { - overflow: hidden; -} -.card-info .description .text { - color: #464646; - font: 13px/15px Roboto Condensed; - overflow: hidden; - width:100%; -} -.card-info .description .util { - position: absolute; - right: 5px; - bottom: 70px; /*-2px;*/ - opacity: 0; - -webkit-transition: opacity 0.5s; - -moz-transition: opacity 0.5s; - -o-transition: opacity 0.5s; - transition: opacity 0.5s; -} -.card-info.empty-desc .title { - white-space: normal; - overflow: visible; -} -.card-info.empty-desc .description { - display: none; -} -/* Truncate card summaries at bounding box and - * and apply ellipsis at lower right */ -.ellipsis { - overflow: hidden; - float:right; - line-height: 15px; - width:100%; -} -.resource-card-6x6 .card-info .description .teddddddxt { - float:left; - position:relative; - margin-left:0; -} -.ellipsis:before { - content:""; - float: left; - width: 5px; - height:100%; -} -.ellipsis > *:first-child.text { - float: right; - width: 100% !important; - margin-left: -5px; -} -.ellipsis:after { - content: "\02026"; - height:17px; - padding-bottom:4px; - - box-sizing: content-box; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - - float: right; position: relative; - top: -16px; left: 100%; - width: 4em; margin-left: -4em; - padding-right: 5px; - - background: -webkit-gradient(linear, left top, right top, - from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white)); - background: -moz-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); - background: -o-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); - background: -ms-linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); - background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); -} -.ellipsis:after { - font-style: normal; color: #aaa; - font-size:13px; - text-align: right; -} - -/* Flow Layout */ -.resource-flow-layout { - display: inline-block; -} -.resource-flow-layout .resource-card, .resource-flow-layout .resource-card-stack { - float: left; - position: relative; -} -.resource-flow-layout .resource-card-stack > .resource-card { - margin-right: 0px !important; -} -.resource-flow-layout:after { - content: "."; - display: block; - height: 0; - position:relative; - clear: both; - visibility: hidden; -} -.resource-card:hover { - cursor: pointer; -} -.static .resource-card:hover { - cursor: auto; -} -.resource-card:hover .card-bg:after { - opacity: 0; -} -/* disabled to make way for fade/ellipsis truncation, - and the plusone moves up. -.resource-card:hover .card-info .description .text { - padding-right: 70px; -} */ -.resource-card:hover .card-info .description .util { - opacity: 1; -} - -/* Carousel Layout */ -/* Carousel styles for landing page */ -.resource-carousel-layout { - margin: 20px 0 20px 0; - position: relative; - overflow: hidden; -} -.resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next { - display: none; -} -.resource-carousel-layout .pagination { - bottom: 0px; -} -.resource-carousel-layout .frame li { - position: relative; -} -.resource-carousel-layout .frame li .card-bg { - height: 300px; -} -.resource-carousel-layout .frame li .card-info { - padding: 7px 15px 0px 15px; - top: 300px; -} -.resource-carousel-layout .frame li .card-info .section { - font-size: 13px; - margin-bottom: 7px; -} -.resource-carousel-layout .frame li .card-info .title { - font-size: 25px; - margin-bottom: 2px; -} -.resource-carousel-layout .frame li .card-info .description { - font-family: 15px/16px Roboto Condensed, sans-serif; -} -.resource-carousel-layout .frame li .card-info .description .text { - height: 40px; -} -.resource-carousel-layout .frame li .card-info .description .util { - bottom:97px; - right:4px; -} - -/* Stack Layout */ -.resource-stack-layout { - display: inline-block; -} -.resource-stack-layout .resource-card-stack { - float: left; - position: relative; -} -.resource-stack-layout .resource-card { - margin-bottom: 20px; - display: block; - position: relative; -} -.resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title { - /*text-transform: uppercase;*/ - color: #898989; - font-size: 17px; - line-height: 24px; - margin-bottom: 6px; -} -.resource-stack-layout .section-card { - height: 284px; -} -.resource-stack-layout .section-card > .card-bg { - height: 192px; -} -.resource-stack-layout .section-card > .card-info { - padding: 4px 12px 6px 12px; - top: 192px; -} -.resource-stack-layout .section-card > .card-info .section { - display: none; -} -.resource-stack-layout .section-card > .card-info .title { - font-size: 17px; - border-bottom: 1px solid #959595; - padding-bottom: 0px; -} -.resource-stack-layout .section-card > .card-info .description { - font-size: 13px; - line-height: 15px; -} -.resource-stack-layout .section-card > .card-info .description .text { - height: 30px; -} -.resource-stack-layout .related-card { - height: 90px; -} -.resource-stack-layout .related-card > .card-bg { - left: 0; - top: 0; - width: 90px; - height: 100%; - position: absolute; - display: block; -} -.resource-stack-layout .related-card > .card-info { - left: 90px; - padding: 4px 12px 4px 12px; -} -.resource-stack-layout .related-card > .card-info .section { - font-size: 12px; - margin-bottom: 1px; - display: none; -} -.resource-stack-layout .related-card > .card-info .title { - font-size: 16px; - margin-bottom: -2px; - white-space: normal; - overflow: visible; - text-overflow: ellipsis; -} -.resource-stack-layout .related-card > .card-info .title:after { - content: url(../images/link-out.png); - display: block; -} -.resource-stack-layout .related-card > .card-info .description { - display: none; -} -.resource-stack-layout .section-card-menu { - /* Flexible height */ - display: block; - height: auto; - width: auto; -} -.resource-stack-layout .section-card-menu .card-bg { - height: 155px; - /* Flexible height */ - position: relative; - display: inline-block; - vertical-align: top; -} -.resource-stack-layout .section-card-menu .card-info { - padding: 4px 12px 0px 12px; - /* Flexible height */ - position: relative; - left: auto; - top: auto; - right: auto; - bottom: auto; -} -.resource-stack-layout .section-card-menu .card-info ul { - list-style: none; - margin: 0; -} -.resource-stack-layout .section-card-menu .card-info ul li { - list-style: none; - margin: 0; - padding: 15px 0; - border-top-width: 1px; - border-top-style: solid; - border-top-color: #959595; -} -.resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:link, .resource-stack-layout .section-card-menu .card-info ul li a:visited, .resource-stack-layout .section-card-menu .card-info ul li a:active, .resource-stack-layout .section-card-menu .card-info ul li a:hover { - color: #363636 !important; -} -.resource-stack-layout .section-card-menu .card-info ul li:first-child { - border-top: none; -} -.resource-stack-layout .section-card-menu .card-info ul li:hover .title:after { - opacity: 1; - -webkit-transition: opacity 0.5s; - -moz-transition: opacity 0.5s; - -o-transition: opacity 0.5s; - transition: opacity 0.5s; -} -.resource-stack-layout .section-card-menu .card-info ul li:hover .description { - max-height: 30px; - opacity: 1; - -webkit-transition: max-height 0.5s, opacity 1s; - -moz-transition: max-height 0.5s, opacity 1s; - -o-transition: max-height 0.5s, opacity 1s; - transition: max-height 0.5s, opacity 1s; -} -.resource-stack-layout .section-card-menu .card-info .title { - font-size: 16px; - margin-bottom: -2px; - position: relative; -} -.resource-stack-layout .section-card-menu .card-info .title:after { - background: url(../images/stack-arrow-right.png); - content: ''; - opacity: 0; - -webkit-transition: opacity 0.25s; - -moz-transition: opacity 0.25s; - -o-transition: opacity 0.25s; - transition: opacity 0.25s; - position: absolute; - right: 0px; - top: 3px; - width: 10px; - height: 15px; -} -.resource-stack-layout .section-card-menu .card-info .title.more { - text-transform: uppercase; - color: #898989; - display: inline-block; -} -.resource-stack-layout .section-card-menu .card-info .title.more:after { - background: url(../images/stack-arrow-right.png); - content: ''; - display: block; - position: absolute; - right: -20px; - top: 3px; - width: 10px; - height: 15px; -} -.resource-stack-layout .section-card-menu .card-info .description { - max-height: 0px; - opacity: 0; - overflow: hidden; - font-size: 13px; - line-height: 15px; - /* Hover off */ - -webkit-transition: max-height 0.5s, opacity 0.5s; - -moz-transition: max-height 0.5s, opacity 0.5s; - -o-transition: max-height 0.5s, opacity 0.5s; - transition: max-height 0.5s, opacity 0.5s; -} -.resource-stack-layout .section-card-menu .card-info .description .text { - height: 30px; -} -.resource-stack-layout:after { - content: "."; - display: block; - height: 0; - clear: both; - visibility: hidden; -} - -/* Generate the flow layout styles for a 3-column 16-col span */ -.resource-flow-layout.col-16 { - margin: 0 -14px 0 0; - width: 954px; -} -.resource-flow-layout.col-16 .resource-card, .resource-flow-layout.col-16 .resource-card-stack { - margin: 0 14px 20px 0; -} -.resource-flow-layout.col-16 .resource-card-row-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-16 .resource-card-col-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-16 .resource-card-3x6 { - width: 145px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-3x12 { - width: 145px; - height: 588px; -} -.resource-flow-layout.col-16 .resource-card-3x18 { - width: 145px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-6x6 { - width: 304px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-6x12 { - width: 304px; - height: 588px; -} -.resource-flow-layout.col-16 .resource-card-6x18 { - width: 304px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-9x6 { - width: 463px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-9x12 { - width: 463px; - height: 588px; -} -.resource-flow-layout.col-16 .resource-card-9x18 { - width: 463px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-12x6 { - width: 622px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-12x12 { - width: 622px; - height: 588px; -} -.resource-flow-layout.col-16 .resource-card-12x18 { - width: 622px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-15x6 { - width: 781px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-15x12 { - width: 781px; - height: 588px; -} -.resource-flow-layout.col-16 .resource-card-15x18 { - width: 781px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-18x6 { - width: 940px; - height: 284px; -} -.resource-flow-layout.col-16 .resource-card-18x12 { - width: 940px; - height: 420px; -} -.resource-flow-layout.col-16 .resource-card-18x18 { - width: 940px; - height: 892px; -} -.resource-flow-layout.col-16 .resource-card-3x2 { - width: 145px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-3x2x3 { - width: 145px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-3x3 { - width: 145px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-3x3x2 { - width: 145px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-16 .resource-card-6x2 { - width: 304px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-6x2x3 { - width: 304px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-6x3 { - width: 304px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-6x3x2 { - width: 304px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-16 .resource-card-9x2 { - width: 463px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-9x2x3 { - width: 463px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-9x3 { - width: 463px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-9x3x2 { - width: 463px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-16 .resource-card-12x2 { - width: 622px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-12x2x3 { - width: 622px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-12x3 { - width: 622px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-12x3x2 { - width: 622px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-16 .resource-card-15x2 { - width: 781px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-15x2x3 { - width: 781px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-15x3 { - width: 781px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-15x3x2 { - width: 781px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-16 .resource-card-18x2 { - width: 940px; - height: 95px; -} -.resource-flow-layout.col-16 .resource-card-18x2x3 { - width: 940px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-16 .resource-card-18x3 { - width: 940px; - height: 142px; -} -.resource-flow-layout.col-16 .resource-card-18x3x2 { - width: 940px; - height: 138px; - margin-bottom: 8px; -} - -/* Generate the flow layout styles for a 3-column 16-col span */ -.resource-flow-layout.col-12 { - margin: 0 -14px 0 0; - width: 714px; -} - -.resource-flow-layout.col-12 .resource-card, .resource-flow-layout.col-12 .resource-card-stack { - margin: 0 14px 20px 0; -} -.resource-flow-layout.col-12 .resource-card-row-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-12 .resource-card-col-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-12 .resource-card-3x6 { - width: 105px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-3x12 { - width: 105px; - height: 588px; -} -.resource-flow-layout.col-12 .resource-card-3x18 { - width: 105px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-6x6 { - width: 224px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-6x12 { - width: 224px; - height: 588px; -} -.resource-flow-layout.col-12 .resource-card-6x18 { - width: 224px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-9x6 { - width: 343px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-9x12 { - width: 343px; - height: 588px; -} -.resource-flow-layout.col-12 .resource-card-9x18 { - width: 343px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-12x6 { - width: 462px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-12x12 { - width: 462px; - height: 588px; -} -.resource-flow-layout.col-12 .resource-card-12x18 { - width: 462px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-15x6 { - width: 581px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-15x12 { - width: 581px; - height: 588px; -} -.resource-flow-layout.col-12 .resource-card-15x18 { - width: 581px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-18x6 { - width: 700px; - height: 284px; -} -.resource-flow-layout.col-12 .resource-card-18x12 { - width: 700px; - height: 420px; -} -.resource-flow-layout.col-12 .resource-card-18x18 { - width: 700px; - height: 892px; -} -.resource-flow-layout.col-12 .resource-card-3x2 { - width: 105px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-3x2x3 { - width: 105px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-3x3 { - width: 105px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-3x3x2 { - width: 105px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-12 .resource-card-6x2 { - width: 224px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-6x2x3 { - width: 224px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-6x3 { - width: 224px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-6x3x2 { - width: 224px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-12 .resource-card-9x2 { - width: 343px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-9x2x3 { - width: 343px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-9x3 { - width: 343px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-9x3x2 { - width: 343px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-12 .resource-card-12x2 { - width: 462px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-12x2x3 { - width: 462px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-12x3 { - width: 462px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-12x3x2 { - width: 462px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-12 .resource-card-15x2 { - width: 581px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-15x2x3 { - width: 581px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-15x3 { - width: 581px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-15x3x2 { - width: 581px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-12 .resource-card-18x2 { - width: 700px; - height: 95px; -} -.resource-flow-layout.col-12 .resource-card-18x2x3 { - width: 700px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-12 .resource-card-18x3 { - width: 700px; - height: 142px; -} -.resource-flow-layout.col-12 .resource-card-18x3x2 { - width: 700px; - height: 138px; - margin-bottom: 8px; -} - -/* Generate the flow layout styles for a 3-column 13-col span */ - -.resource-flow-layout.col-13 { - margin: 0 -14px 0 0; - width: 774px; -} -.resource-flow-layout.col-13 .resource-card, .resource-flow-layout.col-13 .resource-card-stack { - margin: 0 14px 20px 0; -} -.resource-flow-layout.col-13 .resource-card-row-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-13 .resource-card-col-stack-last { - margin-bottom: 0px !important; -} -.resource-flow-layout.col-13 .resource-card-3x6 { - width: 115px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-3x12 { - width: 115px; - height: 588px; -} -.resource-flow-layout.col-13 .resource-card-3x18 { - width: 115px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-6x6 { - width: 244px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-6x12 { - width: 244px; - height: 588px; -} -.resource-flow-layout.col-13 .resource-card-6x18 { - width: 244px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-9x6 { - width: 373px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-9x12 { - width: 373px; - height: 588px; -} -.resource-flow-layout.col-13 .resource-card-9x18 { - width: 373px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-12x6 { - width: 502px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-12x12 { - width: 502px; - height: 588px; -} -.resource-flow-layout.col-13 .resource-card-12x18 { - width: 502px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-15x6 { - width: 631px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-15x12 { - width: 631px; - height: 588px; -} -.resource-flow-layout.col-13 .resource-card-15x18 { - width: 631px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-18x6 { - width: 760px; - height: 284px; -} -.resource-flow-layout.col-13 .resource-card-18x12 { - width: 760px; - height: 420px; -} -.resource-flow-layout.col-13 .resource-card-18x18 { - width: 760px; - height: 892px; -} -.resource-flow-layout.col-13 .resource-card-3x2 { - width: 115px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-3x2x3 { - width: 115px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-3x3 { - width: 115px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-3x3x2 { - width: 115px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-13 .resource-card-6x2 { - width: 244px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-6x2x3 { - width: 244px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-6x3 { - width: 244px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-6x3x2 { - width: 244px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-13 .resource-card-9x2 { - width: 373px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-9x2x3 { - width: 373px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-9x3 { - width: 373px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-9x3x2 { - width: 373px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-13 .resource-card-12x2 { - width: 502px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-12x2x3 { - width: 502px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-12x3 { - width: 502px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-12x3x2 { - width: 502px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-13 .resource-card-15x2 { - width: 631px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-15x2x3 { - width: 631px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-15x3 { - width: 631px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-15x3x2 { - width: 631px; - height: 138px; - margin-bottom: 8px; -} -.resource-flow-layout.col-13 .resource-card-18x2 { - width: 760px; - height: 95px; -} -.resource-flow-layout.col-13 .resource-card-18x2x3 { - width: 760px; - height: 90px; - margin-bottom: 7px; -} -.resource-flow-layout.col-13 .resource-card-18x3 { - width: 760px; - height: 142px; -} -.resource-flow-layout.col-13 .resource-card-18x3x2 { - width: 760px; - height: 138px; - margin-bottom: 8px; -} - -/* - The following are styles for cards in the flowlayout above, styled by the number of rows they span -*/ -/* Single row items, might be simpler to just apply a class */ -.resource-card-3x6 > .card-bg, .resource-card-6x6 > .card-bg, .resource-card-9x6 > .card-bg, .resource-card-12x6 > .card-bg, .resource-card-15x6 > .card-bg, .resource-card-18x6 > .card-bg { - height: 192px; -} -.resource-card-3x6 > .card-info, .resource-card-6x6 > .card-info, .resource-card-9x6 > .card-info, .resource-card-12x6 > .card-info, .resource-card-15x6 > .card-info, .resource-card-18x6 > .card-info { - padding: 4px 12px 6px 12px; - top: 192px; -} -.resource-card-3x6 > .card-info .section, .resource-card-6x6 > .card-info .section, .resource-card-9x6 > .card-info .section, .resource-card-12x6 > .card-info .section, .resource-card-15x6 > .card-info .section, .resource-card-18x6 > .card-info .section { - font-size: 12px; - margin-bottom: 1px; -} -.resource-card-3x6 > .card-info .title, .resource-card-6x6 > .card-info .title, .resource-card-9x6 > .card-info .title, .resource-card-12x6 > .card-info .title, .resource-card-15x6 > .card-info .title, .resource-card-18x6 > .card-info .title { - font-size: 16px; - margin-bottom: -2px; -} -.resource-card-3x6 > .card-info .description, .resource-card-6x6 > .card-info .description, .resource-card-9x6 > .card-info .description, .resource-card-12x6 > .card-info .description, .resource-card-15x6 > .card-info .description, .resource-card-18x6 > .card-info .description { - font-size: 13px; - line-height: 15px; -} -.resource-card-3x6 > .card-info .description .text, .resource-card-6x6 > .card-info .description .text, .resource-card-9x6 > .card-info .description .text, .resource-card-12x6 > .card-info .description .text, .resource-card-15x6 > .card-info .description .text, .resource-card-18x6 > .card-info .description .text { - height: 30px; -} - -/* Double row items */ -.resource-card-3x12 > .card-bg, .resource-card-6x12 > .card-bg, .resource-card-9x12 > .card-bg, .resource-card-12x12 > .card-bg, .resource-card-15x12 > .card-bg, .resource-card-18x12 > .card-bg { - height: 320px; -} -.resource-card-3x12 > .card-info, .resource-card-6x12 > .card-info, .resource-card-9x12 > .card-info, .resource-card-12x12 > .card-info, .resource-card-15x12 > .card-info, .resource-card-18x12 > .card-info { - padding: 4px 12px 6px 12px; - top: 320px; -} -.resource-card-3x12 > .card-info .section, .resource-card-6x12 > .card-info .section, .resource-card-9x12 > .card-info .section, .resource-card-12x12 > .card-info .section, .resource-card-15x12 > .card-info .section, .resource-card-18x12 > .card-info .section { - font-size: 12px; - margin-bottom: 1px; -} -.resource-card-3x12 > .card-info .title, .resource-card-6x12 > .card-info .title, .resource-card-9x12 > .card-info .title, .resource-card-12x12 > .card-info .title, .resource-card-15x12 > .card-info .title, .resource-card-18x12 > .card-info .title { - font-size: 16px; - margin-bottom: -2px; - white-space: normal; -} -.resource-card-3x12 > .card-info .description, .resource-card-6x12 > .card-info .description, .resource-card-9x12 > .card-info .description, .resource-card-12x12 > .card-info .description, .resource-card-15x12 > .card-info .description, .resource-card-18x12 > .card-info .description { - font-size: 13px; - line-height: 15px; -} - -/* 1/3 row items */ -.resource-card-3x2 > .card-bg, .resource-card-6x2 > .card-bg, .resource-card-9x2 > .card-bg, .resource-card-12x2 > .card-bg, .resource-card-15x2 > .card-bg, .resource-card-18x2 > .card-bg { - left: 0; - top: 0; - width: 90px; - height: 100%; - position: absolute; - display: block; -} -.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info { - left: 90px; - padding: 4px 12px 4px 12px; - height: 80px; - overflow: hidden; -} -.resource-card-3x2 > .card-info .section, .resource-card-6x2 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x2 > .card-info .section, .resource-card-12x2 > .card-info .section, .resource-card-15x2 > .card-info .section, .resource-card-18x2 > .card-info .section { - font-size: 12px; - margin-bottom: 1px; - /* display: none; */ -} -.resource-card-3x2 > .card-info .title, .resource-card-6x2 > .card-info .title, .resource-card-9x2 > .card-info .title, .resource-card-12x2 > .card-info .title, .resource-card-15x2 > .card-info .title, .resource-card-18x2 > .card-info .title { - font-size: 16px; - margin-bottom: -2px; - white-space: normal; - overflow: visible; - text-overflow: ellipsis; -} -.resource-card-3x2 > .card-info .title:after, .resource-card-6x2 > .card-info .title:after, .resource-card-9x2 > .card-info .title:after, .resource-card-12x2 > .card-info .title:after, .resource-card-15x2 > .card-info .title:after, .resource-card-18x2 > .card-info .title:after { - /* content: url(../images/link-out.png); */ - display: block; -} -.resource-card-3x2 > .card-info .description, .resource-card-6x2 > .card-info .description, .resource-card-9x2 > .card-info .description, .resource-card-12x2 > .card-info .description, .resource-card-15x2 > .card-info .description, .resource-card-18x2 > .card-info .description { - display: none; -} - - -/* Override to show the description instead of the content section */ -.no-section .resource-card-3x2 > .card-info .section, -.no-section .resource-card-6x2 > .card-info .section { - display: none; -} -.no-section .resource-card-3x2 > .card-info .description, -.no-section .resource-card-6x2 > .card-info .description { - display: block; -} - -/* 1/2 row items */ -.resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg { - left: 0; - top: 0; - width: 90px; - height: 100%; - position: absolute; - display: block; -} -.resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info { - left: 90px; - padding: 4px 12px 0px 12px; -} -.resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section { - font-size: 12px; - margin-bottom: 1px; - display: none; -} -.resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title { - font-size: 16px; - margin-bottom: -2px; - white-space: normal; - overflow: visible; -} -.resource-card-3x3 > .card-info .description .text, .resource-card-6x3 > .card-info .description .text, .resource-card-9x3 > .card-info .description .text, .resource-card-12x3 > .card-info .description .text, .resource-card-15x3 > .card-info .description .text, .resource-card-18x3 > .card-info .description .text { - font-size: 12px; - line-height: 15px; - padding-right: 0px !important; - height: 80px; -} -.resource-card-3x3 > .card-info .description .util, .resource-card-6x3 > .card-info .description .util, .resource-card-9x3 > .card-info .description .util, .resource-card-12x3 > .card-info .description .util, .resource-card-15x3 > .card-info .description .util, .resource-card-18x3 > .card-info .description .util { - display: none; -} -/* placement of plusone */ -.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util { - bottom:2px; -} -.resource-card-18x12 > .card-info .description .util { - bottom:2px; -} -/* Overrides for col-16 6x6 cards linking to local content on landing pages. - Suppresses "section" and puts the title above a hairline rule. */ -.landing .card-info .section, .resource-flow-layout.col-16.landing .resource-card-9x6 .card-info .section { - display:none; -} -.landing .card-info .title { - color: #898989; - font-size: 17px; - line-height: 24px; - margin-bottom: 6px; - border-bottom: 1px solid #959595; - padding-bottom: 0px; -} -.landing .card-info .description { - font-size: 13px; - line-height: 15px; -} -.landing .card-info .description .text { -height:30px; -} -.landing .resource-card-6x6 > .card-info .description .util, .landing .resource-card-9x6 > .card-info .description .util { - bottom:2px; -} -/* - Generate a resource stack layout for a 3 column widget spanning 16 grid cols -*/ -.resource-stack-layout.col-16 { - margin: 0 -14px 0 0; - width: 954px; -} -.resource-stack-layout.col-16 .resource-card-stack { - margin: 0 14px 0 0; - width: 304px; -} - -/* Example of card menu tinting */ -.resource-widget[data-section=distribute\/tools] .section-card-menu -.card-bg:after { - background: rgba(126, 55, 148, 0.4) !important; -} -.resource-widget[data-section=distribute\/tools] .section-card-menu -.card-section-icon .icon { - background-color: #7e3794 !important; -} -.resource-widget[data-section=distribute\/tools] .section-card-menu -.card-info ul li { - border-top-color: #7e3794 !important; -} - -/* tinting for stacks */ - -div.jd-descr > .resource-widget[data-section=distribute\/tools] -.section-card-menu .card-info ul li { - border-top-color: #7e3794 !important; -} - - /** * UTILITIES @@ -6541,11 +4707,13 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] */ .landing-h1 { - font-weight: 100; - font-size: 60px; - line-height: 78px; + color: #44555d; + font-weight: 300; + font-size: 56px; + line-height: 80px; text-align: center; letter-spacing: -1px; + margin-bottom: 6px; } .landing-pre-h1 { @@ -6556,11 +4724,11 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] text-align: center; letter-spacing: -1px; text-transform: uppercase; - } .landing-h1.hero { text-align: left; + color: #fff; } .landing-h2 { @@ -6571,10 +4739,10 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] } .landing-subhead { - color: #999999; + color: #78868d; font-size: 20px; - line-height: 28px; - font-weight:300; + font-weight: 300; + line-height: 32px; text-align: center; } .landing-subhead.hero { @@ -6611,23 +4779,21 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] * LAYOUT */ -#body-content, -.fullpage, -#jd-content, -.jd-descr, -.landing-body-content { - height: 100%; -} - .landing-section { - padding: 80px 10px 80px; - width: 100%; - margin-left: -10px; + background: #eceff1; + clear: both; + padding: 80px 20px 80px; + margin: 0 -20px; text-rendering: optimizeLegibility; } -#extending-android-to-wearables { - padding-top: 30px; +@media (max-width: 719px) { + .landing-section { + margin-left: -10px; + margin-right: -10px; + padding-left: 10px; + padding-right: 10px; + } } .landing-short-section { @@ -6635,7 +4801,7 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] } .landing-gray-background { - background-color: #e9e9e9; + background-color: #b0bec5; } .landing-white-background { @@ -6647,24 +4813,19 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] background-color: hsl(8, 70%, 54%); } -.landing-subhead-red { - color: hsl(8, 71%, 84%); - text-align: left; -} - -.landing-subhead-red p { - margin-top: 20px; +.landing-red-background .landing-h1 { + color: white; } -.landing-hero-container { - height: 100%; +.landing-red-background .landing-subhead { + color: hsl(8, 71%, 84%); + text-align: left; } .preview-hero { - height: calc(100% - 110px); + height: calc(100vh - 128px); min-height: 504px; - margin-top: -5px; padding-top: 0; padding-bottom: 0; background-image: url(../../preview/images/hero.jpg); @@ -6676,9 +4837,8 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] } .wear-hero { - height: calc(100% - 110px); + height: calc(100vh - 128px); min-height: 504px; - margin-top: -5px; padding-top: 0; padding-bottom: 0; background-image: url(../../wear/images/hero.jpg); @@ -6690,9 +4850,8 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] } .tv-hero { - height: calc(100% - 110px); + height: calc(100vh - 128px); min-height: 504px; - margin-top: -5px; padding-top: 0; padding-bottom: 0; background-image: url(../../tv/images/hero.jpg); @@ -6704,9 +4863,8 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] } .auto-hero { - height: calc(100% - 110px); + height: calc(100vh - 128px); min-height: 504px; - margin-top: -5px; padding-top: 0; padding-bottom: 0; background-image: url(../../auto/images/hero.jpg); @@ -6719,16 +4877,16 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] .landing-hero-scrim { background: black; - opacity: .2; + height: 100%; + left: 0; position: absolute; + opacity: .2; width: 100%; - height: 100%; - margin-left: -10px; } .landing-hero-wrap { margin: 0 auto; - width: 940px; + max-width: 940px; clear: both; height: 100%; position: relative; @@ -6747,56 +4905,6 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] line-height: 24px; } -.landing-button { - white-space: nowrap; - display: inline-block; - padding: 16px 32px; - font-size: 18px; - font-weight: 500; - line-height: 24px; - cursor: pointer; - color: white; - -webkit-user-select: none; - -moz-user-select: none; - -o-user-select: none; - user-select: none; - -webkit-transition: .2s background-color ease-in-out; - -moz-transition: .2s background-color ease-in-out; - -o-transition: .2s background-color ease-in-out; - transition: .2s background-color ease-in-out; -} - -.landing-primary { - background-color: hsl(8, 70%, 44%); - color: #f8f8f8; -} - -.landing-button.landing-primary:hover { - background-color: hsl(8, 70%, 36%); -} - -.landing-button.landing-primary:active { - background-color: hsl(8, 70%, 30%); -} - -.landing-button.landing-secondary { - background-color: #2faddb; -} - -.landing-button.landing-secondary:hover { - background-color: #09c; -} - -.landing-button.landing-secondary:active { - background-color: #3990ab; -} - -a.landing-button, -a.landing-button:hover, -a.landing-button:visited { - color: white !important; -} - .landing-video-link { white-space: nowrap; display: inline-block; @@ -6915,17 +5023,6 @@ a.landing-button:visited { margin-bottom: 20px; } -.col-3-wide { - display: inline; - float: left; - margin-left: 10px; - margin-right: 10px; -} - -.col-3-wide { - width: 302px; -} - /** * ANIMATION */ @@ -6969,7 +5066,7 @@ a.landing-button:visited { } #video-frame { - width:940px; + max-width:940px; height:100%; margin:72px auto; display:none; @@ -7032,6 +5129,69 @@ a.video-shadowbox-button.white:after { content:url("../images/play-circle-grey.png") url("../images/play-circle-grey_2x.png"); } +/* + * Responsive YouTube embeds from DevSite + * + * When applied to a <div> that wraps a video, "video-wrapper" forces the video + * to float right at 50% of the column width on desktop, but appear as a block + * element at 100% of the column width on smaller screens. + * "video-wrapper-full-width" works the same but is always 100% width. + */ +.video-wrapper, +.video-wrapper-left { + float: right; + margin: 0 0 40px 40px; + padding-top: calc(((100% - 40px) / 2) / 16 * 9); /* 16:9 including margin */ + position: relative; + width: calc((100% - 40px) / 2); /* 50% including margin */ +} + +/* + * "video-wrapper-left" forces 50% without the float + * This is useful for heading content when you want the video to + * appear next to an element that is already floated right + * (e.g. tb-wrapper <div>) + */ +.video-wrapper-left { + float: none; + margin: 16px 0 20px 0; +} + +.video-wrapper-full-width { + margin: 16px 0; + padding-top: 56.25%; /* Forces div to 16:9 at 100% width */ + position: relative; + width: 100%; +} + +.video-wrapper embed, +.video-wrapper iframe, +.video-wrapper object, +.video-wrapper-full-width embed, +.video-wrapper-full-width iframe, +.video-wrapper-full-width object, +.video-wrapper-left embed, +.video-wrapper-left iframe, +.video-wrapper-left object { + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +@media screen and (max-width: 1000px) { + + .video-wrapper, + .video-wrapper-left { + float: none; + margin: 16px 0; + padding-top: 56.25%; /* Forces div to 16:9 at 100% width */ + width: 100%; + } +} + + /****************** Styles for d.a.c/index: *******************/ @@ -7040,8 +5200,7 @@ Styles for d.a.c/index: /* Generic full screen carousel styling to be used across pages. */ .fullscreen-carousel { - margin: 0 -10px; - width: 100%; + margin: 0 -20px; overflow: hidden; position: relative; } @@ -7080,7 +5239,6 @@ Styles for d.a.c/index: font-weight: 300; font-size: 18px; line-height: 24px; - -webkit-font-smoothing: antialiased; } .fullscreen-carousel .hero .hero-bg { @@ -7214,48 +5372,18 @@ Styles for d.a.c/index: } - - - -/* - Styles for the entity link used in the actions bar and in the cta of - the resources that appear in the tab carousel. -*/ -.actions-bar a:after, -.resource .cta:after { - content: '›'; - font-weight: 400; - font-size: 22px; - left: 5px; - line-height: 1; - position: relative; - top: 1px; - transition: left 190ms ease-out; -} - -.actions-bar a:hover:after, -.resource .cta:hover:after { - left: 10px; -} - - - - /* Styles for the actions bar. */ .actions-bar { - background: #9acd00; - margin: 0 -10px; + background: #b0bec5; text-align: center; } .actions-bar .actions { - padding: 30px 0 30px; - text-align: justify; + padding: 24px 0; font-size: 0.1px; line-height: 0.1px; - margin: 0 10px 0 0; } .actions-bar .actions:after { @@ -7266,26 +5394,36 @@ Styles for d.a.c/index: .actions-bar .actions > div { display: inline-block; + margin: 0 16px; } -.actions-bar a { - font-size: 21px; - line-height: 27px; +.actions-bar .actions a { color: #fff; + font-size: 24px; font-weight: 300; - -webkit-font-smoothing: antialiased; + line-height: 50px; + -webkit-transition: opacity .3s; + transition: opacity .3s; } -.actions-bar a:after { - top: 0px; - font-size: 22px; +.actions-bar .actions a:hover { + opacity: .54; } -.actions-bar a:hover { - color: #fff !important; +.actions-bar .actions .dac-sprite { + margin: 0 -8px 0 -12px; } +@media (max-width: 719px) { + .actions-bar { + text-align: left; + } + .actions-bar .actions > div { + display: block; + margin: 0; + } +} @@ -7449,3 +5587,3203 @@ a.home-new-cta-btn:hover, .resource-card-6x2 > .card-bg.helpouts-card-bg:after { display:none; } + +.dac-visible-mobile-block, .dac-mobile-only, .dac-visible-mobile-inline, .dac-visible-mobile-inline-block, .dac-visible-tablet-block, .dac-visible-tablet-inline, .dac-visible-tablet-inline-block, .dac-visible-desktop-block, .dac-visible-desktop-inline, .dac-visible-desktop-inline-block { + display: none !important; +} + +@media (max-width: 719px) { + .dac-hidden-mobile { + display: none !important; + } + + .dac-visible-mobile-block, .dac-mobile-only { + display: block !important; + } + + .dac-visible-mobile-inline { + display: inline !important; + } + + .dac-visible-mobile-inline-block { + display: inline-block !important; + } +} + +@media (min-width: 720px) and (max-width: 979px) { + .dac-hidden-tablet { + display: none !important; + } + + .dac-visible-tablet-block { + display: block !important; + } + + .dac-visible-tablet-inline { + display: inline !important; + } + + .dac-visible-tablet-inline-block { + display: inline-block !important; + } +} + +@media (min-width: 980px) { + .dac-hidden-desktop { + display: none !important; + } + + .dac-visible-desktop-block { + display: block !important; + } + + .dac-visible-desktop-inline { + display: inline !important; + } + + .dac-visible-desktop-inline-block { + display: inline-block !important; + } +} + +.dac-offset-parent { + position: relative !important; +} + +/** + * Break strings when their length exceeds the width of their container. + */ +.dac-text-break { + word-wrap: break-word !important; +} + +/** + * Horizontal text alignment + */ +.dac-text-center { + text-align: center !important; +} + +.dac-text-left { + text-align: left !important; +} + +.dac-text-right { + text-align: right !important; +} + +/** + * Prevent whitespace wrapping + */ +.dac-text-no-wrap { + white-space: nowrap !important; +} + +/** + * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis. + */ +.dac-text-truncate { + max-width: 100%; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + word-wrap: normal !important; +} + +/** + * Floats + */ +.dac-float-left { + float: left !important; +} + +.dac-float-right { + float: right !important; +} + +/** + * New block formatting context + * + * This affords some useful properties to the element. It won't wrap under + * floats. Will also contain any floated children. + * N.B. This will clip overflow. Use the alternative method below if this is + * problematic. + */ +.dac-nbfc { + overflow: hidden !important; } + +/** + * New block formatting context (alternative) + * + * Alternative method when overflow must not be clipped. + * + * N.B. This breaks down in some browsers when elements within this element + * exceed its width. + */ +.dac-nbfc-alt { + display: table-cell !important; + width: 10000px !important; } + +/* New CSS */ +/************ RESOURCE CARDS ******************/ +/* Basic card-styling with shadow */ +.resource-card { + background: #fff; + box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.21); + display: block; + position: relative; } + +/* Play button is only visible on 6by6 cards */ +.play-button { + background-color: #000; + border-radius: 50%; + box-sizing: border-box; + display: none; + height: 70px; + left: 50%; + margin-left: -35px; + line-height: 65px; + padding-left: 4px; + position: absolute; + opacity: .6; + text-align: center; + -webkit-transition: opacity .5s; + transition: opacity .5s; + top: 50px; + width: 70px; + z-index: 1; } + .resource-card-6x6 .play-button { + display: block; } + +/* Styling for background image including tinting and section icons in stacks */ +.card-bg { + bottom: 131px; + display: block; + position: absolute; + vertical-align: top; + width: 100%; + left: 0; + top: 0; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + background-image: url(../images/resource-card-default-android.jpg); } + .card-bg:after { + content: ""; + display: block; + height: 100%; + width: 100%; + opacity: 1; + background: rgba(0, 0, 0, 0.05); + -webkit-transition: opacity 0.5s; + transition: opacity 0.5s; } + .static .card-bg:after { + display: none; } + .card-bg .card-section-icon { + position: absolute; + top: 50%; + width: 100%; + margin-top: -35px; + text-align: center; + padding-top: 65px; + z-index: 100; } + .card-bg .card-section-icon .icon { + position: absolute; + left: 50%; + margin-left: -28px; + top: 0px; + width: 56px; + height: 56px; + background-repeat: no-repeat; + background-position: 50% 50%; + background-image: url(../images/stack-icon.png); } + .card-bg .card-section-icon .section { + text-transform: uppercase; + color: white; + font-size: 14px; } + +.card-info { + position: absolute; + box-sizing: border-box; + height: 131px; + right: 0; + bottom: 0; + left: 0; + overflow: hidden; + background: #fefefe; + padding: 6px 12px; } + .card-info .section { + color: #898989; + font-size: 11px; + font-weight: 700; + letter-spacing: .3px; + line-height: 20px; + text-transform: uppercase; } + .card-info .title { + color: #333; + font-size: 18px; + font-weight: 500; + line-height: 24px; + margin-bottom: 2px; + max-height: 48px; + overflow: hidden; + padding-bottom: 5px; + text-overflow: ellipsis; + white-space: normal; } + .card-info .description { + overflow: hidden; } + .card-info .description .text { + color: #666; + font-size: 14px; + height: 60px; + line-height: 20px; + overflow: hidden; + width: 100%; } + .card-info .description .util { + position: absolute; + right: 5px; + bottom: 70px; + opacity: 0; + -webkit-transition: opacity 0.5s; + transition: opacity 0.5s; } + .card-info.empty-desc .title { + white-space: normal; + overflow: visible; } + .card-info.empty-desc .description { + display: none; } + +/* Truncate card summaries at bounding box and + * and apply ellipsis at lower right */ +.ellipsis { + overflow: hidden; + float: right; + line-height: 15px; + width: 100%; } + .ellipsis:before { + content: ""; + float: left; + width: 5px; + height: 100%; } + .ellipsis > *:first-child.text { + float: right; + width: 100% !important; + margin-left: -5px; } + .ellipsis:after { + content: "\02026"; + height: 17px; + padding-bottom: 4px; + box-sizing: content-box; + float: right; + position: relative; + top: -16px; + left: 100%; + width: 4em; + margin-left: -4em; + padding-right: 5px; + background: -webkit-gradient(linear, left top, right top, from(rgba(255, 255, 255, 0)), to(white), color-stop(65%, white)); + background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0), white 65%, white); + background: linear-gradient(to right, rgba(255, 255, 255, 0), white 65%, white); } + .ellipsis:after { + font-style: normal; + color: #aaa; + font-size: 13px; + text-align: right; } + +.resource-card:hover { + cursor: pointer; } + .static .resource-card:hover { + cursor: auto; } + .resource-card:hover .card-bg:after { + opacity: 0; } + .resource-card:hover .play-button { + opacity: .3; } + .resource-card:hover .card-info .description .util { + opacity: 1; } + +/* Carousel Layout */ +/* Carousel styles for landing page */ +.resource-carousel-layout { + height: 531px; + margin: 20px 0 20px 0; + padding: 0 !important; + position: relative; + overflow: hidden; } + .resource-carousel-layout .slideshow-prev, .resource-carousel-layout .slideshow-next { + display: none; } + .resource-carousel-layout .pagination { + bottom: 97px; + left: auto; + padding-right: 10px; + right: 0; + text-align: right; + width: 16.66666667%; } + .resource-carousel-layout .pagination ul li { + text-indent: 8000px; } + .resource-carousel-layout .frame li { + position: relative; } + .resource-carousel-layout .frame li .card-bg { + bottom: 131px; } + .resource-carousel-layout .frame li .card-info { + height: 131px; + padding: 6px 12px; + top: auto; } + .resource-carousel-layout .frame li .card-info .title { + font-size: 28px; + font-weight: 400; + line-height: 32px; } + .resource-carousel-layout .frame li .card-info .description .text { + height: 40px; } + .resource-carousel-layout .frame li .card-info .description .util { + bottom: 97px; + right: 4px; } + +/* Stack Layout */ +.resource-stack-layout { + display: inline-block; + padding: 0; } + .resource-stack-layout .section-card-menu > .card-info .section, .resource-stack-layout .section-card > .card-info .title { + /*text-transform: uppercase;*/ + color: #898989; + font-size: 17px; + line-height: 24px; + margin-bottom: 6px; } + .resource-stack-layout .section-card { + height: 284px; } + .resource-stack-layout .section-card > .card-bg { + height: 192px; } + .resource-stack-layout .section-card > .card-info { + padding: 4px 12px 6px 12px; + top: 192px; } + .resource-stack-layout .section-card > .card-info .section { + display: none; } + .resource-stack-layout .section-card > .card-info .title { + font-size: 17px; + border-bottom: 1px solid #959595; + padding-bottom: 0px; } + .resource-stack-layout .section-card > .card-info .description { + font-size: 13px; + line-height: 15px; } + .resource-stack-layout .section-card > .card-info .description .text { + height: 30px; } + .resource-stack-layout .related-card { + height: 90px; } + .resource-stack-layout .related-card > .card-bg { + left: 0; + top: 0; + width: 90px; + height: 100%; + position: absolute; + display: block; } + .resource-stack-layout .related-card > .card-info { + left: 90px; + padding: 4px 12px 4px 12px; } + .resource-stack-layout .related-card > .card-info .section { + font-size: 12px; + margin-bottom: 1px; + display: none; } + .resource-stack-layout .related-card > .card-info .title { + font-size: 16px; + margin-bottom: -2px; + white-space: normal; + overflow: visible; + text-overflow: ellipsis; } + .resource-stack-layout .related-card > .card-info .title:after { + content: url(../images/link-out.png); + display: block; } + .resource-stack-layout .related-card > .card-info .description { + display: none; } + .resource-stack-layout .section-card-menu { + /* Flexible height */ + display: block; + height: auto; + width: auto; } + .resource-stack-layout .section-card-menu .card-bg { + height: 155px; + /* Flexible height */ + position: relative; + display: inline-block; + vertical-align: top; } + .resource-stack-layout .section-card-menu .card-info { + padding: 4px 12px 0px 12px; + /* Flexible height */ + position: relative; + left: auto; + top: auto; + right: auto; + bottom: auto; } + .resource-stack-layout .section-card-menu .card-info ul { + list-style: none; + margin: 0; } + .resource-stack-layout .section-card-menu .card-info ul li { + list-style: none; + margin: 0; + padding: 15px 0; + border-top-width: 1px; + border-top-style: solid; + border-top-color: #959595; } + .resource-stack-layout .section-card-menu .card-info ul li a, .resource-stack-layout .section-card-menu .card-info ul li a:focus, .resource-stack-layout .section-card-menu .card-info ul li a:hover { + color: #333 !important; } + .resource-stack-layout .section-card-menu .card-info ul li:first-child { + border-top: none; } + .resource-stack-layout .section-card-menu .card-info ul li:hover .title:after { + opacity: 1; + -webkit-transition: opacity 0.5s; + transition: opacity 0.5s; } + .resource-stack-layout .section-card-menu .card-info ul li:hover .description { + max-height: 30px; + opacity: 1; + -webkit-transition: max-height 0.5s, opacity 1s; + transition: max-height 0.5s, opacity 1s; } + .resource-stack-layout .section-card-menu .card-info .title { + font-size: 16px; + margin-bottom: -2px; + position: relative; } + .resource-stack-layout .section-card-menu .card-info .title:after { + background: url(../images/stack-arrow-right.png); + content: ''; + opacity: 0; + -webkit-transition: opacity 0.25s; + transition: opacity 0.25s; + position: absolute; + right: 0px; + top: 3px; + width: 10px; + height: 15px; } + .resource-stack-layout .section-card-menu .card-info .title.more { + text-transform: uppercase; + color: #898989; + display: inline-block; } + .resource-stack-layout .section-card-menu .card-info .title.more:after { + background: url(../images/stack-arrow-right.png); + content: ''; + display: block; + position: absolute; + right: -20px; + top: 3px; + width: 10px; + height: 15px; } + .resource-stack-layout .section-card-menu .card-info .description { + max-height: 0px; + opacity: 0; + overflow: hidden; + font-size: 13px; + line-height: 15px; + /* Hover off */ + -webkit-transition: max-height 0.5s, opacity 0.5s; + transition: max-height 0.5s, opacity 0.5s; } + .resource-stack-layout .section-card-menu .card-info .description .text { + height: 30px; } + .resource-stack-layout:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; } + +.resource-card, .resource-card-stack { + margin-bottom: 20px; } + +.resource-card-row-stack-last { + margin-bottom: 0px !important; } + +.resource-card-col-stack-last { + margin-bottom: 0px !important; } + +.resource-card-3x6 { + height: 300px; } + +.resource-card-3x12 { + height: 620px; } + +.resource-card-3x18 { + height: 940px; } + +.resource-card-6x6 { + height: 300px; } + +.resource-card-6x12 { + height: 620px; } + +.resource-card-6x18 { + height: 940px; } + +.resource-card-9x6 { + height: 300px; } + +.resource-card-9x12 { + height: 620px; } + +.resource-card-9x18 { + height: 940px; } + +.resource-card-12x6 { + height: 300px; } + +.resource-card-12x12 { + height: 620px; } + +.resource-card-12x18 { + height: 940px; } + +.resource-card-15x6 { + height: 300px; } + +.resource-card-15x12 { + height: 620px; } + +.resource-card-15x18 { + height: 940px; } + +.resource-card-18x6 { + height: 300px; } + +.resource-card-18x12 { + height: 620px; } + +.resource-card-18x18 { + height: 940px; } + +.resource-card-3x2 { + height: 100px; } + +.resource-card-3x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-3x3 { + height: 150px; } + +.resource-card-3x3x2 { + height: 142px; + margin-bottom: 16px; } + +.resource-card-6x2 { + height: 100px; } + +.resource-card-6x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-6x3 { + height: 150px; } + +.resource-card-6x3x2 { + height: 142px; + margin-bottom: 16px; } + +.resource-card-9x2 { + height: 100px; } + +.resource-card-9x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-9x3 { + height: 150px; } + +.resource-card-9x3x2 { + height: 142px; + margin-bottom: 16px; } + +.resource-card-12x2 { + height: 100px; } + +.resource-card-12x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-12x3 { + height: 150px; } + +.resource-card-12x3x2 { + height: 142px; + margin-bottom: 16px; } + +.resource-card-15x2 { + height: 100px; } + +.resource-card-15x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-15x3 { + height: 150px; } + +.resource-card-15x3x2 { + height: 142px; + margin-bottom: 16px; } + +.resource-card-18x2 { + height: 100px; } + +.resource-card-18x2x3 { + height: 90px; + margin-bottom: 15px; } + +.resource-card-18x3 { + height: 150px; } + +.resource-card-18x3x2 { + height: 142px; + margin-bottom: 16px; } + +/* + The following are styles for cards in the flowlayout above, styled by the number of rows they span +*/ +/* Single row, 2 column items. */ +.resource-card-9x6 { + height: 390px; } + +/* Double row, 1 column items. Eg full width video thumbnails. */ +.resource-card-18x12 { + height: 558px; } + +/* 1/3 row items */ +.resource-card-3x2 > .card-bg, .resource-card-6x2 > .card-bg, .resource-card-9x2 > .card-bg, .resource-card-12x2 > .card-bg, .resource-card-15x2 > .card-bg, .resource-card-18x2 > .card-bg { + left: 0; + top: 0; + width: 90px; + height: 100%; + position: absolute; + display: block; } +.resource-card-3x2 > .card-info, .resource-card-6x2 > .card-info, .resource-card-9x2 > .card-info, .resource-card-12x2 > .card-info, .resource-card-15x2 > .card-info, .resource-card-18x2 > .card-info { + height: 100%; + left: 90px; + padding: 6px 12px; + overflow: hidden; } + .resource-card-3x2 > .card-info .title, .resource-card-6x2 > .card-info .title, .resource-card-9x2 > .card-info .title, .resource-card-12x2 > .card-info .title, .resource-card-15x2 > .card-info .title, .resource-card-18x2 > .card-info .title { + max-height: 48px; + white-space: normal; } + .resource-card-3x2 > .card-info .description, .resource-card-6x2 > .card-info .description, .resource-card-9x2 > .card-info .description, .resource-card-12x2 > .card-info .description, .resource-card-15x2 > .card-info .description, .resource-card-18x2 > .card-info .description { + display: none; } + .resource-card-3x2 > .card-info .text, .resource-card-6x2 > .card-info .text, .resource-card-9x2 > .card-info .text, .resource-card-12x2 > .card-info .text, .resource-card-15x2 > .card-info .text, .resource-card-18x2 > .card-info .text { + height: auto; } + +/* Override to show the description instead of the content section */ +.no-section .resource-card-3x2 > .card-info .section, .no-section .resource-card-6x2 > .card-info .section { + display: none; } + +.no-section .resource-card-3x2 > .card-info .description, .no-section .resource-card-6x2 > .card-info .description { + display: block; } + +/* 1/2 row items */ +.resource-card-3x3, .resource-card-6x3, .resource-card-9x3, .resource-card-12x3, .resource-card-15x3, .resource-card-18x3 { + height: 160px; } + .resource-card-3x3 > .card-bg, .resource-card-6x3 > .card-bg, .resource-card-9x3 > .card-bg, .resource-card-12x3 > .card-bg, .resource-card-15x3 > .card-bg, .resource-card-18x3 > .card-bg { + left: 0; + top: 0; + width: 90px; + height: 100%; + position: absolute; + display: block; } + .resource-card-3x3 > .card-info, .resource-card-6x3 > .card-info, .resource-card-9x3 > .card-info, .resource-card-12x3 > .card-info, .resource-card-15x3 > .card-info, .resource-card-18x3 > .card-info { + height: 100%; + left: 90px; + padding: 6px 12px; } + .resource-card-3x3 > .card-info .section, .resource-card-6x3 > .card-info .section, .resource-card-9x3 > .card-info .section, .resource-card-12x3 > .card-info .section, .resource-card-15x3 > .card-info .section, .resource-card-18x3 > .card-info .section { + display: none; } + .resource-card-3x3 > .card-info .title, .resource-card-6x3 > .card-info .title, .resource-card-9x3 > .card-info .title, .resource-card-12x3 > .card-info .title, .resource-card-15x3 > .card-info .title, .resource-card-18x3 > .card-info .title { + max-height: 96px; + white-space: normal; } + .resource-card-3x3 > .card-info .text, .resource-card-6x3 > .card-info .text, .resource-card-9x3 > .card-info .text, .resource-card-12x3 > .card-info .text, .resource-card-15x3 > .card-info .text, .resource-card-18x3 > .card-info .text { + height: auto; } + .resource-card-3x3 > .card-info .util, .resource-card-6x3 > .card-info .util, .resource-card-9x3 > .card-info .util, .resource-card-12x3 > .card-info .util, .resource-card-15x3 > .card-info .util, .resource-card-18x3 > .card-info .util { + display: none; } + +/* placement of plusone */ +.resource-card-6x12 > .card-info .description .util, .resource-card-9x12 > .card-info .description .util, .resource-card-12x12 > .card-info .description .util, .resource-card-15x12 > .card-info .description .util { + bottom: 2px; } + +.resource-card-18x12 > .card-info .description .util { + bottom: 2px; } + +/* Overrides for col-16 6x6 cards linking to local content on landing pages. + Suppresses "section". */ +.landing .card-info .section { + display: none; } + +/* + Generate a resource stack layout for a 3 column widget spanning 16 grid cols +*/ +.resource-stack-layout.col-16 { + margin: 0 -14px 0 0; + width: 954px; } + .resource-stack-layout.col-16 .resource-card-stack { + margin: 0 14px 0 0; + width: 304px; } + +/* Example of card menu tinting */ +.resource-widget[data-section=distribute\/tools] .section-card-menu .card-bg:after { + background: rgba(126, 55, 148, 0.4) !important; } +.resource-widget[data-section=distribute\/tools] .section-card-menu .card-section-icon .icon { + background-color: #7e3794 !important; } +.resource-widget[data-section=distribute\/tools] .section-card-menu .card-info ul li { + border-top-color: #7e3794 !important; } + +/* tinting for stacks */ +div.jd-descr > .resource-widget[data-section=distribute\/tools] .section-card-menu .card-info ul li { + border-top-color: #7e3794 !important; } + +.dac-fab, .button, .landing-button, .dac-button { + background: transparent; + border: 0; + border-radius: 3px; + box-sizing: border-box; + color: currentColor; + cursor: pointer; + display: inline-block; + font-weight: 500; + font-size: 14px; + font-style: inherit; + font-variant: inherit; + font-family: inherit; + letter-spacing: .5px; + line-height: 24px; + margin: 6px 16px 6px 0; + min-width: 88px; + outline: 0; + padding: 6px 12px; + position: relative; + text-align: center; + text-decoration: none; + text-transform: uppercase; + -webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + white-space: nowrap; } + +.button, .landing-button, .dac-button.dac-raised { + background-color: #FAFAFA; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); } + +.dac-button.dac-raised.dac-primary, .landing-secondary, .button { + background-color: #039bef; } + .dac-button.dac-raised.dac-primary:hover, .landing-secondary:hover, .button:hover { + background-color: #0288d1; } + .dac-button.dac-raised.dac-primary:active, .landing-secondary:active, .button:active { + background-color: #0277bd; } + +.dac-button.dac-raised.dac-red, .landing-primary { + background-color: #bf3722; } + .dac-button.dac-raised.dac-red:hover, .landing-primary:hover { + background-color: #9c2d1c; } + .dac-button.dac-raised.dac-red:active, .landing-primary:active { + background-color: #822517; } + +.dac-button.dac-raised.dac-green, .landing-button.green { + background-color: #90C653; } + +.dac-button.dac-raised.dac-primary, .landing-secondary, .button, .dac-button.dac-raised.dac-red, .landing-primary, .dac-button.dac-raised.dac-green, .landing-button.green { + color: #fff; } + +.dac-button.dac-large, .landing-button { + padding: 12px 24px; } + +.dac-fab { + background: #fff; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.26); + border-radius: 50%; + font-size: 0; + height: 36px; + line-height: 36px; + min-width: 0; + overflow: hidden; + padding: 0; + vertical-align: middle; + width: 36px; } + .dac-fab:hover, a:hover > .dac-fab { + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.26); } + .dac-fab.dac-primary { + background: #00c7a0; } + .dac-fab.dac-large { + height: 54px; + line-height: 54px; + width: 54px; } + +.dac-scroll-button { + height: 54px; + line-height: 54px; + margin: 0; + position: absolute; + right: 0; + top: -27px; + width: 54px; + z-index: 1; } + @media (max-width: 719px) { + .dac-scroll-button { + display: none; } } + +/* Footer component */ +.dac-footer { + background-color: #fff; + border-top: 1px solid #f0f0f0; + clear: both; + color: #999; + font-size: 12px; + margin-top: 96px; + padding-bottom: 20px; + position: relative; + /* Modifier for landing pages, to snuggle closer to sections. */ } + .dac-footer a { + color: #999; } + .dac-footer p { + margin: 7px 0 0; } + .dac-footer-main { + padding: 30px 0; } + .dac-footer-reachout { + text-align: right; } + .dac-footer-contact, .dac-footer-social { + display: inline-block; } + .dac-footer .dac-footer-getnews, .dac-footer .dac-footer-contact-link { + color: #000; + cursor: pointer; + font-size: 20px; + font-weight: 300; + margin: 8px 0; + vertical-align: middle; } + .dac-footer .dac-footer-contact-link, .dac-footer .dac-footer-social-link { + margin-left: 16px; + margin-right: 0; } + .dac-footer-getnews > .dac-fab { + margin-left: 4px; } + .dac-footer-separator { + background: #f0f0f0; + margin: 0 0 12px; } + .dac-footer-links a + a:before { + content: '|'; + cursor: default; + margin: 0 10px 0 8px; } + .dac-footer .locales { + float: right; + margin: 0; } + .dac-footer .locales select { + background-color: #f0f0f0; + border-radius: 3px; + font-size: 12px; + height: auto; + margin-top: -2px; + padding: 8px 12px; + width: 146px; } + .dac-footer.dac-landing { + margin-top: 0; + border-top: 0; } + @media (max-width: 719px) { + .dac-footer-reachout { + text-align: left; } + .dac-footer-social { + display: block; } + .dac-footer-social-link, .dac-footer-contact-link { + display: inline-block; } + .dac-footer .dac-footer-contact-link, .dac-footer .dac-footer-social-link { + margin-left: 0; + margin-right: 16px; } + .dac-footer .locales { + display: block; + float: none; + margin-top: 15px; } } + +/* ============================================================================= + Columns + ========================================================================== */ +.wrap { + margin: 0 auto; + max-width: 940px; + clear: both; } + +.cols { + margin-left: -10px; + margin-right: -10px; + /** + * For modern browsers + * 1. The space content is one way to avoid an Opera bug when the + * contenteditable attribute is included anywhere else in the document. + * Otherwise it causes space to appear at the top and bottom of elements + * that are clearfixed. + * 2. The use of `table` rather than `block` is only necessary if using + * `:before` to contain the top-margins of child elements. + */ } + .cols:before, .cols:after { + content: ' '; + /* 1 */ + display: table; + /* 2 */ } + .cols:after { + clear: both; } + +[class*=col-] { + box-sizing: border-box; + float: left; + min-height: 1px; + padding-left: 10px; + padding-right: 10px; + position: relative; } + +.col-1 { + width: 6.25%; } + +.col-2 { + width: 12.5%; } + +.col-3 { + width: 18.75%; } + +.col-4 { + width: 25%; } + +.col-5 { + width: 31.25%; } + +.col-6 { + width: 37.5%; } + +.col-7 { + width: 43.75%; } + +.col-8 { + width: 50%; } + +.col-9 { + width: 56.25%; } + +.col-10 { + width: 62.5%; } + +.col-11 { + width: 68.75%; } + +.col-12 { + width: 75%; } + +.col-13 { + width: 81.25%; } + +.col-14 { + width: 87.5%; } + +.col-15 { + width: 93.75%; } + +.col-16 { + width: 100%; } + +.col-13 .col-1 { + width: 7.69230769%; } + +.col-13 .col-2 { + width: 15.38461538%; } + +.col-13 .col-3 { + width: 23.07692308%; } + +.col-13 .col-4 { + width: 30.76923077%; } + +.col-13 .col-5 { + width: 38.46153846%; } + +.col-13 .col-6 { + width: 46.15384615%; } + +.col-13 .col-7 { + width: 53.84615385%; } + +.col-13 .col-8 { + width: 61.53846154%; } + +.col-13 .col-9 { + width: 69.23076923%; } + +.col-13 .col-10 { + width: 76.92307692%; } + +.col-13 .col-11 { + width: 84.61538462%; } + +.col-13 .col-12 { + width: 92.30769231%; } + +.col-13 .col-13 { + width: 100%; } + +.col-12 .col-1 { + width: 8.33333333%; } + +.col-12 .col-2 { + width: 16.66666667%; } + +.col-12 .col-3 { + width: 25%; } + +.col-12 .col-4 { + width: 33.33333333%; } + +.col-12 .col-5 { + width: 41.66666667%; } + +.col-12 .col-6 { + width: 50%; } + +.col-12 .col-7 { + width: 58.33333333%; } + +.col-12 .col-8 { + width: 66.66666667%; } + +.col-12 .col-9 { + width: 75%; } + +.col-12 .col-10 { + width: 83.33333333%; } + +.col-12 .col-11 { + width: 91.66666667%; } + +.col-12 .col-12 { + width: 100%; } + +.col-1of1, .col-2of2, .col-3of3, .col-4of4, .col-5of5, .col-6of6, .col-8of8, .col-10of10, .col-12of12, .col-16of16 { + width: 100%; } + +.col-1of2, .col-2of4, .col-3of6, .col-4of8, .col-5of10, .col-6of12, .col-8of16 { + width: 50%; } + +.col-1of3, .col-2of6, .col-4of12 { + width: 33.33333333%; } + +.col-2of3, .col-4of6, .col-8of12 { + width: 66.66666667%; } + +.col-1of4, .col-2of8, .col-3of12, .col-4of16 { + width: 25%; } + +.col-3of4, .col-6of8, .col-9of12, .col-12of16 { + width: 75%; } + +.col-1of5, .col-2of10 { + width: 20%; } + +.col-2of5, .col-4of10 { + width: 40%; } + +.col-3of5, .col-6of10 { + width: 60%; } + +.col-4of5, .col-8of10 { + width: 80%; } + +.col-1of6, .col-2of12 { + width: 16.66666667%; } + +.col-5of6, .col-10of12 { + width: 83.33333333%; } + +.col-1of8, .col-2of16 { + width: 12.5%; } + +.col-3of8, .col-6of16 { + width: 37.5%; } + +.col-5of8, .col-10of16 { + width: 62.5%; } + +.col-7of8, .col-14of16 { + width: 87.5%; } + +.col-1of10 { + width: 10%; } + +.col-3of10 { + width: 30%; } + +.col-7of10 { + width: 70%; } + +.col-9of10 { + width: 90%; } + +.col-1of12 { + width: 8.33333333%; } + +.col-5of12 { + width: 41.66666667%; } + +.col-7of12 { + width: 58.33333333%; } + +.col-11of12 { + width: 91.66666667%; } + +.col-1of16 { + width: 6.25%; } + +.col-3of16 { + width: 18.75%; } + +.col-5of16 { + width: 31.25%; } + +.col-7of16 { + width: 43.75%; } + +.col-9of16 { + width: 56.25%; } + +.col-11of16 { + width: 68.75%; } + +.col-13of16 { + width: 81.25%; } + +.col-15of16 { + width: 93.75%; } + +.col-pull-1of1, .col-pull-2of2, .col-pull-3of3, .col-pull-4of4, .col-pull-5of5, .col-pull-6of6, .col-pull-8of8, .col-pull-10of10, .col-pull-12of12, .col-pull-16of16 { + left: -100%; } + +.col-pull-1of2, .col-pull-2of4, .col-pull-3of6, .col-pull-4of8, .col-pull-5of10, .col-pull-6of12, .col-pull-8of16 { + left: -50%; } + +.col-pull-1of3, .col-pull-2of6, .col-pull-4of12 { + left: -33.33333333%; } + +.col-pull-2of3, .col-pull-4of6, .col-pull-8of12 { + left: -66.66666667%; } + +.col-pull-1of4, .col-pull-2of8, .col-pull-3of12, .col-pull-4of16 { + left: -25%; } + +.col-pull-3of4, .col-pull-6of8, .col-pull-9of12, .col-pull-12of16 { + left: -75%; } + +.col-pull-1of5, .col-pull-2of10 { + left: -20%; } + +.col-pull-2of5, .col-pull-4of10 { + left: -40%; } + +.col-pull-3of5, .col-pull-6of10 { + left: -60%; } + +.col-pull-4of5, .col-pull-8of10 { + left: -80%; } + +.col-pull-1of6, .col-pull-2of12 { + left: -16.66666667%; } + +.col-pull-5of6, .col-pull-10of12 { + left: -83.33333333%; } + +.col-pull-1of8, .col-pull-2of16 { + left: -12.5%; } + +.col-pull-3of8, .col-pull-6of16 { + left: -37.5%; } + +.col-pull-5of8, .col-pull-10of16 { + left: -62.5%; } + +.col-pull-7of8, .col-pull-14of16 { + left: -87.5%; } + +.col-pull-1of10 { + left: -10%; } + +.col-pull-3of10 { + left: -30%; } + +.col-pull-7of10 { + left: -70%; } + +.col-pull-9of10 { + left: -90%; } + +.col-pull-1of12 { + left: -8.33333333%; } + +.col-pull-5of12 { + left: -41.66666667%; } + +.col-pull-7of12 { + left: -58.33333333%; } + +.col-pull-11of12 { + left: -91.66666667%; } + +.col-pull-1of16 { + left: -6.25%; } + +.col-pull-3of16 { + left: -18.75%; } + +.col-pull-5of16 { + left: -31.25%; } + +.col-pull-7of16 { + left: -43.75%; } + +.col-pull-9of16 { + left: -56.25%; } + +.col-pull-11of16 { + left: -68.75%; } + +.col-pull-13of16 { + left: -81.25%; } + +.col-pull-15of16 { + left: -93.75%; } + +.col-push-1of1, .col-push-2of2, .col-push-3of3, .col-push-4of4, .col-push-5of5, .col-push-6of6, .col-push-8of8, .col-push-10of10, .col-push-12of12, .col-push-16of16 { + left: 100%; } + +.col-push-1of2, .col-push-2of4, .col-push-3of6, .col-push-4of8, .col-push-5of10, .col-push-6of12, .col-push-8of16 { + left: 50%; } + +.col-push-1of3, .col-push-2of6, .col-push-4of12 { + left: 33.33333333%; } + +.col-push-2of3, .col-push-4of6, .col-push-8of12 { + left: 66.66666667%; } + +.col-push-1of4, .col-push-2of8, .col-push-3of12, .col-push-4of16 { + left: 25%; } + +.col-push-3of4, .col-push-6of8, .col-push-9of12, .col-push-12of16 { + left: 75%; } + +.col-push-1of5, .col-push-2of10 { + left: 20%; } + +.col-push-2of5, .col-push-4of10 { + left: 40%; } + +.col-push-3of5, .col-push-6of10 { + left: 60%; } + +.col-push-4of5, .col-push-8of10 { + left: 80%; } + +.col-push-1of6, .col-push-2of12 { + left: 16.66666667%; } + +.col-push-5of6, .col-push-10of12 { + left: 83.33333333%; } + +.col-push-1of8, .col-push-2of16 { + left: 12.5%; } + +.col-push-3of8, .col-push-6of16 { + left: 37.5%; } + +.col-push-5of8, .col-push-10of16 { + left: 62.5%; } + +.col-push-7of8, .col-push-14of16 { + left: 87.5%; } + +.col-push-1of10 { + left: 10%; } + +.col-push-3of10 { + left: 30%; } + +.col-push-7of10 { + left: 70%; } + +.col-push-9of10 { + left: 90%; } + +.col-push-1of12 { + left: 8.33333333%; } + +.col-push-5of12 { + left: 41.66666667%; } + +.col-push-7of12 { + left: 58.33333333%; } + +.col-push-11of12 { + left: 91.66666667%; } + +.col-push-1of16 { + left: 6.25%; } + +.col-push-3of16 { + left: 18.75%; } + +.col-push-5of16 { + left: 31.25%; } + +.col-push-7of16 { + left: 43.75%; } + +.col-push-9of16 { + left: 56.25%; } + +.col-push-11of16 { + left: 68.75%; } + +.col-push-13of16 { + left: 81.25%; } + +.col-push-15of16 { + left: 93.75%; } + +@media (max-width: 960px) and (min-width: 720px) { + .col-tablet-1of1, .col-tablet-2of2, .col-tablet-3of3, .col-tablet-4of4, .col-tablet-5of5, .col-tablet-6of6, .col-tablet-8of8, .col-tablet-10of10, .col-tablet-12of12, .col-tablet-16of16 { + width: 100%; } + .col-tablet-1of2, .col-tablet-2of4, .col-tablet-3of6, .col-tablet-4of8, .col-tablet-5of10, .col-tablet-6of12, .col-tablet-8of16 { + width: 50%; } + .col-tablet-1of3, .col-tablet-2of6, .col-tablet-4of12 { + width: 33.33333333%; } + .col-tablet-2of3, .col-tablet-4of6, .col-tablet-8of12 { + width: 66.66666667%; } + .col-tablet-1of4, .col-tablet-2of8, .col-tablet-3of12, .col-tablet-4of16 { + width: 25%; } + .col-tablet-3of4, .col-tablet-6of8, .col-tablet-9of12, .col-tablet-12of16 { + width: 75%; } + .col-tablet-1of5, .col-tablet-2of10 { + width: 20%; } + .col-tablet-2of5, .col-tablet-4of10 { + width: 40%; } + .col-tablet-3of5, .col-tablet-6of10 { + width: 60%; } + .col-tablet-4of5, .col-tablet-8of10 { + width: 80%; } + .col-tablet-1of6, .col-tablet-2of12 { + width: 16.66666667%; } + .col-tablet-5of6, .col-tablet-10of12 { + width: 83.33333333%; } + .col-tablet-1of8, .col-tablet-2of16 { + width: 12.5%; } + .col-tablet-3of8, .col-tablet-6of16 { + width: 37.5%; } + .col-tablet-5of8, .col-tablet-10of16 { + width: 62.5%; } + .col-tablet-7of8, .col-tablet-14of16 { + width: 87.5%; } + .col-tablet-1of10 { + width: 10%; } + .col-tablet-3of10 { + width: 30%; } + .col-tablet-7of10 { + width: 70%; } + .col-tablet-9of10 { + width: 90%; } + .col-tablet-1of12 { + width: 8.33333333%; } + .col-tablet-5of12 { + width: 41.66666667%; } + .col-tablet-7of12 { + width: 58.33333333%; } + .col-tablet-11of12 { + width: 91.66666667%; } + .col-tablet-1of16 { + width: 6.25%; } + .col-tablet-3of16 { + width: 18.75%; } + .col-tablet-5of16 { + width: 31.25%; } + .col-tablet-7of16 { + width: 43.75%; } + .col-tablet-9of16 { + width: 56.25%; } + .col-tablet-11of16 { + width: 68.75%; } + .col-tablet-13of16 { + width: 81.25%; } + .col-tablet-15of16 { + width: 93.75%; } + .col-tablet-pull-1of1, .col-tablet-pull-2of2, .col-tablet-pull-3of3, .col-tablet-pull-4of4, .col-tablet-pull-5of5, .col-tablet-pull-6of6, .col-tablet-pull-8of8, .col-tablet-pull-10of10, .col-tablet-pull-12of12, .col-tablet-pull-16of16 { + left: -100%; } + .col-tablet-pull-1of2, .col-tablet-pull-2of4, .col-tablet-pull-3of6, .col-tablet-pull-4of8, .col-tablet-pull-5of10, .col-tablet-pull-6of12, .col-tablet-pull-8of16 { + left: -50%; } + .col-tablet-pull-1of3, .col-tablet-pull-2of6, .col-tablet-pull-4of12 { + left: -33.33333333%; } + .col-tablet-pull-2of3, .col-tablet-pull-4of6, .col-tablet-pull-8of12 { + left: -66.66666667%; } + .col-tablet-pull-1of4, .col-tablet-pull-2of8, .col-tablet-pull-3of12, .col-tablet-pull-4of16 { + left: -25%; } + .col-tablet-pull-3of4, .col-tablet-pull-6of8, .col-tablet-pull-9of12, .col-tablet-pull-12of16 { + left: -75%; } + .col-tablet-pull-1of5, .col-tablet-pull-2of10 { + left: -20%; } + .col-tablet-pull-2of5, .col-tablet-pull-4of10 { + left: -40%; } + .col-tablet-pull-3of5, .col-tablet-pull-6of10 { + left: -60%; } + .col-tablet-pull-4of5, .col-tablet-pull-8of10 { + left: -80%; } + .col-tablet-pull-1of6, .col-tablet-pull-2of12 { + left: -16.66666667%; } + .col-tablet-pull-5of6, .col-tablet-pull-10of12 { + left: -83.33333333%; } + .col-tablet-pull-1of8, .col-tablet-pull-2of16 { + left: -12.5%; } + .col-tablet-pull-3of8, .col-tablet-pull-6of16 { + left: -37.5%; } + .col-tablet-pull-5of8, .col-tablet-pull-10of16 { + left: -62.5%; } + .col-tablet-pull-7of8, .col-tablet-pull-14of16 { + left: -87.5%; } + .col-tablet-pull-1of10 { + left: -10%; } + .col-tablet-pull-3of10 { + left: -30%; } + .col-tablet-pull-7of10 { + left: -70%; } + .col-tablet-pull-9of10 { + left: -90%; } + .col-tablet-pull-1of12 { + left: -8.33333333%; } + .col-tablet-pull-5of12 { + left: -41.66666667%; } + .col-tablet-pull-7of12 { + left: -58.33333333%; } + .col-tablet-pull-11of12 { + left: -91.66666667%; } + .col-tablet-pull-1of16 { + left: -6.25%; } + .col-tablet-pull-3of16 { + left: -18.75%; } + .col-tablet-pull-5of16 { + left: -31.25%; } + .col-tablet-pull-7of16 { + left: -43.75%; } + .col-tablet-pull-9of16 { + left: -56.25%; } + .col-tablet-pull-11of16 { + left: -68.75%; } + .col-tablet-pull-13of16 { + left: -81.25%; } + .col-tablet-pull-15of16 { + left: -93.75%; } + .col-tablet-push-1of1, .col-tablet-push-2of2, .col-tablet-push-3of3, .col-tablet-push-4of4, .col-tablet-push-5of5, .col-tablet-push-6of6, .col-tablet-push-8of8, .col-tablet-push-10of10, .col-tablet-push-12of12, .col-tablet-push-16of16 { + left: 100%; } + .col-tablet-push-1of2, .col-tablet-push-2of4, .col-tablet-push-3of6, .col-tablet-push-4of8, .col-tablet-push-5of10, .col-tablet-push-6of12, .col-tablet-push-8of16 { + left: 50%; } + .col-tablet-push-1of3, .col-tablet-push-2of6, .col-tablet-push-4of12 { + left: 33.33333333%; } + .col-tablet-push-2of3, .col-tablet-push-4of6, .col-tablet-push-8of12 { + left: 66.66666667%; } + .col-tablet-push-1of4, .col-tablet-push-2of8, .col-tablet-push-3of12, .col-tablet-push-4of16 { + left: 25%; } + .col-tablet-push-3of4, .col-tablet-push-6of8, .col-tablet-push-9of12, .col-tablet-push-12of16 { + left: 75%; } + .col-tablet-push-1of5, .col-tablet-push-2of10 { + left: 20%; } + .col-tablet-push-2of5, .col-tablet-push-4of10 { + left: 40%; } + .col-tablet-push-3of5, .col-tablet-push-6of10 { + left: 60%; } + .col-tablet-push-4of5, .col-tablet-push-8of10 { + left: 80%; } + .col-tablet-push-1of6, .col-tablet-push-2of12 { + left: 16.66666667%; } + .col-tablet-push-5of6, .col-tablet-push-10of12 { + left: 83.33333333%; } + .col-tablet-push-1of8, .col-tablet-push-2of16 { + left: 12.5%; } + .col-tablet-push-3of8, .col-tablet-push-6of16 { + left: 37.5%; } + .col-tablet-push-5of8, .col-tablet-push-10of16 { + left: 62.5%; } + .col-tablet-push-7of8, .col-tablet-push-14of16 { + left: 87.5%; } + .col-tablet-push-1of10 { + left: 10%; } + .col-tablet-push-3of10 { + left: 30%; } + .col-tablet-push-7of10 { + left: 70%; } + .col-tablet-push-9of10 { + left: 90%; } + .col-tablet-push-1of12 { + left: 8.33333333%; } + .col-tablet-push-5of12 { + left: 41.66666667%; } + .col-tablet-push-7of12 { + left: 58.33333333%; } + .col-tablet-push-11of12 { + left: 91.66666667%; } + .col-tablet-push-1of16 { + left: 6.25%; } + .col-tablet-push-3of16 { + left: 18.75%; } + .col-tablet-push-5of16 { + left: 31.25%; } + .col-tablet-push-7of16 { + left: 43.75%; } + .col-tablet-push-9of16 { + left: 56.25%; } + .col-tablet-push-11of16 { + left: 68.75%; } + .col-tablet-push-13of16 { + left: 81.25%; } + .col-tablet-push-15of16 { + left: 93.75%; } } + +.col-3-wide { + width: 33.33333333%; } + +@media (max-width: 719px) { + /* Remove .col-12 and .col-13 backward compatibility support as soon as it's been removed. */ +[class*=col-], .col-12 [class*=col-], .col-13 [class*=col-] { + float: none; + left: 0; + width: auto; +} } + +/* Header component */ +.dac-header { + background: #fff; + height: 64px; + margin: 0 -20px; +} + +@media (max-width: 719px) { + .dac-header { + margin: 0 -10px; + } +} + +.about .dac-header, .distribute .dac-header, .develop .dac-header { + height: 128px; +} + +.dac-header-inner { + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.07); + box-sizing: border-box; + height: 64px; + left: 0; + right: 0; + top: 0; + z-index: 52; +} + +.dac-header.dac-sub .dac-header-inner { + border-bottom: 1px solid #e5e5e5; + box-shadow: none; +} + +.dac-header.is-sticky .dac-header-inner { + position: fixed; + -webkit-animation: .3s dac-header-show; + animation: .3s dac-header-show; +} + +.dac-header-logo { + border-right: 1px solid #e5e5e5; + display: block; + font-size: 20px; + font-weight: 300; + float: left; + letter-spacing: .3px; + line-height: 36px; + margin-right: 16px; + padding: 14px 24px 14px; +} + +.dac-header-logo, .dac-header-logo:hover, .dac-header-logo:focus { + color: #444; +} + +.dac-header-logo-image { + margin-right: 5px; + vertical-align: top; +} + +.dac-header-console-btn { + border: 1px solid #c5c5c5; + border-radius: 3px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.11); + background: #fff; + float: right; + font-size: 14px; + line-height: 28px; + margin: 17px 30px 17px 10px; + padding: 0 10px; + position: relative; + z-index: 52; +} + +.dac-header-console-btn > .dac-sprite { + margin-right: 5px; +} + +.dac-header-console-btn, .dac-header-console-btn:hover, .dac-header-console-btn:focus { + color: #666; +} + +.dac-header-console-btn:focus { + background: rgba(63, 81, 181, 0.1); + outline: 0; +} + +@media (max-width: 719px) { + .dac-header { + height: 64px !important; + text-align: center; + } + + .dac-header-inner { + position: fixed; + } + + .dac-header-logo { + border-right: 0; + display: inline-block; + margin-right: 0; + float: none; + } + + .dac-header.dac-sub { + display: none; + } + + .dac-header-console-btn { + display: none; + } +} + +@-webkit-keyframes dac-header-show { + 0% { + -webkit-transform: translateY(-64px); + transform: translateY(-64px); + } + + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes dac-header-show { + 0% { + -webkit-transform: translateY(-64px); + transform: translateY(-64px); + } + + 100% { + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +/* Header Breadcrumbs component */ +.dac-header-crumbs { + display: none; + list-style-type: none; + margin: 0; +} + +.is-sticky .dac-header-crumbs { + display: block; +} + +.dac-header-crumbs-item { + float: left; + position: relative; + margin: 0; + padding-left: 10px; +} + +.dac-header-crumbs-item:before { + color: #444; + content: '>'; + font-weight: 300; + font-size: 20px; + left: 0; + line-height: 28px; + padding: 16px 0; + position: absolute; +} + +.dac-header-crumbs-item:first-child:before { + content: none; +} + +.dac-header-crumbs-link { + color: #444; + display: block; + font-size: 16px; + font-weight: 300; + line-height: 32px; + padding: 16px 16px; + -webkit-transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); + transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); +} + +.dac-header-crumbs-link:hover, .dac-header-crumbs-link:focus { + color: rgba(68, 68, 68, 0.7); +} + +.dac-header-crumbs-link:focus { + background: rgba(63, 81, 181, 0.1); + outline: 0; +} + +.dac-header-crumbs-link.current { + color: #6ab344; + font-weight: 400; +} + +.dac-header-crumbs-link.current.ndk { + color: #00BCD4; +} + +@media (max-width: 719px) { + .dac-header-crumbs { + display: none; + } +} + +/* Header site search component */ +.dac-header-search { + background: #fff; + border-left: 1px solid #e5e5e5; + display: block; + float: right; + height: 28px; + padding: 18px 0; + position: relative; + overflow: hidden; + -webkit-transition: width 0.4s ease, left 0.4s ease; + transition: width 0.4s ease, left 0.4s ease; + width: 64px; + z-index: 52; +} + +.dac-header-search:hover, .dac-header-search.active { + width: 228px; +} + +.dac-header-search-inner { + width: 228px; +} + +.dac-header-search-btn { + left: 20px; + position: absolute; + top: 20px; + opacity: .54; +} + +.dac-header-search-form { + left: 54px; + opacity: 0; + position: absolute; + right: 24px; + top: 20px; + -webkit-transition: opacity .4s; + transition: opacity .4s; +} + +.dac-header-search:hover .dac-header-search-form, .dac-header-search.active .dac-header-search-form { + opacity: 1; +} + +.dac-header-search-input { + background-color: transparent; + border: none; + border-bottom: 1px solid #CCC; + border-radius: 0; + box-sizing: border-box; + color: #2f2f2f; + font-size: 14px; + height: 24px; + outline: none; + padding: 4px 20px 4px 0; + width: 100%; + z-index: 1500; +} + +.dac-header-search-input:focus { + color: #222; + font-weight: bold; + outline: 0; +} + +.dac-header-search-close { + position: absolute; + right: 4px; + bottom: 4px; + width: 16px; + height: 16px; + margin: 0; + text-indent: -1000em; + background: url(../images/close.png) no-repeat 0 0; + z-index: 9999; +} + +.dac-header-search-close:hover, .dac-header-search-close:focus { + background-position: -16px 0; + cursor: pointer; +} + +@media (max-width: 719px) { + .dac-header-search { + position: absolute; + left: calc(100% - 64px); + right: 0; + top: 0; + width: auto; + } + + .dac-header-search:hover, .dac-header-search.active { + left: 64px; + width: auto; + } +} + +/* Main navigation component */ +.is-sticky .dac-nav, .dac-nav-head, .dac-nav-toggle { + display: none; +} + +.dac-nav-list { + list-style-type: none; + left: 192px; + margin: 0; + position: absolute; + right: 0; + top: 0; + z-index: 51; +} + +.dac-nav-item { + float: left; + margin: 0; +} + +.dac-nav-head { + margin-bottom: 10px; +} + +.dac-nav-dimmer { + background: #000; + display: none; + height: 100%; + left: 0; + opacity: 0; + position: fixed; + top: 0; + -webkit-transition: visibility 0s linear .3s, opacity .3s linear; + transition: visibility 0s linear .3s, opacity .3s linear; + -webkit-transform: translateZ(0); + transform: translateZ(0); + visibility: hidden; + width: 100%; + z-index: 52; +} + +.dac-nav-hamburger { + display: inline-block; + height: 15px; + width: 16px; +} + +.dac-nav-hamburger-top, .dac-nav-hamburger-mid, .dac-nav-hamburger-bot { + background: #999; + display: block; + height: 3px; + margin: 3px 0 0; + width: 100%; +} + +.dac-nav-link { + color: #444; + display: block; + font-size: 16px; + font-weight: 300; + letter-spacing: .24px; + line-height: 32px; + padding: 18px 16px 14px; + -webkit-transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); + transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1); +} + +.dac-nav-link:hover, .dac-nav-link:focus { + color: rgba(68, 68, 68, 0.7); +} + +.dac-nav-link:focus { + background: rgba(63, 81, 181, 0.1); + outline: 0; +} + +.dac-nav-link.has-subnav, .dac-nav-link.selected { + border-bottom: 3px solid #6ab344; + font-weight: 500; + padding-bottom: 11px; +} + +.dac-nav-link.has-subnav.ndk, .dac-nav-link.selected.ndk { + border-bottom: 3px solid #00BCD4; +} + +.dac-nav-secondary { + border-bottom: 1px solid #e5e5e5; + display: none; + left: -192px; + list-style-type: none; + margin: 0; + position: absolute; + top: 64px; + right: 0; +} + +.dac-nav-link.has-subnav + .dac-nav-secondary, .dac-nav-link.selected + .dac-nav-secondary { + display: block; +} + +.dac-nav-secondary .dac-nav-link { + color: #666; + padding: 17px 16px 15px; +} + +.dac-nav-secondary .dac-nav-link:hover, .dac-nav-secondary .dac-nav-link:focus { + color: rgba(102, 102, 102, 0.7); +} + +@media (min-width: 720px) and (max-width: 979px) { + .dac-nav-secondary .dac-nav-link { + padding-left: 8px; + padding-right: 8px; + } +} + +.dac-nav-secondary .dac-nav-link.selected { + border: none; + font-weight: 700; +} + +.dac-nav-secondary .dac-nav-link.selected.ndk { + border: none; + font-weight: 700; +} + +@media (max-width: 719px) { + .dac-nav-open { + overflow: hidden; + } + + .dac-nav-toggle { + border-right: 1px solid #e5e5e5; + display: inline-block; + position: absolute; + left: 0; + line-height: 64px; + text-align: center; + width: 64px; + } + + .dac-nav-head, .dac-nav-secondary, .dac-nav-dimmer { + display: block; + } + + .dac-nav-dimmer.dac-nav-open { + opacity: .8; + -webkit-transition-delay: 0s; + transition-delay: 0s; + visibility: visible; + } + + .dac-nav-list { + background: #fff; + bottom: 0; + left: auto; + max-width: 280px; + -webkit-overflow-scrolling: touch; + overflow-y: scroll; + padding: 0 0 20px 0; + position: fixed; + right: 100%; + top: 0; + -webkit-transition: -webkit-transform .3s ease; + transition: transform .3s ease; + width: 85%; + z-index: 52; + } + + .dac-nav-list.dac-nav-open { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + .dac-nav-secondary { + border: none; + position: static; + width: 100%; + } + + .dac-nav-item { + float: none; + } + + .dac-nav-link { + display: block; + font-size: 12px; + font-weight: 600; + color: #333; + padding: 0 20px; + } + + .dac-nav-link.selected { + color: #09f; + } + + .dac-nav-secondary .dac-nav-link { + font-weight: 400; + margin-left: 20px; + margin-right: 20px; + padding: 0 20px; + } + + .dac-nav-link.has-subnav, .dac-nav-link.selected { + border: none; + padding: 0 20px; + } + + .dac-nav-link.has-subnav.ndk, .dac-nav-link.selected.ndk { + border: none; + padding: 0 20px; + } + + .dac-logo-image { + margin-right: 5px; + vertical-align: top; + } + + .dac-nav-logo { + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.04); + font-size: 20px; + font-weight: 300; + letter-spacing: .3px; + line-height: 36px; + padding: 14px 24px; + } + + .dac-nav-logo, .dac-nav-logo:hover, .dac-nav-logo:focus { + color: #444; + } +} + +/* Hero carousel */ +.dac-hero { + background-color: #fff; + background-position: 50% 30%; + background-size: cover; + box-sizing: border-box; + font-size: 16px; + min-height: 550px; + padding-top: 88px; +} + +.dac-hero.dac-darken::before { + background: rgba(0, 0, 0, 0.3); + bottom: 0; + content: ''; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +@media (max-width: 719px) { + .dac-hero.dac-darken::before { + background: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.9) 80%); + } +} + +.dac-hero.dac-darken .dac-hero-content { + position: relative; +} + +@media (max-width: 719px) { + .dac-hero { + padding-bottom: 20px; + padding-top: 20px; + } +} + +.dac-hero-tag { + font-size: 11px; + font-weight: 700; + letter-spacing: .07em; + margin-bottom: 2px; + text-transform: uppercase; +} + +.dac-hero-title { + margin: 0 0 14px; +} + +@media (max-width: 719px) { + .dac-hero-title { + font-size: 28px; + line-height: 35px; + } +} + +.dac-hero-description { + margin-bottom: 16px; +} + +@media (max-width: 719px) { + .dac-hero-description { + font-size: 14px; + } +} + +.dac-hero-cta { + display: inline-block; + line-height: 40px; + margin-right: 20px; + -webkit-transition: opacity .3s; + transition: opacity .3s; +} + +.dac-hero-cta:hover { + color: currentColor; + opacity: .54; +} + +.dac-hero-cta .dac-sprite { + margin-left: -8px; +} + +@media (max-width: 719px) { + .dac-hero-cta { + line-height: 28px; + } +} + +.dac-hero-figure { + text-align: center; +} + +@media (max-width: 719px) { + .dac-hero-figure { + height: 150px; + margin: 15px 0; + } + + .dac-hero-figure img { + max-height: 150px; + } +} + +.dac-hero-carousel { + height: 550px; + position: relative; +} + +.dac-hero-carousel > .dac-hero { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + will-change: opacity; +} + +.dac-hero-carousel > .dac-hero, .dac-hero-carousel > .dac-hero .wrap { + opacity: 0; +} + +.dac-hero-carousel > .dac-hero.active { + opacity: 1; + -webkit-transition: opacity .5s; + transition: opacity .5s; + z-index: 1; +} + +.dac-hero-carousel > .dac-hero.active .wrap { + opacity: 1; + -webkit-transition: opacity .5s .5s; + transition: opacity .5s .5s; +} + +.dac-hero-carousel > .dac-hero.out, .dac-hero-carousel > .dac-hero.out .wrap { + -webkit-transition: opacity 0s .5s; + transition: opacity 0s .5s; + opacity: 0; +} + +.dac-hero-carousel-action { + bottom: 0; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.dac-hero-carousel .dac-hero-cta { + position: relative; + z-index: 1; +} + +.dac-hero-carousel-pagination { + bottom: 33px; + left: 0; + position: absolute; + right: 0; +} + +@media (max-width: 719px) { + .dac-hero-carousel-pagination { + text-align: center; + bottom: 20px; + } +} + +.dac-hero-carousel-pagination .dac-pagination-item { + position: relative; + z-index: 1; +} + +.dac-pagination { + list-style: none; + margin: 0 -6px; +} + +.dac-pagination-item { + background-clip: content-box; + background-color: rgba(153, 153, 153, 0.4); + border-radius: 50%; + cursor: pointer; + display: inline-block; + height: 14px; + overflow: hidden; + padding: 6px; + pointer-events: all; + text-indent: 100%; + -webkit-transition: background-color .1s ease-in; + transition: background-color .1s ease-in; + white-space: nowrap; + width: 14px; + will-change: background-color; +} + +.dac-pagination-item:hover { + background-color: rgba(153, 153, 153, 0.6); +} + +.dac-pagination-item.active, .dac-pagination-item.active:hover { + background-color: #6ab344; +} + +.dac-invert .dac-pagination-item { + background-color: rgba(204, 204, 204, 0.2); +} + +.dac-invert .dac-pagination-item:hover { + background-color: rgba(153, 153, 153, 0.4); +} + +@media (max-width: 719px) { + .dac-pagination-item { + height: 12px; + width: 12px; + } +} + +/* Form component */ +.dac-form { + color: #505050; + font-size: 16px; + /* Modal Responsive */ +} + +.dac-form a { + color: #000; +} + +.dac-form-aside { + display: inline-block; + font-size: 12px; + margin-top: 0; +} + +.dac-form-required { + color: #ef4300; +} + +.dac-form-fieldset { + padding: 0; +} + +.dac-form-legend { + display: block; + color: #333; + font-weight: 500; + margin: 20px 0 12px; + padding: 0; + width: 100%; +} + +.dac-form-legend > .dac-form-required { + float: right; + margin-top: 3px; +} + +.dac-form-input { + border: 0 solid #e3e3e3; + border-bottom-width: 1px; + display: block; + outline: 0; + padding: 1px 0 8px; + -webkit-transition: border-color .2s; + transition: border-color .2s; + width: 100%; +} + +.dac-form-input-group { + position: relative; +} + +.dac-form-input-group > .dac-form-required { + display: block; + bottom: 3px; + position: absolute; + right: 0; +} + +.dac-form-input:focus { + border-bottom-color: #09f; +} + +.dac-form-floatlabel { + display: block; + cursor: text; + margin-top: 5px; + pointer-events: none; + -webkit-transform-origin: 0 100%; + -ms-transform-origin: 0 100%; + transform-origin: 0 100%; + -webkit-transform: translate3d(0, 22px, 0) scale(1); + transform: translate3d(0, 22px, 0) scale(1); + -webkit-transition: -webkit-transform .2s; + transition: transform .2s; +} + +.dac-focused > .dac-form-floatlabel, .dac-has-value > .dac-form-floatlabel { + cursor: default; + -webkit-transform: translate3d(0, 0, 0) scale(.75); + transform: translate3d(0, 0, 0) scale(.75); +} + +.dac-form-radio, .dac-form-checkbox { + opacity: 0; + position: absolute; +} + +.dac-form-radio-group, .dac-form-checkbox-group { + display: table; + margin-top: 10px; +} + +.dac-form-radio-button, .dac-form-checkbox-button { + box-sizing: border-box; + cursor: pointer; + display: table-cell; + float: left; + height: 18px; + margin: 2px 10px 0 0; + position: relative; + width: 18px; +} + +.dac-form-radio-button::after, .dac-form-radio-button::before, .dac-form-checkbox-button::after, .dac-form-checkbox-button::before { + box-sizing: border-box; + content: ''; + border-radius: 50%; + display: block; + height: 100%; + position: absolute; + width: 100%; +} + +.dac-form-radio-button::before, .dac-form-checkbox-button::before { + background: rgba(0, 0, 0, 0.7); + -webkit-transform: translateZ(0) scale(0); + transform: translateZ(0) scale(0); + -webkit-transition: -webkit-transform .3s; + transition: transform .3s; +} + +.dac-form-radio-button::after, .dac-form-checkbox-button::after { + border: 2px solid rgba(0, 0, 0, 0.7); +} + +.dac-form-radio:checked + .dac-form-radio-button::before, .dac-form-checkbox:checked + .dac-form-checkbox-button::before { + -webkit-transform: translateZ(0) scale(.5); + transform: translateZ(0) scale(.5); +} + +.dac-form-radio:focus + .dac-form-radio-button::after, .dac-form-checkbox:focus + .dac-form-checkbox-button::after { + border: 2px solid #09f; +} + +.dac-form-checkbox-button::after, .dac-form-checkbox-button::before { + border-radius: 0; +} + +@media (max-width: 719px) { + .dac-form-legend { + margin-bottom: 0; + } +} + +/* Media component */ +.dac-media { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; +} + +.dac-media-figure { + margin: 0; +} + +.dac-media-body { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.no-flexbox .dac-media { + display: table; + width: 100%; +} + +.no-flexbox .dac-media-body, .no-flexbox .dac-media-figure { + display: table-cell; +} + +.no-flexbox .dac-media-figure { + padding: 0; +} + +.no-flexbox .dac-media-body { + width: 100%; +} + +.dac-swap { + overflow: hidden; + position: relative; +} + +.dac-swap-section { + left: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + -webkit-transition: opacity 1s, -webkit-transform .5s; + transition: opacity 1s, transform .5s; +} + +.dac-swap-section.dac-up { + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); +} + +.dac-swap-section.dac-down { + -webkit-transform: translateY(100%); + -ms-transform: translateY(100%); + transform: translateY(100%); +} + +.dac-swap-section.dac-left { + -webkit-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); +} + +.dac-swap-section.dac-right { + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); +} + +.dac-swap-section.dac-active { + opacity: 1; + position: relative; + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); + width: auto; +} + +/* Modal component */ +.dac-modal { + background: rgba(0, 0, 0, 0.8); + bottom: 0; + left: 0; + opacity: 0; + overflow-x: hidden; + overflow-y: auto; + position: fixed; + right: 0; + top: 0; + -webkit-transition: visibility 0s linear .3s, opacity .3s linear; + transition: visibility 0s linear .3s, opacity .3s linear; + visibility: hidden; + z-index: 52; +} + +.dac-modal.dac-active { + opacity: 1; + -webkit-transition-delay: 0s; + transition-delay: 0s; + visibility: visible; +} + +.dac-modal-open { + overflow: hidden; +} + +.dac-modal-container { + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4)); + filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.4)); + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + min-height: 100%; + width: 100%; +} + +.dac-modal-window { + background: #fff; + border-radius: 5px; + box-sizing: border-box; + margin: 20px auto; + -webkit-transition: -webkit-transform .3s; + transition: transform .3s; + -webkit-transform: translate(0, -30px); + -ms-transform: translate(0, -30px); + transform: translate(0, -30px); + width: 960px; +} + +.dac-modal.dac-active .dac-modal-window { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} + +.dac-modal-header { + background: #00695c; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + padding: 35px 35px 30px; + position: relative; +} + +.dac-modal-header-close { + background: none; + border: none; + cursor: pointer; + line-height: 0; + outline: 0; + opacity: .7; + padding: 8px; + position: absolute; + right: 5px; + -webkit-transition: background-color .3s; + transition: background-color .3s; + top: 5px; +} + +.dac-modal-header-close:active { + background: rgba(255, 255, 255, 0.2); +} + +.dac-modal-header-title { + color: #fff; + font-size: 24px; + font-weight: 300; + line-height: 32px; + margin: 0; + padding-right: 150px; +} + +.dac-modal-header-subtitle { + bottom: 0; + color: #fff; + display: inline-block; + font: inherit; + font-size: 14px; + margin: 0; + opacity: .8; + position: absolute; + right: 0; +} + +.dac-modal-content { + padding: 12px 35px; +} + +.dac-modal-action { + margin: 0; +} + +.dac-modal-footer { + padding: 24px 35px; +} + +@media (max-width: 1000px) { + .dac-modal-window { + margin: 20px; + width: auto; + } + + .dac-modal-container { + z-index: auto; + } +} + +@media (max-width: 719px) { + .dac-modal-window { + margin: 10px; + } + + .dac-modal-header { + padding: 35px 10px 10px; + } + + .dac-modal-header-title { + font-size: 16px; + line-height: 24px; + padding: 0; + } + + .dac-modal-header-subtitle { + display: block; + margin: 0; + position: static; + text-align: right; + } + + .dac-modal-content { + padding: 10px; + } + + .dac-modal-footer { + border-top: 1px solid #e3e3e3; + padding: 35px 10px; + } +} + +.newsletter .dac-modal-footer { + padding-top: 0; + text-align: right; +} + +.newsletter-checkboxes { + padding-top: 20px; +} + +.newsletter-success-message { + font-size: 32px; + line-height: 1.4; + padding: 40px 30px; + text-align: center; +} + +@media (max-width: 719px) { + .newsletter-success-message { + font-size: 16px; + padding: 12px 0 0; + } +} + +@media (min-width: 720px) { + .newsletter-checkboxes { + padding-top: 46px; + } + + .newsletter-leftCol { + padding-right: 40px; + } + + .newsletter-rightCol { + padding-left: 40px; + } +} + +@media (max-width: 719px) { + .newsletter .dac-modal-footer { + margin-top: 30px; + padding: 30px 10px; + text-align: center; + } +} + +.dac-expand, .dac-section { + margin-left: -20px; + margin-right: -20px; + padding-left: 20px; + padding-right: 20px; +} + +@media (max-width: 719px) { + .dac-expand, .dac-section { + margin-left: -10px; + margin-right: -10px; + padding-left: 10px; + padding-right: 10px; + } +} + +.dac-invert { + color: #b2b2b2; + color: rgba(255, 255, 255, 0.7); +} + +.dac-invert h1, .dac-invert h2, .dac-invert h3 { + color: #fff; +} + +.dac-light.dac-hero, .dac-light.dac-section { + background-color: #eceff1; +} + +.dac-gray.dac-hero, .dac-gray.dac-section { + background-color: #b0bec5; +} + +.dac-dark.dac-hero, .dac-dark.dac-section { + background-color: #37474f; +} + +.dac-red.dac-hero, .dac-red.dac-section { + background-color: #dc4d38; +} + +.dac-hero-cta, .dac-section-title, .dac-section-links { + color: #212121; + color: rgba(0, 0, 0, 0.87); +} + +.dac-invert .dac-hero-cta, .dac-invert .dac-section-title, .dac-invert .dac-section-links { + color: white; +} + +.dac-hero-cta .dac-sprite, .dac-section-title .dac-sprite, .dac-section-links .dac-sprite { + opacity: .87; +} + +.dac-invert .dac-hero-cta .dac-sprite, .dac-invert .dac-section-title .dac-sprite, .dac-invert .dac-section-links .dac-sprite { + opacity: 1; +} + +.dac-hero-tag, .dac-hero-description, .dac-section-subtitle { + color: #757575; + color: rgba(0, 0, 0, 0.54); +} + +.dac-invert .dac-hero-tag, .dac-invert .dac-hero-description, .dac-invert .dac-section-subtitle { + color: #b2b2b2; + color: rgba(255, 255, 255, 0.7); +} + +.dac-section { + background-position: 50% 50%; + background-size: cover; + padding-bottom: 84px; + padding-top: 84px; + position: relative; +} + +@media (max-width: 719px) { + .dac-section { + padding-bottom: 52px; + padding-top: 52px; + } +} + +.dac-section.dac-small { + padding-bottom: 32px; + padding-top: 32px; +} + +.dac-section-title { + text-align: center; + margin-bottom: 40px; + margin-top: 0; +} + +.dac-section-subtitle { + font-size: 16px; + margin-bottom: 40px; + margin-top: -24px; + text-align: center; +} + +.dac-section-links { + font-size: 16px; + list-style: none; + line-height: 40px; + margin: 16px 0 0; + text-align: center; +} + +@media (max-width: 719px) { + .dac-section-links { + margin-left: -8px; + text-align: left; + } +} + +.dac-section-link { + display: inline-block; + margin: 0 32px; + -webkit-transition: opacity .3s; + transition: opacity .3s; +} + +.dac-section-link:hover { + opacity: .54; +} + +@media (max-width: 719px) { + .dac-section-link { + display: block; + margin: 0; + } +} + +.dac-section-link a { + color: inherit; +} + +/* +SCSS variables are information about icon's compiled state, stored under its original file name + +.icon-home { + width: $icon-home-width; +} + +The large array-like variables contain all information about a single icon +$icon-home: x y offset_x offset_y width height total_width total_height image_path; + +At the bottom of this section, we provide information about the spritesheet itself +$spritesheet: width height image $spritesheet-sprites; +*/ +.dac-sprite, #tb li:before, #qv li:before { + background-image: url(/assets/images/sprite.png); + display: inline-block; + vertical-align: middle; } + @media screen and (min-device-pixel-ratio: 1.5) { + .dac-sprite, #tb li:before, #qv li:before { + background-image: url(/assets/images/sprite-2x.png); + background-size: 50% 50%; } } + +.dac-sprite.dac-auto-chevron { + background-position: 0px -196px; + height: 24px; + width: 24px; + vertical-align: -6px; } + .dac-invert .dac-sprite.dac-auto-chevron { + background-position: 0px -222px; + height: 24px; + width: 24px; } +.dac-sprite.dac-auto-chevron-large { + background-position: 0px -404px; + height: 36px; + width: 36px; + vertical-align: -10px; } + .dac-invert .dac-sprite.dac-auto-chevron-large { + background-position: 0px -442px; + height: 36px; + width: 36px; } +.dac-sprite.dac-auto-unfold-less { + background-position: 0px -352px; + height: 24px; + width: 24px; + vertical-align: -6px; } + .dac-invert .dac-sprite.dac-auto-unfold-less { + background-position: 0px -326px; + height: 24px; + width: 24px; } +.dac-sprite.dac-auto-unfold-more { + background-position: 0px -300px; + height: 24px; + width: 24px; + vertical-align: -6px; } + .dac-invert .dac-sprite.dac-auto-unfold-more { + background-position: 0px -378px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-arrow-down-gray { + background-position: 0px 0px; + height: 11px; + width: 19px; } + +.dac-sprite.dac-arrow-right { + background-position: 0px -128px; + height: 18px; + width: 11px; } + +.dac-sprite.dac-chevron-large-right-black { + background-position: 0px -404px; + height: 36px; + width: 36px; } + +.dac-sprite.dac-chevron-large-right-white { + background-position: 0px -442px; + height: 36px; + width: 36px; } + +.dac-sprite.dac-chevron-right-black { + background-position: 0px -196px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-chevron-right-white { + background-position: 0px -222px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-close { + background-position: 0px -27px; + height: 12px; + width: 12px; } + +.dac-sprite.dac-expand-less-black { + background-position: 0px -248px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-expand-more-black { + background-position: 0px -170px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-google-play { + background-position: 0px -108px; + height: 18px; + width: 16px; } + +.dac-sprite.dac-gplus { + background-position: 0px -89px; + height: 17px; + width: 16px; } + +.dac-sprite.dac-mail { + background-position: 0px -13px; + height: 12px; + width: 16px; } + +.dac-sprite.dac-play-white { + background-position: 0px -148px; + height: 20px; + width: 16px; } + +.dac-sprite.dac-rss { + background-position: 0px -41px; + height: 14px; + width: 14px; } + +.dac-sprite.dac-search { + background-position: 0px -274px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-twitter { + background-position: 0px -73px; + height: 14px; + width: 16px; } + +.dac-sprite.dac-unfold-less-white { + background-position: 0px -326px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-unfold-less { + background-position: 0px -352px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-unfold-more-white { + background-position: 0px -378px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-unfold-more { + background-position: 0px -300px; + height: 24px; + width: 24px; } + +.dac-sprite.dac-youtube { + background-position: 0px -57px; + height: 14px; + width: 18px; } + +.dac-toggle-expand { + cursor: pointer; + display: inline-block; } +.dac-toggle-collapse { + cursor: pointer; + display: none; } +.dac-toggle.is-expanded .dac-toggle-expand { + display: none; } +.dac-toggle.is-expanded .dac-toggle-collapse { + display: inline-block; } +.dac-toggle-content { + clear: left; + overflow: hidden; + max-height: 0; + -webkit-transition: .3s max-height; + transition: .3s max-height; } +.dac-toggle.is-expanded .dac-toggle-content { + max-height: none; } +.dac-toggle.dac-mobile .dac-toggle-content { + max-height: none; } +@media (max-width: 719px) { + .dac-toggle.dac-mobile .dac-toggle-content { + max-height: 0; } + .dac-toggle.is-expanded .dac-toggle-content { + max-height: none; } } + +.dac-visible-mobile-block, .dac-mobile-only, .dac-visible-mobile-inline, .dac-visible-mobile-inline-block, .dac-visible-tablet-block, .dac-visible-tablet-inline, .dac-visible-tablet-inline-block, .dac-visible-desktop-block, .dac-visible-desktop-inline, .dac-visible-desktop-inline-block { + display: none !important; } + +@media (max-width: 719px) { + .dac-hidden-mobile { + display: none !important; } + .dac-visible-mobile-block, .dac-mobile-only { + display: block !important; } + .dac-visible-mobile-inline { + display: inline !important; } + .dac-visible-mobile-inline-block { + display: inline-block !important; } } + +@media (min-width: 720px) and (max-width: 979px) { + .dac-hidden-tablet { + display: none !important; } + .dac-visible-tablet-block { + display: block !important; } + .dac-visible-tablet-inline { + display: inline !important; } + .dac-visible-tablet-inline-block { + display: inline-block !important; } } + +@media (min-width: 980px) { + .dac-hidden-desktop { + display: none !important; } + .dac-visible-desktop-block { + display: block !important; } + .dac-visible-desktop-inline { + display: inline !important; } + .dac-visible-desktop-inline-block { + display: inline-block !important; } } + +.dac-offset-parent { + position: relative !important; } + +/** + * Break strings when their length exceeds the width of their container. + */ +.dac-text-break { + word-wrap: break-word !important; } + +/** + * Horizontal text alignment + */ +.dac-text-center { + text-align: center !important; } + +.dac-text-left { + text-align: left !important; } + +.dac-text-right { + text-align: right !important; } + +/** + * Prevent whitespace wrapping + */ +.dac-text-no-wrap { + white-space: nowrap !important; } + +/** + * Prevent text from wrapping onto multiple lines, instead truncate with an ellipsis. + */ +.dac-text-truncate { + max-width: 100%; + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + word-wrap: normal !important; } + +/** + * Floats + */ +.dac-float-left { + float: left !important; } + +.dac-float-right { + float: right !important; } + +/** + * New block formatting context + * + * This affords some useful properties to the element. It won't wrap under + * floats. Will also contain any floated children. + * N.B. This will clip overflow. Use the alternative method below if this is + * problematic. + */ +.dac-nbfc { + overflow: hidden !important; +} + +/** + * New block formatting context (alternative) + * + * Alternative method when overflow must not be clipped. + * + * N.B. This breaks down in some browsers when elements within this element + * exceed its width. + */ +.dac-nbfc-alt { + display: table-cell !important; + width: 10000px !important; +} + +#tb li:before, #qv li:before { + background-position: 0px -196px; + height: 24px; + width: 24px; + content: ''; + left: -8px; + opacity: .7; + position: absolute; + top: -4px; +} diff --git a/tools/droiddoc/templates-sdk/assets/css/fullscreen.css b/tools/droiddoc/templates-sdk/assets/css/fullscreen.css index 7912e34..0f108e0 100644 --- a/tools/droiddoc/templates-sdk/assets/css/fullscreen.css +++ b/tools/droiddoc/templates-sdk/assets/css/fullscreen.css @@ -14,195 +14,7 @@ */ @media screen, projection, print { -.full { - padding: 2.5em 0; - border-top: solid 1px #ddd; - border-bottom: solid 1px #ddd; - background: #f7f7f7; + .wrap { + max-width: none; + } } -.wrap { - margin: 0 auto; - width: 100%; - min-width:600px; - clear: both; -} -.cols { - height: 1%; - margin: 0 -1.533742331288343558282%; - width: 103.06748466257669%} -*+html .cols { - margin-bottom: 20px; -} -.cols:after { - clear: both; - content: ' '; - display: block; - height: 0; - visibility: hidden; -} -.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12, -.col-13, .col-14, .col-15, .col-16 { - float: left; - margin: 0 1.063829787234% 20px 1.063829787234%; -} -* html .col-1, * html .col-2, * html .col-3, * html .col-4, * html .col-5, * html .col-6, * html -.col-7, * html .col-8, * html .col-9, * html .col-10, * html .col-11, * html .col-12, * html -.col-13, * html .col-14, * html .col-15, * html .col-16 { - margin: 0; - margin: 0 1.063829787234% 20px 1.063829787234%; -} -[dir='rtl'] .col-1, [dir='rtl'] .col-2, [dir='rtl'] .col-3, [dir='rtl'] .col-4, [dir='rtl'] .col-5, -[dir='rtl'] .col-6, [dir='rtl'] .col-7, [dir='rtl'] .col-8, [dir='rtl'] .col-9, [dir='rtl'] .col-10, -[dir='rtl'] .col-11, [dir='rtl'] .col-12 { - float: right; -} -.col-1 { - width: 4.16666666666667%; -} -.col-2 { - width: 10.4166666666667%; -} -.col-3 { - width: 16.6666666666667%; -} -.col-4 { - width: 22.9166666666667%; -} -.col-5 { - width: 29.1666666666667%; -} -.col-6 { - width: 35.4166666666667%; -} -.col-7 { - width: 41.6666666666667%; -} -.col-8 { - width: 47.9166666666667%; -} -.col-9 { - width: 55.3333333333333%; -} -.col-10 { - width: 60.4166666666667%; -} -.col-11 { - width: 66.6666666666667%; -} -.col-12 { - width: 72.9166666666667%; -} -.col-13 { - width: 79.1666666666667%; -} -.col-14 { - width: 85.4166666666667%; -} -.col-15 { - width: 91.6666666666667%; -} -.col-16 { - width: 97.9166666666667%; -} - - - - - - - -#header .col-1, -#nav-x .col-1 { width: 40px } -#header .col-2, -#nav-x .col-2 { width: 100px } -#header .col-3, -#nav-x .col-3 { width: 160px } -#header .col-4, -#nav-x .col-4 { width: 220px } -#header .col-5, -#nav-x .col-5 { width: 280px } -#header .col-6, -#nav-x .col-6 { width: 340px } -#header .col-7, -#nav-x .col-7 { width: 400px } -#header .col-8, -#nav-x .col-8 { width: 460px } -#header .col-9, -#nav-x .col-9 { width: 520px } -#header .col-10, -#nav-x .col-10 { width: 580px } -#header .col-11, -#nav-x .col-11 { width: 640px } -#header .col-12, -#nav-x .col-12 { width: 700px } -#header .col-13, -#nav-x .col-13 { width: 760px } -#header .col-14, -#nav-x .col-14 { width: 820px } -#header .col-15, -#nav-x .col-15 { width: 880px } -#header .col-16, -#nav-x .col-16 { width: 940px } - - - -body { - padding:0 20px; -} -#header, -#searchResults, -#nav-x { - margin:0; -} -#body-content { - margin:0; -} -#body-content > .col-12 { - width:77.9804965%; - margin:0 0 0 0.97%; /* this percentage chosen to make IE9 happy */ -} -#side-nav { - width: 19.9804965%; - margin:0 1.063829787234% 0 0; -} - -#header .wrap { - max-width: 100%; -} - -#header-wrapper #nav-x div.wrap, -#searchResults.wrap { - max-width:100%; -} - -.nav-x { - margin:-2px 0 0 0; -} - -#devdoc-nav.fixed, -#devdoc-nav.fixed a.totop { - left:20px; /* !important ... for IE i think */ -} - -#sticky-header { - padding: 0 20px; -} - -#sticky-header > div { - width: 100%; -} - -.sticky-menu { - width:100%; - left:-20px; -} - -.col-right { - margin-right:0px; -} - -@media screen and (max-width:772px) { -.col-5, .col-6, .col-7 { - clear: both; - width: 97.0238096%} -}
\ No newline at end of file diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo.png b/tools/droiddoc/templates-sdk/assets/images/android_logo.png Binary files differnew file mode 100644 index 0000000..5f19215 --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/android_logo.png diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png b/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png Binary files differnew file mode 100644 index 0000000..04132cc --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png Binary files differnew file mode 100644 index 0000000..3f39f4d --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.png b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.png Binary files differnew file mode 100644 index 0000000..8081ac5 --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.png diff --git a/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg b/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg Binary files differindex 8050744..398030f 100644 --- a/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg +++ b/tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpg diff --git a/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png b/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png Binary files differnew file mode 100644 index 0000000..185b7e8 --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png diff --git a/tools/droiddoc/templates-sdk/assets/images/sprite.png b/tools/droiddoc/templates-sdk/assets/images/sprite.png Binary files differnew file mode 100644 index 0000000..7fef43e --- /dev/null +++ b/tools/droiddoc/templates-sdk/assets/images/sprite.png diff --git a/tools/droiddoc/templates-sdk/assets/js/docs.js b/tools/droiddoc/templates-sdk/assets/js/docs.js index 7f4be4e..feaf06b 100644 --- a/tools/droiddoc/templates-sdk/assets/js/docs.js +++ b/tools/droiddoc/templates-sdk/assets/js/docs.js @@ -56,7 +56,7 @@ $(document).ready(function() { // setup keyboard listener for search shortcut $('body').keyup(function(event) { - if (event.which == 191) { + if (event.which == 191 && $(event.target).is(':not(:input)')) { $('#search_autocomplete').focus(); } }); @@ -71,18 +71,12 @@ $(document).ready(function() { }); // initialize the divs with custom scrollbars - $('.scroll-pane').jScrollPane( {verticalGutter:0} ); - - // add HRs below all H2s (except for a few other h2 variants) - $('h2').not('#qv h2') - .not('#tb h2') - .not('.sidebox h2') - .not('#devdoc-nav h2') - .not('h2.norule').css({marginBottom:0}) - .after('<hr/>'); + if (window.innerWidth >= 720) { + $('.scroll-pane').jScrollPane({verticalGutter: 0}); + } // set up the search close button - $('.search .close').click(function() { + $('#search-close').on('click touchend', function() { $searchInput = $('#search_autocomplete'); $searchInput.attr('value', ''); $(this).addClass("hide"); @@ -92,38 +86,13 @@ $(document).ready(function() { hideResults(); }); - // Set up quicknav - var quicknav_open = false; - $("#btn-quicknav").click(function() { - if (quicknav_open) { - $(this).removeClass('active'); - quicknav_open = false; - collapse(); - } else { - $(this).addClass('active'); - quicknav_open = true; - expand(); - } - }) - - var expand = function() { - $('#header-wrap').addClass('quicknav'); - $('#quicknav').stop().show().animate({opacity:'1'}); - } - - var collapse = function() { - $('#quicknav').stop().animate({opacity:'0'}, 100, function() { - $(this).hide(); - $('#header-wrap').removeClass('quicknav'); - }); - } - //Set up search $("#search_autocomplete").focus(function() { $("#search-container").addClass('active'); }) - $("#search-container").mouseover(function() { + $("#search-container").on('mouseover touchend', function(e) { + if ($(e.target).is('#search-close')) { return; } $("#search-container").addClass('active'); $("#search_autocomplete").focus(); }) @@ -180,73 +149,88 @@ $(document).ready(function() { // Highlight the header tabs... // highlight Design tab - if ($("body").hasClass("design")) { - $("#header li.design a").addClass("selected"); - $("#sticky-header").addClass("design"); + var urlSegments = pagePathOriginal.split('/'); + var navEl = $(".dac-nav-list"); + var subNavEl = navEl.find(".dac-nav-secondary"); + var parentNavEl; + if ($("body").hasClass("design")) { + navEl.find("> li.design > a").addClass("selected"); // highlight About tabs } else if ($("body").hasClass("about")) { - var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1)); - if (rootDir == "about") { - $("#nav-x li.about a").addClass("selected"); - } else if (rootDir == "wear") { - $("#nav-x li.wear a").addClass("selected"); - } else if (rootDir == "tv") { - $("#nav-x li.tv a").addClass("selected"); - } else if (rootDir == "auto") { - $("#nav-x li.auto a").addClass("selected"); + if (urlSegments[1] == "about" || urlSegments[1] == "wear" || urlSegments[1] == "tv" || urlSegments[1] == "auto") { + navEl.find("> li.home > a").addClass('has-subnav'); + subNavEl.find("li." + urlSegments[1] + " > a").addClass("selected"); + } else { + navEl.find("> li.home > a").addClass('selected'); + } + +// highlight NDK tabs + } else if ($("body").hasClass("ndk")) { + parentNavEl = navEl.find("> li.ndk > a"); + parentNavEl.addClass('has-subnav'); + if ($("body").hasClass("guide")) { + navEl.find("> li.guides > a").addClass("selected ndk"); + } else if ($("body").hasClass("reference")) { + navEl.find("> li.reference > a").addClass("selected ndk"); + } else if ($("body").hasClass("samples")) { + navEl.find("> li.samples > a").addClass("selected ndk"); + } else if ($("body").hasClass("downloads")) { + navEl.find("> li.downloads > a").addClass("selected ndk"); } + // highlight Develop tab } else if ($("body").hasClass("develop") || $("body").hasClass("google")) { - $("#header li.develop a").addClass("selected"); - $("#sticky-header").addClass("develop"); + parentNavEl = navEl.find("> li.develop > a"); + parentNavEl.addClass('has-subnav'); + // In Develop docs, also highlight appropriate sub-tab - var rootDir = pagePathOriginal.substring(1,pagePathOriginal.indexOf('/', 1)); - if (rootDir == "training") { - $("#nav-x li.training a").addClass("selected"); - } else if (rootDir == "guide") { - $("#nav-x li.guide a").addClass("selected"); - } else if (rootDir == "reference") { + if (urlSegments[1] == "training") { + subNavEl.find("li.training > a").addClass("selected"); + } else if (urlSegments[1] == "guide") { + subNavEl.find("li.guide > a").addClass("selected"); + } else if (urlSegments[1] == "reference") { // If the root is reference, but page is also part of Google Services, select Google if ($("body").hasClass("google")) { - $("#nav-x li.google a").addClass("selected"); + subNavEl.find("li.google > a").addClass("selected"); } else { - $("#nav-x li.reference a").addClass("selected"); + subNavEl.find("li.reference > a").addClass("selected"); } - } else if ((rootDir == "tools") || (rootDir == "sdk")) { - $("#nav-x li.tools a").addClass("selected"); + } else if ((urlSegments[1] == "tools") || (urlSegments[1] == "sdk")) { + subNavEl.find("li.tools > a").addClass("selected"); } else if ($("body").hasClass("google")) { - $("#nav-x li.google a").addClass("selected"); + subNavEl.find("li.google > a").addClass("selected"); } else if ($("body").hasClass("samples")) { - $("#nav-x li.samples a").addClass("selected"); + subNavEl.find("li.samples > a").addClass("selected"); + } else if ($("body").hasClass("preview")) { + subNavEl.find("li.preview > a").addClass("selected"); + } else { + parentNavEl.removeClass('has-subnav').addClass("selected"); } - // highlight Distribute tab } else if ($("body").hasClass("distribute")) { - $("#header li.distribute a").addClass("selected"); - $("#sticky-header").addClass("distribute"); - - var baseFrag = pagePathOriginal.indexOf('/', 1) + 1; - var secondFrag = pagePathOriginal.substring(baseFrag, pagePathOriginal.indexOf('/', baseFrag)); - if (secondFrag == "users") { - $("#nav-x li.users a").addClass("selected"); - } else if (secondFrag == "engage") { - $("#nav-x li.engage a").addClass("selected"); - } else if (secondFrag == "monetize") { - $("#nav-x li.monetize a").addClass("selected"); - } else if (secondFrag == "analyze") { - $("#nav-x li.analyze a").addClass("selected"); - } else if (secondFrag == "tools") { - $("#nav-x li.disttools a").addClass("selected"); - } else if (secondFrag == "stories") { - $("#nav-x li.stories a").addClass("selected"); - } else if (secondFrag == "essentials") { - $("#nav-x li.essentials a").addClass("selected"); - } else if (secondFrag == "googleplay") { - $("#nav-x li.googleplay a").addClass("selected"); + parentNavEl = navEl.find("> li.distribute > a"); + parentNavEl.addClass('has-subnav'); + + if (urlSegments[2] == "users") { + subNavEl.find("li.users > a").addClass("selected"); + } else if (urlSegments[2] == "engage") { + subNavEl.find("li.engage > a").addClass("selected"); + } else if (urlSegments[2] == "monetize") { + subNavEl.find("li.monetize > a").addClass("selected"); + } else if (urlSegments[2] == "analyze") { + subNavEl.find("li.analyze > a").addClass("selected"); + } else if (urlSegments[2] == "tools") { + subNavEl.find("li.essentials > a").addClass("selected"); + } else if (urlSegments[2] == "stories") { + subNavEl.find("li.stories > a").addClass("selected"); + } else if (urlSegments[2] == "essentials") { + subNavEl.find("li.essentials > a").addClass("selected"); + } else if (urlSegments[2] == "googleplay") { + subNavEl.find("li.googleplay > a").addClass("selected"); + } else { + parentNavEl.removeClass('has-subnav').addClass("selected"); } - } else if ($("body").hasClass("about")) { - $("#sticky-header").addClass("about"); } // set global variable so we can highlight the sidenav a bit later (such as for google reference) @@ -392,14 +376,13 @@ false; // navigate across topic boundaries only in design docs var $olClasses = $('<ol class="class-list"></ol>'); var $liClass; - var $imgIcon; var $h2Title; var $pSummary; var $olLessons; var $liLesson; $classLinks.each(function(index) { - $liClass = $('<li></li>'); - $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2>' + $(this).html()+'</h2><span></span></a>'); + $liClass = $('<li class="clearfix"></li>'); + $h2Title = $('<a class="title" href="'+$(this).attr('href')+'"><h2 class="norule">' + $(this).html()+'</h2><span></span></a>'); $pSummary = $('<p class="description">' + $classDescriptions[index] + '</p>'); $olLessons = $('<ol class="lesson-list"></ol>'); @@ -407,18 +390,14 @@ false; // navigate across topic boundaries only in design docs $lessons = $(this).closest('li').find('ul li a'); if ($lessons.length) { - $imgIcon = $('<img src="'+toRoot+'assets/images/resource-tutorial.png" ' - + ' width="64" height="64" alt=""/>'); $lessons.each(function(index) { $olLessons.append('<li><a href="'+$(this).attr('href')+'">' + $(this).html()+'</a></li>'); }); } else { - $imgIcon = $('<img src="'+toRoot+'assets/images/resource-article.png" ' - + ' width="64" height="64" alt=""/>'); $pSummary.addClass('article'); } - $liClass.append($h2Title).append($imgIcon).append($pSummary).append($olLessons); + $liClass.append($h2Title).append($pSummary).append($olLessons); $olClasses.append($liClass); }); $('.jd-descr').append($olClasses); @@ -436,23 +415,15 @@ false; // navigate across topic boundaries only in design docs /* Resize nav height when window height changes */ $(window).resize(function() { if ($('#side-nav').length == 0) return; - var stylesheet = $('link[rel="stylesheet"][class="fullscreen"]'); - setNavBarLeftPos(); // do this even if sidenav isn't fixed because it could become fixed + setNavBarDimensions(); // do this even if sidenav isn't fixed because it could become fixed // make sidenav behave when resizing the window and side-scolling is a concern - if (sticky) { - if ((stylesheet.attr("disabled") == "disabled") || stylesheet.length == 0) { - updateSideNavPosition(); - } else { - updateSidenavFullscreenWidth(); - } - } - resizeNav(); + updateSideNavDimensions(); + checkSticky(); + resizeNav(250); }); - - var navBarLeftPos; if ($('#devdoc-nav').length) { - setNavBarLeftPos(); + setNavBarDimensions(); } @@ -495,7 +466,12 @@ false; // navigate across topic boundaries only in design docs $('h2').click(function() { var id = $(this).attr('id'); if (id) { - document.location.hash = id; + if (history && history.replaceState) { + // Change url without scrolling. + history.replaceState({}, '', '#' + id); + } else { + document.location.hash = id; + } } }); @@ -504,15 +480,6 @@ false; // navigate across topic boundaries only in design docs po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); - - // Revise the sidenav widths to make room for the scrollbar - // which avoids the visible width from changing each time the bar appears - var $sidenav = $("#side-nav"); - var sidenav_width = parseInt($sidenav.innerWidth()); - - $("#devdoc-nav #nav").css("width", sidenav_width - 4 + "px"); // 4px is scrollbar width - - $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller if ($(".scroll-pane").length > 1) { @@ -738,21 +705,28 @@ function initExpandableNavItems(rootTag) { /** Create the list of breadcrumb links in the sticky header */ function buildBreadcrumbs() { - var $breadcrumbUl = $("#sticky-header ul.breadcrumb"); + var $breadcrumbUl = $(".dac-header-crumbs"); + var primaryNavLink = ".dac-nav-list > .dac-nav-item > .dac-nav-link"; + // Add the secondary horizontal nav item, if provided - var $selectedSecondNav = $("div#nav-x ul.nav-x a.selected").clone().removeClass("selected"); + var $selectedSecondNav = $(".dac-nav-secondary .dac-nav-link.selected").clone() + .attr('class', 'dac-header-crumbs-link'); + if ($selectedSecondNav.length) { - $breadcrumbUl.prepend($("<li>").append($selectedSecondNav)) + $breadcrumbUl.prepend($('<li class="dac-header-crumbs-item">').append($selectedSecondNav)); } + // Add the primary horizontal nav - var $selectedFirstNav = $("div#header-wrap ul.nav-x a.selected").clone().removeClass("selected"); + var $selectedFirstNav = $(primaryNavLink + ".selected, " + primaryNavLink + ".has-subnav").clone() + .attr('class', 'dac-header-crumbs-link'); + // If there's no header nav item, use the logo link and title from alt text if ($selectedFirstNav.length < 1) { - $selectedFirstNav = $("<a>") + $selectedFirstNav = $('<a class="dac-header-crumbs-link">') .attr('href', $("div#header .logo a").attr('href')) .text($("div#header .logo img").attr('alt')); } - $breadcrumbUl.prepend($("<li>").append($selectedFirstNav)); + $breadcrumbUl.prepend($('<li class="dac-header-crumbs-item">').append($selectedFirstNav)); } @@ -809,22 +783,25 @@ function toggleFullscreen(enable) { enabled = false; } writeCookie("fullscreen", enabled, null); - setNavBarLeftPos(); + setNavBarDimensions(); resizeNav(delay); - updateSideNavPosition(); + updateSideNavDimensions(); setTimeout(initSidenavHeightResize,delay); } - -function setNavBarLeftPos() { +// TODO: Refactor into a closure. +var navBarLeftPos; +var navBarWidth; +function setNavBarDimensions() { navBarLeftPos = $('#body-content').offset().left; + navBarWidth = $('#side-nav').width(); } -function updateSideNavPosition() { +function updateSideNavDimensions() { var newLeft = $(window).scrollLeft() - navBarLeftPos; - $('#devdoc-nav').css({left: -newLeft}); - $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('margin-left')))}); + $('#devdoc-nav').css({left: -newLeft, width: navBarWidth}); + $('#devdoc-nav .totop').css({left: -(newLeft - parseInt($('#side-nav').css('padding-left')))}); } // TODO: use $(document).ready instead @@ -858,7 +835,7 @@ $(document).ready(function() { -/* ######### RESIZE THE SIDENAV HEIGHT ########## */ +/* ######### RESIZE THE SIDENAV ########## */ function resizeNav(delay) { var $nav = $("#devdoc-nav"); @@ -874,7 +851,7 @@ function resizeNav(delay) { // get the height of space between nav and top of window. // Could be either margin or top position, depending on whether the nav is fixed. - var topMargin = (parseInt($nav.css('margin-top')) || parseInt($nav.css('top'))) + 1; + var topMargin = (parseInt($nav.css('top')) || 20) + 1; // add 1 for the #side-nav bottom margin // Depending on whether the header is visible, set the side nav's height. @@ -889,7 +866,9 @@ function resizeNav(delay) { $scrollPanes = $(".scroll-pane"); - if ($scrollPanes.length > 1) { + if ($window.width() < 720) { + $nav.css('height', ''); + } else if ($scrollPanes.length > 1) { // subtract the height of the api level widget and nav swapper from the available nav height navHeight -= ($('#api-nav-header').outerHeight(true) + $('#nav-swap').outerHeight(true)); @@ -957,7 +936,7 @@ function delayedReInitScrollbars(delay) { function reInitScrollbars() { var pane = $(".scroll-pane").each(function(){ var api = $(this).data('jsp'); - if (!api) { setTimeout(reInitScrollbars,300); return;} + if (!api) {return;} api.reinitialise( {verticalGutter:0} ); }); $(".scroll-pane").removeAttr("tabindex"); // get rid of tabindex added by jscroller @@ -993,6 +972,7 @@ function restoreHeight(packageHeight) { /** Scroll the jScrollPane to make the currently selected item visible This is called when the page finished loading. */ function scrollIntoView(nav) { + return; var $nav = $("#"+nav); var element = $nav.jScrollPane({/* ...settings... */}); var api = element.data('jsp'); @@ -1068,39 +1048,45 @@ var prevScrollLeft = 0; // used to compare current position to previous position /* Sets the vertical scoll position at which the sticky bar should appear. This method is called to reset the position when search results appear or hide */ function setStickyTop() { - stickyTop = $('#header-wrapper').outerHeight() - $('#sticky-header').outerHeight(); + stickyTop = $('#header-wrapper').outerHeight() - $('#header > .dac-header-inner').outerHeight(); } /* * Displays sticky nav bar on pages when dac header scrolls out of view */ $(window).scroll(function(event) { - - setStickyTop(); - var hiding = false; - var $stickyEl = $('#sticky-header'); - var $menuEl = $('.menu-container'); - // Exit if there's no sidenav - if ($('#side-nav').length == 0) return; // Exit if the mouse target is a DIV, because that means the event is coming // from a scrollable div and so there's no need to make adjustments to our layout if ($(event.target).nodeName == "DIV") { return; } + checkSticky(); +}); + +function checkSticky() { + setStickyTop(); + var $headerEl = $('#header'); + // Exit if there's no sidenav + if ($('#side-nav').length == 0) return; + var top = $(window).scrollTop(); // we set the navbar fixed when the scroll position is beyond the height of the site header... - var shouldBeSticky = top >= stickyTop; + var shouldBeSticky = top > stickyTop; // ... except if the document content is shorter than the sidenav height. // (this is necessary to avoid crazy behavior on OSX Lion due to overscroll bouncing) if ($("#doc-col").height() < $("#side-nav").height()) { shouldBeSticky = false; } + // Nor on mobile + if (window.innerWidth < 720) { + shouldBeSticky = false; + } // Account for horizontal scroll var scrollLeft = $(window).scrollLeft(); // When the sidenav is fixed and user scrolls horizontally, reposition the sidenav to match if (sticky && (scrollLeft != prevScrollLeft)) { - updateSideNavPosition(); + updateSideNavDimensions(); prevScrollLeft = scrollLeft; } @@ -1113,41 +1099,29 @@ $(window).scroll(function(event) { // If sticky header visible and position is now near top, hide sticky if (sticky && !shouldBeSticky) { sticky = false; - hiding = true; // make the sidenav static again $('#devdoc-nav') - .removeClass('fixed') - .css({'width':'auto','margin':''}) - .prependTo('#side-nav'); + .removeClass('fixed') + .css({'width':'auto','margin':''}); // delay hide the sticky - $menuEl.removeClass('sticky-menu'); - $stickyEl.fadeOut(250); - hiding = false; + $headerEl.removeClass('is-sticky'); // update the sidenaav position for side scrolling - updateSideNavPosition(); + updateSideNavDimensions(); } else if (!sticky && shouldBeSticky) { sticky = true; - $stickyEl.fadeIn(10); - $menuEl.addClass('sticky-menu'); + $headerEl.addClass('is-sticky'); // make the sidenav fixed - var width = $('#devdoc-nav').width(); $('#devdoc-nav') - .addClass('fixed') - .css({'width':width+'px'}) - .prependTo('#body-content'); + .addClass('fixed'); // update the sidenaav position for side scrolling - updateSideNavPosition(); + updateSideNavDimensions(); - } else if (hiding && top < 15) { - $menuEl.removeClass('sticky-menu'); - $stickyEl.hide(); - hiding = false; } resizeNav(250); // pass true in order to delay the scrollbar re-initialization for performance -}); +} /* * Manages secion card states and nav resize to conclude loading @@ -1352,13 +1326,13 @@ function requestAppendHL(uri) { function changeNavLang(lang) { - var $links = $("#devdoc-nav,#header,#nav-x,.training-nav-top,.content-footer").find("a["+lang+"-lang]"); - $links.each(function(i){ // for each link with a translation + if (lang === 'en') { return; } + + var $links = $('a[' + lang + '-lang]'); + $links.each(function(){ // for each link with a translation var $link = $(this); - if (lang != "en") { // No need to worry about English, because a language change invokes new request - // put the desired language from the attribute as the text - $link.text($link.attr(lang+"-lang")) - } + // put the desired language from the attribute as the text + $link.text($link.attr(lang + '-lang')) }); } @@ -1841,12 +1815,11 @@ function sync_selection_table(toroot) // if there are api results if ((gMatches.length > 0) || (gGoogleMatches.length > 0)) { // reveal suggestion list - $('.suggest-card.dummy').show(); $('.suggest-card.reference').show(); var listIndex = 0; // list index position // reset the lists - $(".search_filtered_wrapper.reference li").remove(); + $(".suggest-card.reference li").remove(); // ########### ANDROID RESULTS ############# if (gMatches.length > 0) { @@ -1876,13 +1849,12 @@ function sync_selection_table(toroot) } } else { $('.suggest-card.reference').hide(); - $('.suggest-card.dummy').hide(); } // ########### JD DOC RESULTS ############# if (gDocsMatches.length > 0) { // reset the lists - $(".search_filtered_wrapper.docs li").remove(); + $(".suggest-card:not(.reference) li").remove(); // determine google results to show // NOTE: The order of the conditions below for the sugg.type MUST BE SPECIFIC: @@ -1947,7 +1919,7 @@ function sync_selection_table(toroot) } } else { - $('.search_filtered_wrapper.docs .suggest-card:not(.dummy)').hide(300); + $('.suggest-card:not(.reference)').hide(300); } } @@ -1971,14 +1943,14 @@ function search_changed(e, kd, toroot) // show/hide the close button if (text != '') { - $(".search .close").removeClass("hide"); + $("#search-close").removeClass("hide"); } else { - $(".search .close").addClass("hide"); + $("#search-close").addClass("hide"); } // 27 = esc if (e.keyCode == 27) { // close all search results - if (kd) $('.search .close').trigger('click'); + if (kd) $('#search-close').trigger('click'); return true; } // 13 = enter @@ -2389,6 +2361,37 @@ function search_changed(e, kd, toroot) } } + // Search for Preview Guides + for (var i=0; i<PREVIEW_RESOURCES.length; i++) { + // current search comparison, with counters for tag and title, + // used later to improve ranking + var s = PREVIEW_RESOURCES[i]; + s.matched_tag = 0; + s.matched_title = 0; + var matched = false; + + // Check if query matches any tags; work backwards toward 1 to assist ranking + for (var j = s.keywords.length - 1; j >= 0; j--) { + // it matches a tag + if (s.keywords[j].toLowerCase().match(textRegex)) { + matched = true; + s.matched_tag = j + 1; // add 1 to index position + } + } + // Check if query matches the doc title, but only for current language + if (s.lang == currentLang) { + // if query matches the doc title + if (s.title.toLowerCase().match(textRegex)) { + matched = true; + s.matched_title = 1; + } + } + if (matched) { + gDocsMatches[matchedCountDocs] = s; + matchedCountDocs++; + } + } + // Rank/sort all the matched pages rank_autocomplete_doc_results(text, gDocsMatches); } @@ -2536,7 +2539,7 @@ function search_focus_changed(obj, focused) { if (!focused) { if(obj.value == ""){ - $(".search .close").addClass("hide"); + $("#search-close").addClass("hide"); } $(".suggest-card").hide(); } @@ -2553,7 +2556,7 @@ function submit_search() { function hideResults() { $("#searchResults").slideUp('fast', setStickyTop); - $(".search .close").addClass("hide"); + $("#search-close").addClass("hide"); location.hash = ''; $("#search_autocomplete").val("").blur(); @@ -2670,7 +2673,7 @@ google.setOnLoadCallback(function(){ } else { // first time loading search results for this page $('#searchResults').slideDown('slow', setStickyTop); - $(".search .close").removeClass("hide"); + $("#search-close").removeClass("hide"); loadSearchResults(); } }, true); @@ -2714,7 +2717,7 @@ $(window).hashchange( function(){ searchControl.execute(query); $('#searchResults').slideDown('slow', setStickyTop); $("#search_autocomplete").focus(); - $(".search .close").removeClass("hide"); + $("#search-close").removeClass("hide"); updateResultTitle(query); }); @@ -3146,6 +3149,10 @@ function init_google_navtree(navtree_id, toroot, root_nodes) me.node = new Object(); me.node.li = document.getElementById(navtree_id); + if (!me.node.li) { + return; + } + me.node.children_data = root_nodes; me.node.children = new Array(); me.node.children_ul = document.createElement("ul"); @@ -3536,6 +3543,10 @@ function showSamples() { var addedPageResources = {}; $(document).ready(function() { + // Need to initialize hero carousel before other sections for dedupe + // to work correctly. + $('[data-carousel-query]').dacCarouselQuery(); + $('.resource-widget').each(function() { initResourceWidget(this); }); @@ -3545,8 +3556,8 @@ function showSamples() { showing lines that are cut off. This works with the css ellipsis classes to fade last text line and apply an ellipsis char. */ - //card text currently uses 15px line height. - var lineHeight = 15; + //card text currently uses 20px line height. + var lineHeight = 20; $('.card-info .text').ellipsisfade(lineHeight); }); @@ -3562,21 +3573,20 @@ function showSamples() { isCarousel = $widget.hasClass('resource-carousel-layout'), isStack = $widget.hasClass('resource-stack-layout'); - // find size of widget by pulling out its class name - var sizeCols = 1; + // remove illegal col-x class which is not relevant anymore thanks to responsive styles. var m = $widget.get(0).className.match(/\bcol-(\d+)\b/); - if (m) { - sizeCols = parseInt(m[1], 10); + if (m && !$widget.is('.cols > *')) { + $widget.removeClass('col-' + m[1]); } var opts = { cardSizes: ($widget.data('cardsizes') || '').split(','), maxResults: parseInt($widget.data('maxresults') || '100', 10), + initialResults: $widget.data('initialResults'), itemsPerPage: $widget.data('itemsperpage'), sortOrder: $widget.data('sortorder'), query: $widget.data('query'), section: $widget.data('section'), - sizeCols: sizeCols, /* Added by LFL 6/6/14 */ resourceStyle: $widget.data('resourcestyle') || 'card', stackSort: $widget.data('stacksort') || 'true' @@ -3604,7 +3614,7 @@ function showSamples() { /* Initializes a Resource Carousel Widget */ function drawResourcesCarouselWidget($widget, opts, resources) { $widget.empty(); - var plusone = true; //always show plusone on carousel + var plusone = false; // stop showing plusone buttons on cards $widget.addClass('resource-card slideshow-container') .append($('<a>').addClass('slideshow-prev').text('Prev')) @@ -3642,7 +3652,7 @@ function showSamples() { function drawResourcesStackWidget($widget, opts, resources, sections) { // Don't empty widget, grab all items inside since they will be the first // items stacked, followed by the resource query - var plusone = true; //by default show plusone on section cards + var plusone = false; // stop showing plusone buttons on cards var cards = $widget.find('.resource-card').detach().toArray(); var numStacks = opts.numStacks || 1; var $stacks = []; @@ -3737,22 +3747,49 @@ function showSamples() { return $el; } + + function createResponsiveFlowColumn(cardSize) { + var cardWidth = parseInt(cardSize.match(/(\d+)/)[1], 10); + var column = $('<div>').addClass('col-' + (cardWidth / 3) + 'of6'); + if (cardWidth < 9) { + column.addClass('col-tablet-1of2'); + } else if (cardWidth > 9 && cardWidth < 18) { + column.addClass('col-tablet-1of1'); + } + if (cardWidth < 18) { + column.addClass('col-mobile-1of1') + } + return column; + } /* Initializes a flow widget, see distribute.scss for generating accompanying css */ function drawResourcesFlowWidget($widget, opts, resources) { - $widget.empty(); + $widget.empty().addClass('cols'); var cardSizes = opts.cardSizes || ['6x6']; + var initialResults = opts.initialResults || resources.length; var i = 0, j = 0; - var plusone = true; // by default show plusone on resource cards + var plusone = false; // stop showing plusone buttons on cards + var cardParent = $widget; while (i < resources.length) { + + if (i === initialResults && initialResults < resources.length) { + // Toggle remaining cards + cardParent = $('<div class="dac-toggle-content clearfix">').appendTo($widget); + $widget.addClass('dac-toggle'); + $('<div class="col-1of1 dac-section-links dac-text-center">') + .append( + $('<div class="dac-section-link" data-toggle="section">') + .append('<span class="dac-toggle-expand">More<i class="dac-sprite dac-auto-unfold-more"></i></span>') + .append('<span class="dac-toggle-collapse">Less<i class="dac-sprite dac-auto-unfold-less"></i></span>') + ) + .appendTo($widget) + } + var cardSize = cardSizes[j++ % cardSizes.length]; cardSize = cardSize.replace(/^\s+|\s+$/,''); - // Some card sizes do not get a plusone button, such as where space is constrained - // or for cards commonly embedded in docs (to improve overall page speed). - plusone = !((cardSize == "6x2") || (cardSize == "6x3") || - (cardSize == "9x2") || (cardSize == "9x3") || - (cardSize == "12x2") || (cardSize == "12x3")); + + var column = createResponsiveFlowColumn(cardSize).appendTo(cardParent); // A stack has a third dimension which is the number of stacked items var isStack = cardSize.match(/(\d+)x(\d+)x(\d+)/); @@ -3763,7 +3800,7 @@ function showSamples() { // Create a stack container which should have the dimensions defined // by the product of the items inside. $stackDiv = $('<div>').addClass('resource-card-stack resource-card-' + isStack[1] - + 'x' + isStack[2] * isStack[3]) .appendTo($widget); + + 'x' + isStack[2] * isStack[3]) .appendTo(column); } // Build each stack item or just a single item @@ -3785,7 +3822,7 @@ function showSamples() { stackCount = 0; } - $card.appendTo($stackDiv || $widget); + $card.appendTo($stackDiv || column); } while (++i < resources.length && stackCount > 0); } @@ -3800,6 +3837,10 @@ function showSamples() { } function buildResourceList(opts) { + return $.queryResources(opts); + } + + $.queryResources = function(opts) { var maxResults = opts.maxResults || 100; var query = opts.query || ''; @@ -3848,8 +3889,9 @@ function showSamples() { // add to list of already added indices for (var j = 0; j < resources.length; j++) { - // console.log(resources[j].title); - addedResourceIndices[resources[j].index] = 1; + if (resources[j]) { + addedResourceIndices[resources[j].index] = 1; + } } // concat to final results list @@ -3891,7 +3933,7 @@ function showSamples() { function getResourceNotAlreadyAddedFilter(addedResourceIndices) { return function(resource) { - return !addedResourceIndices[resource.index]; + return resource && !addedResourceIndices[resource.index]; }; } @@ -4020,6 +4062,12 @@ function showSamples() { imgUrl = toRoot + imgUrl; } + if (resource.type === 'youtube') { + $('<div>').addClass('play-button') + .append($('<i class="dac-sprite dac-play-white">')) + .appendTo(this); + } + $('<div>').addClass('card-bg') .css('background-image', 'url(' + (imgUrl || toRoot + 'assets/images/resource-card-default-android.jpg') + ')') @@ -4155,7 +4203,7 @@ function showSamples() { $this.parent().siblings().each(function () { if ($(this).is(":visible")) { - var h = $(this).height(); + var h = $(this).outerHeight(true); remainingHeight = remainingHeight - h; } }); @@ -4354,3 +4402,895 @@ function showSamples() { } } })(); + +/** + * Auto TOC + * + * Upgrades h2s on the page to have a rule and be toggle-able on mobile. + */ +(function($) { + var upgraded = false; + var h2Titles; + + function initWidget() { + // add HRs below all H2s (except for a few other h2 variants) + // Consider doing this with css instead. + h2Titles = $('h2').not('#qv h2, #tb h2, .sidebox h2, #devdoc-nav h2, h2.norule'); + h2Titles.css({marginBottom:0}).after('<hr/>'); + + // Exit early if on older browser. + if (!window.matchMedia) { + return; + } + + // Only run logic in mobile layout. + var query = window.matchMedia('(max-width: 719px)'); + if (query.matches) { + makeTogglable(); + } else { + query.addListener(makeTogglable); + } + } + + function makeTogglable() { + // Only run this logic once. + if (upgraded) { return; } + upgraded = true; + + // Only make content h2s togglable. + var contentTitles = h2Titles.filter('#jd-content *'); + + // If there are more than 1 + if (contentTitles.size() < 2) { + return; + } + + contentTitles.each(function() { + // Find all the relevant nodes. + var $title = $(this); + var $hr = $title.next(); + var $contents = $hr.nextUntil('h2, .next-docs'); + var $section = $($title) + .add($hr) + .add($title.prev('a[name]')) + .add($contents); + var $anchor = $section.first().prev(); + var anchorMethod = 'after'; + if ($anchor.length === 0) { + $anchor = $title.parent(); + anchorMethod = 'prepend'; + } + + // Some h2s are in their own container making it pretty hard to find the end, so skip. + if ($contents.length === 0) { + return; + } + + // Remove from DOM before messing with it. DOM is slow! + $section.detach(); + + // Add mobile-only expand arrows. + $title.prepend('<span class="dac-visible-mobile-inline-block">' + + '<i class="dac-toggle-expand dac-sprite dac-expand-more-black"></i>' + + '<i class="dac-toggle-collapse dac-sprite dac-expand-less-black"></i>' + + '</span>') + .attr('data-toggle', 'section'); + + // Wrap in magic markup. + $section = $section.wrapAll('<div class="dac-toggle dac-mobile">').parent(); + $contents.wrapAll('<div class="dac-toggle-content"><div>'); // extra div used for max-height calculation. + + // Pre-expand section if requested. + if ($title.hasClass('is-expanded')) { + $section.addClass('is-expanded'); + } + + // Pre-expand section if targetted by hash. + if (location.hash && $section.find(location.hash).length) { + $section.addClass('is-expanded'); + } + + // Add it back to the dom. + $anchor[anchorMethod].call($anchor, $section); + }); + } + + $(function() { + initWidget(); + }); +})(jQuery); + +(function($) { + 'use strict'; + + /** + * Toggle Floating Label state. + * @param {HTMLElement} el - The DOM element. + * @param options + * @constructor + */ + function FloatingLabel(el, options) { + this.el = $(el); + this.options = $.extend({}, FloatingLabel.DEFAULTS_, options); + this.group = this.el.closest('.dac-form-input-group'); + this.input = this.group.find('.dac-form-input'); + + this.checkValue_ = this.checkValue_.bind(this); + this.checkValue_(); + + this.input.on('focus', function() { + this.group.addClass('dac-focused'); + }.bind(this)); + this.input.on('blur', function() { + this.group.removeClass('dac-focused'); + this.checkValue_(); + }.bind(this)); + this.input.on('keyup', this.checkValue_); + } + + /** + * The label is moved out of the textbox when it has a value. + */ + FloatingLabel.prototype.checkValue_ = function() { + if (this.input.val().length) { + this.group.addClass('dac-has-value'); + } else { + this.group.removeClass('dac-has-value'); + } + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacFloatingLabel = function(options) { + return this.each(function() { + new FloatingLabel(this, options); + }); + }; + + $(document).on('ready.aranja', function() { + $('.dac-form-floatlabel').each(function() { + $(this).dacFloatingLabel($(this).data()); + }); + }); +})(jQuery); + +/* global toRoot, CAROUSEL_OVERRIDE */ +(function($) { + // Ordering matters + var TAG_MAP = [ + {from: 'developerstory', to: 'Android Developer Story'}, + {from: 'googleplay', to: 'Google Play'} + ]; + + function DacCarouselQuery(el) { + this.el = $(el); + + var opts = this.el.data(); + opts.maxResults = parseInt(opts.maxResults || '100', 10); + opts.query = opts.carouselQuery; + var resources = $.queryResources(opts); + + this.el.empty(); + $(resources).map(function() { + var resource = $.extend({}, this, CAROUSEL_OVERRIDE[this.url]); + var slide = $('<article class="dac-expand dac-hero">'); + var image = cleanUrl(resource.heroImage || resource.image); + var fullBleed = image && !resource.heroColor; + + // Configure background + slide.css({ + backgroundImage: fullBleed ? 'url(' + image + ')' : '', + backgroundColor: resource.heroColor || '' + }); + + // Should copy be inverted + slide.toggleClass('dac-invert', resource.heroInvert || fullBleed); + slide.toggleClass('dac-darken', fullBleed); + + // Should be clickable + slide.append($('<a class="dac-hero-carousel-action">').attr('href', cleanUrl(resource.url))); + + var cols = $('<div class="cols dac-hero-content">'); + + // inline image column + var rightCol = $('<div class="col-1of2 col-push-1of2 dac-hero-figure">') + .appendTo(cols); + + if (!fullBleed && image) { + rightCol.append($('<img>').attr('src', image)); + } + + // info column + $('<div class="col-1of2 col-pull-1of2">') + .append($('<div class="dac-hero-tag">').text(formatTag(resource))) + .append($('<h1 class="dac-hero-title">').text(formatTitle(resource))) + .append($('<p class="dac-hero-description">').text(resource.summary)) + .append($('<a class="dac-hero-cta">') + .text(formatCTA(resource)) + .attr('href', cleanUrl(resource.url)) + .prepend($('<span class="dac-sprite dac-auto-chevron">')) + ) + .appendTo(cols); + + slide.append(cols.wrap('<div class="wrap">').parent()); + return slide[0]; + }).prependTo(this.el); + + // Pagination element. + this.el.append('<div class="dac-hero-carousel-pagination"><div class="wrap" data-carousel-pagination>'); + + this.el.dacCarousel(); + } + + function cleanUrl(url) { + if (url && url.indexOf('//') === -1) { + url = toRoot + url; + } + return url; + } + + function formatTag(resource) { + // Hmm, need a better more scalable solution for this. + for (var i = 0, mapping; mapping = TAG_MAP[i]; i++) { + if (resource.tags.indexOf(mapping.from) > -1) { + return mapping.to; + } + } + return resource.type; + } + + function formatTitle(resource) { + return resource.title.replace(/android developer story: /i, ''); + } + + function formatCTA(resource) { + return resource.type === 'youtube' ? 'Watch the video' : 'Learn more'; + } + + // jQuery plugin + $.fn.dacCarouselQuery = function() { + return this.each(function() { + var el = $(this); + var data = el.data('dac.carouselQuery'); + + if (!data) { el.data('dac.carouselQuery', (data = new DacCarouselQuery(el))); } + }); + }; + + // Data API + $(function() { + $('[data-carousel-query]').dacCarouselQuery(); + }); +})(jQuery); + +(function($) { + /** + * A CSS based carousel, inspired by SequenceJS. + * @param {jQuery} el + * @param {object} options + * @constructor + */ + function DacCarousel(el, options) { + this.el = $(el); + this.options = options = $.extend({}, DacCarousel.OPTIONS, this.el.data(), options || {}); + this.frames = this.el.find(options.frameSelector); + this.count = this.frames.size(); + this.current = options.start; + + this.initPagination(); + this.initEvents(); + this.initFrame(); + } + + DacCarousel.OPTIONS = { + auto: true, + autoTime: 10000, + autoMinTime: 5000, + btnPrev: '[data-carousel-prev]', + btnNext: '[data-carousel-next]', + frameSelector: 'article', + loop: true, + start: 0, + swipeThreshold: 160, + pagination: '[data-carousel-pagination]' + }; + + DacCarousel.prototype.initPagination = function() { + this.pagination = $([]); + if (!this.options.pagination) { return; } + + var pagination = $('<ul class="dac-pagination">'); + var parent = this.el; + if (typeof this.options.pagination === 'string') { parent = this.el.find(this.options.pagination); } + + if (this.count > 1) { + for (var i = 0; i < this.count; i++) { + var li = $('<li class="dac-pagination-item">').text(i); + if (i === this.options.start) { li.addClass('active'); } + li.click(this.go.bind(this, i)); + + pagination.append(li); + } + this.pagination = pagination.children(); + parent.append(pagination); + } + }; + + DacCarousel.prototype.initEvents = function() { + var that = this; + + this.touch = { + start: {x: 0, y: 0}, + end: {x: 0, y: 0} + }; + + this.el.on('touchstart', this.touchstart_.bind(this)); + this.el.on('touchend', this.touchend_.bind(this)); + this.el.on('touchmove', this.touchmove_.bind(this)); + + this.el.hover(function() { + that.pauseRotateTimer(); + }, function() { + that.startRotateTimer(); + }); + + $(this.options.btnPrev).click(function(e) { + e.preventDefault(); + that.prev(); + }); + + $(this.options.btnNext).click(function(e) { + e.preventDefault(); + that.next(); + }); + }; + + DacCarousel.prototype.touchstart_ = function(event) { + var t = event.originalEvent.touches[0]; + this.touch.start = {x: t.screenX, y: t.screenY}; + }; + + DacCarousel.prototype.touchend_ = function() { + var deltaX = this.touch.end.x - this.touch.start.x; + var deltaY = Math.abs(this.touch.end.y - this.touch.start.y); + var shouldSwipe = (deltaY < Math.abs(deltaX)) && (Math.abs(deltaX) >= this.options.swipeThreshold); + + if (shouldSwipe) { + if (deltaX > 0) { + this.prev(); + } else { + this.next(); + } + } + }; + + DacCarousel.prototype.touchmove_ = function(event) { + var t = event.originalEvent.touches[0]; + this.touch.end = {x: t.screenX, y: t.screenY}; + }; + + DacCarousel.prototype.initFrame = function() { + this.frames.removeClass('active').eq(this.options.start).addClass('active'); + }; + + DacCarousel.prototype.startRotateTimer = function() { + if (!this.options.auto || this.rotateTimer) { return; } + this.rotateTimer = setTimeout(this.next.bind(this), this.options.autoTime); + }; + + DacCarousel.prototype.pauseRotateTimer = function() { + clearTimeout(this.rotateTimer); + this.rotateTimer = null; + }; + + DacCarousel.prototype.prev = function() { + this.go(this.current - 1); + }; + + DacCarousel.prototype.next = function() { + this.go(this.current + 1); + }; + + DacCarousel.prototype.go = function(next) { + // Figure out what the next slide is. + while (this.count > 0 && next >= this.count) { next -= this.count; } + while (next < 0) { next += this.count; } + + // Cancel if we're already on that slide. + if (next === this.current) { return; } + + // Prepare next slide. + this.frames.eq(next).removeClass('out'); + + // Recalculate styles before starting slide transition. + this.el.resolveStyles(); + // Update pagination + this.pagination.removeClass('active').eq(next).addClass('active'); + + // Transition out current frame + this.frames.eq(this.current).toggleClass('active out'); + + // Transition in a new frame + this.frames.eq(next).toggleClass('active'); + + this.current = next; + }; + + // Helper which resolves new styles for an element, so it can start transitioning + // from the new values. + $.fn.resolveStyles = function() { + /*jshint expr:true*/ + this[0] && this[0].offsetTop; + return this; + }; + + // jQuery plugin + $.fn.dacCarousel = function() { + this.each(function() { + var $el = $(this); + $el.data('dac-carousel', new DacCarousel(this)); + }); + return this; + }; + + // Data API + $(function() { + $('[data-carousel]').dacCarousel(); + }); +})(jQuery); + +(function($) { + 'use strict'; + + function Modal(el, options) { + this.el = $(el); + this.options = $.extend({}, ToggleModal.DEFAULTS_, options); + this.isOpen = false; + + this.el.on('click', function(event) { + if (!$.contains($('.dac-modal-window')[0], event.target)) { + return this.el.trigger('modal-close'); + } + }.bind(this)); + + this.el.on('modal-open', this.open_.bind(this)); + this.el.on('modal-close', this.close_.bind(this)); + this.el.on('modal-toggle', this.toggle_.bind(this)); + } + + Modal.prototype.toggle_ = function() { + this.el.trigger('modal-' + (this.isOpen ? 'close' : 'open')); + }; + + Modal.prototype.close_ = function() { + this.el.removeClass('dac-active'); + $('body').removeClass('dac-modal-open'); + this.isOpen = false; + }; + + Modal.prototype.open_ = function() { + this.el.addClass('dac-active'); + $('body').addClass('dac-modal-open'); + this.isOpen = true; + }; + + function ToggleModal(el, options) { + this.el = $(el); + this.options = $.extend({}, ToggleModal.DEFAULTS_, options); + this.modal = this.options.modalToggle ? $('[data-modal="' + this.options.modalToggle + '"]') : + this.el.closest('[data-modal]'); + + this.el.on('click', this.clickHandler_.bind(this)); + } + + ToggleModal.prototype.clickHandler_ = function(event) { + event.preventDefault(); + this.modal.trigger('modal-toggle'); + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacModal = function(options) { + return this.each(function() { + new Modal(this, options); + }); + }; + + $.fn.dacToggleModal = function(options) { + return this.each(function() { + new ToggleModal(this, options); + }); + }; + + /** + * Data Attribute API + */ + $(document).on('ready.aranja', function() { + $('[data-modal]').each(function() { + $(this).dacModal($(this).data()); + }); + + $('[data-modal-toggle]').each(function() { + $(this).dacToggleModal($(this).data()); + }); + }); +})(jQuery); + +(function($) { + 'use strict'; + + /** + * Toggle the visabilty of the mobile navigation. + * @param {HTMLElement} el - The DOM element. + * @param options + * @constructor + */ + function ToggleNav(el, options) { + this.el = $(el); + this.options = $.extend({}, ToggleNav.DEFAULTS_, options); + this.options.target = [this.options.navigation]; + + if (this.options.body) {this.options.target.push('body')} + if (this.options.dimmer) {this.options.target.push(this.options.dimmer)} + + this.el.on('click', this.clickHandler_.bind(this)); + } + + /** + * ToggleNav Default Settings + * @type {{body: boolean, dimmer: string, navigation: string, toggleClass: string}} + * @private + */ + ToggleNav.DEFAULTS_ = { + body: true, + dimmer: '.dac-nav-dimmer', + navigation: '[data-dac-nav]', + toggleClass: 'dac-nav-open' + }; + + /** + * The actual toggle logic. + * @param event + * @private + */ + ToggleNav.prototype.clickHandler_ = function(event) { + event.preventDefault(); + $(this.options.target.join(', ')).toggleClass(this.options.toggleClass); + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacToggleMobileNav = function(options) { + return this.each(function() { + new ToggleNav(this, options); + }); + }; + + /** + * Data Attribute API + */ + $(window).on('load.aranja', function() { + $('[data-dac-toggle-nav]').each(function() { + $(this).dacToggleMobileNav($(this).data()); + }); + }); +})(jQuery); + +(function($) { + 'use strict'; + + /** + * Submit the newsletter form to a Google Form. + * @param {HTMLElement} el - The Form DOM element. + * @constructor + */ + function NewsletterForm(el) { + this.el = $(el); + this.form = this.el.find('form'); + $('<iframe/>').hide() + .attr('name', 'dac-newsletter-iframe') + .attr('src', '') + .insertBefore(this.form); + this.form.on('submit', this.submitHandler_.bind(this)); + } + + /** + * Milliseconds until modal has vanished after modal-close is triggered. + * @type {number} + * @private + */ + NewsletterForm.CLOSE_DELAY_ = 300; + + /** + * Switch view to display form after close. + * @private + */ + NewsletterForm.prototype.closeHandler_ = function() { + setTimeout(function() { + this.el.trigger('swap-reset'); + }.bind(this), NewsletterForm.CLOSE_DELAY_); + }; + + /** + * Reset the modal to initial state. + * @private + */ + NewsletterForm.prototype.reset_ = function() { + this.form.trigger('reset'); + this.el.one('modal-close', this.closeHandler_.bind(this)); + }; + + /** + * Display a success view on submit. + * @private + */ + NewsletterForm.prototype.submitHandler_ = function() { + this.el.one('swap-complete', this.reset_.bind(this)); + this.el.trigger('swap-content'); + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacNewsletterForm = function(options) { + return this.each(function() { + new NewsletterForm(this, options); + }); + }; + + /** + * Data Attribute API + */ + $(document).on('ready.aranja', function() { + $('[data-newsletter]').each(function() { + $(this).dacNewsletterForm(); + }); + }); +})(jQuery); + +(function($) { + 'use strict'; + + /** + * Smoothly scroll to location on current page. + * @param el + * @param options + * @constructor + */ + function ScrollButton(el, options) { + this.el = $(el); + this.target = $(this.el.attr('href')); + this.options = $.extend({}, ScrollButton.DEFAULTS_, options); + + if (typeof this.options.offset === 'string') { + this.options.offset = $(this.options.offset).height(); + } + + this.el.on('click', this.clickHandler_.bind(this)); + } + + /** + * Default options + * @type {{duration: number, easing: string, offset: number, scrollContainer: string}} + * @private + */ + ScrollButton.DEFAULTS_ = { + duration: 300, + easing: 'swing', + offset: 0, + scrollContainer: 'html, body' + }; + + /** + * Scroll logic + * @param event + * @private + */ + ScrollButton.prototype.clickHandler_ = function(event) { + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) { + return; + } + + event.preventDefault(); + + $(this.options.scrollContainer).animate({ + scrollTop: this.target.offset().top - this.options.offset + }, this.options); + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacScrollButton = function(options) { + return this.each(function() { + new ScrollButton(this, options); + }); + }; + + /** + * Data Attribute API + */ + $(document).on('ready.aranja', function() { + $('[data-scroll-button]').each(function() { + $(this).dacScrollButton($(this).data()); + }); + }); +})(jQuery); + +(function($) { + 'use strict'; + + /** + * A component that swaps two dynamic height views with an animation. + * Listens for the following events: + * * swap-content: triggers SwapContent.swap_() + * * swap-reset: triggers SwapContent.reset() + * @param el + * @param options + * @constructor + */ + function SwapContent(el, options) { + this.el = $(el); + this.options = $.extend({}, SwapContent.DEFAULTS_, options); + this.containers = this.el.find(this.options.container); + this.initiallyActive = this.containers.children('.' + this.options.activeClass).eq(0); + this.el.on('swap-content', this.swap.bind(this)); + this.el.on('swap-reset', this.reset.bind(this)); + } + + /** + * SwapContent's default settings. + * @type {{activeClass: string, container: string, transitionSpeed: number}} + * @private + */ + SwapContent.DEFAULTS_ = { + activeClass: 'dac-active', + container: '[data-swap-container]', + transitionSpeed: 500 + }; + + /** + * Returns container's visible height. + * @param container + * @returns {number} + */ + SwapContent.prototype.currentHeight = function(container) { + return container.children('.' + this.options.activeClass).outerHeight(); + }; + + /** + * Reset to show initial content + */ + SwapContent.prototype.reset = function() { + if (!this.initiallyActive.hasClass(this.initiallyActive)) { + this.containers.children().toggleClass(this.options.activeClass); + } + }; + + /** + * Complete the swap. + */ + SwapContent.prototype.complete = function() { + this.containers.height('auto'); + this.containers.trigger('swap-complete'); + }; + + /** + * Perform the swap of content. + */ + SwapContent.prototype.swap = function() { + console.log(this.containers); + this.containers.each(function(index, container) { + container = $(container); + container.height(this.currentHeight(container)).children().toggleClass(this.options.activeClass); + container.animate({height: this.currentHeight(container)}, this.options.transitionSpeed, + this.complete.bind(this)); + }.bind(this)); + }; + + /** + * jQuery plugin + * @param {object} options - Override default options. + */ + $.fn.dacSwapContent = function(options) { + return this.each(function() { + new SwapContent(this, options); + }); + }; + + /** + * Data Attribute API + */ + $(document).on('ready.aranja', function() { + $('[data-swap]').each(function() { + $(this).dacSwapContent($(this).data()); + }); + }); +})(jQuery); + +(function($) { + function Toggle(el) { + $(el).on('click.dac.togglesection', this.toggle); + } + + Toggle.prototype.toggle = function() { + var $this = $(this); + + var $parent = getParent($this); + var isExpanded = $parent.hasClass('is-expanded'); + + transitionMaxHeight($parent.find('.dac-toggle-content'), !isExpanded); + $parent.toggleClass('is-expanded'); + + return false; + }; + + function getParent($this) { + var selector = $this.attr('data-target'); + + if (!selector) { + selector = $this.attr('href'); + selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); + } + + var $parent = selector && $(selector); + + $parent = $parent && $parent.length ? $parent : $this.closest('.dac-toggle'); + + return $parent.length ? $parent : $this.parent(); + } + + /** + * Runs a transition of max-height along with responsive styles which hide or expand the element. + * @param $el + * @param visible + */ + function transitionMaxHeight($el, visible) { + var contentHeight = $el.prop('scrollHeight'); + var targetHeight = visible ? contentHeight : 0; + var duration = $el.transitionDuration(); + + // If we're hiding, first set the maxHeight we're transitioning from. + if (!visible) { + $el.css('maxHeight', contentHeight + 'px') + .resolveStyles(); + } + + // Transition to new state + $el.css('maxHeight', targetHeight); + + // Reset maxHeight to css value after transition. + setTimeout(function() { + $el.css('maxHeight', ''); + }, duration); + } + + // Utility to get the transition duration for the element. + $.fn.transitionDuration = function() { + var d = $(this).css('transitionDuration') || '0s'; + + return +(parseFloat(d) * (/ms/.test(d) ? 1 : 1000)).toFixed(0); + }; + + // jQuery plugin + $.fn.toggleSection = function(option) { + return this.each(function() { + var $this = $(this); + var data = $this.data('dac.togglesection'); + if (!data) {$this.data('dac.togglesection', (data = new Toggle(this)));} + if (typeof option === 'string') {data[option].call($this);} + }); + }; + + // Data api + $(document) + .on('click.toggle', '[data-toggle="section"]', Toggle.prototype.toggle); +})(jQuery); diff --git a/tools/droiddoc/templates-sdk/class.cs b/tools/droiddoc/templates-sdk/class.cs index 693eaed..44eae97 100644 --- a/tools/droiddoc/templates-sdk/class.cs +++ b/tools/droiddoc/templates-sdk/class.cs @@ -169,15 +169,13 @@ Summary: <div class="jd-descr"> <?cs call:deprecated_warning(class) ?> -<?cs if:subcount(class.descr) || subcount(class.annotationdocumentation) ?> +<?cs if:subcount(class.descr) ?> <h2>Class Overview</h2> -<?cs if:subcount(class.descr) ?><p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p><?cs /if ?> -<?cs if:subcount(class.annotationdocumentation) ?><?cs each:annodoc = class.annotationdocumentation?> -<p><?cs var:annodoc.text ?></p> -<?cs /each?><?cs /if?> +<p itemprop="articleBody"><?cs call:tag_list(class.descr) ?></p> <?cs /if ?> <?cs call:see_also_tags(class.seeAlso) ?> + </div><!-- jd-descr --> @@ -198,12 +196,12 @@ Summary: </td> <td class="jd-linkcol" width="100%"><nobr> <span class="sympad"><?cs call:cond_link(method.name, toroot, method.href, included) ?></span>(<?cs call:parameter_list(method.params) ?>)</nobr> - <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) || subcount(method.showAnnotations) ?> - <div class="jd-descrdiv"> - <?cs if:subcount(method.shortDescr) || subcount(method.annotationdocumentation) ?><?cs call:short_descr(method)?><?cs /if?> - <?cs call:show_annotations_list(method) ?> - </div> - <?cs /if ?> + <?cs if:subcount(method.shortDescr) || subcount(method.deprecated) ?> + <div class="jd-descrdiv"> + <?cs call:short_descr(method) ?> + <?cs call:show_annotations_list(method) ?> + </div> + <?cs /if ?> </td></tr> <?cs set:count = count + #1 ?> <?cs /each ?> @@ -669,10 +667,9 @@ From <?cs var:cl.kind ?> <?cs # the next two lines must be exactly like this to be parsed by eclipse ?> <!-- ========= END OF CLASS DATA ========= --> <A NAME="navbar_top"></A> - -<?cs include:"footer.cs" ?> </div> <!-- jd-content --> +<?cs include:"footer.cs" ?> </div><!-- end doc-content --> <?cs include:"trailer.cs" ?> diff --git a/tools/droiddoc/templates-sdk/classes.cs b/tools/droiddoc/templates-sdk/classes.cs index 405892d..32966a0 100644 --- a/tools/droiddoc/templates-sdk/classes.cs +++ b/tools/droiddoc/templates-sdk/classes.cs @@ -43,11 +43,12 @@ </table> <?cs /each ?> -<?cs include:"footer.cs" ?> </div><!-- end jd-content --> + +<?cs include:"footer.cs" ?> </div><!-- end doc-content --> <?cs include:"trailer.cs" ?> </body> -</html>
\ No newline at end of file +</html> diff --git a/tools/droiddoc/templates-sdk/components/masthead.cs b/tools/droiddoc/templates-sdk/components/masthead.cs index c09dc02..838ddbe 100644 --- a/tools/droiddoc/templates-sdk/components/masthead.cs +++ b/tools/droiddoc/templates-sdk/components/masthead.cs @@ -1,10 +1,7 @@ <?cs def:custom_masthead() ?> -<?cs if:preview ?> - <?cs call:preview_masthead() ?> -<?cs else ?> <a name="top"></a> -<!-- dialog to prompt lang pref change when loaded from hardcoded URL +<!-- dialog to prompt lang pref change when loaded from hardcoded URL <div id="langMessage" style="display:none"> <div> <div class="lang en"> @@ -52,321 +49,228 @@ <?cs if:!devsite ?><?cs # leave out the global header for devsite; it is in devsite template ?> <!-- Header --> <div id="header-wrapper"> - <div id="header"><?cs call:butter_bar() ?> - <div class="wrap" id="header-wrap"> - <div class="col-3 logo"> - <a href="<?cs var:toroot ?>index.html"> - <img src="<?cs var:toroot ?>assets/images/dac_logo.png" - srcset="<?cs var:toroot ?>assets/images/dac_logo@2x.png 2x" - width="123" height="25" alt="Android Developers" /> - </a> - <div class="btn-quicknav" id="btn-quicknav"> - <a href="#" class="arrow-inactive">Quicknav</a> - <a href="#" class="arrow-active">Quicknav</a> - </div> - </div> - <ul class="nav-x col-9"> - <li class="design"> - <a href="<?cs var:toroot ?>design/index.html" - zh-tw-lang="設計" - zh-cn-lang="设计" - ru-lang="Проектирование" - ko-lang="디자인" - ja-lang="設計" - es-lang="Diseñar" - >Design</a></li> - <li class="develop"><a href="<?cs var:toroot ?>develop/index.html" - zh-tw-lang="開發" - zh-cn-lang="开发" - ru-lang="Разработка" - ko-lang="개발" - ja-lang="開発" - es-lang="Desarrollar" - >Develop</a></li> - <li class="distribute last"><a href="<?cs var:toroot ?>distribute/<?cs - if:android.whichdoc == "offline" ?>googleplay/<?cs /if ?>index.html" - zh-tw-lang="發佈" - zh-cn-lang="分发" - ru-lang="Распространение" - ko-lang="배포" - ja-lang="配布" - es-lang="Distribuir" - >Distribute</a></li> - </ul> + <div class="dac-header" id="header"><?cs call:butter_bar() ?> + <div class="dac-header-inner"> + <a class="dac-nav-toggle" data-dac-toggle-nav href="javascript:;" title="Open navigation"> + <span class="dac-nav-hamburger"> + <span class="dac-nav-hamburger-top"></span> + <span class="dac-nav-hamburger-mid"></span> + <span class="dac-nav-hamburger-bot"></span> + </span> + </a> + <?cs if:ndk ?><a class="dac-header-logo" href="<?cs var:toroot ?>ndk/index.html"> + <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo_ndk.png" + srcset="<?cs var:toroot ?>assets/images/android_logo_ndk@2x.png 2x" + width="32" height="36" alt="Android" /> NDK + </a><?cs else ?><a class="dac-header-logo" href="<?cs var:toroot ?>index.html"> + <img class="dac-header-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png" + srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x" + width="32" height="36" alt="Android" /> Developers + </a><?cs /if ?> + <ul class="dac-header-crumbs"> + <?cs # More <li> elements added here with javascript ?> + <?cs if:!section.landing ?><li class="dac-header-crumbs-item"><span class="dac-header-crumbs-link current <?cs + if:ndk ?>ndk<?cs /if ?>"><?cs var:page.title ?></a></li><?cs + /if ?> + </ul> <?cs # ADD SEARCH AND MENU ?> + <?cs if:!ndk ?> <?cs call:header_search_widget() ?> + <?cs /if ?> + <?cs if:ndk ?><a class="dac-header-console-btn" href="http://developer.android.com"> + <span class="dac-visible-desktop-inline">Back to Android Developers</span> + </a><?cs else ?><a class="dac-header-console-btn" href="https://play.google.com/apps/publish/"> + <span class="dac-sprite dac-google-play"></span> + <span class="dac-visible-desktop-inline">Developer</span> + Console + </a><?cs /if ?> - <!-- Expanded quicknav --> - <div id="quicknav" class="col-13"> - <ul> - <li class="about"> - <ul> - <li><a href="<?cs var:toroot ?>about/index.html">About</a></li> - <li><a href="<?cs var:toroot ?>wear/index.html">Wear</a></li> - <li><a href="<?cs var:toroot ?>tv/index.html">TV</a></li> - <li><a href="<?cs var:toroot ?>auto/index.html">Auto</a></li> - </ul> - </li> - <li class="design"> - <ul> - <li><a href="<?cs var:toroot ?>design/index.html">Get Started</a></li> - <li><a href="<?cs var:toroot ?>design/devices.html">Devices</a></li> - <li><a href="<?cs var:toroot ?>design/style/index.html">Style</a></li> - <li><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></li> - <li><a href="<?cs var:toroot ?>design/building-blocks/index.html">Building Blocks</a></li> - <li><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></li> - <li><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></li> - </ul> - </li> - <li class="develop"> - <ul> - <li><a href="<?cs var:toroot ?>training/index.html" - zh-tw-lang="訓練課程" - zh-cn-lang="培训" - ru-lang="Курсы" - ko-lang="교육" - ja-lang="トレーニング" - es-lang="Capacitación" - >Training</a></li> - <li><a href="<?cs var:toroot ?>guide/index.html" - zh-tw-lang="API 指南" - zh-cn-lang="API 指南" - ru-lang="Руководства по API" - ko-lang="API 가이드" - ja-lang="API ガイド" - es-lang="Guías de la API" - >API Guides</a></li> - <li><a href="<?cs var:toroot ?>reference/packages.html" - zh-tw-lang="參考資源" - zh-cn-lang="参考" - ru-lang="Справочник" - ko-lang="참조문서" - ja-lang="リファレンス" - es-lang="Referencia" - >Reference</a></li> - <li><a href="<?cs var:toroot ?>sdk/index.html" - zh-tw-lang="相關工具" - zh-cn-lang="工具" - ru-lang="Инструменты" - ko-lang="도구" - ja-lang="ツール" - es-lang="Herramientas" - >Tools</a> - </li> - <li><a href="<?cs var:toroot ?>google/index.html">Google Services</a> - </li> - <?cs if:android.hasSamples ?> - <li><a href="<?cs var:toroot ?>samples/index.html">Samples</a> - </li> - <?cs /if ?> - </ul> - </li> - <li class="distribute last"> - <ul> - <li><a href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li> - <li><a href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li> - <li><a href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li> - <li><a href="<?cs var:toroot ?>distribute/engage/index.html">Engage & Retain</a></li> - <li><a href="<?cs var:toroot ?>distribute/monetize/index.html">Monetize</a></li> - <li><a href="<?cs var:toroot ?>distribute/analyze/index.html">Analyze</a></li> - <li><a href="<?cs var:toroot ?>distribute/tools/index.html">Tools & Reference</a></li> - <li><a href="<?cs var:toroot ?>distribute/stories/index.html">Developer Stories</a></li> - </ul> - </li> - </ul> - </div><!-- /Expanded quicknav --> </div><!-- end header-wrap.wrap --> </div><!-- end header --> - <?cs if:about || wear || tv || auto ?> - <!-- Secondary x-nav --> - <div id="nav-x"> - <div class="wrap"> - <ul class="nav-x col-9 about" style="width:100%"> - <li class="about"><a href="<?cs var:toroot ?>about/index.html" - >About</a></li> - <li class="wear"><a href="<?cs var:toroot ?>wear/index.html" - >Wear</a></li> - <li class="tv"><a href="<?cs var:toroot ?>tv/index.html" - >TV</a></li> - <li class="auto"><a href="<?cs var:toroot ?>auto/index.html" - >Auto</a></li> - </ul> - </div> - </div> - <!-- /Sendondary x-nav ABOUT --> - - - - <?cs elif:training || guide || reference || tools || develop || google || samples ?> - <!-- Secondary x-nav --> - <div id="nav-x"> - <div class="wrap" style="position:relative;z-index:1"> - - <?cs if:reference ?> - <?cs # HIDE HELPOUTS RECRUIT BANNER - <a id="helpoutsLink" class="resource resource-card resource-card-6x2x3 resource-card-6x2 helpouts-card" - href="http://helpouts.google.com/partner/landing/provider/googledevelopers?utm_source=dac&utm_medium=banner&utm_campaign=android_provider_banner3" target="_blank"> - <div class="card-bg helpouts-card-bg"></div> - <div class="card-info"> - <div class="helpouts-description"> - <div class="text">Help Android Wear and TV developers<br/> - <span id="helpoutsLinkText" class="link-color" - style="display:block;padding-top:5px;text-align:right">Learn more</span> - </div> - </div> - </div> - </a> - # END HIDE HELPOUTS ?> - <?cs /if ?> - - <ul class="nav-x col-9 develop" style="width:100%"> - <li class="training"><a href="<?cs var:toroot ?>training/index.html" - zh-tw-lang="訓練課程" - zh-cn-lang="培训" - ru-lang="Курсы" - ko-lang="교육" - ja-lang="トレーニング" - es-lang="Capacitación" - >Training</a></li> - <li class="guide"><a href="<?cs var:toroot ?>guide/index.html" - zh-tw-lang="API 指南" - zh-cn-lang="API 指南" - ru-lang="Руководства по API" - ko-lang="API 가이드" - ja-lang="API ガイド" - es-lang="Guías de la API" - >API Guides</a></li> - <li class="reference"><a href="<?cs var:toroot ?>reference/packages.html" - zh-tw-lang="參考資源" - zh-cn-lang="参考" - ru-lang="Справочник" - ko-lang="참조문서" - ja-lang="リファレンス" - es-lang="Referencia" - >Reference</a></li> - <li class="tools"><a href="<?cs var:toroot ?>sdk/index.html" - zh-tw-lang="相關工具" - zh-cn-lang="工具" - ru-lang="Инструменты" - ko-lang="도구" - ja-lang="ツール" - es-lang="Herramientas" - >Tools</a></li> - <li class="google"><a href="<?cs var:toroot ?>google/index.html" - >Google Services</a> - </li> - <?cs if:android.hasSamples ?> - <li class="samples"><a href="<?cs var:toroot ?>samples/index.html" - >Samples</a> - </li> - <?cs /if ?> - </ul> - </div> - </div> - <!-- /Sendondary x-nav DEVELOP --> - - <?cs elif:distribute || googleplay || essentials || users || engage || monetize || analyze || disttools || stories ?> - <!-- Secondary distribute x-nav --> - <div id="nav-x"> - <div class="wrap"> - <ul class="nav-x distribute"> - <li class="googleplay"><a href="<?cs var:toroot ?>distribute/googleplay/index.html" - >Google Play</a></li> - <li class="essentials"><a href="<?cs var:toroot ?>distribute/essentials/index.html" - >Essentials</a></li> - <li class="users"><a href="<?cs var:toroot ?>distribute/users/index.html" - >Get Users</a></li> - <li class="engage"><a href="<?cs var:toroot ?>distribute/engage/index.html" - >Engage & Retain</a></li> - <li class="monetize"><a href="<?cs var:toroot ?>distribute/monetize/index.html" - >Monetize</a> - </li> - <li class="analyze"><a href="<?cs var:toroot ?>distribute/analyze/index.html" - >Analyze</a> - </li> - <li class="disttools"><a href="<?cs var:toroot ?>distribute/tools/index.html" - >Tools</a> - </li> - <li class="stories"><a href="<?cs var:toroot ?>distribute/stories/index.html" - >Stories</a> - </li> - </ul> - <a href="https://play.google.com/apps/publish/" class="developer-console-btn">Developer Console</a> - </div> <!-- /Secondary distribute x-nav --> - </div> - <!-- /Sendondary x-nav DISTRIBUTE --> - <?cs /if ?> - <div id="searchResults" class="wrap" style="display:none;"> <h2 id="searchTitle">Results</h2> <div id="leftSearchControl" class="search-control">Loading...</div> </div> </div> <!--end header-wrapper --> - <div id="sticky-header"> - <div> - <a class="logo" href="#top"></a> - <a class="top" href="#top"></a> - <ul class="breadcrumb"> - <?cs # More <li> elements added here with javascript ?> - <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs - /if ?> - </ul> - </div> - </div> - -<?cs /if ?><?cs # end if/else !devsite ?> -<?cs /if ?><?cs # end if/else preview ?><?cs -/def ?> - -<?cs def:preview_masthead() ?> -<a name="top"></a> + <?cs if:ndk ?> + <!-- NDK Navigation--> + <nav class="dac-nav"> + <div class="dac-nav-dimmer" data-dac-toggle-nav></div> - -<!-- Header --> -<div id="header-wrapper"> - <div id="header"><?cs call:butter_bar() ?> - <div class="wrap" id="header-wrap"> - <div class="col_3 logo landing-logo" style="width:240px"> - <a href="<?cs var:toroot ?>preview/index.html"> - <img src="<?cs var:toroot ?>assets/images/android.png" height="25" alt="Android" - style="margin:-3px 0 0" /> + <ul class="dac-nav-list" data-dac-nav> + <li class="dac-nav-item dac-nav-head"> + <a class="dac-nav-link dac-nav-logo" data-dac-toggle-nav href="javascript:;" title="Close navigation"> + <img class="dac-logo-image" src="<?cs var:toroot ?>assets/images/android_logo_ndk.png" + srcset="<?cs var:toroot ?>assets/images/android_logo_ndk@2x.png 2x" + width="32" height="36" alt="Android" /> NDK </a> - </div> - <div class="col-8" style="margin:0"><h1 style="margin: 4px 0 0 0px;padding:0;line-height:16px; -color:#666;font-weight:100;font-size:27px;">L Developer Preview</h1></div> - - <?cs # ADD SEARCH AND MENU ?> - <?cs call:header_search_widget() ?> - - </div><!-- end header-wrap --> - </div><!-- /Header --> - - - <div id="searchResults" class="wrap" style="display:none;"> - <h2 id="searchTitle">Results</h2> - <div id="leftSearchControl" class="search-control">Loading...</div> - </div> -</div> <!--end header-wrapper --> + </li> + <li class="dac-nav-item guides"> + <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/guides/index.html" + zh-tw-lang="API 指南" + zh-cn-lang="API 指南" + ru-lang="Руководства по API" + ko-lang="API 가이드" + ja-lang="API ガイド" + es-lang="Guías de la API">Guides</a> + </li> + <li class="dac-nav-item reference"> + <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/reference/index.html" + zh-tw-lang="參考資源" + zh-cn-lang="参考" + ru-lang="Справочник" + ko-lang="참조문서" + ja-lang="リファレンス" + es-lang="Referencia">Reference</a> + </li> + <li class="dac-nav-item samples"> + <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/samples/index.html" + >Samples</a> + </li> + <li class="dac-nav-item downloads"> + <a class="dac-nav-link" href="<?cs var:toroot ?>ndk/downloads/index.html" + >Downloads</a> + </li> + </ul> + </nav> + <!-- end NDK navigation--> + <?cs else ?> + <!-- Navigation--> + <nav class="dac-nav"> + <div class="dac-nav-dimmer" data-dac-toggle-nav></div> -<div id="sticky-header"> - <div> - <a class="logo" href="#top"></a> - <a class="top" href="#top"></a> - <ul class="breadcrumb"> - <?cs # More <li> elements added here with javascript ?> - <?cs if:!section.landing ?><li class="current"><?cs var:page.title ?></li><?cs - /if ?> + <ul class="dac-nav-list" data-dac-nav> + <li class="dac-nav-item dac-nav-head"> + <a class="dac-nav-link dac-nav-logo" data-dac-toggle-nav href="javascript:;" title="Close navigation"> + <img class="dac-logo-image" src="<?cs var:toroot ?>assets/images/android_logo.png" + srcset="<?cs var:toroot ?>assets/images/android_logo@2x.png 2x" + width="32" height="36" alt="Android" /> Developers + </a> + </li> + <li class="dac-nav-item home"> + <a class="dac-nav-link dac-visible-mobile-block" href="<?cs var:toroot ?>index.html">Home</a> + <ul class="dac-nav-secondary about"> + <li class="dac-nav-item about"> + <a class="dac-nav-link" href="<?cs var:toroot ?>about/index.html">Android</a> + </li> + <li class="dac-nav-item wear"> + <a class="dac-nav-link" href="<?cs var:toroot ?>wear/index.html">Wear</a> + </li> + <li class="dac-nav-item tv"> + <a class="dac-nav-link" href="<?cs var:toroot ?>tv/index.html">TV</a> + </li> + <li class="dac-nav-item auto"> + <a class="dac-nav-link" href="<?cs var:toroot ?>auto/index.html">Auto</a> + </li> + </ul> + </li> + <li class="dac-nav-item design"> + <a class="dac-nav-link" href="<?cs var:toroot ?>design/index.html" + zh-tw-lang="設計" + zh-cn-lang="设计" + ru-lang="Проектирование" + ko-lang="디자인" + ja-lang="設計" + es-lang="Diseñar">Design</a> + </li> + <li class="dac-nav-item develop"> + <a class="dac-nav-link" href="<?cs var:toroot ?>develop/index.html" + zh-tw-lang="開發" + zh-cn-lang="开发" + ru-lang="Разработка" + ko-lang="개발" + ja-lang="開発" + es-lang="Desarrollar">Develop</a> + <ul class="dac-nav-secondary develop"> + <li class="dac-nav-item training"> + <a class="dac-nav-link" href="<?cs var:toroot ?>training/index.html" + zh-tw-lang="訓練課程" + zh-cn-lang="培训" + ru-lang="Курсы" + ko-lang="교육" + ja-lang="トレーニング" + es-lang="Capacitación">Training</a> + </li> + <li class="dac-nav-item guide"> + <a class="dac-nav-link" href="<?cs var:toroot ?>guide/index.html" + zh-tw-lang="API 指南" + zh-cn-lang="API 指南" + ru-lang="Руководства по API" + ko-lang="API 가이드" + ja-lang="API ガイド" + es-lang="Guías de la API">API Guides</a> + </li> + <li class="dac-nav-item reference"> + <a class="dac-nav-link" href="<?cs var:toroot ?>reference/packages.html" + zh-tw-lang="參考資源" + zh-cn-lang="参考" + ru-lang="Справочник" + ko-lang="참조문서" + ja-lang="リファレンス" + es-lang="Referencia">Reference</a> + </li> + <li class="dac-nav-item tools"> + <a class="dac-nav-link" href="<?cs var:toroot ?>sdk/index.html" + zh-tw-lang="相關工具" + zh-cn-lang="工具" + ru-lang="Инструменты" + ko-lang="도구" + ja-lang="ツール" + es-lang="Herramientas">Tools</a></li> + <li class="dac-nav-item google"> + <a class="dac-nav-link" href="<?cs var:toroot ?>google/index.html">Google Services</a> + </li> + <?cs if:android.hasSamples ?> + <li class="dac-nav-item samples"> + <a class="dac-nav-link" href="<?cs var:toroot ?>samples/index.html">Samples</a> + </li> + <?cs /if ?> + <li class="dac-nav-item preview"> + <a class="dac-nav-link" href="<?cs var:toroot ?>preview/index.html">Preview</a> + </li> + </ul> + </li> + <li class="dac-nav-item distribute"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/<?cs if:android.whichdoc == 'offline' ?>googleplay/<?cs /if ?>index.html" + zh-tw-lang="發佈" + zh-cn-lang="分发" + ru-lang="Распространение" + ko-lang="배포" + ja-lang="配布" + es-lang="Distribuir">Distribute</a> + <ul class="dac-nav-secondary distribute"> + <li class="dac-nav-item googleplay"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/googleplay/index.html">Google Play</a></li> + <li class="dac-nav-item essentials"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/essentials/index.html">Essentials</a></li> + <li class="dac-nav-item users"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/users/index.html">Get Users</a></li> + <li class="dac-nav-item engage"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/engage/index.html">Engage & Retain</a></li> + <li class="dac-nav-item monetize"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/monetize/index.html">Earn</a> + </li> + <li class="dac-nav-item analyze"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/analyze/index.html">Analyze</a> + </li> + <li class="dac-nav-item stories"> + <a class="dac-nav-link" href="<?cs var:toroot ?>distribute/stories/index.html">Stories</a> + </li> + </ul> + </li> </ul> - </div> -</div> + </nav> + <!-- end navigation--> + <?cs /if ?> +<?cs /if ?><?cs # end if/else !devsite ?> - <?cs -/def ?> +<?cs +/def ?><?cs # end custom_masthead() ?> <?cs # (UN)COMMENT THE INSIDE OF THIS METHOD TO TOGGLE VISIBILITY ?> @@ -383,6 +287,6 @@ color:#666;font-weight:100;font-size:27px;">L Developer Preview</h1></div> </div> </div> -?> +?> <?cs /def ?> diff --git a/tools/droiddoc/templates-sdk/customizations.cs b/tools/droiddoc/templates-sdk/customizations.cs index c8c88cc..aaef8ed 100644 --- a/tools/droiddoc/templates-sdk/customizations.cs +++ b/tools/droiddoc/templates-sdk/customizations.cs @@ -1,33 +1,41 @@ -<?cs +<?cs +def:mobile_nav_toggle() ?> + <div class="dac-visible-mobile-block" data-toggle="section"> + <span class="dac-toggle-expand dac-devdoc-toggle"><i class="dac-sprite dac-expand-more-black"></i> Show navigation</span> + <span class="dac-toggle-collapse dac-devdoc-toggle" data-toggle-section><i class="dac-sprite dac-expand-less-black"></i> Hide navigation</span> + </div> +<?cs /def ?><?cs + def:fullpage() ?> <div id="body-content"> + <div> <?cs /def ?> <?cs def:sdk_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/sdk/sdk_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/sdk/sdk_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <?cs /def ?><?cs def:no_nav() ?> <div class="wrap clearfix" id="body-content"> + <div> <?cs /def ?><?cs def:tools_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> -<?cs - include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/tools/tools_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -38,15 +46,13 @@ def:tools_nav() ?> <?cs /def ?> <?cs def:training_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - - -<?cs - include:"../../../../frameworks/base/docs/html/training/training_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/training/training_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -57,10 +63,30 @@ def:training_nav() ?> <?cs /def ?><?cs def:googleplay_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/googleplay/googleplay_toc.cs" ?> + </div> + </div> + </div> <!-- end side-nav --> + <script> + $(document).ready(function() { + scrollIntoView("devdoc-nav"); + }); + </script> +<?cs /def ?><?cs + +def:preview_nav() ?> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -71,10 +97,13 @@ def:googleplay_nav() ?> <?cs /def ?><?cs def:essentials_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/essentials/essentials_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -85,10 +114,13 @@ def:essentials_nav() ?> <?cs /def ?><?cs def:users_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/users/users_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -99,10 +131,13 @@ def:users_nav() ?> <?cs /def ?><?cs def:engage_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/engage/engage_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -113,10 +148,13 @@ def:engage_nav() ?> <?cs /def ?><?cs def:analyze_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/analyze/analyze_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -127,10 +165,13 @@ def:analyze_nav() ?> <?cs /def ?><?cs def:monetize_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/monetize/monetize_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -141,10 +182,13 @@ def:monetize_nav() ?> <?cs /def ?><?cs def:disttools_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/tools/disttools_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -155,10 +199,13 @@ def:disttools_nav() ?> <?cs /def ?><?cs def:stories_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> <?cs include:"../../../../frameworks/base/docs/html/distribute/stories/stories_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -169,14 +216,13 @@ def:stories_nav() ?> <?cs /def ?><?cs def:guide_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/guide/guide_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -187,15 +233,13 @@ def:guide_nav() ?> <?cs /def ?> <?cs def:design_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - - -<?cs - include:"../../../../frameworks/base/docs/html/design/design_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/design/design_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -206,14 +250,13 @@ def:design_nav() ?> <?cs /def ?> <?cs def:distribute_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/distribute/distribute_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/distribute/distribute_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -225,13 +268,13 @@ def:distribute_nav() ?> <?cs def:samples_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?> - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/samples/samples_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> @@ -244,14 +287,13 @@ def:samples_nav() ?> <?cs def:google_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/google/google_toc.cs" ?> + </div> </div> <script type="text/javascript"> showGoogleRefTree(); @@ -267,14 +309,13 @@ def:google_nav() ?> <?cs def:about_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-3" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/about/about_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -287,14 +328,13 @@ def:about_nav() ?> <?cs def:wear_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - -<?cs - include:"../../../../frameworks/base/docs/html/wear/wear_toc.cs" ?> - - + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs include:"../../../../frameworks/base/docs/html/wear/wear_toc.cs" ?> + </div> </div> </div> <!-- end side-nav --> <script> @@ -304,29 +344,14 @@ def:wear_nav() ?> </script> <?cs /def ?> -<?cs -def:preview_nav() ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div id="devdoc-nav" class="scroll-pane"> - <?cs - include:"../../../../frameworks/base/docs/html/preview/preview_toc.cs" ?> - </div> - </div> <!-- end side-nav --> - <script> - $(document).ready(function() { - scrollIntoView("devdoc-nav"); - }); - </script> -<?cs /def ?> -<?cs # The default side navigation for the reference docs ?><?cs +<?cs # The default side navigation for the reference docs ?><?cs def:default_left_nav() ?> <?cs if:reference.gcm || reference.gms ?> <?cs call:google_nav() ?> <?cs else ?> - <div class="wrap clearfix" id="body-content"> - <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-4 dac-hidden-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> <div id="devdoc-nav"> <div id="api-nav-header"> <div id="api-level-toggle"> @@ -341,15 +366,15 @@ def:default_left_nav() ?> <div id="api-nav-title">Android APIs</div> </div><!-- end nav header --> <script> - var SINCE_DATA = [ <?cs - each:since = since ?>'<?cs - var:since.name ?>'<?cs + var SINCE_DATA = [ <?cs + each:since = since ?>'<?cs + var:since.name ?>'<?cs if:!last(since) ?>, <?cs /if ?><?cs - /each + /each ?> ]; buildApiLevelSelector(); </script> - + <div id="swapper"> <div id="nav-panels"> <div id="resize-packages-nav"> @@ -364,7 +389,7 @@ def:default_left_nav() ?> <div id="classes-nav" class="scroll-pane"> -<?cs +<?cs if:subcount(class.package) ?> <ul> <?cs call:list("Annotations", class.package.annotations) ?> @@ -373,7 +398,7 @@ def:default_left_nav() ?> <?cs call:list("Enums", class.package.enums) ?> <?cs call:list("Exceptions", class.package.exceptions) ?> <?cs call:list("Errors", class.package.errors) ?> - </ul><?cs + </ul><?cs elif:subcount(package) ?> <ul> <?cs call:class_link_list("Annotations", package.annotations) ?> @@ -382,11 +407,11 @@ def:default_left_nav() ?> <?cs call:class_link_list("Enums", package.enums) ?> <?cs call:class_link_list("Exceptions", package.exceptions) ?> <?cs call:class_link_list("Errors", package.errors) ?> - </ul><?cs + </ul><?cs else ?> - <p style="padding:10px">Select a package to view its members</p><?cs + <p style="padding:10px">Select a package to view its members</p><?cs /if ?><br/> - + </div><!-- end classes --> </div><!-- end nav-panels --> @@ -427,84 +452,53 @@ def:default_left_nav() ?> }); </script> <?cs /if ?> - <?cs + <?cs /def ?> +<?cs +def:ndk_nav() ?> + <div class="wrap clearfix" id="body-content"><div class="cols"> + <div class="col-3 dac-toggle dac-mobile" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <?cs call:mobile_nav_toggle() ?> + <div class="dac-toggle-content" id="devdoc-nav"> + <div class="scroll-pane"> +<?cs +if:guide ?><?cs include:"../../../../frameworks/base/docs/html/ndk/guides/guides_toc.cs" ?><?cs +elif:reference ?><?cs include:"../../../../frameworks/base/docs/html/ndk/reference/reference_toc.cs" ?><?cs +elif:downloads ?><?cs include:"../../../../frameworks/base/docs/html/ndk/downloads/downloads_toc.cs" ?><?cs +elif:samples ?><?cs include:"../../../../frameworks/base/docs/html/ndk/samples/samples_toc.cs" ?><?cs +/if ?> + </div> + </div> + </div> <!-- end side-nav --> + <script> + $(document).ready(function() { + scrollIntoView("devdoc-nav"); + }); + </script> +<?cs /def ?> <?cs def:header_search_widget() ?> -<div class="menu-container"> - <div class="moremenu"> - <div id="more-btn"></div> - </div> - <div class="morehover" id="moremenu"> - <div class="top"></div> - <div class="mid"> - <div class="header">Links</div> - <ul> - <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li> - <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li> - <li><a href="<?cs var:toroot ?>about/index.html">About Android</a></li> - </ul> - <div class="header">Android Sites</div> - <ul> - <li><a href="http://www.android.com">Android.com</a></li> - <li class="active"><a>Android Developers</a></li> - <li><a href="http://source.android.com">Android Open Source Project</a></li> - </ul> - - <?cs # Include language switcher only in online docs ?> - <?cs if:android.whichdoc == "online" ?> - <div class="header">Language</div> - <div id="language" class="locales"> - <select name="language" onChange="changeLangPref(this.value, true)"> - <option value="en">English</option> - <option value="es">Español</option> - <option value="ja">日本語</option> - <option value="ko">한국어</option> - <option value="ru">Русский</option> - <option value="zh-cn">中文(简体)</option> - <option value="zh-tw">中文(繁體)</option> - </select> - </div> - <script type="text/javascript"> - <!-- - loadLangPref(); - //--> - </script> - <?cs /if ?> - <?cs # End of lang switcher ?> - <br class="clearfix" /> - </div><!-- end 'mid' --> - <div class="bottom"></div> - </div><!-- end 'moremenu' --> - - <div class="search" id="search-container"> - <div class="search-inner"> - <div id="search-btn"></div> - <div class="left"></div> - <form onsubmit="return submit_search()"> + <div class="dac-header-search" id="search-container"> + <div class="dac-header-search-inner"> + <div class="dac-sprite dac-search dac-header-search-btn" id="search-btn"></div> + <form class="dac-header-search-form" onsubmit="return submit_search()"> <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q" onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)" onkeydown="return search_changed(event, true, '<?cs var:toroot ?>')" - onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" /> + onkeyup="return search_changed(event, false, '<?cs var:toroot ?>')" + class="dac-header-search-input" placeholder="Search" /> + <a class="dac-header-search-close hide" id="search-close">close</a> </form> - <div class="right"></div> - <a class="close hide">close</a> - <div class="left"></div> - <div class="right"></div> - </div><!-- end search-inner --> - </div><!-- end search-container --> - - <div class="search_filtered_wrapper reference"> + </div><!-- end dac-header-search-inner --> + </div><!-- end dac-header-search --> + + <div class="search_filtered_wrapper"> <div class="suggest-card reference no-display"> <ul class="search_filtered"> </ul> </div> - </div> - - <div class="search_filtered_wrapper docs"> - <div class="suggest-card dummy no-display"> </div> <div class="suggest-card develop no-display"> <ul class="search_filtered"> </ul> @@ -524,87 +518,98 @@ def:header_search_widget() ?> </ul> </div> </div> -</div><!-- end menu-container (search and menu widget) --> <?cs /def ?> - -<?cs +<?cs def:custom_left_nav() ?><?cs - if:fullpage ?><?cs - call:fullpage() ?><?cs - elif:nonavpage ?><?cs - call:no_nav() ?><?cs - elif:guide ?><?cs - call:guide_nav() ?><?cs - elif:design ?><?cs - call:design_nav() ?><?cs - elif:training ?><?cs - call:training_nav() ?><?cs - elif:tools ?><?cs - call:tools_nav() ?><?cs - elif:google ?><?cs - call:google_nav() ?><?cs - elif:samples ?><?cs - call:samples_nav() ?><?cs - elif:distribute ?><?cs - if:googleplay ?><?cs - call:googleplay_nav() ?><?cs - elif:essentials ?><?cs - call:essentials_nav() ?><?cs - elif:users ?><?cs - call:users_nav() ?><?cs - elif:engage ?><?cs - call:engage_nav() ?><?cs - elif:monetize ?><?cs - call:monetize_nav() ?><?cs - elif:analyze ?><?cs - call:analyze_nav() ?><?cs - elif:disttools ?><?cs - call:disttools_nav() ?><?cs - elif:stories ?><?cs - call:stories_nav() ?><?cs + if:ndk ?><?cs + if:fullpage ?><?cs + call:fullpage() ?><?cs + elif:nonavpage ?><?cs + call:no_nav() ?><?cs + elif:guide || reference || samples || downloads ?><?cs + call:ndk_nav() ?><?cs + else ?><?cs + call:default_left_nav() ?> <?cs /if ?><?cs - elif:about ?><?cs - call:about_nav() ?><?cs - elif:distribute ?><?cs - call:distribute_nav() ?><?cs - elif:wear ?><?cs - call:wear_nav() ?><?cs - elif:preview ?><?cs - call:preview_nav() ?><?cs else ?><?cs - call:default_left_nav() ?> <?cs + if:fullpage ?><?cs + call:fullpage() ?><?cs + elif:nonavpage ?><?cs + call:no_nav() ?><?cs + elif:guide ?><?cs + call:guide_nav() ?><?cs + elif:design ?><?cs + call:design_nav() ?><?cs + elif:training ?><?cs + call:training_nav() ?><?cs + elif:tools ?><?cs + call:tools_nav() ?><?cs + elif:google ?><?cs + call:google_nav() ?><?cs + elif:samples ?><?cs + call:samples_nav() ?><?cs + elif:preview ?><?cs + call:preview_nav() ?><?cs + elif:distribute ?><?cs + if:googleplay ?><?cs + call:googleplay_nav() ?><?cs + elif:essentials ?><?cs + call:essentials_nav() ?><?cs + elif:users ?><?cs + call:users_nav() ?><?cs + elif:engage ?><?cs + call:engage_nav() ?><?cs + elif:monetize ?><?cs + call:monetize_nav() ?><?cs + elif:analyze ?><?cs + call:analyze_nav() ?><?cs + elif:disttools ?><?cs + call:disttools_nav() ?><?cs + elif:stories ?><?cs + call:stories_nav() ?><?cs + /if ?><?cs + elif:about ?><?cs + call:about_nav() ?><?cs + elif:distribute ?><?cs + call:distribute_nav() ?><?cs + elif:wear ?><?cs + call:wear_nav() ?><?cs + else ?><?cs + call:default_left_nav() ?> <?cs + /if ?><?cs /if ?><?cs /def ?> -<?cs # appears at the bottom of every page ?><?cs +<?cs # appears at the bottom of every page ?><?cs def:custom_cc_copyright() ?> - Except as noted, this content is + Except as noted, this content is licensed under <a href="http://creativecommons.org/licenses/by/2.5/"> - Creative Commons Attribution 2.5</a>. For details and - restrictions, see the <a href="<?cs var:toroot ?>license.html">Content - License</a>.<?cs + Creative Commons Attribution 2.5</a>. For details and + restrictions, see the <a href="<?cs var:toroot ?>license.html">Content + License</a>.<?cs /def ?> -<?cs +<?cs def:custom_copyright() ?> Except as noted, this content is licensed under <a - href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. + href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a>. For details and restrictions, see the <a href="<?cs var:toroot ?>license.html"> - Content License</a>.<?cs + Content License</a>.<?cs /def ?> -<?cs +<?cs def:custom_footerlinks() ?> - <p> - <a href="<?cs var:toroot ?>about/index.html">About Android</a> | - <a href="<?cs var:toroot ?>legal.html">Legal</a> | - <a href="<?cs var:toroot ?>support.html">Support</a> - </p><?cs + <a href="<?cs var:toroot ?>about/index.html">About Android</a> + <a href="<?cs var:toroot ?>auto/index.html">Auto</a> + <a href="<?cs var:toroot ?>tv/index.html">TV</a> + <a href="<?cs var:toroot ?>wear/index.html">Wear</a> + <a href="<?cs var:toroot ?>legal.html">Legal</a> + <?cs /def ?> -<?cs # appears on the right side of the blue bar at the bottom off every page ?><?cs +<?cs # appears on the right side of the blue bar at the bottom off every page ?><?cs def:custom_buildinfo() ?><?cs if:!google && !reference.gcm && !reference.gms ?> Android <?cs var:sdk.version ?> r<?cs var:sdk.rel.id ?> — <?cs diff --git a/tools/droiddoc/templates-sdk/designpage.cs b/tools/droiddoc/templates-sdk/designpage.cs index 2be179d..b945a1c 100644 --- a/tools/droiddoc/templates-sdk/designpage.cs +++ b/tools/droiddoc/templates-sdk/designpage.cs @@ -37,14 +37,12 @@ <?cs if:header.hide ?> <?cs else ?> -<div class="layout-content-row content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>"> - <div class="layout-content-col span-9"> +<div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>"> <?cs if:header.justLinks ?> <?cs elif:header.title ?><h2><?cs var:header.title ?></h2> <?cs else ?><h2><?cs var:page.title ?></h2> <?cs /if ?> - </div> - <div class="paging-links layout-content-col span-4" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="paging-links" itemscope itemtype="http://schema.org/SiteNavigationElement"> <a href="#" class="prev-page-link">Previous</a> <a href="#" class="next-page-link">Next</a> </div> @@ -55,9 +53,9 @@ <?cs if:footer.hide ?> <?cs else ?> -<div class="layout-content-row content-footer" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div class="paging-links layout-content-col span-9"> </div> - <div class="paging-links layout-content-col span-4"> +<div class="cols content-footer" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="paging-links col-9"> </div> + <div class="paging-links col-4"> <a href="#" class="prev-page-link">Previous</a> <a href="#" class="next-page-link">Next</a> </div> diff --git a/tools/droiddoc/templates-sdk/docpage.cs b/tools/droiddoc/templates-sdk/docpage.cs index 83b1199..204e06c 100644 --- a/tools/droiddoc/templates-sdk/docpage.cs +++ b/tools/droiddoc/templates-sdk/docpage.cs @@ -4,31 +4,39 @@ <?cs include:"head_tag.cs" ?> <body class="gc-documentation +<?cs # add document classes for navigation header selection (and other stuff) ?> <?cs -if:(google || reference.gms || reference.gcm) ?>google<?cs /if ?><?cs - if:(guide||develop||training||reference||tools||sdk||samples) ?>develop<?cs + if:(google || reference.gms || reference.gcm) ?>google <?cs /if ?><?cs + if:ndk ?>ndk<?cs if:guide ?> guide<?cs /if ?><?cs if:samples ?> samples<?cs /if ?><?cs - elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories) - ?>distribute<?cs - if:googleplay ?> googleplay<?cs /if ?><?cs - if:essentials ?> essentials<?cs /if ?><?cs - if:users ?> users<?cs /if ?><?cs - if:engage ?> engage<?cs /if ?><?cs - if:monetize ?> monetize<?cs /if ?><?cs - if:disttools ?> disttools<?cs /if ?><?cs - if:stories ?> stories<?cs /if ?><?cs - elif:(about||wear||tv||auto) ?>about<?cs - elif:design ?>design<?cs -/if ?><?cs -if:page.trainingcourse ?> trainingcourse<?cs + if:reference ?> reference<?cs /if ?><?cs + if:downloads ?> downloads<?cs /if ?><?cs + else ?><?cs + if:(guide||develop||training||reference||tools||sdk||google||samples||preview) ?>develop<?cs + if:guide ?> guide<?cs /if ?><?cs + if:samples ?> samples<?cs /if ?><?cs + if:preview ?> preview<?cs /if ?><?cs + elif:(distribute||googleplay||essentials||users||engage||monetize||disttools||stories||analyze) ?>distribute<?cs + if:googleplay ?> googleplay<?cs /if ?><?cs + if:essentials ?> essentials<?cs /if ?><?cs + if:users ?> users<?cs /if ?><?cs + if:engage ?> engage<?cs /if ?><?cs + if:monetize ?> monetize<?cs /if ?><?cs + if:disttools ?> disttools<?cs /if ?><?cs + if:stories ?> stories<?cs /if ?><?cs + if:analyze ?> analyze<?cs /if ?><?cs + elif:(about||wear||tv||auto) ?>about<?cs + elif:design ?>design<?cs + /if ?><?cs + if:page.trainingcourse ?> trainingcourse<?cs /if ?><?cs /if ?>" itemscope itemtype="http://schema.org/Article"><?cs include:"header.cs" ?> <div <?cs if:fullpage ?>class="fullpage"<?cs - elif:(design||tools||about||sdk||googleplay||essentials||users||monetize||disttools) && !nonavpage + elif:(design||tools||about||sdk||googleplay||essentials||users||engage||monetize||disttools||stories) && !nonavpage ?>class="col-13" id="doc-col"<?cs elif:!nonavpage ?>class="col-12" id="doc-col"<?cs /if ?> > @@ -36,14 +44,12 @@ include:"header.cs" ?> <?cs if:(design||training||walkthru) && !page.trainingcourse && !page.article ?><?cs # header logic for docs that provide previous/next buttons ?> <?cs if:header.hide ?> <?cs else ?> - <div class="layout-content-row content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>"> - <div class="layout-content-col <?cs if:training ?>span-7<?cs else ?>span-9<?cs /if ?>"> + <div class="content-header <?cs if:header.justLinks ?>just-links<?cs /if ?>"> <?cs if:header.justLinks ?> <?cs else ?><h1 itemprop="name"><?cs var:page.title ?></h1> <?cs /if ?> - </div> <?cs if:training ?> - <div class="training-nav-top layout-content-col span-5" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="training-nav-top" itemscope itemtype="http://schema.org/SiteNavigationElement"> <a href="#" class="prev-page-link hide" zh-tw-lang="上一堂課" zh-cn-lang="上一课" @@ -70,7 +76,7 @@ include:"header.cs" ?> >Get started</a> </div> <?cs elif:!page.trainingcourse ?> - <div class="paging-links layout-content-col span-4" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="paging-links" itemscope itemtype="http://schema.org/SiteNavigationElement"> <a href="#" class="prev-page-link hide" zh-tw-lang="上一堂課" zh-cn-lang="上一课" @@ -116,16 +122,18 @@ include:"header.cs" ?> <?cs if:page.landing ?><?cs # header logic for docs that are landing pages ?> <div class="landing-banner"> <?cs if:page.landing.image ?><?cs # use two-column layout only if there is an image ?> - <div class="col-6"> - <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" /> - </div> - <div class="col-6"> + <div class="cols"> + <div class="col-6"> + <img src="<?cs var:toroot ?><?cs var:page.landing.image ?>" alt="" /> + </div> + <div class="col-6"> <?cs /if ?> <h1 itemprop="name" style="margin-bottom:0;"><?cs var:page.title ?></h1> <p itemprop="description"><?cs var:page.landing.intro ?></p> <p><a class="next-page-link topic-start-link"></a></p> <?cs if:page.landing.image ?> + </div> </div> <?cs /if ?> </div> @@ -153,13 +161,11 @@ include:"header.cs" ?> <?cs call:tag_list(root.descr) ?> </div> + <?cs if:!fullscreen && (design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?> <div class="content-footer <?cs - if:fullpage ?>wrap<?cs - else ?>layout-content-row<?cs /if ?>" + if:fullpage ?>wrap<?cs /if ?>" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <?cs if:!fullscreen ?> - <div class="paging-links layout-content-col col-10"> - <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?> + <div class="paging-links"> <a href="#" class="next-page-link hide" zh-tw-lang="下一堂課" zh-cn-lang="下一课" @@ -177,15 +183,9 @@ include:"header.cs" ?> es-lang="Empezar" >Get started</a> <a href="#" class="next-class-link hide">Next class</a> - <?cs /if ?> - </div> - <div class="layout-content-col plus-container col-2" > - <?cs if:!page.noplus ?><?cs if:fullpage ?><style>#___plusone_0 {float:right !important;}</style><?cs /if ?> - <div class="g-plusone" data-size="medium"></div> - <?cs /if ?> - </div> - <?cs /if ?> + </div> </div> + <?cs /if ?> </div> <!-- end jd-content --> @@ -194,13 +194,10 @@ include:"header.cs" ?> <?cs include:"trailer.cs" ?> <script src="https://developer.android.com/ytblogger_lists_unified.js" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_lists_unified.js?v=9" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_extras.js?v=11" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_collections.js?v=12" type="text/javascript"></script> - <script src="<?cs var:toroot ?>jd_tag_helpers.js?v=5" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_lists_unified.js?v=14" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_extras.js?v=14" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_collections.js?v=14" type="text/javascript"></script> + <script src="<?cs var:toroot ?>jd_tag_helpers.js?v=14" type="text/javascript"></script> </body> </html> - - - diff --git a/tools/droiddoc/templates-sdk/footer.cs b/tools/droiddoc/templates-sdk/footer.cs index b609d3b..c960953 100644 --- a/tools/droiddoc/templates-sdk/footer.cs +++ b/tools/droiddoc/templates-sdk/footer.cs @@ -1,20 +1,171 @@ -<div id="footer" class="wrap" <?cs if:fullpage ?>style="width:940px"<?cs /if ?>> - -<?cs if:reference ?> - <div id="copyright"> - <?cs call:custom_copyright() ?> +<div class="wrap"> + <div class="dac-footer<?cs if:fullpage ?> dac-landing<?cs /if ?>"> + <div class="cols dac-footer-main"> + <div class="col-1of2"> + <a class="dac-footer-getnews" data-modal-toggle="newsletter" href="javascript:;">Get news & tips <span + class="dac-fab dac-primary"><i class="dac-sprite dac-mail"></i></span></a> + </div> + <div class="col-1of2 dac-footer-reachout"> + <div class="dac-footer-contact"> + <a class="dac-footer-contact-link" href="http://android-developers.blogspot.com/">Blog</a> + <a class="dac-footer-contact-link" href="/support.html">Support</a> + </div> + <div class="dac-footer-social"> + <a class="dac-fab dac-footer-social-link" href="https://www.youtube.com/user/androiddevelopers"><i class="dac-sprite dac-youtube"></i></a> + <a class="dac-fab dac-footer-social-link" href="https://plus.google.com/+AndroidDevelopers"><i class="dac-sprite dac-gplus"></i></a> + <a class="dac-fab dac-footer-social-link" href="https://twitter.com/AndroidDev"><i class="dac-sprite dac-twitter"></i></a> + </div> + </div> + </div> + + <hr class="dac-footer-separator"/> + + <?cs if:reference ?> + <p class="dac-footer-copyright"> + <?cs call:custom_copyright() ?> + </p> + <p class="dac-footer-build"> + <?cs call:custom_buildinfo() ?> + </p> + <?cs elif:!hide_license_footer ?> + <p class="dac-footer-copyright"> + <?cs call:custom_cc_copyright() ?> + </p> + <?cs /if ?> + + <p class="dac-footer-links"> + <a href="/about/index.html">About Android</a> + <a href="/auto/index.html">Auto</a> + <a href="/tv/index.html">TV</a> + <a href="/wear/index.html">Wear</a> + <a href="/legal.html">Legal</a> + + <span id="language" class="locales"> + <select name="language" onchange="changeLangPref(this.value, true)"> + <option value="en" selected="selected">English</option> + <option value="es">Español</option> + <option value="ja">日本語</option> + <option value="ko">한국어</option> + <option value="ru">Русский</option> + <option value="zh-cn">中文(简体)</option> + <option value="zh-tw">中文(繁體)</option> + </select> + </span> + </p> </div> - <div id="build_info"> - <?cs call:custom_buildinfo() ?> +</div> <!-- end footer --> + +<div data-modal="newsletter" data-newsletter data-swap class="dac-modal newsletter"> + <div class="dac-modal-container"> + <div class="dac-modal-window"> + <header class="dac-modal-header"> + <button class="dac-modal-header-close" data-modal-toggle><i class="dac-sprite dac-close"></i></button> + <div class="dac-swap" data-swap-container> + <section class="dac-swap-section dac-active dac-down"> + <h2 class="norule dac-modal-header-title">Get the latest Android developer news and tips that will help you find success on Google Play.</h2> + <p class="dac-modal-header-subtitle">* Required Fields</p> + </section> + <section class="dac-swap-section dac-up"> + <h2 class="norule dac-modal-header-title">Hooray!</h2> + </section> + </div> + </header> + <div class="dac-swap" data-swap-container> + <section class="dac-swap-section dac-active dac-left"> + <form action="https://docs.google.com/forms/d/1QgnkzbEJIDu9lMEea0mxqWrXUJu0oBCLD7ar23V0Yys/formResponse" class="dac-form" method="post" target="dac-newsletter-iframe"> + <section class="dac-modal-content"> + <fieldset class="dac-form-fieldset"> + <div class="cols"> + <div class="col-1of2 newsletter-leftCol"> + <div class="dac-form-input-group"> + <label for="newsletter-full-name" class="dac-form-floatlabel">Full name</label> + <input type="text" class="dac-form-input" name="entry.1357890476" id="newsletter-full-name" required> + <span class="dac-form-required">*</span> + </div> + <div class="dac-form-input-group"> + <label for="newsletter-email" class="dac-form-floatlabel">Email address</label> + <input type="email" class="dac-form-input" name="entry.472100832" id="newsletter-email" required> + <span class="dac-form-required">*</span> + </div> + </div> + <div class="col-1of2 newsletter-rightCol"> + <div class="dac-form-input-group"> + <label for="newsletter-company" class="dac-form-floatlabel">Company / developer name</label> + <input type="text" class="dac-form-input" name="entry.1664780309" id="newsletter-company"> + </div> + <div class="dac-form-input-group"> + <label for="newsletter-play-store" class="dac-form-floatlabel">One of your Play Store app URLs</label> + <input type="url" class="dac-form-input" name="entry.47013838" id="newsletter-play-store" required> + <span class="dac-form-required">*</span> + </div> + </div> + </div> + </fieldset> + <fieldset class="dac-form-fieldset"> + <div class="cols"> + <div class="col-1of2 newsletter-leftCol"> + <legend class="dac-form-legend">Which best describes your business:<span class="dac-form-required">*</span> + </legend> + <div class="dac-form-radio-group"> + <input type="radio" value="Apps" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-app" required> + <label for="newsletter-business-type-app" class="dac-form-radio-button"></label> + <label for="newsletter-business-type-app" class="dac-form-label">Apps</label> + </div> + <div class="dac-form-radio-group"> + <input type="radio" value="Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-games" required> + <label for="newsletter-business-type-games" class="dac-form-radio-button"></label> + <label for="newsletter-business-type-games" class="dac-form-label">Games</label> + </div> + <div class="dac-form-radio-group"> + <input type="radio" value="Apps and Games" class="dac-form-radio" name="entry.1796324055" id="newsletter-business-type-appsgames" required> + <label for="newsletter-business-type-appsgames" class="dac-form-radio-button"></label> + <label for="newsletter-business-type-appsgames" class="dac-form-label">Apps & Games</label> + </div> + </div> + <div class="col-1of2 newsletter-rightCol newsletter-checkboxes"> + <div class="dac-form-radio-group"> + <div class="dac-media"> + <div class="dac-media-figure"> + <input type="checkbox" class="dac-form-checkbox" name="entry.732309842" id="newsletter-add" required value="Add me to the mailing list for the monthly newsletter and occasional emails about development and Google Play opportunities."> + <label for="newsletter-add" class="dac-form-checkbox-button"></label> + </div> + <div class="dac-media-body"> + <label for="newsletter-add" class="dac-form-label dac-form-aside">Add me to the mailing list for the monthly newsletter and occasional emails about development and Google Play opportunities.<span class="dac-form-required">*</span></label> + </div> + </div> + </div> + <div class="dac-form-radio-group"> + <div class="dac-media"> + <div class="dac-media-figure"> + <input type="checkbox" class="dac-form-checkbox" name="entry.2045036090" id="newsletter-terms" required value="I acknowledge that the information provided in this form will be subject to Google's privacy policy (https://www.google.com/policies/privacy/)."> + <label for="newsletter-terms" class="dac-form-checkbox-button"></label> + </div> + <div class="dac-media-body"> + <label for="newsletter-terms" class="dac-form-label dac-form-aside">I acknowledge that the information provided in this form will be subject to <a href="https://www.google.com/policies/privacy/">Google's privacy policy</a>.<span class="dac-form-required">*</span></label> + </div> + </div> + </div> + </div> + </div> + </fieldset> + </section> + <footer class="dac-modal-footer"> + <div class="cols"> + <div class="col-2of5"> + </div> + </div> + <button type="submit" value="Submit" class="dac-fab dac-primary dac-large dac-modal-action"><i class="dac-sprite dac-arrow-right"></i></button> + </footer> + </form> + </section> + <section class="dac-swap-section dac-right"> + <div class="dac-modal-content"> + <p class="newsletter-success-message"> + You have successfully signed up for the latest Android developer news and tips. + </p> + </div> + </section> + </div> + </div> </div> -<?cs elif:!hide_license_footer ?> - <div id="copyright"> - <?cs call:custom_cc_copyright() ?> - </div> -<?cs /if ?> -<?cs if:!no_footer_links ?> - <div id="footerlinks"> - <?cs call:custom_footerlinks() ?> - </div> -<?cs /if ?> -</div> <!-- end footer -->
\ No newline at end of file +</div> <!-- end footer --> diff --git a/tools/droiddoc/templates-sdk/head_tag.cs b/tools/droiddoc/templates-sdk/head_tag.cs index 9f79f54..dfbff5a 100644 --- a/tools/droiddoc/templates-sdk/head_tag.cs +++ b/tools/droiddoc/templates-sdk/head_tag.cs @@ -15,10 +15,8 @@ ?><?cs # END if/else devsite ?> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<meta name="viewport" content="width=<?cs - if:page.viewport_width ?><?cs - var:page.viewport_width ?><?cs - else ?>device-width<?cs /if ?>" /> +<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" /> +<meta content="IE=edge" http-equiv="X-UA-Compatible"> <?cs if:page.metaDescription ?> <meta name="Description" content="<?cs var:page.metaDescription ?>"><?cs @@ -38,7 +36,12 @@ if:android.whichdoc != 'online' ?>http:<?cs if:android.whichdoc != 'online' ?>http:<?cs /if ?>//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto"> -<link href="<?cs var:toroot ?>assets/css/default.css?v=5" rel="stylesheet" type="text/css"> +<?cs + if:ndk ?><link rel="stylesheet" href="<?cs + if:android.whichdoc != 'online' ?>http:<?cs + /if ?>//fonts.googleapis.com/css?family=Roboto+Mono:400,500,700" title="roboto-mono" type="text/css"><?cs +/if ?> +<link href="<?cs var:toroot ?>assets/css/default.css?v=7" rel="stylesheet" type="text/css"> <?cs if:reference && !(reference.gms || reference.gcm || preview) ?> <!-- FULLSCREEN STYLESHEET --> @@ -62,7 +65,7 @@ else var metaTags = [<?cs var:meta.tags ?>]; var devsite = <?cs if:devsite ?>true<?cs else ?>false<?cs /if ?>; </script> -<script src="<?cs var:toroot ?>assets/js/docs.js?v=3" type="text/javascript"></script> +<script src="<?cs var:toroot ?>assets/js/docs.js?v=5" type="text/javascript"></script> <?cs if:helpoutsWidget ?> <script type="text/javascript" src="https://helpouts.google.com/ps/res/embed.js" defer async diff --git a/tools/droiddoc/templates-sdk/nosidenavpage.cs b/tools/droiddoc/templates-sdk/nosidenavpage.cs index 8e59693..61754f0 100644 --- a/tools/droiddoc/templates-sdk/nosidenavpage.cs +++ b/tools/droiddoc/templates-sdk/nosidenavpage.cs @@ -11,6 +11,7 @@ <?cs call:custom_masthead() ?> <div id="body-content"> +<div> <div id="doc-content" style="position:relative;"> <?cs call:tag_list(root.descr) ?> diff --git a/tools/droiddoc/templates-sdk/package.cs b/tools/droiddoc/templates-sdk/package.cs index 2225565..72d5538 100644 --- a/tools/droiddoc/templates-sdk/package.cs +++ b/tools/droiddoc/templates-sdk/package.cs @@ -55,8 +55,9 @@ <?cs call:class_table("Exceptions", package.exceptions) ?> <?cs call:class_table("Errors", package.errors) ?> -<?cs include:"footer.cs" ?> </div><!-- end jd-content --> + +<?cs include:"footer.cs" ?> </div><!-- doc-content --> <?cs include:"trailer.cs" ?> diff --git a/tools/droiddoc/templates-sdk/packages.cs b/tools/droiddoc/templates-sdk/packages.cs index 5056d3a..fe6a5aa 100644 --- a/tools/droiddoc/templates-sdk/packages.cs +++ b/tools/droiddoc/templates-sdk/packages.cs @@ -35,8 +35,9 @@ <?cs /each ?> </table> -<?cs include:"footer.cs" ?> </div><!-- end jd-content --> + +<?cs include:"footer.cs" ?> </div> <!-- end doc-content --> <?cs include:"trailer.cs" ?> diff --git a/tools/droiddoc/templates-sdk/sample.cs b/tools/droiddoc/templates-sdk/sample.cs index 32a0788..7b4bf0f 100644 --- a/tools/droiddoc/templates-sdk/sample.cs +++ b/tools/droiddoc/templates-sdk/sample.cs @@ -92,9 +92,9 @@ <div class="content-footer <?cs if:fullpage ?>wrap<?cs - else ?>layout-content-row<?cs /if ?>" + else ?>cols<?cs /if ?>" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div class="layout-content-col <?cs + <div class="<?cs if:fullpage ?>col-16<?cs elif:training||guide ?>col-8<?cs else ?>col-9<?cs /if ?>" style="padding-top:4px"> @@ -103,7 +103,7 @@ <?cs /if ?> </div> <?cs if:!fullscreen ?> - <div class="paging-links layout-content-col col-4"> + <div class="paging-links col-4"> <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?> <a href="#" class="prev-page-link hide" zh-tw-lang="上一堂課" @@ -128,7 +128,7 @@ <?cs # for training classes, provide a different kind of link when the next page is a different class ?> <?cs if:training && !page.article ?> - <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement"> <a href="#" class="next-class-link hide">Next class: </a> </div> <?cs /if ?> diff --git a/tools/droiddoc/templates-sdk/sampleindex.cs b/tools/droiddoc/templates-sdk/sampleindex.cs index 1bacb53..e62d3fe 100644 --- a/tools/droiddoc/templates-sdk/sampleindex.cs +++ b/tools/droiddoc/templates-sdk/sampleindex.cs @@ -82,9 +82,9 @@ <?cs /if ?><?cs # end if/else online docs ?> <div class="content-footer <?cs if:fullpage ?>wrap<?cs - else ?>layout-content-row<?cs /if ?>" + else ?>cols<?cs /if ?>" itemscope itemtype="http://schema.org/SiteNavigationElement"> - <div class="layout-content-col <?cs + <div class="<?cs if:fullpage ?>col-16<?cs elif:training||guide ?>col-8<?cs else ?>col-9<?cs /if ?>" style="padding-top:4px"> @@ -93,7 +93,7 @@ <?cs /if ?> </div> <?cs if:!fullscreen ?> - <div class="paging-links layout-content-col col-4"> + <div class="paging-links col-4"> <?cs if:(design||training||walkthru) && !page.landing && !page.trainingcourse && !footer.hide ?> <a href="#" class="prev-page-link hide" zh-tw-lang="上一堂課" @@ -118,7 +118,7 @@ <?cs # for training classes, provide a different kind of link when the next page is a different class ?> <?cs if:training && !page.article ?> - <div class="layout-content-row content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement"> + <div class="content-footer next-class" style="display:none" itemscope itemtype="http://schema.org/SiteNavigationElement"> <a href="#" class="next-class-link hide">Next class: </a> </div> <?cs /if ?> diff --git a/tools/droiddoc/templates-sdk/sdkpage.cs b/tools/droiddoc/templates-sdk/sdkpage.cs index 817ac47..8ec034f 100644 --- a/tools/droiddoc/templates-sdk/sdkpage.cs +++ b/tools/droiddoc/templates-sdk/sdkpage.cs @@ -116,6 +116,7 @@ <td><?cs var:ndk.win64.legacy_bytes ?></td> <td><?cs var:ndk.win64.legacy_checksum ?></td> </tr> --> +<!-- (this item is deprecated) <tr> <td>Mac OS X 32-bit</td> <td> @@ -124,8 +125,9 @@ </td> <td><?cs var:ndk.mac32_bytes ?></td> <td><?cs var:ndk.mac32_checksum ?></td> - </tr> - <!-- <tr> + </tr> --> + <!-- (this item is deprecated) + <tr> <td> <a onClick="return onDownload(this)" href="http://dl.google.com/android/ndk/<?cs var:ndk.mac32.legacy_download ?>"><?cs var:ndk.mac32.legacy_download ?></a> @@ -399,9 +401,6 @@ var:sdk.linux_download -</div><!-- end col-13 for lower-half content --> - - <script> diff --git a/tools/droiddoc/templates-sdk/trailer.cs b/tools/droiddoc/templates-sdk/trailer.cs index 337f8d3..225b2c1 100644 --- a/tools/droiddoc/templates-sdk/trailer.cs +++ b/tools/droiddoc/templates-sdk/trailer.cs @@ -1,3 +1,4 @@ +</div> <!-- end .cols --> <?cs # normally opened by header.cs ?> </div> <!-- end body-content --> <?cs # normally opened by header.cs ?> <?cs if:carousel ?> diff --git a/tools/fs_config/Android.mk b/tools/fs_config/Android.mk index 02deabb..34a3522 100644 --- a/tools/fs_config/Android.mk +++ b/tools/fs_config/Android.mk @@ -13,11 +13,73 @@ # limitations under the License. LOCAL_PATH := $(call my-dir) + include $(CLEAR_VARS) LOCAL_SRC_FILES := fs_config.c LOCAL_MODULE := fs_config -LOCAL_STATIC_LIBRARIES := libselinux -LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_SHARED_LIBRARIES := libcutils libselinux +LOCAL_CFLAGS := -Werror + +include $(BUILD_HOST_EXECUTABLE) + +# To Build the custom target binary for the host to generate the fs_config +# override files. The executable is hard coded to include the +# $(TARGET_ANDROID_FILESYSTEM_CONFIG_H) file if it exists. +# Expectations: +# device/<vendor>/<device>/android_filesystem_config.h +# fills in struct fs_path_config android_device_dirs[] and +# struct fs_path_config android_device_files[] +# device/<vendor>/<device>/device.mk +# PRODUCT_PACKAGES += fs_config_dirs fs_config_files +# If not specified, check if default one to be found +ANDROID_FS_CONFIG_H := android_filesystem_config.h + +ifneq ($(TARGET_ANDROID_FILESYSTEM_CONFIG_H),) +ifeq ($(filter %/$(ANDROID_FS_CONFIG_H),$(TARGET_ANDROID_FILESYSTEM_CONFIG_H)),) +$(error TARGET_ANDROID_FILESYSTEM_CONFIG_H file name must be $(ANDROID_FS_CONFIG_H), \ + see "$(notdir $(TARGET_ANDROID_FILESYSTEM_CONFIG_H))".) +endif + +my_fs_config_h := $(TARGET_ANDROID_FILESYSTEM_CONFIG_H) +else ifneq ($(wildcard $(TARGET_DEVICE_DIR)/$(ANDROID_FS_CONFIG_H)),) +my_fs_config_h := $(TARGET_DEVICE_DIR)/$(ANDROID_FS_CONFIG_H) +else +my_fs_config_h := $(LOCAL_PATH)/default/$(ANDROID_FS_CONFIG_H) +endif + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := fs_config_generate.c +LOCAL_MODULE := fs_config_generate_$(TARGET_DEVICE) +LOCAL_SHARED_LIBRARIES := libcutils +LOCAL_CFLAGS := -Werror -Wno-error=\#warnings +LOCAL_C_INCLUDES := $(dir $(my_fs_config_h)) include $(BUILD_HOST_EXECUTABLE) +fs_config_generate_bin := $(LOCAL_INSTALLED_MODULE) + +# Generate the system/etc/fs_config_dirs binary file for the target +# Add fs_config_dirs to PRODUCT_PACKAGES in the device make file to enable +include $(CLEAR_VARS) + +LOCAL_MODULE := fs_config_dirs +LOCAL_MODULE_CLASS := ETC +include $(BUILD_SYSTEM)/base_rules.mk +$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin) + @mkdir -p $(dir $@) + $< -D -o $@ + +# Generate the system/etc/fs_config_files binary file for the target +# Add fs_config_files to PRODUCT_PACKAGES in the device make file to enable +include $(CLEAR_VARS) + +LOCAL_MODULE := fs_config_files +LOCAL_MODULE_CLASS := ETC +include $(BUILD_SYSTEM)/base_rules.mk +$(LOCAL_BUILT_MODULE): $(fs_config_generate_bin) + @mkdir -p $(dir $@) + $< -F -o $@ + +ANDROID_FS_CONFIG_H := +my_fs_config_h := +fs_config_generate_bin := diff --git a/tools/fs_config/default/android_filesystem_config.h b/tools/fs_config/default/android_filesystem_config.h new file mode 100644 index 0000000..820b04a --- /dev/null +++ b/tools/fs_config/default/android_filesystem_config.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file is used to enhance the properties of the filesystem +** images generated by build tools (mkbootfs and mkyaffs2image) and +** by the device side of adb. +*/ + +/* +** Resorting to the default file means someone requested fs_config_dirs or +** fs_config_files in their device configuration without providing an +** associated header. +*/ +#warning No device-supplied android_filesystem_config.h, using empty default. + +/* Rules for directories. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. +*/ + +#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS 1 /* opt out of specifying */ + +/* Rules for files. +** These rules are applied based on "first match", so they +** should start with the most specific path and work their +** way up to the root. Prefixes ending in * denotes wildcard +** and will allow partial matches. +*/ + +#define NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES 1 /* opt out of specifying */ diff --git a/tools/fs_config/fs_config_generate.c b/tools/fs_config/fs_config_generate.c new file mode 100644 index 0000000..c06213f --- /dev/null +++ b/tools/fs_config/fs_config_generate.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <private/android_filesystem_config.h> + +/* + * This program expects android_device_dirs and android_device_files + * to be defined in the supplied android_filesystem_config.h file in + * the device/<vendor>/<product> $(TARGET_DEVICE_DIR). Then generates + * the binary format used in the /system/etc/fs_config_dirs and + * the /system/etc/fs_config_files to be used by the runtimes. + */ +#include "android_filesystem_config.h" + +#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS + static const struct fs_path_config android_device_dirs[] = { +}; +#endif + +#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES +static const struct fs_path_config android_device_files[] = { +#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS + { 0, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" }, +#endif + { 0, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files" }, +}; +#endif + +static void usage() { + fprintf(stderr, + "Generate binary content for fs_config_dirs (-D) and fs_config_files (-F)\n" + "from device-specific android_filesystem_config.h override\n\n" + "Usage: fs_config_generate -D|-F [-o output-file]\n"); +} + +int main(int argc, char** argv) { + const struct fs_path_config *pc; + const struct fs_path_config *end; + bool dir = false, file = false; + FILE *fp = stdout; + int opt; + + while((opt = getopt(argc, argv, "DFho:")) != -1) { + switch(opt) { + case 'D': + if (file) { + fprintf(stderr, "Must specify only -D or -F\n"); + usage(); + exit(EXIT_FAILURE); + } + dir = true; + break; + case 'F': + if (dir) { + fprintf(stderr, "Must specify only -F or -D\n"); + usage(); + exit(EXIT_FAILURE); + } + file = true; + break; + case 'o': + if (fp != stdout) { + fprintf(stderr, "Specify only one output file\n"); + usage(); + exit(EXIT_FAILURE); + } + fp = fopen(optarg, "wb"); + if (fp == NULL) { + fprintf(stderr, "Can not open \"%s\"\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (!file && !dir) { + fprintf(stderr, "Must specify either -F or -D\n"); + usage(); + exit(EXIT_FAILURE); + } + + if (dir) { + pc = android_device_dirs; + end = &android_device_dirs[sizeof(android_device_dirs) / sizeof(android_device_dirs[0])]; + } else { + pc = android_device_files; + end = &android_device_files[sizeof(android_device_files) / sizeof(android_device_files[0])]; + } + for(; (pc < end) && pc->prefix; pc++) { + char buffer[512]; + ssize_t len = fs_config_generate(buffer, sizeof(buffer), pc); + if (len < 0) { + fprintf(stderr, "Entry too large\n"); + exit(EXIT_FAILURE); + } + if (fwrite(buffer, 1, len, fp) != (size_t)len) { + fprintf(stderr, "Write failure\n"); + exit(EXIT_FAILURE); + } + } + fclose(fp); + + return 0; +} diff --git a/tools/fs_get_stats/Android.mk b/tools/fs_get_stats/Android.mk index c9b4a05..4501c1f 100644 --- a/tools/fs_get_stats/Android.mk +++ b/tools/fs_get_stats/Android.mk @@ -6,4 +6,6 @@ LOCAL_SRC_FILES := fs_get_stats.c LOCAL_MODULE := fs_get_stats +LOCAL_SHARED_LIBRARIES := libcutils liblog + include $(BUILD_HOST_EXECUTABLE) diff --git a/tools/post_process_props.py b/tools/post_process_props.py index 030826d..fa6106f 100755 --- a/tools/post_process_props.py +++ b/tools/post_process_props.py @@ -56,8 +56,6 @@ def validate(prop): """ check_pass = True buildprops = prop.to_dict() - dev_build = buildprops.get("ro.build.version.incremental", - "").startswith("eng") for key, value in buildprops.iteritems(): # Check build properties' length. if len(key) > PROP_NAME_MAX: @@ -66,19 +64,10 @@ def validate(prop): (key, PROP_NAME_MAX)) sys.stderr.write("%s (%d)\n" % (key, len(key))) if len(value) > PROP_VALUE_MAX: - # If dev build, show a warning message, otherwise fail the - # build with error message - if dev_build: - sys.stderr.write("warning: %s exceeds %d bytes: " % - (key, PROP_VALUE_MAX)) - sys.stderr.write("%s (%d)\n" % (value, len(value))) - sys.stderr.write("warning: This will cause the %s " % key) - sys.stderr.write("property return as empty at runtime\n") - else: - check_pass = False - sys.stderr.write("error: %s cannot exceed %d bytes: " % - (key, PROP_VALUE_MAX)) - sys.stderr.write("%s (%d)\n" % (value, len(value))) + check_pass = False + sys.stderr.write("error: %s cannot exceed %d bytes: " % + (key, PROP_VALUE_MAX)) + sys.stderr.write("%s (%d)\n" % (value, len(value))) return check_pass class PropFile: diff --git a/tools/product_debug.py b/tools/product_debug.py index 661c5b7..ff2657c 100755 --- a/tools/product_debug.py +++ b/tools/product_debug.py @@ -89,7 +89,6 @@ def main(argv): "PRODUCT_COPY_FILES", "PRODUCT_PACKAGES", "PRODUCT_LOCALES", - "PRODUCT_FACTORY_RAMDISK_MODULES", "PRODUCT_PROPERTY_OVERRIDES", ) diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py index e98e4b6..7984ad6 100755 --- a/tools/releasetools/add_img_to_target_files.py +++ b/tools/releasetools/add_img_to_target_files.py @@ -30,9 +30,6 @@ if sys.hexversion < 0x02070000: import errno import os -import re -import shutil -import subprocess import tempfile import zipfile @@ -58,22 +55,20 @@ def AddSystem(output_zip, prefix="IMAGES/", recovery_img=None, boot_img=None): return def output_sink(fn, data): - ofile = open(os.path.join(OPTIONS.input_tmp,"SYSTEM",fn), "w") - ofile.write(data) - ofile.close() + ofile = open(os.path.join(OPTIONS.input_tmp, "SYSTEM", fn), "w") + ofile.write(data) + ofile.close() if OPTIONS.rebuild_recovery: - print("Building new recovery patch") - common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, boot_img, - info_dict=OPTIONS.info_dict) + print "Building new recovery patch" + common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, recovery_img, + boot_img, info_dict=OPTIONS.info_dict) block_list = common.MakeTempFile(prefix="system-blocklist-", suffix=".map") imgname = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, block_list=block_list) - with open(imgname, "rb") as f: - common.ZipWriteStr(output_zip, prefix + "system.img", f.read()) - with open(block_list, "rb") as f: - common.ZipWriteStr(output_zip, prefix + "system.map", f.read()) + common.ZipWrite(output_zip, imgname, prefix + "system.img") + common.ZipWrite(output_zip, block_list, prefix + "system.map") def BuildSystem(input_dir, info_dict, block_list=None): @@ -93,11 +88,9 @@ def AddVendor(output_zip, prefix="IMAGES/"): block_list = common.MakeTempFile(prefix="vendor-blocklist-", suffix=".map") imgname = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict, - block_list=block_list) - with open(imgname, "rb") as f: - common.ZipWriteStr(output_zip, prefix + "vendor.img", f.read()) - with open(block_list, "rb") as f: - common.ZipWriteStr(output_zip, prefix + "vendor.map", f.read()) + block_list=block_list) + common.ZipWrite(output_zip, imgname, prefix + "vendor.img") + common.ZipWrite(output_zip, block_list, prefix + "vendor.map") def BuildVendor(input_dir, info_dict, block_list=None): @@ -117,18 +110,18 @@ def CreateImage(input_dir, info_dict, what, block_list=None): try: os.symlink(os.path.join(input_dir, what.upper()), os.path.join(input_dir, what)) - except OSError, e: - # bogus error on my mac version? - # File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem - # os.path.join(OPTIONS.input_tmp, "system")) - # OSError: [Errno 17] File exists - if (e.errno == errno.EEXIST): + except OSError as e: + # bogus error on my mac version? + # File "./build/tools/releasetools/img_from_target_files" + # os.path.join(OPTIONS.input_tmp, "system")) + # OSError: [Errno 17] File exists + if e.errno == errno.EEXIST: pass image_props = build_image.ImagePropFromGlobalDict(info_dict, what) fstab = info_dict["fstab"] if fstab: - image_props["fs_type" ] = fstab["/" + what].fs_type + image_props["fs_type"] = fstab["/" + what].fs_type if what == "system": fs_config_prefix = "" @@ -137,16 +130,27 @@ def CreateImage(input_dir, info_dict, what, block_list=None): fs_config = os.path.join( input_dir, "META/" + fs_config_prefix + "filesystem_config.txt") - if not os.path.exists(fs_config): fs_config = None + if not os.path.exists(fs_config): + fs_config = None fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts") - if not os.path.exists(fc_config): fc_config = None + if not os.path.exists(fc_config): + fc_config = None + + # Override values loaded from info_dict. + if fs_config: + image_props["fs_config"] = fs_config + if fc_config: + image_props["selinux_fc"] = fc_config + if block_list: + image_props["block_list"] = block_list + if image_props.get("system_root_image") == "true": + image_props["ramdisk_dir"] = os.path.join(input_dir, "BOOT/RAMDISK") + image_props["ramdisk_fs_config"] = os.path.join( + input_dir, "META/boot_filesystem_config.txt") succ = build_image.BuildImage(os.path.join(input_dir, what), - image_props, img, - fs_config=fs_config, - fc_config=fc_config, - block_list=block_list) + image_props, img) assert succ, "build " + what + ".img image failed" return img @@ -180,7 +184,7 @@ def AddUserdata(output_zip, prefix="IMAGES/"): fstab = OPTIONS.info_dict["fstab"] if fstab: - image_props["fs_type" ] = fstab["/data"].fs_type + image_props["fs_type"] = fstab["/data"].fs_type succ = build_image.BuildImage(user_dir, image_props, img.name) assert succ, "build userdata.img image failed" @@ -217,7 +221,7 @@ def AddCache(output_zip, prefix="IMAGES/"): fstab = OPTIONS.info_dict["fstab"] if fstab: - image_props["fs_type" ] = fstab["/cache"].fs_type + image_props["fs_type"] = fstab["/cache"].fs_type succ = build_image.BuildImage(user_dir, image_props, img.name) assert succ, "build cache.img image failed" @@ -296,8 +300,7 @@ def AddImagesToTargetFiles(filename): output_zip.close() def main(argv): - - def option_handler(o, a): + def option_handler(o, _): if o in ("-a", "--add_missing"): OPTIONS.add_missing = True elif o in ("-r", "--rebuild_recovery",): @@ -306,12 +309,10 @@ def main(argv): return False return True - args = common.ParseOptions(argv, __doc__, - extra_opts="ar", - extra_long_opts=["add_missing", - "rebuild_recovery", - ], - extra_option_handler=option_handler) + args = common.ParseOptions( + argv, __doc__, extra_opts="ar", + extra_long_opts=["add_missing", "rebuild_recovery"], + extra_option_handler=option_handler) if len(args) != 1: @@ -325,7 +326,7 @@ if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) - except common.ExternalError, e: + except common.ExternalError as e: print print " ERROR: %s" % (e,) print diff --git a/tools/releasetools/blockimgdiff.py b/tools/releasetools/blockimgdiff.py index 8b179d5..d549f70 100644 --- a/tools/releasetools/blockimgdiff.py +++ b/tools/releasetools/blockimgdiff.py @@ -20,17 +20,17 @@ import heapq import itertools import multiprocessing import os -import pprint import re import subprocess -import sys import threading import tempfile -from rangelib import * +from rangelib import RangeSet + __all__ = ["EmptyImage", "DataImage", "BlockImageDiff"] + def compute_patch(src, tgt, imgdiff=False): srcfd, srcfile = tempfile.mkstemp(prefix="src-") tgtfd, tgtfile = tempfile.mkstemp(prefix="tgt-") @@ -69,7 +69,16 @@ def compute_patch(src, tgt, imgdiff=False): except OSError: pass -class EmptyImage(object): + +class Image(object): + def ReadRangeSet(self, ranges): + raise NotImplementedError + + def TotalSha1(self): + raise NotImplementedError + + +class EmptyImage(Image): """A zero-length image.""" blocksize = 4096 care_map = RangeSet() @@ -81,7 +90,7 @@ class EmptyImage(object): return sha1().hexdigest() -class DataImage(object): +class DataImage(Image): """An image wrapped around a single string of data.""" def __init__(self, data, trim=False, pad=False): @@ -126,9 +135,7 @@ class DataImage(object): return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges] def TotalSha1(self): - if not hasattr(self, "sha1"): - self.sha1 = sha1(self.data).hexdigest() - return self.sha1 + return sha1(self.data).hexdigest() class Transfer(object): @@ -140,8 +147,11 @@ class Transfer(object): self.style = style self.intact = (getattr(tgt_ranges, "monotonic", False) and getattr(src_ranges, "monotonic", False)) - self.goes_before = {} - self.goes_after = {} + + # We use OrderedDict rather than dict so that the output is repeatable; + # otherwise it would depend on the hash values of the Transfer objects. + self.goes_before = OrderedDict() + self.goes_after = OrderedDict() self.stash_before = [] self.use_stash = [] @@ -193,9 +203,13 @@ class BlockImageDiff(object): def __init__(self, tgt, src=None, threads=None, version=2): if threads is None: threads = multiprocessing.cpu_count() // 2 - if threads == 0: threads = 1 + if threads == 0: + threads = 1 self.threads = threads self.version = version + self.transfers = [] + self.src_basenames = {} + self.src_numpatterns = {} assert version in (1, 2) @@ -244,6 +258,15 @@ class BlockImageDiff(object): self.ComputePatches(prefix) self.WriteTransfers(prefix) + def HashBlocks(self, source, ranges): # pylint: disable=no-self-use + data = source.ReadRangeSet(ranges) + ctx = sha1() + + for p in data: + ctx.update(p) + + return ctx.hexdigest() + def WriteTransfers(self, prefix): out = [] @@ -277,9 +300,11 @@ class BlockImageDiff(object): if stashed_blocks > max_stashed_blocks: max_stashed_blocks = stashed_blocks + free_string = [] + if self.version == 1: - src_string = xf.src_ranges.to_string_raw() - elif self.version == 2: + src_str = xf.src_ranges.to_string_raw() + elif self.version >= 2: # <# blocks> <src ranges> # OR @@ -288,7 +313,7 @@ class BlockImageDiff(object): # <# blocks> - <stash refs...> size = xf.src_ranges.size() - src_string = [str(size)] + src_str = [str(size)] unstashed_src_ranges = xf.src_ranges mapped_stashes = [] @@ -298,21 +323,29 @@ class BlockImageDiff(object): unstashed_src_ranges = unstashed_src_ranges.subtract(sr) sr = xf.src_ranges.map_within(sr) mapped_stashes.append(sr) - src_string.append("%d:%s" % (sid, sr.to_string_raw())) + if self.version == 2: + src_str.append("%d:%s" % (sid, sr.to_string_raw())) + else: + assert sh in stashes + src_str.append("%s:%s" % (sh, sr.to_string_raw())) + stashes[sh] -= 1 + if stashes[sh] == 0: + free_string.append("free %s\n" % (sh)) + stashes.pop(sh) heapq.heappush(free_stash_ids, sid) if unstashed_src_ranges: - src_string.insert(1, unstashed_src_ranges.to_string_raw()) + src_str.insert(1, unstashed_src_ranges.to_string_raw()) if xf.use_stash: mapped_unstashed = xf.src_ranges.map_within(unstashed_src_ranges) - src_string.insert(2, mapped_unstashed.to_string_raw()) + src_str.insert(2, mapped_unstashed.to_string_raw()) mapped_stashes.append(mapped_unstashed) self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) else: - src_string.insert(1, "-") + src_str.insert(1, "-") self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) - src_string = " ".join(src_string) + src_str = " ".join(src_str) # both versions: # zero <rangeset> @@ -325,9 +358,14 @@ class BlockImageDiff(object): # move <src rangeset> <tgt rangeset> # # version 2: - # bsdiff patchstart patchlen <tgt rangeset> <src_string> - # imgdiff patchstart patchlen <tgt rangeset> <src_string> - # move <tgt rangeset> <src_string> + # bsdiff patchstart patchlen <tgt rangeset> <src_str> + # imgdiff patchstart patchlen <tgt rangeset> <src_str> + # move <tgt rangeset> <src_str> + # + # version 3: + # bsdiff patchstart patchlen srchash tgthash <tgt rangeset> <src_str> + # imgdiff patchstart patchlen srchash tgthash <tgt rangeset> <src_str> + # move hash <tgt rangeset> <src_str> tgt_size = xf.tgt_ranges.size() @@ -347,7 +385,18 @@ class BlockImageDiff(object): elif self.version == 2: out.append("%s %s %s\n" % ( xf.style, - xf.tgt_ranges.to_string_raw(), src_string)) + xf.tgt_ranges.to_string_raw(), src_str)) + elif self.version >= 3: + # take into account automatic stashing of overlapping blocks + if xf.src_ranges.overlaps(xf.tgt_ranges): + temp_stash_usage = stashed_blocks + xf.src_ranges.size(); + if temp_stash_usage > max_stashed_blocks: + max_stashed_blocks = temp_stash_usage + + out.append("%s %s %s %s\n" % ( + xf.style, + self.HashBlocks(self.tgt, xf.tgt_ranges), + xf.tgt_ranges.to_string_raw(), src_str)) total += tgt_size elif xf.style in ("bsdiff", "imgdiff"): performs_read = True @@ -360,7 +409,20 @@ class BlockImageDiff(object): elif self.version == 2: out.append("%s %d %d %s %s\n" % ( xf.style, xf.patch_start, xf.patch_len, - xf.tgt_ranges.to_string_raw(), src_string)) + xf.tgt_ranges.to_string_raw(), src_str)) + elif self.version >= 3: + # take into account automatic stashing of overlapping blocks + if xf.src_ranges.overlaps(xf.tgt_ranges): + temp_stash_usage = stashed_blocks + xf.src_ranges.size(); + if temp_stash_usage > max_stashed_blocks: + max_stashed_blocks = temp_stash_usage + + out.append("%s %d %d %s %s %s %s\n" % ( + xf.style, + xf.patch_start, xf.patch_len, + self.HashBlocks(self.src, xf.src_ranges), + self.HashBlocks(self.tgt, xf.tgt_ranges), + xf.tgt_ranges.to_string_raw(), src_str)) total += tgt_size elif xf.style == "zero": assert xf.tgt_ranges @@ -369,8 +431,10 @@ class BlockImageDiff(object): out.append("%s %s\n" % (xf.style, to_zero.to_string_raw())) total += to_zero.size() else: - raise ValueError, "unknown transfer style '%s'\n" % (xf.style,) + raise ValueError("unknown transfer style '%s'\n" % xf.style) + if free_string: + out.append("".join(free_string)) # sanity check: abort if we're going to need more than 512 MB if # stash space @@ -476,11 +540,13 @@ class BlockImageDiff(object): patches = [None] * patch_num + # TODO: Rewrite with multiprocessing.ThreadPool? lock = threading.Lock() def diff_worker(): while True: with lock: - if not diff_q: return + if not diff_q: + return tgt_size, src, tgt, xf, patchnum = diff_q.pop() patch = compute_patch(src, tgt, imgdiff=(xf.style == "imgdiff")) size = len(patch) @@ -492,7 +558,7 @@ class BlockImageDiff(object): xf.tgt_name + " (from " + xf.src_name + ")"))) threads = [threading.Thread(target=diff_worker) - for i in range(self.threads)] + for _ in range(self.threads)] for th in threads: th.start() while threads: @@ -619,8 +685,6 @@ class BlockImageDiff(object): stash_size = 0 for xf in self.transfers: - lost = 0 - size = xf.src_ranges.size() for u in xf.goes_before.copy(): # xf should go before u if xf.order < u.order: @@ -686,7 +750,8 @@ class BlockImageDiff(object): # Put all sinks at the end of the sequence. while True: sinks = [u for u in G if not u.outgoing] - if not sinks: break + if not sinks: + break for u in sinks: s2.appendleft(u) del G[u] @@ -696,14 +761,16 @@ class BlockImageDiff(object): # Put all the sources at the beginning of the sequence. while True: sources = [u for u in G if not u.incoming] - if not sources: break + if not sources: + break for u in sources: s1.append(u) del G[u] for iu in u.outgoing: del iu.incoming[u] - if not G: break + if not G: + break # Find the "best" vertex to put next. "Best" is the one that # maximizes the net difference in source blocks saved we get by @@ -741,7 +808,8 @@ class BlockImageDiff(object): print("Generating digraph...") for a in self.transfers: for b in self.transfers: - if a is b: continue + if a is b: + continue # If the blocks written by A are read by B, then B needs to go before A. i = a.tgt_ranges.intersect(b.src_ranges) @@ -756,7 +824,6 @@ class BlockImageDiff(object): a.goes_after[b] = size def FindTransfers(self): - self.transfers = [] empty = RangeSet() for tgt_fn, tgt_ranges in self.tgt.file_map.items(): if tgt_fn == "__ZERO": @@ -796,9 +863,6 @@ class BlockImageDiff(object): Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) def AbbreviateSourceNames(self): - self.src_basenames = {} - self.src_numpatterns = {} - for k in self.src.file_map.keys(): b = os.path.basename(k) self.src_basenames[b] = k diff --git a/tools/releasetools/build_image.py b/tools/releasetools/build_image.py index a45f50f..033ade9 100755 --- a/tools/releasetools/build_image.py +++ b/tools/releasetools/build_image.py @@ -72,14 +72,15 @@ def AdjustPartitionSizeForVerity(partition_size): """ success, verity_tree_size = GetVerityTreeSize(partition_size) if not success: - return 0; + return 0 success, verity_metadata_size = GetVerityMetadataSize(partition_size) if not success: return 0 return partition_size - verity_tree_size - verity_metadata_size def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict): - cmd = ("build_verity_tree -A %s %s %s" % (FIXED_SALT, sparse_image_path, verity_image_path)) + cmd = "build_verity_tree -A %s %s %s" % ( + FIXED_SALT, sparse_image_path, verity_image_path) print cmd status, output = commands.getstatusoutput(cmd) if status: @@ -92,14 +93,10 @@ def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict): def BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt, block_device, signer_path, key): - cmd = ("system/extras/verity/build_verity_metadata.py %s %s %s %s %s %s %s" % - (image_size, - verity_metadata_path, - root_hash, - salt, - block_device, - signer_path, - key)) + cmd_template = ( + "system/extras/verity/build_verity_metadata.py %s %s %s %s %s %s %s") + cmd = cmd_template % (image_size, verity_metadata_path, root_hash, salt, + block_device, signer_path, key) print cmd status, output = commands.getstatusoutput(cmd) if status: @@ -125,10 +122,13 @@ def Append2Simg(sparse_image_path, unsparse_image_path, error_message): return False return True -def BuildVerifiedImage(data_image_path, verity_image_path, verity_metadata_path): - if not Append2Simg(data_image_path, verity_metadata_path, "Could not append verity metadata!"): +def BuildVerifiedImage(data_image_path, verity_image_path, + verity_metadata_path): + if not Append2Simg(data_image_path, verity_metadata_path, + "Could not append verity metadata!"): return False - if not Append2Simg(data_image_path, verity_image_path, "Could not append verity tree!"): + if not Append2Simg(data_image_path, verity_image_path, + "Could not append verity tree!"): return False return True @@ -153,7 +153,8 @@ def MakeVerityEnabledImage(out_file, prop_dict): Args: out_file: the location to write the verifiable image at - prop_dict: a dictionary of properties required for image creation and verification + prop_dict: a dictionary of properties required for image creation and + verification Returns: True on success, False otherwise. """ @@ -178,13 +179,8 @@ def MakeVerityEnabledImage(out_file, prop_dict): # build the metadata blocks root_hash = prop_dict["verity_root_hash"] salt = prop_dict["verity_salt"] - if not BuildVerityMetadata(image_size, - verity_metadata_path, - root_hash, - salt, - block_dev, - signer_path, - signer_key): + if not BuildVerityMetadata(image_size, verity_metadata_path, root_hash, salt, + block_dev, signer_path, signer_key): shutil.rmtree(tempdir_name, ignore_errors=True) return False @@ -198,33 +194,51 @@ def MakeVerityEnabledImage(out_file, prop_dict): shutil.rmtree(tempdir_name, ignore_errors=True) return True -def BuildImage(in_dir, prop_dict, out_file, - fs_config=None, - fc_config=None, - block_list=None): +def BuildImage(in_dir, prop_dict, out_file): """Build an image to out_file from in_dir with property prop_dict. Args: in_dir: path of input directory. prop_dict: property dictionary. out_file: path of the output image file. - fs_config: path to the fs_config file (typically - META/filesystem_config.txt). If None then the configuration in - the local client will be used. - fc_config: path to the SELinux file_contexts file. If None then - the value from prop_dict['selinux_fc'] will be used. Returns: True iff the image is built successfully. """ + # system_root_image=true: build a system.img that combines the contents of /system + # and the ramdisk, and can be mounted at the root of the file system. + origin_in = in_dir + fs_config = prop_dict.get("fs_config") + if (prop_dict.get("system_root_image") == "true" + and prop_dict["mount_point"] == "system"): + in_dir = tempfile.mkdtemp() + # Change the mount point to "/" + prop_dict["mount_point"] = "/" + if fs_config: + # We need to merge the fs_config files of system and ramdisk. + fd, merged_fs_config = tempfile.mkstemp(prefix="root_fs_config", + suffix=".txt") + os.close(fd) + with open(merged_fs_config, "w") as fw: + if "ramdisk_fs_config" in prop_dict: + with open(prop_dict["ramdisk_fs_config"]) as fr: + fw.writelines(fr.readlines()) + with open(fs_config) as fr: + fw.writelines(fr.readlines()) + fs_config = merged_fs_config + build_command = [] fs_type = prop_dict.get("fs_type", "") run_fsck = False + fs_spans_partition = True + if fs_type.startswith("squash"): + fs_spans_partition = False + is_verity_partition = "verity_block_device" in prop_dict verity_supported = prop_dict.get("verity") == "true" # adjust the partition size to make room for the hashes if this is to be verified - if verity_supported and is_verity_partition: + if verity_supported and is_verity_partition and fs_spans_partition: partition_size = int(prop_dict.get("partition_size")) adjusted_size = AdjustPartitionSizeForVerity(partition_size) if not adjusted_size: @@ -244,22 +258,19 @@ def BuildImage(in_dir, prop_dict, out_file, build_command.extend(["-j", prop_dict["journal_size"]]) if "timestamp" in prop_dict: build_command.extend(["-T", str(prop_dict["timestamp"])]) - if fs_config is not None: + if fs_config: build_command.extend(["-C", fs_config]) - if block_list is not None: - build_command.extend(["-B", block_list]) - if fc_config is not None: - build_command.append(fc_config) - elif "selinux_fc" in prop_dict: + if "block_list" in prop_dict: + build_command.extend(["-B", prop_dict["block_list"]]) + build_command.extend(["-L", prop_dict["mount_point"]]) + if "selinux_fc" in prop_dict: build_command.append(prop_dict["selinux_fc"]) elif fs_type.startswith("squash"): build_command = ["mksquashfsimage.sh"] build_command.extend([in_dir, out_file]) build_command.extend(["-s"]) build_command.extend(["-m", prop_dict["mount_point"]]) - if fc_config is not None: - build_command.extend(["-c", fc_config]) - elif "selinux_fc" in prop_dict: + if "selinux_fc" in prop_dict: build_command.extend(["-c", prop_dict["selinux_fc"]]) if "squashfs_compressor" in prop_dict: build_command.extend(["-z", prop_dict["squashfs_compressor"]]) @@ -278,10 +289,40 @@ def BuildImage(in_dir, prop_dict, out_file, build_command.append(prop_dict["selinux_fc"]) build_command.append(prop_dict["mount_point"]) - exit_code = RunCommand(build_command) + if in_dir != origin_in: + # Construct a staging directory of the root file system. + ramdisk_dir = prop_dict.get("ramdisk_dir") + if ramdisk_dir: + shutil.rmtree(in_dir) + shutil.copytree(ramdisk_dir, in_dir, symlinks=True) + staging_system = os.path.join(in_dir, "system") + shutil.rmtree(staging_system, ignore_errors=True) + shutil.copytree(origin_in, staging_system, symlinks=True) + try: + exit_code = RunCommand(build_command) + finally: + if in_dir != origin_in: + # Clean up temporary directories and files. + shutil.rmtree(in_dir, ignore_errors=True) + if fs_config: + os.remove(fs_config) if exit_code != 0: return False + if not fs_spans_partition: + mount_point = prop_dict.get("mount_point") + partition_size = int(prop_dict.get("partition_size")) + image_size = os.stat(out_file).st_size + if image_size > partition_size: + print "Error: %s image size of %d is larger than partition size of %d" % (mount_point, image_size, partition_size) + return False + if verity_supported and is_verity_partition: + if 2 * image_size - AdjustPartitionSizeForVerity(image_size) > partition_size: + print "Error: No more room on %s to fit verity data" % mount_point + return False + prop_dict["original_partition_size"] = prop_dict["partition_size"] + prop_dict["partition_size"] = str(image_size) + # create the verified image if this is to be verified if verity_supported and is_verity_partition: if not MakeVerityEnabledImage(out_file, prop_dict): @@ -333,11 +374,14 @@ def ImagePropFromGlobalDict(glob_dict, mount_point): d["mount_point"] = mount_point if mount_point == "system": copy_prop("fs_type", "fs_type") - # Copy the generic sysetem fs type first, override with specific one if available. + # Copy the generic sysetem fs type first, override with specific one if + # available. copy_prop("system_fs_type", "fs_type") copy_prop("system_size", "partition_size") copy_prop("system_journal_size", "journal_size") copy_prop("system_verity_block_device", "verity_block_device") + copy_prop("system_root_image","system_root_image") + copy_prop("ramdisk_dir","ramdisk_dir") copy_prop("system_squashfs_compressor", "squashfs_compressor") copy_prop("system_squashfs_compressor_opt", "squashfs_compressor_opt") elif mount_point == "data": @@ -408,7 +452,8 @@ def main(argv): image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) if not BuildImage(in_dir, image_properties, out_file): - print >> sys.stderr, "error: failed to build %s from %s" % (out_file, in_dir) + print >> sys.stderr, "error: failed to build %s from %s" % (out_file, + in_dir) exit(1) diff --git a/tools/releasetools/check_target_files_signatures b/tools/releasetools/check_target_files_signatures index b2f46c1..9f62aa3 100755..120000 --- a/tools/releasetools/check_target_files_signatures +++ b/tools/releasetools/check_target_files_signatures @@ -1,441 +1 @@ -#!/usr/bin/env python -# -# 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. - -""" -Check the signatures of all APKs in a target_files .zip file. With --c, compare the signatures of each package to the ones in a separate -target_files (usually a previously distributed build for the same -device) and flag any changes. - -Usage: check_target_file_signatures [flags] target_files - - -c (--compare_with) <other_target_files> - Look for compatibility problems between the two sets of target - files (eg., packages whose keys have changed). - - -l (--local_cert_dirs) <dir,dir,...> - Comma-separated list of top-level directories to scan for - .x509.pem files. Defaults to "vendor,build". Where cert files - can be found that match APK signatures, the filename will be - printed as the cert name, otherwise a hash of the cert plus its - subject string will be printed instead. - - -t (--text) - Dump the certificate information for both packages in comparison - mode (this output is normally suppressed). - -""" - -import sys - -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." - sys.exit(1) - -import os -import re -import shutil -import subprocess -import tempfile -import zipfile - -try: - from hashlib import sha1 as sha1 -except ImportError: - from sha import sha as sha1 - -import common - -# Work around a bug in python's zipfile module that prevents opening -# of zipfiles if any entry has an extra field of between 1 and 3 bytes -# (which is common with zipaligned APKs). This overrides the -# ZipInfo._decodeExtra() method (which contains the bug) with an empty -# version (since we don't need to decode the extra field anyway). -class MyZipInfo(zipfile.ZipInfo): - def _decodeExtra(self): - pass -zipfile.ZipInfo = MyZipInfo - -OPTIONS = common.OPTIONS - -OPTIONS.text = False -OPTIONS.compare_with = None -OPTIONS.local_cert_dirs = ("vendor", "build") - -PROBLEMS = [] -PROBLEM_PREFIX = [] - -def AddProblem(msg): - PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) -def Push(msg): - PROBLEM_PREFIX.append(msg) -def Pop(): - PROBLEM_PREFIX.pop() - - -def Banner(msg): - print "-" * 70 - print " ", msg - print "-" * 70 - - -def GetCertSubject(cert): - p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - out, err = p.communicate(cert) - if err and not err.strip(): - return "(error reading cert subject)" - for line in out.split("\n"): - line = line.strip() - if line.startswith("Subject:"): - return line[8:].strip() - return "(unknown cert subject)" - - -class CertDB(object): - def __init__(self): - self.certs = {} - - def Add(self, cert, name=None): - if cert in self.certs: - if name: - self.certs[cert] = self.certs[cert] + "," + name - else: - if name is None: - name = "unknown cert %s (%s)" % (common.sha1(cert).hexdigest()[:12], - GetCertSubject(cert)) - self.certs[cert] = name - - def Get(self, cert): - """Return the name for a given cert.""" - return self.certs.get(cert, None) - - def FindLocalCerts(self): - to_load = [] - for top in OPTIONS.local_cert_dirs: - for dirpath, dirnames, filenames in os.walk(top): - certs = [os.path.join(dirpath, i) - for i in filenames if i.endswith(".x509.pem")] - if certs: - to_load.extend(certs) - - for i in to_load: - f = open(i) - cert = common.ParseCertificate(f.read()) - f.close() - name, _ = os.path.splitext(i) - name, _ = os.path.splitext(name) - self.Add(cert, name) - -ALL_CERTS = CertDB() - - -def CertFromPKCS7(data, filename): - """Read the cert out of a PKCS#7-format file (which is what is - stored in a signed .apk).""" - Push(filename + ":") - try: - p = common.Run(["openssl", "pkcs7", - "-inform", "DER", - "-outform", "PEM", - "-print_certs"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - out, err = p.communicate(data) - if err and not err.strip(): - AddProblem("error reading cert:\n" + err) - return None - - cert = common.ParseCertificate(out) - if not cert: - AddProblem("error parsing cert output") - return None - return cert - finally: - Pop() - - -class APK(object): - def __init__(self, full_filename, filename): - self.filename = filename - Push(filename+":") - try: - self.RecordCerts(full_filename) - self.ReadManifest(full_filename) - finally: - Pop() - - def RecordCerts(self, full_filename): - out = set() - try: - f = open(full_filename) - apk = zipfile.ZipFile(f, "r") - pkcs7 = None - for info in apk.infolist(): - if info.filename.startswith("META-INF/") and \ - (info.filename.endswith(".DSA") or info.filename.endswith(".RSA")): - pkcs7 = apk.read(info.filename) - cert = CertFromPKCS7(pkcs7, info.filename) - out.add(cert) - ALL_CERTS.Add(cert) - if not pkcs7: - AddProblem("no signature") - finally: - f.close() - self.certs = frozenset(out) - - def ReadManifest(self, full_filename): - p = common.Run(["aapt", "dump", "xmltree", full_filename, - "AndroidManifest.xml"], - stdout=subprocess.PIPE) - manifest, err = p.communicate() - if err: - AddProblem("failed to read manifest") - return - - self.shared_uid = None - self.package = None - - for line in manifest.split("\n"): - line = line.strip() - m = re.search('A: (\S*?)(?:\(0x[0-9a-f]+\))?="(.*?)" \(Raw', line) - if m: - name = m.group(1) - if name == "android:sharedUserId": - if self.shared_uid is not None: - AddProblem("multiple sharedUserId declarations") - self.shared_uid = m.group(2) - elif name == "package": - if self.package is not None: - AddProblem("multiple package declarations") - self.package = m.group(2) - - if self.package is None: - AddProblem("no package declaration") - - -class TargetFiles(object): - def __init__(self): - self.max_pkg_len = 30 - self.max_fn_len = 20 - - def LoadZipFile(self, filename): - d, z = common.UnzipTemp(filename, '*.apk') - try: - self.apks = {} - self.apks_by_basename = {} - for dirpath, dirnames, filenames in os.walk(d): - for fn in filenames: - if fn.endswith(".apk"): - fullname = os.path.join(dirpath, fn) - displayname = fullname[len(d)+1:] - apk = APK(fullname, displayname) - self.apks[apk.package] = apk - self.apks_by_basename[os.path.basename(apk.filename)] = apk - - self.max_pkg_len = max(self.max_pkg_len, len(apk.package)) - self.max_fn_len = max(self.max_fn_len, len(apk.filename)) - finally: - shutil.rmtree(d) - - self.certmap = common.ReadApkCerts(z) - z.close() - - def CheckSharedUids(self): - """Look for any instances where packages signed with different - certs request the same sharedUserId.""" - apks_by_uid = {} - for apk in self.apks.itervalues(): - if apk.shared_uid: - apks_by_uid.setdefault(apk.shared_uid, []).append(apk) - - for uid in sorted(apks_by_uid.keys()): - apks = apks_by_uid[uid] - for apk in apks[1:]: - if apk.certs != apks[0].certs: - break - else: - # all packages have the same set of certs; this uid is fine. - continue - - AddProblem("different cert sets for packages with uid %s" % (uid,)) - - print "uid %s is shared by packages with different cert sets:" % (uid,) - for apk in apks: - print "%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename) - for cert in apk.certs: - print " ", ALL_CERTS.Get(cert) - print - - def CheckExternalSignatures(self): - for apk_filename, certname in self.certmap.iteritems(): - if certname == "EXTERNAL": - # Apps marked EXTERNAL should be signed with the test key - # during development, then manually re-signed after - # predexopting. Consider it an error if this app is now - # signed with any key that is present in our tree. - apk = self.apks_by_basename[apk_filename] - name = ALL_CERTS.Get(apk.cert) - if not name.startswith("unknown "): - Push(apk.filename) - AddProblem("hasn't been signed with EXTERNAL cert") - Pop() - - def PrintCerts(self): - """Display a table of packages grouped by cert.""" - by_cert = {} - for apk in self.apks.itervalues(): - for cert in apk.certs: - by_cert.setdefault(cert, []).append((apk.package, apk)) - - order = [(-len(v), k) for (k, v) in by_cert.iteritems()] - order.sort() - - for _, cert in order: - print "%s:" % (ALL_CERTS.Get(cert),) - apks = by_cert[cert] - apks.sort() - for _, apk in apks: - if apk.shared_uid: - print " %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, - self.max_pkg_len, apk.package, - apk.shared_uid) - else: - print " %-*s %-*s" % (self.max_fn_len, apk.filename, - self.max_pkg_len, apk.package) - print - - def CompareWith(self, other): - """Look for instances where a given package that exists in both - self and other have different certs.""" - - all = set(self.apks.keys()) - all.update(other.apks.keys()) - - max_pkg_len = max(self.max_pkg_len, other.max_pkg_len) - - by_certpair = {} - - for i in all: - if i in self.apks: - if i in other.apks: - # in both; should have same set of certs - if self.apks[i].certs != other.apks[i].certs: - by_certpair.setdefault((other.apks[i].certs, - self.apks[i].certs), []).append(i) - else: - print "%s [%s]: new APK (not in comparison target_files)" % ( - i, self.apks[i].filename) - else: - if i in other.apks: - print "%s [%s]: removed APK (only in comparison target_files)" % ( - i, other.apks[i].filename) - - if by_certpair: - AddProblem("some APKs changed certs") - Banner("APK signing differences") - for (old, new), packages in sorted(by_certpair.items()): - for i, o in enumerate(old): - if i == 0: - print "was", ALL_CERTS.Get(o) - else: - print " ", ALL_CERTS.Get(o) - for i, n in enumerate(new): - if i == 0: - print "now", ALL_CERTS.Get(n) - else: - print " ", ALL_CERTS.Get(n) - for i in sorted(packages): - old_fn = other.apks[i].filename - new_fn = self.apks[i].filename - if old_fn == new_fn: - print " %-*s [%s]" % (max_pkg_len, i, old_fn) - else: - print " %-*s [was: %s; now: %s]" % (max_pkg_len, i, - old_fn, new_fn) - print - - -def main(argv): - def option_handler(o, a): - if o in ("-c", "--compare_with"): - OPTIONS.compare_with = a - elif o in ("-l", "--local_cert_dirs"): - OPTIONS.local_cert_dirs = [i.strip() for i in a.split(",")] - elif o in ("-t", "--text"): - OPTIONS.text = True - else: - return False - return True - - args = common.ParseOptions(argv, __doc__, - extra_opts="c:l:t", - extra_long_opts=["compare_with=", - "local_cert_dirs="], - extra_option_handler=option_handler) - - if len(args) != 1: - common.Usage(__doc__) - sys.exit(1) - - ALL_CERTS.FindLocalCerts() - - Push("input target_files:") - try: - target_files = TargetFiles() - target_files.LoadZipFile(args[0]) - finally: - Pop() - - compare_files = None - if OPTIONS.compare_with: - Push("comparison target_files:") - try: - compare_files = TargetFiles() - compare_files.LoadZipFile(OPTIONS.compare_with) - finally: - Pop() - - if OPTIONS.text or not compare_files: - Banner("target files") - target_files.PrintCerts() - target_files.CheckSharedUids() - target_files.CheckExternalSignatures() - if compare_files: - if OPTIONS.text: - Banner("comparison files") - compare_files.PrintCerts() - target_files.CompareWith(compare_files) - - if PROBLEMS: - print "%d problem(s) found:\n" % (len(PROBLEMS),) - for p in PROBLEMS: - print p - return 1 - - return 0 - - -if __name__ == '__main__': - try: - r = main(sys.argv[1:]) - sys.exit(r) - except common.ExternalError, e: - print - print " ERROR: %s" % (e,) - print - sys.exit(1) +check_target_files_signatures.py
\ No newline at end of file diff --git a/tools/releasetools/check_target_files_signatures.py b/tools/releasetools/check_target_files_signatures.py new file mode 100755 index 0000000..dd57033 --- /dev/null +++ b/tools/releasetools/check_target_files_signatures.py @@ -0,0 +1,442 @@ +#!/usr/bin/env python +# +# 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. + +""" +Check the signatures of all APKs in a target_files .zip file. With +-c, compare the signatures of each package to the ones in a separate +target_files (usually a previously distributed build for the same +device) and flag any changes. + +Usage: check_target_file_signatures [flags] target_files + + -c (--compare_with) <other_target_files> + Look for compatibility problems between the two sets of target + files (eg., packages whose keys have changed). + + -l (--local_cert_dirs) <dir,dir,...> + Comma-separated list of top-level directories to scan for + .x509.pem files. Defaults to "vendor,build". Where cert files + can be found that match APK signatures, the filename will be + printed as the cert name, otherwise a hash of the cert plus its + subject string will be printed instead. + + -t (--text) + Dump the certificate information for both packages in comparison + mode (this output is normally suppressed). + +""" + +import sys + +if sys.hexversion < 0x02070000: + print >> sys.stderr, "Python 2.7 or newer is required." + sys.exit(1) + +import os +import re +import shutil +import subprocess +import zipfile + +import common + +# Work around a bug in python's zipfile module that prevents opening +# of zipfiles if any entry has an extra field of between 1 and 3 bytes +# (which is common with zipaligned APKs). This overrides the +# ZipInfo._decodeExtra() method (which contains the bug) with an empty +# version (since we don't need to decode the extra field anyway). +class MyZipInfo(zipfile.ZipInfo): + def _decodeExtra(self): + pass +zipfile.ZipInfo = MyZipInfo + +OPTIONS = common.OPTIONS + +OPTIONS.text = False +OPTIONS.compare_with = None +OPTIONS.local_cert_dirs = ("vendor", "build") + +PROBLEMS = [] +PROBLEM_PREFIX = [] + +def AddProblem(msg): + PROBLEMS.append(" ".join(PROBLEM_PREFIX) + " " + msg) +def Push(msg): + PROBLEM_PREFIX.append(msg) +def Pop(): + PROBLEM_PREFIX.pop() + + +def Banner(msg): + print "-" * 70 + print " ", msg + print "-" * 70 + + +def GetCertSubject(cert): + p = common.Run(["openssl", "x509", "-inform", "DER", "-text"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + out, err = p.communicate(cert) + if err and not err.strip(): + return "(error reading cert subject)" + for line in out.split("\n"): + line = line.strip() + if line.startswith("Subject:"): + return line[8:].strip() + return "(unknown cert subject)" + + +class CertDB(object): + def __init__(self): + self.certs = {} + + def Add(self, cert, name=None): + if cert in self.certs: + if name: + self.certs[cert] = self.certs[cert] + "," + name + else: + if name is None: + name = "unknown cert %s (%s)" % (common.sha1(cert).hexdigest()[:12], + GetCertSubject(cert)) + self.certs[cert] = name + + def Get(self, cert): + """Return the name for a given cert.""" + return self.certs.get(cert, None) + + def FindLocalCerts(self): + to_load = [] + for top in OPTIONS.local_cert_dirs: + for dirpath, _, filenames in os.walk(top): + certs = [os.path.join(dirpath, i) + for i in filenames if i.endswith(".x509.pem")] + if certs: + to_load.extend(certs) + + for i in to_load: + f = open(i) + cert = common.ParseCertificate(f.read()) + f.close() + name, _ = os.path.splitext(i) + name, _ = os.path.splitext(name) + self.Add(cert, name) + +ALL_CERTS = CertDB() + + +def CertFromPKCS7(data, filename): + """Read the cert out of a PKCS#7-format file (which is what is + stored in a signed .apk).""" + Push(filename + ":") + try: + p = common.Run(["openssl", "pkcs7", + "-inform", "DER", + "-outform", "PEM", + "-print_certs"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + out, err = p.communicate(data) + if err and not err.strip(): + AddProblem("error reading cert:\n" + err) + return None + + cert = common.ParseCertificate(out) + if not cert: + AddProblem("error parsing cert output") + return None + return cert + finally: + Pop() + + +class APK(object): + def __init__(self, full_filename, filename): + self.filename = filename + self.certs = None + self.shared_uid = None + self.package = None + + Push(filename+":") + try: + self.RecordCerts(full_filename) + self.ReadManifest(full_filename) + finally: + Pop() + + def RecordCerts(self, full_filename): + out = set() + try: + f = open(full_filename) + apk = zipfile.ZipFile(f, "r") + pkcs7 = None + for info in apk.infolist(): + if info.filename.startswith("META-INF/") and \ + (info.filename.endswith(".DSA") or info.filename.endswith(".RSA")): + pkcs7 = apk.read(info.filename) + cert = CertFromPKCS7(pkcs7, info.filename) + out.add(cert) + ALL_CERTS.Add(cert) + if not pkcs7: + AddProblem("no signature") + finally: + f.close() + self.certs = frozenset(out) + + def ReadManifest(self, full_filename): + p = common.Run(["aapt", "dump", "xmltree", full_filename, + "AndroidManifest.xml"], + stdout=subprocess.PIPE) + manifest, err = p.communicate() + if err: + AddProblem("failed to read manifest") + return + + self.shared_uid = None + self.package = None + + for line in manifest.split("\n"): + line = line.strip() + m = re.search(r'A: (\S*?)(?:\(0x[0-9a-f]+\))?="(.*?)" \(Raw', line) + if m: + name = m.group(1) + if name == "android:sharedUserId": + if self.shared_uid is not None: + AddProblem("multiple sharedUserId declarations") + self.shared_uid = m.group(2) + elif name == "package": + if self.package is not None: + AddProblem("multiple package declarations") + self.package = m.group(2) + + if self.package is None: + AddProblem("no package declaration") + + +class TargetFiles(object): + def __init__(self): + self.max_pkg_len = 30 + self.max_fn_len = 20 + self.apks = None + self.apks_by_basename = None + self.certmap = None + + def LoadZipFile(self, filename): + d, z = common.UnzipTemp(filename, '*.apk') + try: + self.apks = {} + self.apks_by_basename = {} + for dirpath, _, filenames in os.walk(d): + for fn in filenames: + if fn.endswith(".apk"): + fullname = os.path.join(dirpath, fn) + displayname = fullname[len(d)+1:] + apk = APK(fullname, displayname) + self.apks[apk.package] = apk + self.apks_by_basename[os.path.basename(apk.filename)] = apk + + self.max_pkg_len = max(self.max_pkg_len, len(apk.package)) + self.max_fn_len = max(self.max_fn_len, len(apk.filename)) + finally: + shutil.rmtree(d) + + self.certmap = common.ReadApkCerts(z) + z.close() + + def CheckSharedUids(self): + """Look for any instances where packages signed with different + certs request the same sharedUserId.""" + apks_by_uid = {} + for apk in self.apks.itervalues(): + if apk.shared_uid: + apks_by_uid.setdefault(apk.shared_uid, []).append(apk) + + for uid in sorted(apks_by_uid.keys()): + apks = apks_by_uid[uid] + for apk in apks[1:]: + if apk.certs != apks[0].certs: + break + else: + # all packages have the same set of certs; this uid is fine. + continue + + AddProblem("different cert sets for packages with uid %s" % (uid,)) + + print "uid %s is shared by packages with different cert sets:" % (uid,) + for apk in apks: + print "%-*s [%s]" % (self.max_pkg_len, apk.package, apk.filename) + for cert in apk.certs: + print " ", ALL_CERTS.Get(cert) + print + + def CheckExternalSignatures(self): + for apk_filename, certname in self.certmap.iteritems(): + if certname == "EXTERNAL": + # Apps marked EXTERNAL should be signed with the test key + # during development, then manually re-signed after + # predexopting. Consider it an error if this app is now + # signed with any key that is present in our tree. + apk = self.apks_by_basename[apk_filename] + name = ALL_CERTS.Get(apk.cert) + if not name.startswith("unknown "): + Push(apk.filename) + AddProblem("hasn't been signed with EXTERNAL cert") + Pop() + + def PrintCerts(self): + """Display a table of packages grouped by cert.""" + by_cert = {} + for apk in self.apks.itervalues(): + for cert in apk.certs: + by_cert.setdefault(cert, []).append((apk.package, apk)) + + order = [(-len(v), k) for (k, v) in by_cert.iteritems()] + order.sort() + + for _, cert in order: + print "%s:" % (ALL_CERTS.Get(cert),) + apks = by_cert[cert] + apks.sort() + for _, apk in apks: + if apk.shared_uid: + print " %-*s %-*s [%s]" % (self.max_fn_len, apk.filename, + self.max_pkg_len, apk.package, + apk.shared_uid) + else: + print " %-*s %-*s" % (self.max_fn_len, apk.filename, + self.max_pkg_len, apk.package) + print + + def CompareWith(self, other): + """Look for instances where a given package that exists in both + self and other have different certs.""" + + all_apks = set(self.apks.keys()) + all_apks.update(other.apks.keys()) + + max_pkg_len = max(self.max_pkg_len, other.max_pkg_len) + + by_certpair = {} + + for i in all: + if i in self.apks: + if i in other.apks: + # in both; should have same set of certs + if self.apks[i].certs != other.apks[i].certs: + by_certpair.setdefault((other.apks[i].certs, + self.apks[i].certs), []).append(i) + else: + print "%s [%s]: new APK (not in comparison target_files)" % ( + i, self.apks[i].filename) + else: + if i in other.apks: + print "%s [%s]: removed APK (only in comparison target_files)" % ( + i, other.apks[i].filename) + + if by_certpair: + AddProblem("some APKs changed certs") + Banner("APK signing differences") + for (old, new), packages in sorted(by_certpair.items()): + for i, o in enumerate(old): + if i == 0: + print "was", ALL_CERTS.Get(o) + else: + print " ", ALL_CERTS.Get(o) + for i, n in enumerate(new): + if i == 0: + print "now", ALL_CERTS.Get(n) + else: + print " ", ALL_CERTS.Get(n) + for i in sorted(packages): + old_fn = other.apks[i].filename + new_fn = self.apks[i].filename + if old_fn == new_fn: + print " %-*s [%s]" % (max_pkg_len, i, old_fn) + else: + print " %-*s [was: %s; now: %s]" % (max_pkg_len, i, + old_fn, new_fn) + print + + +def main(argv): + def option_handler(o, a): + if o in ("-c", "--compare_with"): + OPTIONS.compare_with = a + elif o in ("-l", "--local_cert_dirs"): + OPTIONS.local_cert_dirs = [i.strip() for i in a.split(",")] + elif o in ("-t", "--text"): + OPTIONS.text = True + else: + return False + return True + + args = common.ParseOptions(argv, __doc__, + extra_opts="c:l:t", + extra_long_opts=["compare_with=", + "local_cert_dirs="], + extra_option_handler=option_handler) + + if len(args) != 1: + common.Usage(__doc__) + sys.exit(1) + + ALL_CERTS.FindLocalCerts() + + Push("input target_files:") + try: + target_files = TargetFiles() + target_files.LoadZipFile(args[0]) + finally: + Pop() + + compare_files = None + if OPTIONS.compare_with: + Push("comparison target_files:") + try: + compare_files = TargetFiles() + compare_files.LoadZipFile(OPTIONS.compare_with) + finally: + Pop() + + if OPTIONS.text or not compare_files: + Banner("target files") + target_files.PrintCerts() + target_files.CheckSharedUids() + target_files.CheckExternalSignatures() + if compare_files: + if OPTIONS.text: + Banner("comparison files") + compare_files.PrintCerts() + target_files.CompareWith(compare_files) + + if PROBLEMS: + print "%d problem(s) found:\n" % (len(PROBLEMS),) + for p in PROBLEMS: + print p + return 1 + + return 0 + + +if __name__ == '__main__': + try: + r = main(sys.argv[1:]) + sys.exit(r) + except common.ExternalError as e: + print + print " ERROR: %s" % (e,) + print + sys.exit(1) diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 3c1575b..592ed19 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -30,44 +30,45 @@ import time import zipfile import blockimgdiff -from rangelib import * +import rangelib try: from hashlib import sha1 as sha1 except ImportError: from sha import sha as sha1 -# missing in Python 2.4 and before -if not hasattr(os, "SEEK_SET"): - os.SEEK_SET = 0 -class Options(object): pass -OPTIONS = Options() - -DEFAULT_SEARCH_PATH_BY_PLATFORM = { - "linux2": "out/host/linux-x86", - "darwin": "out/host/darwin-x86", +class Options(object): + def __init__(self): + platform_search_path = { + "linux2": "out/host/linux-x86", + "darwin": "out/host/darwin-x86", } -OPTIONS.search_path = DEFAULT_SEARCH_PATH_BY_PLATFORM.get(sys.platform, None) -OPTIONS.signapk_path = "framework/signapk.jar" # Relative to search_path -OPTIONS.extra_signapk_args = [] -OPTIONS.java_path = "java" # Use the one on the path by default. -OPTIONS.java_args = "-Xmx2048m" # JVM Args -OPTIONS.public_key_suffix = ".x509.pem" -OPTIONS.private_key_suffix = ".pk8" -OPTIONS.verbose = False -OPTIONS.tempfiles = [] -OPTIONS.device_specific = None -OPTIONS.extras = {} -OPTIONS.info_dict = None + self.search_path = platform_search_path.get(sys.platform, None) + self.signapk_path = "framework/signapk.jar" # Relative to search_path + self.extra_signapk_args = [] + self.java_path = "java" # Use the one on the path by default. + self.java_args = "-Xmx2048m" # JVM Args + self.public_key_suffix = ".x509.pem" + self.private_key_suffix = ".pk8" + self.verbose = False + self.tempfiles = [] + self.device_specific = None + self.extras = {} + self.info_dict = None + self.worker_threads = None + + +OPTIONS = Options() # Values for "certificate" in apkcerts that mean special things. SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") -class ExternalError(RuntimeError): pass +class ExternalError(RuntimeError): + pass def Run(args, **kwargs): @@ -94,19 +95,19 @@ def CloseInheritedPipes(): pass -def LoadInfoDict(input): +def LoadInfoDict(input_file): """Read and parse the META/misc_info.txt key/value pairs from the input target files and return a dict.""" def read_helper(fn): - if isinstance(input, zipfile.ZipFile): - return input.read(fn) + if isinstance(input_file, zipfile.ZipFile): + return input_file.read(fn) else: - path = os.path.join(input, *fn.split("/")) + path = os.path.join(input_file, *fn.split("/")) try: with open(path) as f: return f.read() - except IOError, e: + except IOError as e: if e.errno == errno.ENOENT: raise KeyError(fn) d = {} @@ -122,14 +123,16 @@ def LoadInfoDict(input): if "mkyaffs2_extra_flags" not in d: try: - d["mkyaffs2_extra_flags"] = read_helper("META/mkyaffs2-extra-flags.txt").strip() + d["mkyaffs2_extra_flags"] = read_helper( + "META/mkyaffs2-extra-flags.txt").strip() except KeyError: # ok if flags don't exist pass if "recovery_api_version" not in d: try: - d["recovery_api_version"] = read_helper("META/recovery-api-version.txt").strip() + d["recovery_api_version"] = read_helper( + "META/recovery-api-version.txt").strip() except KeyError: raise ValueError("can't find recovery API version in input target-files") @@ -146,9 +149,11 @@ def LoadInfoDict(input): try: data = read_helper("META/imagesizes.txt") for line in data.split("\n"): - if not line: continue + if not line: + continue name, value = line.split(" ", 1) - if not value: continue + if not value: + continue if name == "blocksize": d[name] = value else: @@ -186,7 +191,8 @@ def LoadDictionaryFromLines(lines): d = {} for line in lines: line = line.strip() - if not line or line.startswith("#"): continue + if not line or line.startswith("#"): + continue if "=" in line: name, value = line.split("=", 1) d[name] = value @@ -194,7 +200,12 @@ def LoadDictionaryFromLines(lines): def LoadRecoveryFSTab(read_helper, fstab_version): class Partition(object): - pass + def __init__(self, mount_point, fs_type, device, length, device2): + self.mount_point = mount_point + self.fs_type = fs_type + self.device = device + self.length = length + self.device2 = device2 try: data = read_helper("RECOVERY/RAMDISK/etc/recovery.fstab") @@ -206,68 +217,65 @@ def LoadRecoveryFSTab(read_helper, fstab_version): d = {} for line in data.split("\n"): line = line.strip() - if not line or line.startswith("#"): continue + if not line or line.startswith("#"): + continue pieces = line.split() - if not (3 <= len(pieces) <= 4): + if not 3 <= len(pieces) <= 4: raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) - - p = Partition() - p.mount_point = pieces[0] - p.fs_type = pieces[1] - p.device = pieces[2] - p.length = 0 options = None if len(pieces) >= 4: if pieces[3].startswith("/"): - p.device2 = pieces[3] + device2 = pieces[3] if len(pieces) >= 5: options = pieces[4] else: - p.device2 = None + device2 = None options = pieces[3] else: - p.device2 = None + device2 = None + mount_point = pieces[0] + length = 0 if options: options = options.split(",") for i in options: if i.startswith("length="): - p.length = int(i[7:]) + length = int(i[7:]) else: - print "%s: unknown option \"%s\"" % (p.mount_point, i) + print "%s: unknown option \"%s\"" % (mount_point, i) - d[p.mount_point] = p + d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[1], + device=pieces[2], length=length, + device2=device2) elif fstab_version == 2: d = {} for line in data.split("\n"): line = line.strip() - if not line or line.startswith("#"): continue + if not line or line.startswith("#"): + continue pieces = line.split() if len(pieces) != 5: raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) # Ignore entries that are managed by vold options = pieces[4] - if "voldmanaged=" in options: continue + if "voldmanaged=" in options: + continue # It's a good line, parse it - p = Partition() - p.device = pieces[0] - p.mount_point = pieces[1] - p.fs_type = pieces[2] - p.device2 = None - p.length = 0 - + length = 0 options = options.split(",") for i in options: if i.startswith("length="): - p.length = int(i[7:]) + length = int(i[7:]) else: # Ignore all unknown options in the unified fstab continue - d[p.mount_point] = p + mount_point = pieces[1] + d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[2], + device=pieces[0], length=length, device2=None) else: raise ValueError("Unknown fstab_version: \"%d\"" % (fstab_version,)) @@ -279,6 +287,7 @@ def DumpInfoDict(d): for k, v in sorted(d.items()): print "%-25s = (%s) %s" % (k, type(v).__name__, v) + def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): """Take a kernel, cmdline, and ramdisk directory from the input (in 'sourcedir'), and turn them into a boot image. Return the image @@ -305,8 +314,8 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): p2.wait() p1.wait() - assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (targetname,) - assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (targetname,) + assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,) + assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,) # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg" @@ -337,8 +346,14 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): if args and args.strip(): cmd.extend(shlex.split(args)) - cmd.extend(["--ramdisk", ramdisk_img.name, - "--output", img.name]) + img_unsigned = None + if info_dict.get("vboot", None): + img_unsigned = tempfile.NamedTemporaryFile() + cmd.extend(["--ramdisk", ramdisk_img.name, + "--output", img_unsigned.name]) + else: + cmd.extend(["--ramdisk", ramdisk_img.name, + "--output", img.name]) p = Run(cmd, stdout=subprocess.PIPE) p.communicate() @@ -347,11 +362,24 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): if info_dict.get("verity_key", None): path = "/" + os.path.basename(sourcedir).lower() - cmd = ["boot_signer", path, img.name, info_dict["verity_key"] + ".pk8", info_dict["verity_key"] + ".x509.pem", img.name] + cmd = ["boot_signer", path, img.name, info_dict["verity_key"] + ".pk8", + info_dict["verity_key"] + ".x509.pem", img.name] p = Run(cmd, stdout=subprocess.PIPE) p.communicate() assert p.returncode == 0, "boot_signer of %s image failed" % path + # Sign the image if vboot is non-empty. + elif info_dict.get("vboot", None): + path = "/" + os.path.basename(sourcedir).lower() + img_keyblock = tempfile.NamedTemporaryFile() + cmd = [info_dict["vboot_signer_cmd"], info_dict["futility"], + img_unsigned.name, info_dict["vboot_key"] + ".vbpubk", + info_dict["vboot_key"] + ".vbprivk", img_keyblock.name, + img.name] + p = Run(cmd, stdout=subprocess.PIPE) + p.communicate() + assert p.returncode == 0, "vboot_signer of %s image failed" % path + img.seek(os.SEEK_SET, 0) data = img.read() @@ -453,7 +481,7 @@ def GetKeyPasswords(keylist): stdin=devnull.fileno(), stdout=devnull.fileno(), stderr=subprocess.PIPE) - stdout, stderr = p.communicate() + _, stderr = p.communicate() if p.returncode == 0: # Encrypted key with empty string as password. key_passwords[k] = '' @@ -524,20 +552,23 @@ def CheckSize(data, target, info_dict): any, for the given target. Raise exception if the data is too big. Print a warning if the data is nearing the maximum size.""" - if target.endswith(".img"): target = target[:-4] + if target.endswith(".img"): + target = target[:-4] mount_point = "/" + target fs_type = None limit = None if info_dict["fstab"]: - if mount_point == "/userdata": mount_point = "/data" + if mount_point == "/userdata": + mount_point = "/data" p = info_dict["fstab"][mount_point] fs_type = p.fs_type device = p.device if "/" in device: device = device[device.rfind("/")+1:] limit = info_dict.get(device + "_size", None) - if not fs_type or not limit: return + if not fs_type or not limit: + return if fs_type == "yaffs2": # image size should be increased by 1/64th to account for the @@ -562,7 +593,8 @@ def ReadApkCerts(tf_zip): certmap = {} for line in tf_zip.read("META/apkcerts.txt").split("\n"): line = line.strip() - if not line: continue + if not line: + continue m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' r'private_key="(.*)"$', line) if m: @@ -622,13 +654,11 @@ def ParseOptions(argv, "java_path=", "java_args=", "public_key_suffix=", "private_key_suffix=", "device_specific=", "extra="] + list(extra_long_opts)) - except getopt.GetoptError, err: + except getopt.GetoptError as err: Usage(docstring) print "**", str(err), "**" sys.exit(2) - path_specified = False - for o, a in opts: if o in ("-h", "--help"): Usage(docstring) @@ -707,7 +737,8 @@ class PasswordManager(object): if i not in current or not current[i]: missing.append(i) # Are all the passwords already in the file? - if not missing: return current + if not missing: + return current for i in missing: current[i] = "" @@ -721,7 +752,7 @@ class PasswordManager(object): current = self.UpdateAndReadFile(current) - def PromptResult(self, current): + def PromptResult(self, current): # pylint: disable=no-self-use """Prompt the user to enter a value (password) for each key in 'current' whose value is fales. Returns a new dict with all the values. @@ -732,9 +763,10 @@ class PasswordManager(object): result[k] = v else: while True: - result[k] = getpass.getpass("Enter password for %s key> " - % (k,)).strip() - if result[k]: break + result[k] = getpass.getpass( + "Enter password for %s key> " % k).strip() + if result[k]: + break return result def UpdateAndReadFile(self, current): @@ -742,14 +774,13 @@ class PasswordManager(object): return self.PromptResult(current) f = open(self.pwfile, "w") - os.chmod(self.pwfile, 0600) + os.chmod(self.pwfile, 0o600) f.write("# Enter key passwords between the [[[ ]]] brackets.\n") f.write("# (Additional spaces are harmless.)\n\n") first_line = None - sorted = [(not v, k, v) for (k, v) in current.iteritems()] - sorted.sort() - for i, (_, k, v) in enumerate(sorted): + sorted_list = sorted([(not v, k, v) for (k, v) in current.iteritems()]) + for i, (_, k, v) in enumerate(sorted_list): f.write("[[[ %s ]]] %s\n" % (v, k)) if not v and first_line is None: # position cursor on first line with no password. @@ -763,34 +794,76 @@ class PasswordManager(object): def ReadFile(self): result = {} - if self.pwfile is None: return result + if self.pwfile is None: + return result try: f = open(self.pwfile, "r") for line in f: line = line.strip() - if not line or line[0] == '#': continue + if not line or line[0] == '#': + continue m = re.match(r"^\[\[\[\s*(.*?)\s*\]\]\]\s*(\S+)$", line) if not m: print "failed to parse password file: ", line else: result[m.group(2)] = m.group(1) f.close() - except IOError, e: + except IOError as e: if e.errno != errno.ENOENT: print "error reading password file: ", str(e) return result -def ZipWriteStr(zip, filename, data, perms=0644, compression=None): +def ZipWrite(zip_file, filename, arcname=None, perms=0o644, + compress_type=None): + import datetime + + # http://b/18015246 + # Python 2.7's zipfile implementation wrongly thinks that zip64 is required + # for files larger than 2GiB. We can work around this by adjusting their + # limit. Note that `zipfile.writestr()` will not work for strings larger than + # 2GiB. The Python interpreter sometimes rejects strings that large (though + # it isn't clear to me exactly what circumstances cause this). + # `zipfile.write()` must be used directly to work around this. + # + # This mess can be avoided if we port to python3. + saved_zip64_limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = (1 << 32) - 1 + + if compress_type is None: + compress_type = zip_file.compression + if arcname is None: + arcname = filename + + saved_stat = os.stat(filename) + + try: + # `zipfile.write()` doesn't allow us to pass ZipInfo, so just modify the + # file to be zipped and reset it when we're done. + os.chmod(filename, perms) + + # Use a fixed timestamp so the output is repeatable. + epoch = datetime.datetime.fromtimestamp(0) + timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() + os.utime(filename, (timestamp, timestamp)) + + zip_file.write(filename, arcname=arcname, compress_type=compress_type) + finally: + os.chmod(filename, saved_stat.st_mode) + os.utime(filename, (saved_stat.st_atime, saved_stat.st_mtime)) + zipfile.ZIP64_LIMIT = saved_zip64_limit + + +def ZipWriteStr(zip_file, filename, data, perms=0o644, compression=None): # use a fixed timestamp so the output is repeatable. zinfo = zipfile.ZipInfo(filename=filename, date_time=(2009, 1, 1, 0, 0, 0)) if compression is None: - zinfo.compress_type = zip.compression + zinfo.compress_type = zip_file.compression else: zinfo.compress_type = compression zinfo.external_attr = perms << 16 - zip.writestr(zinfo, data) + zip_file.writestr(zinfo, data) class DeviceSpecificParams(object): @@ -805,7 +878,8 @@ class DeviceSpecificParams(object): if self.module is None: path = OPTIONS.device_specific - if not path: return + if not path: + return try: if os.path.isdir(path): info = imp.find_module("releasetools", [path]) @@ -943,7 +1017,8 @@ class Difference(object): err = [] def run(): _, e = p.communicate() - if e: err.append(e) + if e: + err.append(e) th = threading.Thread(target=run) th.start() th.join(timeout=300) # 5 mins @@ -1010,7 +1085,7 @@ def ComputeDifferences(diffs): print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % ( dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name) lock.release() - except Exception, e: + except Exception as e: print e raise @@ -1023,8 +1098,9 @@ def ComputeDifferences(diffs): threads.pop().join() -class BlockDifference: - def __init__(self, partition, tgt, src=None, check_first_block=False, version=None): +class BlockDifference(object): + def __init__(self, partition, tgt, src=None, check_first_block=False, + version=None): self.tgt = tgt self.src = src self.partition = partition @@ -1054,62 +1130,83 @@ class BlockDifference: else: script.Print("Patching %s image after verification." % (self.partition,)) - if progress: script.ShowProgress(progress, 0) + if progress: + script.ShowProgress(progress, 0) self._WriteUpdate(script, output_zip) def WriteVerifyScript(self, script): + partition = self.partition if not self.src: - script.Print("Image %s will be patched unconditionally." % (self.partition,)) + script.Print("Image %s will be patched unconditionally." % (partition,)) else: + if self.version >= 3: + script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || ' + 'block_image_verify("%s", ' + 'package_extract_file("%s.transfer.list"), ' + '"%s.new.dat", "%s.patch.dat")) then') % ( + self.device, self.src.care_map.to_string_raw(), + self.src.TotalSha1(), + self.device, partition, partition, partition)) + else: + script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( + self.device, self.src.care_map.to_string_raw(), + self.src.TotalSha1())) + script.Print('Verified %s image...' % (partition,)) + script.AppendExtra('else') + + # When generating incrementals for the system and vendor partitions, + # explicitly check the first block (which contains the superblock) of + # the partition to see if it's what we expect. If this check fails, + # give an explicit log message about the partition having been + # remounted R/W (the most likely explanation) and the need to flash to + # get OTAs working again. if self.check_first_block: self._CheckFirstBlock(script) - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % - (self.device, self.src.care_map.to_string_raw(), - self.src.TotalSha1())) - script.Print("Verified %s image..." % (self.partition,)) - # Abort the OTA update if it doesn't support resumable OTA (i.e. version<3) - # and the checksum doesn't match the one in the source partition. - if self.version < 3: - script.AppendExtra(('else\n' - ' abort("%s partition has unexpected contents");\n' - 'endif;') % (self.partition)) - else: - script.AppendExtra(('else\n' - ' (range_sha1("%s", "%s") == "%s") ||\n' - ' abort("%s partition has unexpected contents");\n' - 'endif;') % - (self.device, self.tgt.care_map.to_string_raw(), - self.tgt.TotalSha1(), self.partition)) + # Abort the OTA update. Note that the incremental OTA cannot be applied + # even if it may match the checksum of the target partition. + # a) If version < 3, operations like move and erase will make changes + # unconditionally and damage the partition. + # b) If version >= 3, it won't even reach here. + script.AppendExtra(('abort("%s partition has unexpected contents");\n' + 'endif;') % (partition,)) def _WriteUpdate(self, script, output_zip): - partition = self.partition - with open(self.path + ".transfer.list", "rb") as f: - ZipWriteStr(output_zip, partition + ".transfer.list", f.read()) - with open(self.path + ".new.dat", "rb") as f: - ZipWriteStr(output_zip, partition + ".new.dat", f.read()) - with open(self.path + ".patch.dat", "rb") as f: - ZipWriteStr(output_zip, partition + ".patch.dat", f.read(), - compression=zipfile.ZIP_STORED) - - call = (('block_image_update("%s", ' - 'package_extract_file("%s.transfer.list"), ' - '"%s.new.dat", "%s.patch.dat");\n') % - (self.device, partition, partition, partition)) - script.AppendExtra(script._WordWrap(call)) + ZipWrite(output_zip, + '{}.transfer.list'.format(self.path), + '{}.transfer.list'.format(self.partition)) + ZipWrite(output_zip, + '{}.new.dat'.format(self.path), + '{}.new.dat'.format(self.partition)) + ZipWrite(output_zip, + '{}.patch.dat'.format(self.path), + '{}.patch.dat'.format(self.partition), + compress_type=zipfile.ZIP_STORED) + + call = ('block_image_update("{device}", ' + 'package_extract_file("{partition}.transfer.list"), ' + '"{partition}.new.dat", "{partition}.patch.dat");\n'.format( + device=self.device, partition=self.partition)) + script.AppendExtra(script.WordWrap(call)) + + def _HashBlocks(self, source, ranges): # pylint: disable=no-self-use + data = source.ReadRangeSet(ranges) + ctx = sha1() + + for p in data: + ctx.update(p) + + return ctx.hexdigest() def _CheckFirstBlock(self, script): - r = RangeSet((0, 1)) - h = sha1() - for data in self.src.ReadRangeSet(r): - h.update(data) - h = h.hexdigest() + r = rangelib.RangeSet((0, 1)) + srchash = self._HashBlocks(self.src, r) script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || ' 'abort("%s has been remounted R/W; ' 'reflash device to reenable OTA updates");') - % (self.device, r.to_string_raw(), h, self.device)) - + % (self.device, r.to_string_raw(), srchash, + self.device)) DataImage = blockimgdiff.DataImage @@ -1127,9 +1224,10 @@ PARTITION_TYPES = { def GetTypeAndDevice(mount_point, info): fstab = info["fstab"] if fstab: - return PARTITION_TYPES[fstab[mount_point].fs_type], fstab[mount_point].device + return (PARTITION_TYPES[fstab[mount_point].fs_type], + fstab[mount_point].device) else: - return None + raise KeyError def ParseCertificate(data): @@ -1176,14 +1274,11 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, _, _, patch = d.ComputePatch() output_sink("recovery-from-boot.p", patch) - td_pair = GetTypeAndDevice("/boot", info_dict) - if not td_pair: - return - boot_type, boot_device = td_pair - td_pair = GetTypeAndDevice("/recovery", info_dict) - if not td_pair: + try: + boot_type, boot_device = GetTypeAndDevice("/boot", info_dict) + recovery_type, recovery_device = GetTypeAndDevice("/recovery", info_dict) + except KeyError: return - recovery_type, recovery_device = td_pair sh = """#!/system/bin/sh if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then @@ -1191,16 +1286,15 @@ if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(rec else log -t recovery "Recovery image already installed" fi -""" % { 'boot_size': boot_img.size, - 'boot_sha1': boot_img.sha1, - 'recovery_size': recovery_img.size, - 'recovery_sha1': recovery_img.sha1, - 'boot_type': boot_type, - 'boot_device': boot_device, - 'recovery_type': recovery_type, - 'recovery_device': recovery_device, - 'bonus_args': bonus_args, - } +""" % {'boot_size': boot_img.size, + 'boot_sha1': boot_img.sha1, + 'recovery_size': recovery_img.size, + 'recovery_sha1': recovery_img.sha1, + 'boot_type': boot_type, + 'boot_device': boot_device, + 'recovery_type': recovery_type, + 'recovery_device': recovery_device, + 'bonus_args': bonus_args} # The install script location moved from /system/etc to /system/bin # in the L release. Parse the init.rc file to find out where the @@ -1209,12 +1303,12 @@ fi try: with open(os.path.join(input_dir, "BOOT", "RAMDISK", "init.rc")) as f: for line in f: - m = re.match("^service flash_recovery /system/(\S+)\s*$", line) + m = re.match(r"^service flash_recovery /system/(\S+)\s*$", line) if m: sh_location = m.group(1) print "putting script in", sh_location break - except (OSError, IOError), e: + except (OSError, IOError) as e: print "failed to read init.rc: %s" % (e,) output_sink(sh_location, sh) diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py index e52c264..3d0da88 100644 --- a/tools/releasetools/edify_generator.py +++ b/tools/releasetools/edify_generator.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import re import common @@ -36,7 +35,7 @@ class EdifyGenerator(object): return x @staticmethod - def _WordWrap(cmd, linelen=80): + def WordWrap(cmd, linelen=80): """'cmd' should be a function call with null characters after each parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd to a given line length, replacing nulls with spaces and/or newlines @@ -74,35 +73,33 @@ class EdifyGenerator(object): raise ValueError("must specify an OEM property") if not value: raise ValueError("must specify the OEM value") - cmd = ('file_getprop("/oem/oem.prop", "%s") == "%s" || ' - 'abort("This package expects the value \\"%s\\" for ' - '\\"%s\\" on the OEM partition; ' - 'this has value \\"" + file_getprop("/oem/oem.prop") + "\\".");' - ) % (name, value, name, value) + cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' + 'abort("This package expects the value \\"{value}\\" for ' + '\\"{name}\\" on the OEM partition; this has value \\"" + ' + 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( + name=name, value=value) self.script.append(cmd) def AssertSomeFingerprint(self, *fp): """Assert that the current recovery build fingerprint is one of *fp.""" if not fp: raise ValueError("must specify some fingerprints") - cmd = ( - ' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') - % i for i in fp]) + + cmd = (' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') % i + for i in fp]) + ' ||\n abort("Package expects build fingerprint of %s; this ' - 'device has " + getprop("ro.build.fingerprint") + ".");' - ) % (" or ".join(fp),) + 'device has " + getprop("ro.build.fingerprint") + ".");') % ( + " or ".join(fp)) self.script.append(cmd) def AssertSomeThumbprint(self, *fp): """Assert that the current recovery build thumbprint is one of *fp.""" if not fp: raise ValueError("must specify some thumbprints") - cmd = ( - ' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') - % i for i in fp]) + + cmd = (' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') % i + for i in fp]) + ' ||\n abort("Package expects build thumbprint of %s; this ' - 'device has " + getprop("ro.build.thumbprint") + ".");' - ) % (" or ".join(fp),) + 'device has " + getprop("ro.build.thumbprint") + ".");') % ( + " or ".join(fp)) self.script.append(cmd) def AssertOlderBuild(self, timestamp, timestamp_text): @@ -111,15 +108,15 @@ class EdifyGenerator(object): self.script.append( ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' 'abort("Can\'t install this package (%s) over newer ' - 'build (" + getprop("ro.build.date") + ").");' - ) % (timestamp, timestamp_text)) + 'build (" + getprop("ro.build.date") + ").");') % (timestamp, + timestamp_text)) def AssertDevice(self, device): """Assert that the device identifier is the given string.""" cmd = ('getprop("ro.product.device") == "%s" || ' 'abort("This package is for \\"%s\\" devices; ' - 'this is a \\"" + getprop("ro.product.device") + "\\".");' - ) % (device, device) + 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( + device, device) self.script.append(cmd) def AssertSomeBootloader(self, *bootloaders): @@ -128,7 +125,7 @@ class EdifyGenerator(object): " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,) for b in bootloaders]) + ");") - self.script.append(self._WordWrap(cmd)) + self.script.append(self.WordWrap(cmd)) def ShowProgress(self, frac, dur): """Update the progress bar, advancing it over 'frac' over the next @@ -180,9 +177,9 @@ class EdifyGenerator(object): if "=" in option: key, value = option.split("=", 1) mount_dict[key] = value - self.script.append('mount("%s", "%s", "%s", "%s", "%s");' % - (p.fs_type, common.PARTITION_TYPES[p.fs_type], - p.device, p.mount_point, mount_dict.get(p.fs_type, ""))) + self.script.append('mount("%s", "%s", "%s", "%s", "%s");' % ( + p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device, + p.mount_point, mount_dict.get(p.fs_type, ""))) self.mounts.add(p.mount_point) def UnpackPackageDir(self, src, dst): @@ -205,18 +202,17 @@ class EdifyGenerator(object): fstab = self.info.get("fstab", None) if fstab: p = fstab[partition] - if (p.fs_type not in ( "ext2", "ext3", "ext4")): + if p.fs_type not in ("ext2", "ext3", "ext4"): raise ValueError("Partition %s cannot be tuned\n" % (partition,)) - self.script.append('tune2fs(' + - "".join(['"%s", ' % (i,) for i in options]) + - '"%s") || abort("Failed to tune partition %s");' - % ( p.device,partition)); + self.script.append( + 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + + '"%s") || abort("Failed to tune partition %s");' % ( + p.device, partition)) def FormatPartition(self, partition): """Format the given partition, specified by its mount point (eg, "/system").""" - reserve_size = 0 fstab = self.info.get("fstab", None) if fstab: p = fstab[partition] @@ -235,9 +231,10 @@ class EdifyGenerator(object): def DeleteFiles(self, file_list): """Delete all files in file_list.""" - if not file_list: return + if not file_list: + return cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");" - self.script.append(self._WordWrap(cmd)) + self.script.append(self.WordWrap(cmd)) def RenameFile(self, srcfile, tgtfile): """Moves a file from one location to another.""" @@ -251,7 +248,7 @@ class EdifyGenerator(object): skip the action if the file exists. Used when a patch is later renamed.""" cmd = ('sha1_check(read_file("%s"), %s) || ' % (tgtfile, tgtsha1)) - self.script.append(self._WordWrap(cmd)) + self.script.append(self.WordWrap(cmd)) def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): """Apply binary patches (in *patchpairs) to the given srcfile to @@ -265,7 +262,7 @@ class EdifyGenerator(object): cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) cmd.append(');') cmd = "".join(cmd) - self.script.append(self._WordWrap(cmd)) + self.script.append(self.WordWrap(cmd)) def WriteRawImage(self, mount_point, fn, mapfn=None): """Write the given package file into the partition for the given @@ -289,33 +286,37 @@ class EdifyGenerator(object): self.script.append( 'package_extract_file("%(fn)s", "%(device)s");' % args) else: - raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,)) + raise ValueError( + "don't know how to write \"%s\" partitions" % p.fs_type) def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities): """Set file ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) else: - if capabilities is None: capabilities = "0x0" + if capabilities is None: + capabilities = "0x0" cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, ' \ '"capabilities", %s' % (fn, uid, gid, mode, capabilities) if selabel is not None: - cmd += ', "selabel", "%s"' % ( selabel ) + cmd += ', "selabel", "%s"' % selabel cmd += ');' self.script.append(cmd) - def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, capabilities): + def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, + capabilities): """Recursively set path ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' % (uid, gid, dmode, fmode, fn)) else: - if capabilities is None: capabilities = "0x0" + if capabilities is None: + capabilities = "0x0" cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \ '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \ % (fn, uid, gid, dmode, fmode, capabilities) if selabel is not None: - cmd += ', "selabel", "%s"' % ( selabel ) + cmd += ', "selabel", "%s"' % selabel cmd += ');' self.script.append(cmd) @@ -328,15 +329,15 @@ class EdifyGenerator(object): for dest, links in sorted(by_dest.iteritems()): cmd = ('symlink("%s", ' % (dest,) + ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");") - self.script.append(self._WordWrap(cmd)) + self.script.append(self.WordWrap(cmd)) def AppendExtra(self, extra): """Append text verbatim to the output script.""" self.script.append(extra) def Unmount(self, mount_point): - self.script.append('unmount("%s");' % (mount_point,)) - self.mounts.remove(mount_point); + self.script.append('unmount("%s");' % mount_point) + self.mounts.remove(mount_point) def UnmountAll(self): for p in sorted(self.mounts): @@ -359,4 +360,4 @@ class EdifyGenerator(object): else: data = open(input_path, "rb").read() common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary", - data, perms=0755) + data, perms=0o755) diff --git a/tools/releasetools/img_from_target_files.py b/tools/releasetools/img_from_target_files.py index 4b88e73..8c5acd8 100755 --- a/tools/releasetools/img_from_target_files.py +++ b/tools/releasetools/img_from_target_files.py @@ -32,18 +32,10 @@ if sys.hexversion < 0x02070000: print >> sys.stderr, "Python 2.7 or newer is required." sys.exit(1) -import errno import os -import re import shutil -import subprocess -import tempfile import zipfile -# missing in Python 2.4 and before -if not hasattr(os, "SEEK_SET"): - os.SEEK_SET = 0 - import common OPTIONS = common.OPTIONS @@ -58,7 +50,7 @@ def CopyInfo(output_zip): def main(argv): bootable_only = [False] - def option_handler(o, a): + def option_handler(o, _): if o in ("-z", "--bootable_zip"): bootable_only[0] = True else: @@ -88,11 +80,13 @@ def main(argv): # and all we have to do is copy them to the output zip. images = os.listdir(images_path) if images: - for i in images: - if bootable_only and i not in ("boot.img", "recovery.img"): continue - if not i.endswith(".img"): continue - with open(os.path.join(images_path, i), "r") as f: - common.ZipWriteStr(output_zip, i, f.read()) + for image in images: + if bootable_only and image not in ("boot.img", "recovery.img"): + continue + if not image.endswith(".img"): + continue + common.ZipWrite( + output_zip, os.path.join(images_path, image), image) done = True if not done: @@ -114,7 +108,7 @@ def main(argv): boot_image = common.GetBootableImage( "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") if boot_image: - boot_image.AddToZip(output_zip) + boot_image.AddToZip(output_zip) recovery_image = common.GetBootableImage( "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") if recovery_image: @@ -139,7 +133,13 @@ def main(argv): finally: print "cleaning up..." + # http://b/18015246 + # See common.py for context. zipfile also refers to ZIP64_LIMIT during + # close() when it writes out the central directory. + saved_zip64_limit = zipfile.ZIP64_LIMIT + zipfile.ZIP64_LIMIT = (1 << 32) - 1 output_zip.close() + zipfile.ZIP64_LIMIT = saved_zip64_limit shutil.rmtree(OPTIONS.input_tmp) print "done." @@ -149,7 +149,7 @@ if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) - except common.ExternalError, e: + except common.ExternalError as e: print print " ERROR: %s" % (e,) print diff --git a/tools/releasetools/make_recovery_patch b/tools/releasetools/make_recovery_patch index 08d1450..45cec08 100755..120000 --- a/tools/releasetools/make_recovery_patch +++ b/tools/releasetools/make_recovery_patch @@ -1,53 +1 @@ -#!/usr/bin/env python -# -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys - -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." - sys.exit(1) - -import os -import common - -OPTIONS = common.OPTIONS - -def main(argv): - # def option_handler(o, a): - # return False - - args = common.ParseOptions(argv, __doc__) - input_dir, output_dir = args - - OPTIONS.info_dict = common.LoadInfoDict(input_dir) - - recovery_img = common.GetBootableImage("recovery.img", "recovery.img", - input_dir, "RECOVERY") - boot_img = common.GetBootableImage("boot.img", "boot.img", - input_dir, "BOOT") - - if not recovery_img or not boot_img: - sys.exit(0) - - def output_sink(fn, data): - with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f: - f.write(data) - - common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img) - - -if __name__ == '__main__': - main(sys.argv[1:]) +make_recovery_patch.py
\ No newline at end of file diff --git a/tools/releasetools/make_recovery_patch.py b/tools/releasetools/make_recovery_patch.py new file mode 100755 index 0000000..08d1450 --- /dev/null +++ b/tools/releasetools/make_recovery_patch.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys + +if sys.hexversion < 0x02070000: + print >> sys.stderr, "Python 2.7 or newer is required." + sys.exit(1) + +import os +import common + +OPTIONS = common.OPTIONS + +def main(argv): + # def option_handler(o, a): + # return False + + args = common.ParseOptions(argv, __doc__) + input_dir, output_dir = args + + OPTIONS.info_dict = common.LoadInfoDict(input_dir) + + recovery_img = common.GetBootableImage("recovery.img", "recovery.img", + input_dir, "RECOVERY") + boot_img = common.GetBootableImage("boot.img", "boot.img", + input_dir, "BOOT") + + if not recovery_img or not boot_img: + sys.exit(0) + + def output_sink(fn, data): + with open(os.path.join(output_dir, "SYSTEM", *fn.split("/")), "wb") as f: + f.write(data) + + common.MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files index 25309a4..6755a90 100755..120000 --- a/tools/releasetools/ota_from_target_files +++ b/tools/releasetools/ota_from_target_files @@ -1,1576 +1 @@ -#!/usr/bin/env python -# -# 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. - -""" -Given a target-files zipfile, produces an OTA package that installs -that build. An incremental OTA is produced if -i is given, otherwise -a full OTA is produced. - -Usage: ota_from_target_files [flags] input_target_files output_ota_package - - --board_config <file> - Deprecated. - - -k (--package_key) <key> Key to use to sign the package (default is - the value of default_system_dev_certificate from the input - target-files's META/misc_info.txt, or - "build/target/product/security/testkey" if that value is not - specified). - - For incremental OTAs, the default value is based on the source - target-file, not the target build. - - -i (--incremental_from) <file> - Generate an incremental OTA using the given target-files zip as - the starting build. - - -v (--verify) - Remount and verify the checksums of the files written to the - system and vendor (if used) partitions. Incremental builds only. - - -o (--oem_settings) <file> - Use the file to specify the expected OEM-specific properties - on the OEM partition of the intended device. - - -w (--wipe_user_data) - Generate an OTA package that will wipe the user data partition - when installed. - - -n (--no_prereq) - Omit the timestamp prereq check normally included at the top of - the build scripts (used for developer OTA packages which - legitimately need to go back and forth). - - -e (--extra_script) <file> - Insert the contents of file at the end of the update script. - - -a (--aslr_mode) <on|off> - Specify whether to turn on ASLR for the package (on by default). - - -2 (--two_step) - Generate a 'two-step' OTA package, where recovery is updated - first, so that any changes made to the system partition are done - using the new recovery (new kernel, etc.). - - --block - Generate a block-based OTA if possible. Will fall back to a - file-based OTA if the target_files is older and doesn't support - block-based OTAs. - - -b (--binary) <file> - Use the given binary as the update-binary in the output package, - instead of the binary in the build's target_files. Use for - development only. - - -t (--worker_threads) <int> - Specifies the number of worker-threads that will be used when - generating patches for incremental updates (defaults to 3). - -""" - -import sys - -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." - sys.exit(1) - -import copy -import errno -import multiprocessing -import os -import re -import subprocess -import tempfile -import time -import zipfile - -from hashlib import sha1 as sha1 - -import common -import edify_generator -import build_image -import blockimgdiff -import sparse_img - -OPTIONS = common.OPTIONS -OPTIONS.package_key = None -OPTIONS.incremental_source = None -OPTIONS.verify = False -OPTIONS.require_verbatim = set() -OPTIONS.prohibit_verbatim = set(("system/build.prop",)) -OPTIONS.patch_threshold = 0.95 -OPTIONS.wipe_user_data = False -OPTIONS.omit_prereq = False -OPTIONS.extra_script = None -OPTIONS.aslr_mode = True -OPTIONS.worker_threads = multiprocessing.cpu_count() // 2 -if OPTIONS.worker_threads == 0: - OPTIONS.worker_threads = 1 -OPTIONS.two_step = False -OPTIONS.no_signing = False -OPTIONS.block_based = False -OPTIONS.updater_binary = None -OPTIONS.oem_source = None -OPTIONS.fallback_to_full = True - -def MostPopularKey(d, default): - """Given a dict, return the key corresponding to the largest - value. Returns 'default' if the dict is empty.""" - x = [(v, k) for (k, v) in d.iteritems()] - if not x: return default - x.sort() - return x[-1][1] - - -def IsSymlink(info): - """Return true if the zipfile.ZipInfo object passed in represents a - symlink.""" - return (info.external_attr >> 16) == 0120777 - -def IsRegular(info): - """Return true if the zipfile.ZipInfo object passed in represents a - symlink.""" - return (info.external_attr >> 28) == 010 - -def ClosestFileMatch(src, tgtfiles, existing): - """Returns the closest file match between a source file and list - of potential matches. The exact filename match is preferred, - then the sha1 is searched for, and finally a file with the same - basename is evaluated. Rename support in the updater-binary is - required for the latter checks to be used.""" - - result = tgtfiles.get("path:" + src.name) - if result is not None: - return result - - if not OPTIONS.target_info_dict.get("update_rename_support", False): - return None - - if src.size < 1000: - return None - - result = tgtfiles.get("sha1:" + src.sha1) - if result is not None and existing.get(result.name) is None: - return result - result = tgtfiles.get("file:" + src.name.split("/")[-1]) - if result is not None and existing.get(result.name) is None: - return result - return None - -class ItemSet: - def __init__(self, partition, fs_config): - self.partition = partition - self.fs_config = fs_config - self.ITEMS = {} - - def Get(self, name, dir=False): - if name not in self.ITEMS: - self.ITEMS[name] = Item(self, name, dir=dir) - return self.ITEMS[name] - - def GetMetadata(self, input_zip): - # The target_files contains a record of what the uid, - # gid, and mode are supposed to be. - output = input_zip.read(self.fs_config) - - for line in output.split("\n"): - if not line: continue - columns = line.split() - name, uid, gid, mode = columns[:4] - selabel = None - capabilities = None - - # After the first 4 columns, there are a series of key=value - # pairs. Extract out the fields we care about. - for element in columns[4:]: - key, value = element.split("=") - if key == "selabel": - selabel = value - if key == "capabilities": - capabilities = value - - i = self.ITEMS.get(name, None) - if i is not None: - i.uid = int(uid) - i.gid = int(gid) - i.mode = int(mode, 8) - i.selabel = selabel - i.capabilities = capabilities - if i.dir: - i.children.sort(key=lambda i: i.name) - - # set metadata for the files generated by this script. - i = self.ITEMS.get("system/recovery-from-boot.p", None) - if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None - i = self.ITEMS.get("system/etc/install-recovery.sh", None) - if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None - - -class Item: - """Items represent the metadata (user, group, mode) of files and - directories in the system image.""" - def __init__(self, itemset, name, dir=False): - self.itemset = itemset - self.name = name - self.uid = None - self.gid = None - self.mode = None - self.selabel = None - self.capabilities = None - self.dir = dir - - if name: - self.parent = itemset.Get(os.path.dirname(name), dir=True) - self.parent.children.append(self) - else: - self.parent = None - if dir: - self.children = [] - - def Dump(self, indent=0): - if self.uid is not None: - print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) - else: - print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) - if self.dir: - print "%s%s" % (" "*indent, self.descendants) - print "%s%s" % (" "*indent, self.best_subtree) - for i in self.children: - i.Dump(indent=indent+1) - - def CountChildMetadata(self): - """Count up the (uid, gid, mode, selabel, capabilities) tuples for - all children and determine the best strategy for using set_perm_recursive and - set_perm to correctly chown/chmod all the files to their desired - values. Recursively calls itself for all descendants. - - Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up - all descendants of this node. (dmode or fmode may be None.) Also - sets the best_subtree of each directory Item to the (uid, gid, - dmode, fmode, selabel, capabilities) tuple that will match the most - descendants of that Item. - """ - - assert self.dir - d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1} - for i in self.children: - if i.dir: - for k, v in i.CountChildMetadata().iteritems(): - d[k] = d.get(k, 0) + v - else: - k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities) - d[k] = d.get(k, 0) + 1 - - # Find the (uid, gid, dmode, fmode, selabel, capabilities) - # tuple that matches the most descendants. - - # First, find the (uid, gid) pair that matches the most - # descendants. - ug = {} - for (uid, gid, _, _, _, _), count in d.iteritems(): - ug[(uid, gid)] = ug.get((uid, gid), 0) + count - ug = MostPopularKey(ug, (0, 0)) - - # Now find the dmode, fmode, selabel, and capabilities that match - # the most descendants with that (uid, gid), and choose those. - best_dmode = (0, 0755) - best_fmode = (0, 0644) - best_selabel = (0, None) - best_capabilities = (0, None) - for k, count in d.iteritems(): - if k[:2] != ug: continue - if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) - if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) - if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4]) - if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5]) - self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) - - return d - - def SetPermissions(self, script): - """Append set_perm/set_perm_recursive commands to 'script' to - set all permissions, users, and groups for the tree of files - rooted at 'self'.""" - - self.CountChildMetadata() - - def recurse(item, current): - # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current - # item (and all its children) have already been set to. We only - # need to issue set_perm/set_perm_recursive commands if we're - # supposed to be something different. - if item.dir: - if current != item.best_subtree: - script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) - current = item.best_subtree - - if item.uid != current[0] or item.gid != current[1] or \ - item.mode != current[2] or item.selabel != current[4] or \ - item.capabilities != current[5]: - script.SetPermissions("/"+item.name, item.uid, item.gid, - item.mode, item.selabel, item.capabilities) - - for i in item.children: - recurse(i, current) - else: - if item.uid != current[0] or item.gid != current[1] or \ - item.mode != current[3] or item.selabel != current[4] or \ - item.capabilities != current[5]: - script.SetPermissions("/"+item.name, item.uid, item.gid, - item.mode, item.selabel, item.capabilities) - - recurse(self, (-1, -1, -1, -1, None, None)) - - -def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): - """Copies files for the partition in the input zip to the output - zip. Populates the Item class with their metadata, and returns a - list of symlinks. output_zip may be None, in which case the copy is - skipped (but the other side effects still happen). substitute is an - optional dict of {output filename: contents} to be output instead of - certain input files. - """ - - symlinks = [] - - partition = itemset.partition - - for info in input_zip.infolist(): - if info.filename.startswith(partition.upper() + "/"): - basefilename = info.filename[7:] - if IsSymlink(info): - symlinks.append((input_zip.read(info.filename), - "/" + partition + "/" + basefilename)) - else: - info2 = copy.copy(info) - fn = info2.filename = partition + "/" + basefilename - if substitute and fn in substitute and substitute[fn] is None: - continue - if output_zip is not None: - if substitute and fn in substitute: - data = substitute[fn] - else: - data = input_zip.read(info.filename) - output_zip.writestr(info2, data) - if fn.endswith("/"): - itemset.Get(fn[:-1], dir=True) - else: - itemset.Get(fn, dir=False) - - symlinks.sort() - return symlinks - - -def SignOutput(temp_zip_name, output_zip_name): - key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) - pw = key_passwords[OPTIONS.package_key] - - common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, - whole_file=True) - - -def AppendAssertions(script, info_dict, oem_dict = None): - oem_props = info_dict.get("oem_fingerprint_properties") - if oem_props is None or len(oem_props) == 0: - device = GetBuildProp("ro.product.device", info_dict) - script.AssertDevice(device) - else: - if oem_dict is None: - raise common.ExternalError("No OEM file provided to answer expected assertions") - for prop in oem_props.split(): - if oem_dict.get(prop) is None: - raise common.ExternalError("The OEM file is missing the property %s" % prop) - script.AssertOemProperty(prop, oem_dict.get(prop)) - - -def HasRecoveryPatch(target_files_zip): - try: - target_files_zip.getinfo("SYSTEM/recovery-from-boot.p") - return True - except KeyError: - return False - -def HasVendorPartition(target_files_zip): - try: - target_files_zip.getinfo("VENDOR/") - return True - except KeyError: - return False - -def GetOemProperty(name, oem_props, oem_dict, info_dict): - if oem_props is not None and name in oem_props: - return oem_dict[name] - return GetBuildProp(name, info_dict) - - -def CalculateFingerprint(oem_props, oem_dict, info_dict): - if oem_props is None: - return GetBuildProp("ro.build.fingerprint", info_dict) - return "%s/%s/%s:%s" % ( - GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict), - GetBuildProp("ro.build.thumbprint", info_dict)) - - -def GetImage(which, tmpdir, info_dict): - # Return an image object (suitable for passing to BlockImageDiff) - # for the 'which' partition (most be "system" or "vendor"). If a - # prebuilt image and file map are found in tmpdir they are used, - # otherwise they are reconstructed from the individual files. - - assert which in ("system", "vendor") - - path = os.path.join(tmpdir, "IMAGES", which + ".img") - mappath = os.path.join(tmpdir, "IMAGES", which + ".map") - if os.path.exists(path) and os.path.exists(mappath): - print "using %s.img from target-files" % (which,) - # This is a 'new' target-files, which already has the image in it. - - else: - print "building %s.img from target-files" % (which,) - - # This is an 'old' target-files, which does not contain images - # already built. Build them. - - mappath = tempfile.mkstemp()[1] - OPTIONS.tempfiles.append(mappath) - - import add_img_to_target_files - if which == "system": - path = add_img_to_target_files.BuildSystem( - tmpdir, info_dict, block_list=mappath) - elif which == "vendor": - path = add_img_to_target_files.BuildVendor( - tmpdir, info_dict, block_list=mappath) - - return sparse_img.SparseImage(path, mappath) - - -def WriteFullOTAPackage(input_zip, output_zip): - # TODO: how to determine this? We don't know what version it will - # be installed on top of. For now, we expect the API just won't - # change very often. - script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) - - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines()) - - metadata = {"post-build": CalculateFingerprint( - oem_props, oem_dict, OPTIONS.info_dict), - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.info_dict), - } - - device_specific = common.DeviceSpecificParams( - input_zip=input_zip, - input_version=OPTIONS.info_dict["recovery_api_version"], - output_zip=output_zip, - script=script, - input_tmp=OPTIONS.input_tmp, - metadata=metadata, - info_dict=OPTIONS.info_dict) - - has_recovery_patch = HasRecoveryPatch(input_zip) - block_based = OPTIONS.block_based and has_recovery_patch - - if not OPTIONS.omit_prereq: - ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict) - ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) - script.AssertOlderBuild(ts, ts_text) - - AppendAssertions(script, OPTIONS.info_dict, oem_dict) - device_specific.FullOTA_Assertions() - - # Two-step package strategy (in chronological order, which is *not* - # the order in which the generated script has things): - # - # if stage is not "2/3" or "3/3": - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # set stage to "" - # do normal full package installation: - # wipe and install system, boot image, etc. - # set up system to update recovery partition on first boot - # complete script normally (allow recovery to mark itself finished and reboot) - - recovery_img = common.GetBootableImage("recovery.img", "recovery.img", - OPTIONS.input_tmp, "RECOVERY") - if OPTIONS.two_step: - if not OPTIONS.info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") == "3/3" then -""" % bcb_dev) - - device_specific.FullOTA_InstallBegin() - - system_progress = 0.75 - - if OPTIONS.wipe_user_data: - system_progress -= 0.1 - if HasVendorPartition(input_zip): - system_progress -= 0.1 - - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - - system_items = ItemSet("system", "META/filesystem_config.txt") - script.ShowProgress(system_progress, 0) - - if block_based: - # Full OTA is done as an "incremental" against an empty source - # image. This has the effect of writing new data from the package - # to the entire partition, but lets us reuse the updater code that - # writes incrementals to do it. - system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict) - system_tgt.ResetFileMap() - system_diff = common.BlockDifference("system", system_tgt, src=None) - system_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/system") - script.Mount("/system", recovery_mount_options) - if not has_recovery_patch: - script.UnpackPackageDir("recovery", "/system") - script.UnpackPackageDir("system", "/system") - - symlinks = CopyPartitionFiles(system_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - - boot_img = common.GetBootableImage("boot.img", "boot.img", - OPTIONS.input_tmp, "BOOT") - - if not block_based: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn, dir=False) - - common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, - recovery_img, boot_img) - - system_items.GetMetadata(input_zip) - system_items.Get("system").SetPermissions(script) - - if HasVendorPartition(input_zip): - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - script.ShowProgress(0.1, 0) - - if block_based: - vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict) - vendor_tgt.ResetFileMap() - vendor_diff = common.BlockDifference("vendor", vendor_tgt) - vendor_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/vendor") - script.Mount("/vendor", recovery_mount_options) - script.UnpackPackageDir("vendor", "/vendor") - - symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - - vendor_items.GetMetadata(input_zip) - vendor_items.Get("vendor").SetPermissions(script) - - common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) - common.ZipWriteStr(output_zip, "boot.img", boot_img.data) - - script.ShowProgress(0.05, 5) - script.WriteRawImage("/boot", "boot.img") - - script.ShowProgress(0.2, 10) - device_specific.FullOTA_InstallEnd() - - if OPTIONS.extra_script is not None: - script.AppendExtra(OPTIONS.extra_script) - - script.UnmountAll() - - if OPTIONS.wipe_user_data: - script.ShowProgress(0.1, 10) - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -""" % bcb_dev) - script.AppendExtra("else\n") - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) - WriteMetadata(metadata, output_zip) - - -def WritePolicyConfig(file_context, output_zip): - f = open(file_context, 'r'); - basename = os.path.basename(file_context) - common.ZipWriteStr(output_zip, basename, f.read()) - - -def WriteMetadata(metadata, output_zip): - common.ZipWriteStr(output_zip, "META-INF/com/android/metadata", - "".join(["%s=%s\n" % kv - for kv in sorted(metadata.iteritems())])) - - -def LoadPartitionFiles(z, partition): - """Load all the files from the given partition in a given target-files - ZipFile, and return a dict of {filename: File object}.""" - out = {} - prefix = partition.upper() + "/" - for info in z.infolist(): - if info.filename.startswith(prefix) and not IsSymlink(info): - basefilename = info.filename[7:] - fn = partition + "/" + basefilename - data = z.read(info.filename) - out[fn] = common.File(fn, data) - return out - - -def GetBuildProp(prop, info_dict): - """Return the fingerprint of the build of a given target-files info_dict.""" - try: - return info_dict.get("build.prop", {})[prop] - except KeyError: - raise common.ExternalError("couldn't find %s in build.prop" % (prop,)) - - -def AddToKnownPaths(filename, known_paths): - if filename[-1] == "/": - return - dirs = filename.split("/")[:-1] - while len(dirs) > 0: - path = "/".join(dirs) - if path in known_paths: - break; - known_paths.add(path) - dirs.pop() - - -def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): - source_version = OPTIONS.source_info_dict["recovery_api_version"] - target_version = OPTIONS.target_info_dict["recovery_api_version"] - - if source_version == 0: - print ("WARNING: generating edify script for a source that " - "can't install it.") - script = edify_generator.EdifyGenerator(source_version, - OPTIONS.target_info_dict) - - metadata = {"pre-device": GetBuildProp("ro.product.device", - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } - - device_specific = common.DeviceSpecificParams( - source_zip=source_zip, - source_version=source_version, - target_zip=target_zip, - target_version=target_version, - output_zip=output_zip, - script=script, - metadata=metadata, - info_dict=OPTIONS.info_dict) - - source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict) - target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict) - metadata["pre-build"] = source_fp - metadata["post-build"] = target_fp - - source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) - target_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) - - source_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY", - OPTIONS.source_info_dict) - target_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") - updating_recovery = (source_recovery.data != target_recovery.data) - - system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict) - system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict) - - blockimgdiff_version = 1 - if OPTIONS.info_dict: - blockimgdiff_version = max( - int(i) for i in - OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) - - system_diff = common.BlockDifference("system", system_tgt, system_src, - check_first_block=True, - version=blockimgdiff_version) - - if HasVendorPartition(target_zip): - if not HasVendorPartition(source_zip): - raise RuntimeError("can't generate incremental that adds /vendor") - vendor_src = GetImage("vendor", OPTIONS.source_tmp, OPTIONS.source_info_dict) - vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, OPTIONS.target_info_dict) - vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src, - check_first_block=True, - version=blockimgdiff_version) - else: - vendor_diff = None - - oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.target_info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines()) - - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) - device_specific.IncrementalOTA_Assertions() - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n"); - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - script.Print("Verifying current system...") - - device_specific.IncrementalOTA_VerifyBegin() - - if oem_props is None: - # When blockimgdiff version is less than 3 (non-resumable block-based OTA), - # patching on a device that's already on the target build will damage the - # system. Because operations like move don't check the block state, they - # always apply the changes unconditionally. - if blockimgdiff_version <= 2: - script.AssertSomeFingerprint(source_fp) - else: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - if blockimgdiff_version <= 2: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - - if updating_boot: - boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) - d = common.Difference(target_boot, source_boot) - _, _, d = d.ComputePatch() - if d is None: - include_full_boot = True - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - else: - include_full_boot = False - - print "boot target: %d source: %d diff: %d" % ( - target_boot.size, source_boot.size, len(d)) - - common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - - script.PatchCheck("%s:%s:%d:%s:%d:%s" % - (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1)) - - device_specific.IncrementalOTA_VerifyEnd() - - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - - # Verify the existing partitions. - system_diff.WriteVerifyScript(script) - if vendor_diff: - vendor_diff.WriteVerifyScript(script) - - script.Comment("---- start making changes here ----") - - device_specific.IncrementalOTA_InstallBegin() - - system_diff.WriteScript(script, output_zip, - progress=0.8 if vendor_diff else 0.9) - if vendor_diff: - vendor_diff.WriteScript(script, output_zip, progress=0.1) - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" - - if not OPTIONS.two_step: - if updating_boot: - if include_full_boot: - print "boot image changed; including full." - script.Print("Installing boot image...") - script.WriteRawImage("/boot", "boot.img") - else: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - print "boot image changed; including patch." - script.Print("Patching boot image...") - script.ShowProgress(0.1, 10) - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - else: - print "boot image unchanged; skipping." - - # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() - - if OPTIONS.extra_script is not None: - script.AppendExtra(OPTIONS.extra_script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - script.SetProgress(1) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) - WriteMetadata(metadata, output_zip) - - -class FileDifference: - def __init__(self, partition, source_zip, target_zip, output_zip): - print "Loading target..." - self.target_data = target_data = LoadPartitionFiles(target_zip, partition) - print "Loading source..." - self.source_data = source_data = LoadPartitionFiles(source_zip, partition) - - self.verbatim_targets = verbatim_targets = [] - self.patch_list = patch_list = [] - diffs = [] - self.renames = renames = {} - known_paths = set() - largest_source_size = 0 - - matching_file_cache = {} - for fn, sf in source_data.items(): - assert fn == sf.name - matching_file_cache["path:" + fn] = sf - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - # Only allow eligibility for filename/sha matching - # if there isn't a perfect path match. - if target_data.get(sf.name) is None: - matching_file_cache["file:" + fn.split("/")[-1]] = sf - matching_file_cache["sha:" + sf.sha1] = sf - - for fn in sorted(target_data.keys()): - tf = target_data[fn] - assert fn == tf.name - sf = ClosestFileMatch(tf, matching_file_cache, renames) - if sf is not None and sf.name != tf.name: - print "File has moved from " + sf.name + " to " + tf.name - renames[sf.name] = tf - - if sf is None or fn in OPTIONS.require_verbatim: - # This file should be included verbatim - if fn in OPTIONS.prohibit_verbatim: - raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) - print "send", fn, "verbatim" - tf.AddToZip(output_zip) - verbatim_targets.append((fn, tf.size, tf.sha1)) - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - elif tf.sha1 != sf.sha1: - # File is different; consider sending as a patch - diffs.append(common.Difference(tf, sf)) - else: - # Target file data identical to source (may still be renamed) - pass - - common.ComputeDifferences(diffs) - - for diff in diffs: - tf, sf, d = diff.GetPatch() - path = "/".join(tf.name.split("/")[:-1]) - if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \ - path not in known_paths: - # patch is almost as big as the file; don't bother patching - # or a patch + rename cannot take place due to the target - # directory not existing - tf.AddToZip(output_zip) - verbatim_targets.append((tf.name, tf.size, tf.sha1)) - if sf.name in renames: - del renames[sf.name] - AddToKnownPaths(tf.name, known_paths) - else: - common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d) - patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest())) - largest_source_size = max(largest_source_size, sf.size) - - self.largest_source_size = largest_source_size - - def EmitVerification(self, script): - so_far = 0 - for tf, sf, size, patch_sha in self.patch_list: - if tf.name != sf.name: - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1) - so_far += sf.size - return so_far - - def EmitExplicitTargetVerification(self, script): - for fn, size, sha1 in self.verbatim_targets: - if (fn[-1] != "/"): - script.FileCheck("/"+fn, sha1) - for tf, _, _, _ in self.patch_list: - script.FileCheck(tf.name, tf.sha1) - - def RemoveUnneededFiles(self, script, extras=()): - script.DeleteFiles(["/"+i[0] for i in self.verbatim_targets] + - ["/"+i for i in sorted(self.source_data) - if i not in self.target_data and - i not in self.renames] + - list(extras)) - - def TotalPatchSize(self): - return sum(i[1].size for i in self.patch_list) - - def EmitPatches(self, script, total_patch_size, so_far): - self.deferred_patch_list = deferred_patch_list = [] - for item in self.patch_list: - tf, sf, size, _ = item - if tf.name == "system/build.prop": - deferred_patch_list.append(item) - continue - if (sf.name != tf.name): - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p") - so_far += tf.size - script.SetProgress(so_far / total_patch_size) - return so_far - - def EmitDeferredPatches(self, script): - for item in self.deferred_patch_list: - tf, sf, size, _ = item - script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, "patch/"+sf.name+".p") - script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None) - - def EmitRenames(self, script): - if len(self.renames) > 0: - script.Print("Renaming files...") - for src, tgt in self.renames.iteritems(): - print "Renaming " + src + " to " + tgt.name - script.RenameFile(src, tgt.name) - - - - -def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): - target_has_recovery_patch = HasRecoveryPatch(target_zip) - source_has_recovery_patch = HasRecoveryPatch(source_zip) - - if (OPTIONS.block_based and - target_has_recovery_patch and - source_has_recovery_patch): - return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip) - - source_version = OPTIONS.source_info_dict["recovery_api_version"] - target_version = OPTIONS.target_info_dict["recovery_api_version"] - - if source_version == 0: - print ("WARNING: generating edify script for a source that " - "can't install it.") - script = edify_generator.EdifyGenerator(source_version, - OPTIONS.target_info_dict) - - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines(open(OPTIONS.oem_source).readlines()) - - metadata = {"pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } - - device_specific = common.DeviceSpecificParams( - source_zip=source_zip, - source_version=source_version, - target_zip=target_zip, - target_version=target_version, - output_zip=output_zip, - script=script, - metadata=metadata, - info_dict=OPTIONS.info_dict) - - system_diff = FileDifference("system", source_zip, target_zip, output_zip) - script.Mount("/system", recovery_mount_options) - if HasVendorPartition(target_zip): - vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip) - script.Mount("/vendor", recovery_mount_options) - else: - vendor_diff = None - - target_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.target_info_dict) - source_fp = CalculateFingerprint(oem_props, oem_dict, OPTIONS.source_info_dict) - - if oem_props is None: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - - metadata["pre-build"] = source_fp - metadata["post-build"] = target_fp - - source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) - target_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) - - source_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY", - OPTIONS.source_info_dict) - target_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") - updating_recovery = (source_recovery.data != target_recovery.data) - - # Here's how we divide up the progress bar: - # 0.1 for verifying the start state (PatchCheck calls) - # 0.8 for applying patches (ApplyPatch calls) - # 0.1 for unpacking verbatim files, symlinking, and doing the - # device-specific commands. - - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) - device_specific.IncrementalOTA_Assertions() - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n"); - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - script.Print("Verifying current system...") - - device_specific.IncrementalOTA_VerifyBegin() - - script.ShowProgress(0.1, 0) - so_far = system_diff.EmitVerification(script) - if vendor_diff: - so_far += vendor_diff.EmitVerification(script) - - if updating_boot: - d = common.Difference(target_boot, source_boot) - _, _, d = d.ComputePatch() - print "boot target: %d source: %d diff: %d" % ( - target_boot.size, source_boot.size, len(d)) - - common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - - boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) - - script.PatchCheck("%s:%s:%d:%s:%d:%s" % - (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1)) - so_far += source_boot.size - - size = [] - if system_diff.patch_list: size.append(system_diff.largest_source_size) - if vendor_diff: - if vendor_diff.patch_list: size.append(vendor_diff.largest_source_size) - if size or updating_recovery or updating_boot: - script.CacheFreeSpaceCheck(max(size)) - - device_specific.IncrementalOTA_VerifyEnd() - - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - - script.Comment("---- start making changes here ----") - - device_specific.IncrementalOTA_InstallBegin() - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" - - script.Print("Removing unneeded files...") - system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",)) - if vendor_diff: - vendor_diff.RemoveUnneededFiles(script) - - script.ShowProgress(0.8, 0) - total_patch_size = 1.0 + system_diff.TotalPatchSize() - if vendor_diff: - total_patch_size += vendor_diff.TotalPatchSize() - if updating_boot: - total_patch_size += target_boot.size - - script.Print("Patching system files...") - so_far = system_diff.EmitPatches(script, total_patch_size, 0) - if vendor_diff: - script.Print("Patching vendor files...") - so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far) - - if not OPTIONS.two_step: - if updating_boot: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - script.Print("Patching boot image...") - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - so_far += target_boot.size - script.SetProgress(so_far / total_patch_size) - print "boot image changed; including." - else: - print "boot image unchanged; skipping." - - system_items = ItemSet("system", "META/filesystem_config.txt") - if vendor_diff: - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - - if updating_recovery: - # Recovery is generated as a patch using both the boot image - # (which contains the same linux kernel as recovery) and the file - # /system/etc/recovery-resource.dat (which contains all the images - # used in the recovery UI) as sources. This lets us minimize the - # size of the patch, which must be included in every OTA package. - # - # For older builds where recovery-resource.dat is not present, we - # use only the boot image as the source. - - if not target_has_recovery_patch: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn, dir=False) - - common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink, - target_recovery, target_boot) - script.DeleteFiles(["/system/recovery-from-boot.p", - "/system/etc/install-recovery.sh"]) - print "recovery image changed; including as patch from boot." - else: - print "recovery image unchanged; skipping." - - script.ShowProgress(0.1, 10) - - target_symlinks = CopyPartitionFiles(system_items, target_zip, None) - if vendor_diff: - target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None)) - - temp_script = script.MakeTemporary() - system_items.GetMetadata(target_zip) - system_items.Get("system").SetPermissions(temp_script) - if vendor_diff: - vendor_items.GetMetadata(target_zip) - vendor_items.Get("vendor").SetPermissions(temp_script) - - # Note that this call will mess up the trees of Items, so make sure - # we're done with them. - source_symlinks = CopyPartitionFiles(system_items, source_zip, None) - if vendor_diff: - source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None)) - - target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) - source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) - - # Delete all the symlinks in source that aren't in target. This - # needs to happen before verbatim files are unpacked, in case a - # symlink in the source is replaced by a real file in the target. - to_delete = [] - for dest, link in source_symlinks: - if link not in target_symlinks_d: - to_delete.append(link) - script.DeleteFiles(to_delete) - - if system_diff.verbatim_targets: - script.Print("Unpacking new system files...") - script.UnpackPackageDir("system", "/system") - if vendor_diff and vendor_diff.verbatim_targets: - script.Print("Unpacking new vendor files...") - script.UnpackPackageDir("vendor", "/vendor") - - if updating_recovery and not target_has_recovery_patch: - script.Print("Unpacking new recovery...") - script.UnpackPackageDir("recovery", "/system") - - system_diff.EmitRenames(script) - if vendor_diff: - vendor_diff.EmitRenames(script) - - script.Print("Symlinks and permissions...") - - # Create all the symlinks that don't already exist, or point to - # somewhere different than what we want. Delete each symlink before - # creating it, since the 'symlink' command won't overwrite. - to_create = [] - for dest, link in target_symlinks: - if link in source_symlinks_d: - if dest != source_symlinks_d[link]: - to_create.append((dest, link)) - else: - to_create.append((dest, link)) - script.DeleteFiles([i[1] for i in to_create]) - script.MakeSymlinks(to_create) - - # Now that the symlinks are created, we can set all the - # permissions. - script.AppendScript(temp_script) - - # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() - - if OPTIONS.extra_script is not None: - script.AppendExtra(OPTIONS.extra_script) - - # Patch the build.prop file last, so if something fails but the - # device can still come up, it appears to be the old build and will - # get set the OTA package again to retry. - script.Print("Patching remaining system files...") - system_diff.EmitDeferredPatches(script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - if OPTIONS.verify and system_diff: - script.Print("Remounting and verifying system partition files...") - script.Unmount("/system") - script.Mount("/system") - system_diff.EmitExplicitTargetVerification(script) - - if OPTIONS.verify and vendor_diff: - script.Print("Remounting and verifying vendor partition files...") - script.Unmount("/vendor") - script.Mount("/vendor") - vendor_diff.EmitExplicitTargetVerification(script) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) - - WriteMetadata(metadata, output_zip) - - -def main(argv): - - def option_handler(o, a): - if o == "--board_config": - pass # deprecated - elif o in ("-k", "--package_key"): - OPTIONS.package_key = a - elif o in ("-i", "--incremental_from"): - OPTIONS.incremental_source = a - elif o in ("-w", "--wipe_user_data"): - OPTIONS.wipe_user_data = True - elif o in ("-n", "--no_prereq"): - OPTIONS.omit_prereq = True - elif o in ("-o", "--oem_settings"): - OPTIONS.oem_source = a - elif o in ("-e", "--extra_script"): - OPTIONS.extra_script = a - elif o in ("-a", "--aslr_mode"): - if a in ("on", "On", "true", "True", "yes", "Yes"): - OPTIONS.aslr_mode = True - else: - OPTIONS.aslr_mode = False - elif o in ("-t", "--worker_threads"): - if a.isdigit(): - OPTIONS.worker_threads = int(a) - else: - raise ValueError("Cannot parse value %r for option %r - only " - "integers are allowed." % (a, o)) - elif o in ("-2", "--two_step"): - OPTIONS.two_step = True - elif o == "--no_signing": - OPTIONS.no_signing = True - elif o in ("--verify"): - OPTIONS.verify = True - elif o == "--block": - OPTIONS.block_based = True - elif o in ("-b", "--binary"): - OPTIONS.updater_binary = a - elif o in ("--no_fallback_to_full",): - OPTIONS.fallback_to_full = False - else: - return False - return True - - args = common.ParseOptions(argv, __doc__, - extra_opts="b:k:i:d:wne:t:a:2o:", - extra_long_opts=["board_config=", - "package_key=", - "incremental_from=", - "wipe_user_data", - "no_prereq", - "extra_script=", - "worker_threads=", - "aslr_mode=", - "two_step", - "no_signing", - "block", - "binary=", - "oem_settings=", - "verify", - "no_fallback_to_full", - ], - extra_option_handler=option_handler) - - if len(args) != 2: - common.Usage(__doc__) - sys.exit(1) - - if OPTIONS.extra_script is not None: - OPTIONS.extra_script = open(OPTIONS.extra_script).read() - - print "unzipping target target-files..." - OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) - - OPTIONS.target_tmp = OPTIONS.input_tmp - OPTIONS.info_dict = common.LoadInfoDict(input_zip) - - # If this image was originally labelled with SELinux contexts, make sure we - # also apply the labels in our new image. During building, the "file_contexts" - # is in the out/ directory tree, but for repacking from target-files.zip it's - # in the root directory of the ramdisk. - if "selinux_fc" in OPTIONS.info_dict: - OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK", - "file_contexts") - - if OPTIONS.verbose: - print "--- target info ---" - common.DumpInfoDict(OPTIONS.info_dict) - - # If the caller explicitly specified the device-specific extensions - # path via -s/--device_specific, use that. Otherwise, use - # META/releasetools.py if it is present in the target target_files. - # Otherwise, take the path of the file from 'tool_extensions' in the - # info dict and look for that in the local filesystem, relative to - # the current directory. - - if OPTIONS.device_specific is None: - from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") - if os.path.exists(from_input): - print "(using device-specific extensions from target_files)" - OPTIONS.device_specific = from_input - else: - OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) - - if OPTIONS.device_specific is not None: - OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) - - while True: - - if OPTIONS.no_signing: - if os.path.exists(args[1]): os.unlink(args[1]) - output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) - else: - temp_zip_file = tempfile.NamedTemporaryFile() - output_zip = zipfile.ZipFile(temp_zip_file, "w", - compression=zipfile.ZIP_DEFLATED) - - if OPTIONS.incremental_source is None: - WriteFullOTAPackage(input_zip, output_zip) - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - break - - else: - print "unzipping source target-files..." - OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source) - OPTIONS.target_info_dict = OPTIONS.info_dict - OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) - if "selinux_fc" in OPTIONS.source_info_dict: - OPTIONS.source_info_dict["selinux_fc"] = os.path.join(OPTIONS.source_tmp, "BOOT", "RAMDISK", - "file_contexts") - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.source_info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - if OPTIONS.verbose: - print "--- source info ---" - common.DumpInfoDict(OPTIONS.source_info_dict) - try: - WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) - break - except ValueError: - if not OPTIONS.fallback_to_full: raise - print "--- failed to build incremental; falling back to full ---" - OPTIONS.incremental_source = None - output_zip.close() - - output_zip.close() - - if not OPTIONS.no_signing: - SignOutput(temp_zip_file.name, args[1]) - temp_zip_file.close() - - print "done." - - -if __name__ == '__main__': - try: - common.CloseInheritedPipes() - main(sys.argv[1:]) - except common.ExternalError, e: - print - print " ERROR: %s" % (e,) - print - sys.exit(1) - finally: - common.Cleanup() +ota_from_target_files.py
\ No newline at end of file diff --git a/tools/releasetools/ota_from_target_files.py b/tools/releasetools/ota_from_target_files.py new file mode 100755 index 0000000..eab3daa --- /dev/null +++ b/tools/releasetools/ota_from_target_files.py @@ -0,0 +1,1631 @@ +#!/usr/bin/env python +# +# 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. + +""" +Given a target-files zipfile, produces an OTA package that installs +that build. An incremental OTA is produced if -i is given, otherwise +a full OTA is produced. + +Usage: ota_from_target_files [flags] input_target_files output_ota_package + + --board_config <file> + Deprecated. + + -k (--package_key) <key> Key to use to sign the package (default is + the value of default_system_dev_certificate from the input + target-files's META/misc_info.txt, or + "build/target/product/security/testkey" if that value is not + specified). + + For incremental OTAs, the default value is based on the source + target-file, not the target build. + + -i (--incremental_from) <file> + Generate an incremental OTA using the given target-files zip as + the starting build. + + --full_radio + When generating an incremental OTA, always include a full copy of + radio image. This option is only meaningful when -i is specified, + because a full radio is always included in a full OTA if applicable. + + -v (--verify) + Remount and verify the checksums of the files written to the + system and vendor (if used) partitions. Incremental builds only. + + -o (--oem_settings) <file> + Use the file to specify the expected OEM-specific properties + on the OEM partition of the intended device. + + -w (--wipe_user_data) + Generate an OTA package that will wipe the user data partition + when installed. + + -n (--no_prereq) + Omit the timestamp prereq check normally included at the top of + the build scripts (used for developer OTA packages which + legitimately need to go back and forth). + + -e (--extra_script) <file> + Insert the contents of file at the end of the update script. + + -a (--aslr_mode) <on|off> + Specify whether to turn on ASLR for the package (on by default). + + -2 (--two_step) + Generate a 'two-step' OTA package, where recovery is updated + first, so that any changes made to the system partition are done + using the new recovery (new kernel, etc.). + + --block + Generate a block-based OTA if possible. Will fall back to a + file-based OTA if the target_files is older and doesn't support + block-based OTAs. + + -b (--binary) <file> + Use the given binary as the update-binary in the output package, + instead of the binary in the build's target_files. Use for + development only. + + -t (--worker_threads) <int> + Specifies the number of worker-threads that will be used when + generating patches for incremental updates (defaults to 3). + +""" + +import sys + +if sys.hexversion < 0x02070000: + print >> sys.stderr, "Python 2.7 or newer is required." + sys.exit(1) + +import copy +import multiprocessing +import os +import tempfile +import zipfile + +import common +import edify_generator +import sparse_img + +OPTIONS = common.OPTIONS +OPTIONS.package_key = None +OPTIONS.incremental_source = None +OPTIONS.verify = False +OPTIONS.require_verbatim = set() +OPTIONS.prohibit_verbatim = set(("system/build.prop",)) +OPTIONS.patch_threshold = 0.95 +OPTIONS.wipe_user_data = False +OPTIONS.omit_prereq = False +OPTIONS.extra_script = None +OPTIONS.aslr_mode = True +OPTIONS.worker_threads = multiprocessing.cpu_count() // 2 +if OPTIONS.worker_threads == 0: + OPTIONS.worker_threads = 1 +OPTIONS.two_step = False +OPTIONS.no_signing = False +OPTIONS.block_based = False +OPTIONS.updater_binary = None +OPTIONS.oem_source = None +OPTIONS.fallback_to_full = True +OPTIONS.full_radio = False + +def MostPopularKey(d, default): + """Given a dict, return the key corresponding to the largest + value. Returns 'default' if the dict is empty.""" + x = [(v, k) for (k, v) in d.iteritems()] + if not x: + return default + x.sort() + return x[-1][1] + + +def IsSymlink(info): + """Return true if the zipfile.ZipInfo object passed in represents a + symlink.""" + return (info.external_attr >> 16) == 0o120777 + +def IsRegular(info): + """Return true if the zipfile.ZipInfo object passed in represents a + symlink.""" + return (info.external_attr >> 28) == 0o10 + +def ClosestFileMatch(src, tgtfiles, existing): + """Returns the closest file match between a source file and list + of potential matches. The exact filename match is preferred, + then the sha1 is searched for, and finally a file with the same + basename is evaluated. Rename support in the updater-binary is + required for the latter checks to be used.""" + + result = tgtfiles.get("path:" + src.name) + if result is not None: + return result + + if not OPTIONS.target_info_dict.get("update_rename_support", False): + return None + + if src.size < 1000: + return None + + result = tgtfiles.get("sha1:" + src.sha1) + if result is not None and existing.get(result.name) is None: + return result + result = tgtfiles.get("file:" + src.name.split("/")[-1]) + if result is not None and existing.get(result.name) is None: + return result + return None + +class ItemSet(object): + def __init__(self, partition, fs_config): + self.partition = partition + self.fs_config = fs_config + self.ITEMS = {} + + def Get(self, name, is_dir=False): + if name not in self.ITEMS: + self.ITEMS[name] = Item(self, name, is_dir=is_dir) + return self.ITEMS[name] + + def GetMetadata(self, input_zip): + # The target_files contains a record of what the uid, + # gid, and mode are supposed to be. + output = input_zip.read(self.fs_config) + + for line in output.split("\n"): + if not line: + continue + columns = line.split() + name, uid, gid, mode = columns[:4] + selabel = None + capabilities = None + + # After the first 4 columns, there are a series of key=value + # pairs. Extract out the fields we care about. + for element in columns[4:]: + key, value = element.split("=") + if key == "selabel": + selabel = value + if key == "capabilities": + capabilities = value + + i = self.ITEMS.get(name, None) + if i is not None: + i.uid = int(uid) + i.gid = int(gid) + i.mode = int(mode, 8) + i.selabel = selabel + i.capabilities = capabilities + if i.is_dir: + i.children.sort(key=lambda i: i.name) + + # set metadata for the files generated by this script. + i = self.ITEMS.get("system/recovery-from-boot.p", None) + if i: + i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None + i = self.ITEMS.get("system/etc/install-recovery.sh", None) + if i: + i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None + + +class Item(object): + """Items represent the metadata (user, group, mode) of files and + directories in the system image.""" + def __init__(self, itemset, name, is_dir=False): + self.itemset = itemset + self.name = name + self.uid = None + self.gid = None + self.mode = None + self.selabel = None + self.capabilities = None + self.is_dir = is_dir + self.descendants = None + self.best_subtree = None + + if name: + self.parent = itemset.Get(os.path.dirname(name), is_dir=True) + self.parent.children.append(self) + else: + self.parent = None + if self.is_dir: + self.children = [] + + def Dump(self, indent=0): + if self.uid is not None: + print "%s%s %d %d %o" % ( + " " * indent, self.name, self.uid, self.gid, self.mode) + else: + print "%s%s %s %s %s" % ( + " " * indent, self.name, self.uid, self.gid, self.mode) + if self.is_dir: + print "%s%s" % (" "*indent, self.descendants) + print "%s%s" % (" "*indent, self.best_subtree) + for i in self.children: + i.Dump(indent=indent+1) + + def CountChildMetadata(self): + """Count up the (uid, gid, mode, selabel, capabilities) tuples for + all children and determine the best strategy for using set_perm_recursive + and set_perm to correctly chown/chmod all the files to their desired + values. Recursively calls itself for all descendants. + + Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} + counting up all descendants of this node. (dmode or fmode may be None.) + Also sets the best_subtree of each directory Item to the (uid, gid, dmode, + fmode, selabel, capabilities) tuple that will match the most descendants of + that Item. + """ + + assert self.is_dir + key = (self.uid, self.gid, self.mode, None, self.selabel, + self.capabilities) + self.descendants = {key: 1} + d = self.descendants + for i in self.children: + if i.is_dir: + for k, v in i.CountChildMetadata().iteritems(): + d[k] = d.get(k, 0) + v + else: + k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities) + d[k] = d.get(k, 0) + 1 + + # Find the (uid, gid, dmode, fmode, selabel, capabilities) + # tuple that matches the most descendants. + + # First, find the (uid, gid) pair that matches the most + # descendants. + ug = {} + for (uid, gid, _, _, _, _), count in d.iteritems(): + ug[(uid, gid)] = ug.get((uid, gid), 0) + count + ug = MostPopularKey(ug, (0, 0)) + + # Now find the dmode, fmode, selabel, and capabilities that match + # the most descendants with that (uid, gid), and choose those. + best_dmode = (0, 0o755) + best_fmode = (0, 0o644) + best_selabel = (0, None) + best_capabilities = (0, None) + for k, count in d.iteritems(): + if k[:2] != ug: + continue + if k[2] is not None and count >= best_dmode[0]: + best_dmode = (count, k[2]) + if k[3] is not None and count >= best_fmode[0]: + best_fmode = (count, k[3]) + if k[4] is not None and count >= best_selabel[0]: + best_selabel = (count, k[4]) + if k[5] is not None and count >= best_capabilities[0]: + best_capabilities = (count, k[5]) + self.best_subtree = ug + ( + best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) + + return d + + def SetPermissions(self, script): + """Append set_perm/set_perm_recursive commands to 'script' to + set all permissions, users, and groups for the tree of files + rooted at 'self'.""" + + self.CountChildMetadata() + + def recurse(item, current): + # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple + # that the current item (and all its children) have already been set to. + # We only need to issue set_perm/set_perm_recursive commands if we're + # supposed to be something different. + if item.is_dir: + if current != item.best_subtree: + script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) + current = item.best_subtree + + if item.uid != current[0] or item.gid != current[1] or \ + item.mode != current[2] or item.selabel != current[4] or \ + item.capabilities != current[5]: + script.SetPermissions("/"+item.name, item.uid, item.gid, + item.mode, item.selabel, item.capabilities) + + for i in item.children: + recurse(i, current) + else: + if item.uid != current[0] or item.gid != current[1] or \ + item.mode != current[3] or item.selabel != current[4] or \ + item.capabilities != current[5]: + script.SetPermissions("/"+item.name, item.uid, item.gid, + item.mode, item.selabel, item.capabilities) + + recurse(self, (-1, -1, -1, -1, None, None)) + + +def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): + """Copies files for the partition in the input zip to the output + zip. Populates the Item class with their metadata, and returns a + list of symlinks. output_zip may be None, in which case the copy is + skipped (but the other side effects still happen). substitute is an + optional dict of {output filename: contents} to be output instead of + certain input files. + """ + + symlinks = [] + + partition = itemset.partition + + for info in input_zip.infolist(): + prefix = partition.upper() + "/" + if info.filename.startswith(prefix): + basefilename = info.filename[len(prefix):] + if IsSymlink(info): + symlinks.append((input_zip.read(info.filename), + "/" + partition + "/" + basefilename)) + else: + info2 = copy.copy(info) + fn = info2.filename = partition + "/" + basefilename + if substitute and fn in substitute and substitute[fn] is None: + continue + if output_zip is not None: + if substitute and fn in substitute: + data = substitute[fn] + else: + data = input_zip.read(info.filename) + output_zip.writestr(info2, data) + if fn.endswith("/"): + itemset.Get(fn[:-1], is_dir=True) + else: + itemset.Get(fn) + + symlinks.sort() + return symlinks + + +def SignOutput(temp_zip_name, output_zip_name): + key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) + pw = key_passwords[OPTIONS.package_key] + + common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, + whole_file=True) + + +def AppendAssertions(script, info_dict, oem_dict=None): + oem_props = info_dict.get("oem_fingerprint_properties") + if oem_props is None or len(oem_props) == 0: + device = GetBuildProp("ro.product.device", info_dict) + script.AssertDevice(device) + else: + if oem_dict is None: + raise common.ExternalError( + "No OEM file provided to answer expected assertions") + for prop in oem_props.split(): + if oem_dict.get(prop) is None: + raise common.ExternalError( + "The OEM file is missing the property %s" % prop) + script.AssertOemProperty(prop, oem_dict.get(prop)) + + +def HasRecoveryPatch(target_files_zip): + try: + target_files_zip.getinfo("SYSTEM/recovery-from-boot.p") + return True + except KeyError: + return False + +def HasVendorPartition(target_files_zip): + try: + target_files_zip.getinfo("VENDOR/") + return True + except KeyError: + return False + +def GetOemProperty(name, oem_props, oem_dict, info_dict): + if oem_props is not None and name in oem_props: + return oem_dict[name] + return GetBuildProp(name, info_dict) + + +def CalculateFingerprint(oem_props, oem_dict, info_dict): + if oem_props is None: + return GetBuildProp("ro.build.fingerprint", info_dict) + return "%s/%s/%s:%s" % ( + GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict), + GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict), + GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict), + GetBuildProp("ro.build.thumbprint", info_dict)) + + +def GetImage(which, tmpdir, info_dict): + # Return an image object (suitable for passing to BlockImageDiff) + # for the 'which' partition (most be "system" or "vendor"). If a + # prebuilt image and file map are found in tmpdir they are used, + # otherwise they are reconstructed from the individual files. + + assert which in ("system", "vendor") + + path = os.path.join(tmpdir, "IMAGES", which + ".img") + mappath = os.path.join(tmpdir, "IMAGES", which + ".map") + if os.path.exists(path) and os.path.exists(mappath): + print "using %s.img from target-files" % (which,) + # This is a 'new' target-files, which already has the image in it. + + else: + print "building %s.img from target-files" % (which,) + + # This is an 'old' target-files, which does not contain images + # already built. Build them. + + mappath = tempfile.mkstemp()[1] + OPTIONS.tempfiles.append(mappath) + + import add_img_to_target_files + if which == "system": + path = add_img_to_target_files.BuildSystem( + tmpdir, info_dict, block_list=mappath) + elif which == "vendor": + path = add_img_to_target_files.BuildVendor( + tmpdir, info_dict, block_list=mappath) + + return sparse_img.SparseImage(path, mappath) + + +def WriteFullOTAPackage(input_zip, output_zip): + # TODO: how to determine this? We don't know what version it will + # be installed on top of. For now, we expect the API just won't + # change very often. + script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) + + oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") + recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") + oem_dict = None + if oem_props is not None and len(oem_props) > 0: + if OPTIONS.oem_source is None: + raise common.ExternalError("OEM source required for this build") + script.Mount("/oem", recovery_mount_options) + oem_dict = common.LoadDictionaryFromLines( + open(OPTIONS.oem_source).readlines()) + + metadata = { + "post-build": CalculateFingerprint(oem_props, oem_dict, + OPTIONS.info_dict), + "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + OPTIONS.info_dict), + "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), + } + + device_specific = common.DeviceSpecificParams( + input_zip=input_zip, + input_version=OPTIONS.info_dict["recovery_api_version"], + output_zip=output_zip, + script=script, + input_tmp=OPTIONS.input_tmp, + metadata=metadata, + info_dict=OPTIONS.info_dict) + + has_recovery_patch = HasRecoveryPatch(input_zip) + block_based = OPTIONS.block_based and has_recovery_patch + + if not OPTIONS.omit_prereq: + ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict) + ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) + script.AssertOlderBuild(ts, ts_text) + + AppendAssertions(script, OPTIONS.info_dict, oem_dict) + device_specific.FullOTA_Assertions() + + # Two-step package strategy (in chronological order, which is *not* + # the order in which the generated script has things): + # + # if stage is not "2/3" or "3/3": + # write recovery image to boot partition + # set stage to "2/3" + # reboot to boot partition and restart recovery + # else if stage is "2/3": + # write recovery image to recovery partition + # set stage to "3/3" + # reboot to recovery partition and restart recovery + # else: + # (stage must be "3/3") + # set stage to "" + # do normal full package installation: + # wipe and install system, boot image, etc. + # set up system to update recovery partition on first boot + # complete script normally + # (allow recovery to mark itself finished and reboot) + + recovery_img = common.GetBootableImage("recovery.img", "recovery.img", + OPTIONS.input_tmp, "RECOVERY") + if OPTIONS.two_step: + if not OPTIONS.info_dict.get("multistage_support", None): + assert False, "two-step packages not supported by this build" + fs = OPTIONS.info_dict["fstab"]["/misc"] + assert fs.fs_type.upper() == "EMMC", \ + "two-step packages only supported on devices with EMMC /misc partitions" + bcb_dev = {"bcb_dev": fs.device} + common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data) + script.AppendExtra(""" +if get_stage("%(bcb_dev)s") == "2/3" then +""" % bcb_dev) + script.WriteRawImage("/recovery", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "3/3"); +reboot_now("%(bcb_dev)s", "recovery"); +else if get_stage("%(bcb_dev)s") == "3/3" then +""" % bcb_dev) + + # Dump fingerprints + script.Print("Target: %s" % CalculateFingerprint( + oem_props, oem_dict, OPTIONS.info_dict)) + + device_specific.FullOTA_InstallBegin() + + system_progress = 0.75 + + if OPTIONS.wipe_user_data: + system_progress -= 0.1 + if HasVendorPartition(input_zip): + system_progress -= 0.1 + + if "selinux_fc" in OPTIONS.info_dict: + WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) + + recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") + + system_items = ItemSet("system", "META/filesystem_config.txt") + script.ShowProgress(system_progress, 0) + + if block_based: + # Full OTA is done as an "incremental" against an empty source + # image. This has the effect of writing new data from the package + # to the entire partition, but lets us reuse the updater code that + # writes incrementals to do it. + system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict) + system_tgt.ResetFileMap() + system_diff = common.BlockDifference("system", system_tgt, src=None) + system_diff.WriteScript(script, output_zip) + else: + script.FormatPartition("/system") + script.Mount("/system", recovery_mount_options) + if not has_recovery_patch: + script.UnpackPackageDir("recovery", "/system") + script.UnpackPackageDir("system", "/system") + + symlinks = CopyPartitionFiles(system_items, input_zip, output_zip) + script.MakeSymlinks(symlinks) + + boot_img = common.GetBootableImage("boot.img", "boot.img", + OPTIONS.input_tmp, "BOOT") + + if not block_based: + def output_sink(fn, data): + common.ZipWriteStr(output_zip, "recovery/" + fn, data) + system_items.Get("system/" + fn) + + common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, + recovery_img, boot_img) + + system_items.GetMetadata(input_zip) + system_items.Get("system").SetPermissions(script) + + if HasVendorPartition(input_zip): + vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") + script.ShowProgress(0.1, 0) + + if block_based: + vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict) + vendor_tgt.ResetFileMap() + vendor_diff = common.BlockDifference("vendor", vendor_tgt) + vendor_diff.WriteScript(script, output_zip) + else: + script.FormatPartition("/vendor") + script.Mount("/vendor", recovery_mount_options) + script.UnpackPackageDir("vendor", "/vendor") + + symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip) + script.MakeSymlinks(symlinks) + + vendor_items.GetMetadata(input_zip) + vendor_items.Get("vendor").SetPermissions(script) + + common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) + common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + + script.ShowProgress(0.05, 5) + script.WriteRawImage("/boot", "boot.img") + + script.ShowProgress(0.2, 10) + device_specific.FullOTA_InstallEnd() + + if OPTIONS.extra_script is not None: + script.AppendExtra(OPTIONS.extra_script) + + script.UnmountAll() + + if OPTIONS.wipe_user_data: + script.ShowProgress(0.1, 10) + script.FormatPartition("/data") + + if OPTIONS.two_step: + script.AppendExtra(""" +set_stage("%(bcb_dev)s", ""); +""" % bcb_dev) + script.AppendExtra("else\n") + script.WriteRawImage("/boot", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "2/3"); +reboot_now("%(bcb_dev)s", ""); +endif; +endif; +""" % bcb_dev) + script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) + WriteMetadata(metadata, output_zip) + + +def WritePolicyConfig(file_name, output_zip): + common.ZipWrite(output_zip, file_name, os.path.basename(file_name)) + + +def WriteMetadata(metadata, output_zip): + common.ZipWriteStr(output_zip, "META-INF/com/android/metadata", + "".join(["%s=%s\n" % kv + for kv in sorted(metadata.iteritems())])) + + +def LoadPartitionFiles(z, partition): + """Load all the files from the given partition in a given target-files + ZipFile, and return a dict of {filename: File object}.""" + out = {} + prefix = partition.upper() + "/" + for info in z.infolist(): + if info.filename.startswith(prefix) and not IsSymlink(info): + basefilename = info.filename[len(prefix):] + fn = partition + "/" + basefilename + data = z.read(info.filename) + out[fn] = common.File(fn, data) + return out + + +def GetBuildProp(prop, info_dict): + """Return the fingerprint of the build of a given target-files info_dict.""" + try: + return info_dict.get("build.prop", {})[prop] + except KeyError: + raise common.ExternalError("couldn't find %s in build.prop" % (prop,)) + + +def AddToKnownPaths(filename, known_paths): + if filename[-1] == "/": + return + dirs = filename.split("/")[:-1] + while len(dirs) > 0: + path = "/".join(dirs) + if path in known_paths: + break + known_paths.add(path) + dirs.pop() + + +def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): + source_version = OPTIONS.source_info_dict["recovery_api_version"] + target_version = OPTIONS.target_info_dict["recovery_api_version"] + + if source_version == 0: + print ("WARNING: generating edify script for a source that " + "can't install it.") + script = edify_generator.EdifyGenerator(source_version, + OPTIONS.target_info_dict) + + metadata = { + "pre-device": GetBuildProp("ro.product.device", + OPTIONS.source_info_dict), + "post-timestamp": GetBuildProp("ro.build.date.utc", + OPTIONS.target_info_dict), + } + + device_specific = common.DeviceSpecificParams( + source_zip=source_zip, + source_version=source_version, + target_zip=target_zip, + target_version=target_version, + output_zip=output_zip, + script=script, + metadata=metadata, + info_dict=OPTIONS.info_dict) + + # TODO: Currently this works differently from WriteIncrementalOTAPackage(). + # This function doesn't consider thumbprints when writing + # metadata["pre/post-build"]. One possible reason is that the current + # devices with thumbprints are all using file-based OTAs. Long term we + # should factor out the common parts into a shared one to avoid further + # divergence. + source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict) + target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict) + metadata["pre-build"] = source_fp + metadata["post-build"] = target_fp + + source_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", + OPTIONS.source_info_dict) + target_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") + updating_boot = (not OPTIONS.two_step and + (source_boot.data != target_boot.data)) + + target_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") + + system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict) + system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict) + + blockimgdiff_version = 1 + if OPTIONS.info_dict: + blockimgdiff_version = max( + int(i) for i in + OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) + + system_diff = common.BlockDifference("system", system_tgt, system_src, + check_first_block=True, + version=blockimgdiff_version) + + if HasVendorPartition(target_zip): + if not HasVendorPartition(source_zip): + raise RuntimeError("can't generate incremental that adds /vendor") + vendor_src = GetImage("vendor", OPTIONS.source_tmp, + OPTIONS.source_info_dict) + vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, + OPTIONS.target_info_dict) + vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src, + check_first_block=True, + version=blockimgdiff_version) + else: + vendor_diff = None + + oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") + recovery_mount_options = OPTIONS.target_info_dict.get( + "recovery_mount_options") + oem_dict = None + if oem_props is not None and len(oem_props) > 0: + if OPTIONS.oem_source is None: + raise common.ExternalError("OEM source required for this build") + script.Mount("/oem", recovery_mount_options) + oem_dict = common.LoadDictionaryFromLines( + open(OPTIONS.oem_source).readlines()) + + AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + device_specific.IncrementalOTA_Assertions() + + # Two-step incremental package strategy (in chronological order, + # which is *not* the order in which the generated script has + # things): + # + # if stage is not "2/3" or "3/3": + # do verification on current system + # write recovery image to boot partition + # set stage to "2/3" + # reboot to boot partition and restart recovery + # else if stage is "2/3": + # write recovery image to recovery partition + # set stage to "3/3" + # reboot to recovery partition and restart recovery + # else: + # (stage must be "3/3") + # perform update: + # patch system files, etc. + # force full install of new boot image + # set up system to update recovery partition on first boot + # complete script normally + # (allow recovery to mark itself finished and reboot) + + if OPTIONS.two_step: + if not OPTIONS.info_dict.get("multistage_support", None): + assert False, "two-step packages not supported by this build" + fs = OPTIONS.info_dict["fstab"]["/misc"] + assert fs.fs_type.upper() == "EMMC", \ + "two-step packages only supported on devices with EMMC /misc partitions" + bcb_dev = {"bcb_dev": fs.device} + common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) + script.AppendExtra(""" +if get_stage("%(bcb_dev)s") == "2/3" then +""" % bcb_dev) + script.AppendExtra("sleep(20);\n") + script.WriteRawImage("/recovery", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "3/3"); +reboot_now("%(bcb_dev)s", "recovery"); +else if get_stage("%(bcb_dev)s") != "3/3" then +""" % bcb_dev) + + # Dump fingerprints + script.Print("Source: %s" % CalculateFingerprint( + oem_props, oem_dict, OPTIONS.source_info_dict)) + script.Print("Target: %s" % CalculateFingerprint( + oem_props, oem_dict, OPTIONS.target_info_dict)) + + script.Print("Verifying current system...") + + device_specific.IncrementalOTA_VerifyBegin() + + if oem_props is None: + # When blockimgdiff version is less than 3 (non-resumable block-based OTA), + # patching on a device that's already on the target build will damage the + # system. Because operations like move don't check the block state, they + # always apply the changes unconditionally. + if blockimgdiff_version <= 2: + script.AssertSomeFingerprint(source_fp) + else: + script.AssertSomeFingerprint(source_fp, target_fp) + else: + if blockimgdiff_version <= 2: + script.AssertSomeThumbprint( + GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + else: + script.AssertSomeThumbprint( + GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), + GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + + if updating_boot: + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) + d = common.Difference(target_boot, source_boot) + _, _, d = d.ComputePatch() + if d is None: + include_full_boot = True + common.ZipWriteStr(output_zip, "boot.img", target_boot.data) + else: + include_full_boot = False + + print "boot target: %d source: %d diff: %d" % ( + target_boot.size, source_boot.size, len(d)) + + common.ZipWriteStr(output_zip, "patch/boot.img.p", d) + + script.PatchCheck("%s:%s:%d:%s:%d:%s" % + (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1)) + + device_specific.IncrementalOTA_VerifyEnd() + + if OPTIONS.two_step: + script.WriteRawImage("/boot", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "2/3"); +reboot_now("%(bcb_dev)s", ""); +else +""" % bcb_dev) + + # Verify the existing partitions. + system_diff.WriteVerifyScript(script) + if vendor_diff: + vendor_diff.WriteVerifyScript(script) + + script.Comment("---- start making changes here ----") + + device_specific.IncrementalOTA_InstallBegin() + + system_diff.WriteScript(script, output_zip, + progress=0.8 if vendor_diff else 0.9) + if vendor_diff: + vendor_diff.WriteScript(script, output_zip, progress=0.1) + + if OPTIONS.two_step: + common.ZipWriteStr(output_zip, "boot.img", target_boot.data) + script.WriteRawImage("/boot", "boot.img") + print "writing full boot image (forced by two-step mode)" + + if not OPTIONS.two_step: + if updating_boot: + if include_full_boot: + print "boot image changed; including full." + script.Print("Installing boot image...") + script.WriteRawImage("/boot", "boot.img") + else: + # Produce the boot image by applying a patch to the current + # contents of the boot partition, and write it back to the + # partition. + print "boot image changed; including patch." + script.Print("Patching boot image...") + script.ShowProgress(0.1, 10) + script.ApplyPatch("%s:%s:%d:%s:%d:%s" + % (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1), + "-", + target_boot.size, target_boot.sha1, + source_boot.sha1, "patch/boot.img.p") + else: + print "boot image unchanged; skipping." + + # Do device-specific installation (eg, write radio image). + device_specific.IncrementalOTA_InstallEnd() + + if OPTIONS.extra_script is not None: + script.AppendExtra(OPTIONS.extra_script) + + if OPTIONS.wipe_user_data: + script.Print("Erasing user data...") + script.FormatPartition("/data") + + if OPTIONS.two_step: + script.AppendExtra(""" +set_stage("%(bcb_dev)s", ""); +endif; +endif; +""" % bcb_dev) + + script.SetProgress(1) + script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) + WriteMetadata(metadata, output_zip) + + +class FileDifference(object): + def __init__(self, partition, source_zip, target_zip, output_zip): + self.deferred_patch_list = None + print "Loading target..." + self.target_data = target_data = LoadPartitionFiles(target_zip, partition) + print "Loading source..." + self.source_data = source_data = LoadPartitionFiles(source_zip, partition) + + self.verbatim_targets = verbatim_targets = [] + self.patch_list = patch_list = [] + diffs = [] + self.renames = renames = {} + known_paths = set() + largest_source_size = 0 + + matching_file_cache = {} + for fn, sf in source_data.items(): + assert fn == sf.name + matching_file_cache["path:" + fn] = sf + if fn in target_data.keys(): + AddToKnownPaths(fn, known_paths) + # Only allow eligibility for filename/sha matching + # if there isn't a perfect path match. + if target_data.get(sf.name) is None: + matching_file_cache["file:" + fn.split("/")[-1]] = sf + matching_file_cache["sha:" + sf.sha1] = sf + + for fn in sorted(target_data.keys()): + tf = target_data[fn] + assert fn == tf.name + sf = ClosestFileMatch(tf, matching_file_cache, renames) + if sf is not None and sf.name != tf.name: + print "File has moved from " + sf.name + " to " + tf.name + renames[sf.name] = tf + + if sf is None or fn in OPTIONS.require_verbatim: + # This file should be included verbatim + if fn in OPTIONS.prohibit_verbatim: + raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) + print "send", fn, "verbatim" + tf.AddToZip(output_zip) + verbatim_targets.append((fn, tf.size, tf.sha1)) + if fn in target_data.keys(): + AddToKnownPaths(fn, known_paths) + elif tf.sha1 != sf.sha1: + # File is different; consider sending as a patch + diffs.append(common.Difference(tf, sf)) + else: + # Target file data identical to source (may still be renamed) + pass + + common.ComputeDifferences(diffs) + + for diff in diffs: + tf, sf, d = diff.GetPatch() + path = "/".join(tf.name.split("/")[:-1]) + if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \ + path not in known_paths: + # patch is almost as big as the file; don't bother patching + # or a patch + rename cannot take place due to the target + # directory not existing + tf.AddToZip(output_zip) + verbatim_targets.append((tf.name, tf.size, tf.sha1)) + if sf.name in renames: + del renames[sf.name] + AddToKnownPaths(tf.name, known_paths) + else: + common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d) + patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest())) + largest_source_size = max(largest_source_size, sf.size) + + self.largest_source_size = largest_source_size + + def EmitVerification(self, script): + so_far = 0 + for tf, sf, _, _ in self.patch_list: + if tf.name != sf.name: + script.SkipNextActionIfTargetExists(tf.name, tf.sha1) + script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1) + so_far += sf.size + return so_far + + def EmitExplicitTargetVerification(self, script): + for fn, _, sha1 in self.verbatim_targets: + if fn[-1] != "/": + script.FileCheck("/"+fn, sha1) + for tf, _, _, _ in self.patch_list: + script.FileCheck(tf.name, tf.sha1) + + def RemoveUnneededFiles(self, script, extras=()): + script.DeleteFiles( + ["/" + i[0] for i in self.verbatim_targets] + + ["/" + i for i in sorted(self.source_data) + if i not in self.target_data and i not in self.renames] + + list(extras)) + + def TotalPatchSize(self): + return sum(i[1].size for i in self.patch_list) + + def EmitPatches(self, script, total_patch_size, so_far): + self.deferred_patch_list = deferred_patch_list = [] + for item in self.patch_list: + tf, sf, _, _ = item + if tf.name == "system/build.prop": + deferred_patch_list.append(item) + continue + if sf.name != tf.name: + script.SkipNextActionIfTargetExists(tf.name, tf.sha1) + script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1, + "patch/" + sf.name + ".p") + so_far += tf.size + script.SetProgress(so_far / total_patch_size) + return so_far + + def EmitDeferredPatches(self, script): + for item in self.deferred_patch_list: + tf, sf, _, _ = item + script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, + "patch/" + sf.name + ".p") + script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None) + + def EmitRenames(self, script): + if len(self.renames) > 0: + script.Print("Renaming files...") + for src, tgt in self.renames.iteritems(): + print "Renaming " + src + " to " + tgt.name + script.RenameFile(src, tgt.name) + + +def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): + target_has_recovery_patch = HasRecoveryPatch(target_zip) + source_has_recovery_patch = HasRecoveryPatch(source_zip) + + if (OPTIONS.block_based and + target_has_recovery_patch and + source_has_recovery_patch): + return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip) + + source_version = OPTIONS.source_info_dict["recovery_api_version"] + target_version = OPTIONS.target_info_dict["recovery_api_version"] + + if source_version == 0: + print ("WARNING: generating edify script for a source that " + "can't install it.") + script = edify_generator.EdifyGenerator(source_version, + OPTIONS.target_info_dict) + + oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") + recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") + oem_dict = None + if oem_props is not None and len(oem_props) > 0: + if OPTIONS.oem_source is None: + raise common.ExternalError("OEM source required for this build") + script.Mount("/oem", recovery_mount_options) + oem_dict = common.LoadDictionaryFromLines( + open(OPTIONS.oem_source).readlines()) + + metadata = { + "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, + OPTIONS.source_info_dict), + "post-timestamp": GetBuildProp("ro.build.date.utc", + OPTIONS.target_info_dict), + } + + device_specific = common.DeviceSpecificParams( + source_zip=source_zip, + source_version=source_version, + target_zip=target_zip, + target_version=target_version, + output_zip=output_zip, + script=script, + metadata=metadata, + info_dict=OPTIONS.info_dict) + + system_diff = FileDifference("system", source_zip, target_zip, output_zip) + script.Mount("/system", recovery_mount_options) + if HasVendorPartition(target_zip): + vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip) + script.Mount("/vendor", recovery_mount_options) + else: + vendor_diff = None + + target_fp = CalculateFingerprint(oem_props, oem_dict, + OPTIONS.target_info_dict) + source_fp = CalculateFingerprint(oem_props, oem_dict, + OPTIONS.source_info_dict) + + if oem_props is None: + script.AssertSomeFingerprint(source_fp, target_fp) + else: + script.AssertSomeThumbprint( + GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), + GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + + metadata["pre-build"] = source_fp + metadata["post-build"] = target_fp + + source_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", + OPTIONS.source_info_dict) + target_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") + updating_boot = (not OPTIONS.two_step and + (source_boot.data != target_boot.data)) + + source_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY", + OPTIONS.source_info_dict) + target_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") + updating_recovery = (source_recovery.data != target_recovery.data) + + # Here's how we divide up the progress bar: + # 0.1 for verifying the start state (PatchCheck calls) + # 0.8 for applying patches (ApplyPatch calls) + # 0.1 for unpacking verbatim files, symlinking, and doing the + # device-specific commands. + + AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + device_specific.IncrementalOTA_Assertions() + + # Two-step incremental package strategy (in chronological order, + # which is *not* the order in which the generated script has + # things): + # + # if stage is not "2/3" or "3/3": + # do verification on current system + # write recovery image to boot partition + # set stage to "2/3" + # reboot to boot partition and restart recovery + # else if stage is "2/3": + # write recovery image to recovery partition + # set stage to "3/3" + # reboot to recovery partition and restart recovery + # else: + # (stage must be "3/3") + # perform update: + # patch system files, etc. + # force full install of new boot image + # set up system to update recovery partition on first boot + # complete script normally + # (allow recovery to mark itself finished and reboot) + + if OPTIONS.two_step: + if not OPTIONS.info_dict.get("multistage_support", None): + assert False, "two-step packages not supported by this build" + fs = OPTIONS.info_dict["fstab"]["/misc"] + assert fs.fs_type.upper() == "EMMC", \ + "two-step packages only supported on devices with EMMC /misc partitions" + bcb_dev = {"bcb_dev": fs.device} + common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) + script.AppendExtra(""" +if get_stage("%(bcb_dev)s") == "2/3" then +""" % bcb_dev) + script.AppendExtra("sleep(20);\n") + script.WriteRawImage("/recovery", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "3/3"); +reboot_now("%(bcb_dev)s", "recovery"); +else if get_stage("%(bcb_dev)s") != "3/3" then +""" % bcb_dev) + + # Dump fingerprints + script.Print("Source: %s" % (source_fp,)) + script.Print("Target: %s" % (target_fp,)) + + script.Print("Verifying current system...") + + device_specific.IncrementalOTA_VerifyBegin() + + script.ShowProgress(0.1, 0) + so_far = system_diff.EmitVerification(script) + if vendor_diff: + so_far += vendor_diff.EmitVerification(script) + + if updating_boot: + d = common.Difference(target_boot, source_boot) + _, _, d = d.ComputePatch() + print "boot target: %d source: %d diff: %d" % ( + target_boot.size, source_boot.size, len(d)) + + common.ZipWriteStr(output_zip, "patch/boot.img.p", d) + + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) + + script.PatchCheck("%s:%s:%d:%s:%d:%s" % + (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1)) + so_far += source_boot.size + + size = [] + if system_diff.patch_list: + size.append(system_diff.largest_source_size) + if vendor_diff: + if vendor_diff.patch_list: + size.append(vendor_diff.largest_source_size) + if size or updating_recovery or updating_boot: + script.CacheFreeSpaceCheck(max(size)) + + device_specific.IncrementalOTA_VerifyEnd() + + if OPTIONS.two_step: + script.WriteRawImage("/boot", "recovery.img") + script.AppendExtra(""" +set_stage("%(bcb_dev)s", "2/3"); +reboot_now("%(bcb_dev)s", ""); +else +""" % bcb_dev) + + script.Comment("---- start making changes here ----") + + device_specific.IncrementalOTA_InstallBegin() + + if OPTIONS.two_step: + common.ZipWriteStr(output_zip, "boot.img", target_boot.data) + script.WriteRawImage("/boot", "boot.img") + print "writing full boot image (forced by two-step mode)" + + script.Print("Removing unneeded files...") + system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",)) + if vendor_diff: + vendor_diff.RemoveUnneededFiles(script) + + script.ShowProgress(0.8, 0) + total_patch_size = 1.0 + system_diff.TotalPatchSize() + if vendor_diff: + total_patch_size += vendor_diff.TotalPatchSize() + if updating_boot: + total_patch_size += target_boot.size + + script.Print("Patching system files...") + so_far = system_diff.EmitPatches(script, total_patch_size, 0) + if vendor_diff: + script.Print("Patching vendor files...") + so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far) + + if not OPTIONS.two_step: + if updating_boot: + # Produce the boot image by applying a patch to the current + # contents of the boot partition, and write it back to the + # partition. + script.Print("Patching boot image...") + script.ApplyPatch("%s:%s:%d:%s:%d:%s" + % (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1), + "-", + target_boot.size, target_boot.sha1, + source_boot.sha1, "patch/boot.img.p") + so_far += target_boot.size + script.SetProgress(so_far / total_patch_size) + print "boot image changed; including." + else: + print "boot image unchanged; skipping." + + system_items = ItemSet("system", "META/filesystem_config.txt") + if vendor_diff: + vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") + + if updating_recovery: + # Recovery is generated as a patch using both the boot image + # (which contains the same linux kernel as recovery) and the file + # /system/etc/recovery-resource.dat (which contains all the images + # used in the recovery UI) as sources. This lets us minimize the + # size of the patch, which must be included in every OTA package. + # + # For older builds where recovery-resource.dat is not present, we + # use only the boot image as the source. + + if not target_has_recovery_patch: + def output_sink(fn, data): + common.ZipWriteStr(output_zip, "recovery/" + fn, data) + system_items.Get("system/" + fn) + + common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink, + target_recovery, target_boot) + script.DeleteFiles(["/system/recovery-from-boot.p", + "/system/etc/install-recovery.sh"]) + print "recovery image changed; including as patch from boot." + else: + print "recovery image unchanged; skipping." + + script.ShowProgress(0.1, 10) + + target_symlinks = CopyPartitionFiles(system_items, target_zip, None) + if vendor_diff: + target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None)) + + temp_script = script.MakeTemporary() + system_items.GetMetadata(target_zip) + system_items.Get("system").SetPermissions(temp_script) + if vendor_diff: + vendor_items.GetMetadata(target_zip) + vendor_items.Get("vendor").SetPermissions(temp_script) + + # Note that this call will mess up the trees of Items, so make sure + # we're done with them. + source_symlinks = CopyPartitionFiles(system_items, source_zip, None) + if vendor_diff: + source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None)) + + target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) + source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) + + # Delete all the symlinks in source that aren't in target. This + # needs to happen before verbatim files are unpacked, in case a + # symlink in the source is replaced by a real file in the target. + to_delete = [] + for dest, link in source_symlinks: + if link not in target_symlinks_d: + to_delete.append(link) + script.DeleteFiles(to_delete) + + if system_diff.verbatim_targets: + script.Print("Unpacking new system files...") + script.UnpackPackageDir("system", "/system") + if vendor_diff and vendor_diff.verbatim_targets: + script.Print("Unpacking new vendor files...") + script.UnpackPackageDir("vendor", "/vendor") + + if updating_recovery and not target_has_recovery_patch: + script.Print("Unpacking new recovery...") + script.UnpackPackageDir("recovery", "/system") + + system_diff.EmitRenames(script) + if vendor_diff: + vendor_diff.EmitRenames(script) + + script.Print("Symlinks and permissions...") + + # Create all the symlinks that don't already exist, or point to + # somewhere different than what we want. Delete each symlink before + # creating it, since the 'symlink' command won't overwrite. + to_create = [] + for dest, link in target_symlinks: + if link in source_symlinks_d: + if dest != source_symlinks_d[link]: + to_create.append((dest, link)) + else: + to_create.append((dest, link)) + script.DeleteFiles([i[1] for i in to_create]) + script.MakeSymlinks(to_create) + + # Now that the symlinks are created, we can set all the + # permissions. + script.AppendScript(temp_script) + + # Do device-specific installation (eg, write radio image). + device_specific.IncrementalOTA_InstallEnd() + + if OPTIONS.extra_script is not None: + script.AppendExtra(OPTIONS.extra_script) + + # Patch the build.prop file last, so if something fails but the + # device can still come up, it appears to be the old build and will + # get set the OTA package again to retry. + script.Print("Patching remaining system files...") + system_diff.EmitDeferredPatches(script) + + if OPTIONS.wipe_user_data: + script.Print("Erasing user data...") + script.FormatPartition("/data") + + if OPTIONS.two_step: + script.AppendExtra(""" +set_stage("%(bcb_dev)s", ""); +endif; +endif; +""" % bcb_dev) + + if OPTIONS.verify and system_diff: + script.Print("Remounting and verifying system partition files...") + script.Unmount("/system") + script.Mount("/system") + system_diff.EmitExplicitTargetVerification(script) + + if OPTIONS.verify and vendor_diff: + script.Print("Remounting and verifying vendor partition files...") + script.Unmount("/vendor") + script.Mount("/vendor") + vendor_diff.EmitExplicitTargetVerification(script) + script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) + + WriteMetadata(metadata, output_zip) + + +def main(argv): + + def option_handler(o, a): + if o == "--board_config": + pass # deprecated + elif o in ("-k", "--package_key"): + OPTIONS.package_key = a + elif o in ("-i", "--incremental_from"): + OPTIONS.incremental_source = a + elif o == "--full_radio": + OPTIONS.full_radio = True + elif o in ("-w", "--wipe_user_data"): + OPTIONS.wipe_user_data = True + elif o in ("-n", "--no_prereq"): + OPTIONS.omit_prereq = True + elif o in ("-o", "--oem_settings"): + OPTIONS.oem_source = a + elif o in ("-e", "--extra_script"): + OPTIONS.extra_script = a + elif o in ("-a", "--aslr_mode"): + if a in ("on", "On", "true", "True", "yes", "Yes"): + OPTIONS.aslr_mode = True + else: + OPTIONS.aslr_mode = False + elif o in ("-t", "--worker_threads"): + if a.isdigit(): + OPTIONS.worker_threads = int(a) + else: + raise ValueError("Cannot parse value %r for option %r - only " + "integers are allowed." % (a, o)) + elif o in ("-2", "--two_step"): + OPTIONS.two_step = True + elif o == "--no_signing": + OPTIONS.no_signing = True + elif o == "--verify": + OPTIONS.verify = True + elif o == "--block": + OPTIONS.block_based = True + elif o in ("-b", "--binary"): + OPTIONS.updater_binary = a + elif o in ("--no_fallback_to_full",): + OPTIONS.fallback_to_full = False + else: + return False + return True + + args = common.ParseOptions(argv, __doc__, + extra_opts="b:k:i:d:wne:t:a:2o:", + extra_long_opts=[ + "board_config=", + "package_key=", + "incremental_from=", + "full_radio", + "wipe_user_data", + "no_prereq", + "extra_script=", + "worker_threads=", + "aslr_mode=", + "two_step", + "no_signing", + "block", + "binary=", + "oem_settings=", + "verify", + "no_fallback_to_full", + ], extra_option_handler=option_handler) + + if len(args) != 2: + common.Usage(__doc__) + sys.exit(1) + + if OPTIONS.extra_script is not None: + OPTIONS.extra_script = open(OPTIONS.extra_script).read() + + print "unzipping target target-files..." + OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) + + OPTIONS.target_tmp = OPTIONS.input_tmp + OPTIONS.info_dict = common.LoadInfoDict(input_zip) + + # If this image was originally labelled with SELinux contexts, make sure we + # also apply the labels in our new image. During building, the "file_contexts" + # is in the out/ directory tree, but for repacking from target-files.zip it's + # in the root directory of the ramdisk. + if "selinux_fc" in OPTIONS.info_dict: + OPTIONS.info_dict["selinux_fc"] = os.path.join( + OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts") + + if OPTIONS.verbose: + print "--- target info ---" + common.DumpInfoDict(OPTIONS.info_dict) + + # If the caller explicitly specified the device-specific extensions + # path via -s/--device_specific, use that. Otherwise, use + # META/releasetools.py if it is present in the target target_files. + # Otherwise, take the path of the file from 'tool_extensions' in the + # info dict and look for that in the local filesystem, relative to + # the current directory. + + if OPTIONS.device_specific is None: + from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") + if os.path.exists(from_input): + print "(using device-specific extensions from target_files)" + OPTIONS.device_specific = from_input + else: + OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) + + if OPTIONS.device_specific is not None: + OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) + + while True: + + if OPTIONS.no_signing: + if os.path.exists(args[1]): + os.unlink(args[1]) + output_zip = zipfile.ZipFile(args[1], "w", + compression=zipfile.ZIP_DEFLATED) + else: + temp_zip_file = tempfile.NamedTemporaryFile() + output_zip = zipfile.ZipFile(temp_zip_file, "w", + compression=zipfile.ZIP_DEFLATED) + + if OPTIONS.incremental_source is None: + WriteFullOTAPackage(input_zip, output_zip) + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + break + + else: + print "unzipping source target-files..." + OPTIONS.source_tmp, source_zip = common.UnzipTemp( + OPTIONS.incremental_source) + OPTIONS.target_info_dict = OPTIONS.info_dict + OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) + if "selinux_fc" in OPTIONS.source_info_dict: + OPTIONS.source_info_dict["selinux_fc"] = os.path.join( + OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts") + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.source_info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + if OPTIONS.verbose: + print "--- source info ---" + common.DumpInfoDict(OPTIONS.source_info_dict) + try: + WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) + break + except ValueError: + if not OPTIONS.fallback_to_full: + raise + print "--- failed to build incremental; falling back to full ---" + OPTIONS.incremental_source = None + output_zip.close() + + output_zip.close() + + if not OPTIONS.no_signing: + SignOutput(temp_zip_file.name, args[1]) + temp_zip_file.close() + + print "done." + + +if __name__ == '__main__': + try: + common.CloseInheritedPipes() + main(sys.argv[1:]) + except common.ExternalError as e: + print + print " ERROR: %s" % (e,) + print + sys.exit(1) + finally: + common.Cleanup() diff --git a/tools/releasetools/pylintrc b/tools/releasetools/pylintrc new file mode 100644 index 0000000..90de1af --- /dev/null +++ b/tools/releasetools/pylintrc @@ -0,0 +1,382 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,input + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=__.*__ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )?<?https?://\S+>?$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format=LF + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/tools/releasetools/rangelib.py b/tools/releasetools/rangelib.py index 7279c60..8b327fe 100644 --- a/tools/releasetools/rangelib.py +++ b/tools/releasetools/rangelib.py @@ -24,6 +24,7 @@ class RangeSet(object): lots of runs.""" def __init__(self, data=None): + self.monotonic = False if isinstance(data, str): self._parse_internal(data) elif data: @@ -185,7 +186,7 @@ class RangeSet(object): # This is like intersect, but we can stop as soon as we discover the # output is going to be nonempty. z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), + for _, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), zip(other.data, itertools.cycle((+1, -1)))): if (z == 1 and d == 1) or (z == 2 and d == -1): return True diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks index 931acb8..b5ec59a 100755..120000 --- a/tools/releasetools/sign_target_files_apks +++ b/tools/releasetools/sign_target_files_apks @@ -1,498 +1 @@ -#!/usr/bin/env python -# -# 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. - -""" -Signs all the APK files in a target-files zipfile, producing a new -target-files zip. - -Usage: sign_target_files_apks [flags] input_target_files output_target_files - - -e (--extra_apks) <name,name,...=key> - Add extra APK name/key pairs as though they appeared in - apkcerts.txt (so mappings specified by -k and -d are applied). - Keys specified in -e override any value for that app contained - in the apkcerts.txt file. Option may be repeated to give - multiple extra packages. - - -k (--key_mapping) <src_key=dest_key> - Add a mapping from the key name as specified in apkcerts.txt (the - src_key) to the real key you wish to sign the package with - (dest_key). Option may be repeated to give multiple key - mappings. - - -d (--default_key_mappings) <dir> - Set up the following key mappings: - - $devkey/devkey ==> $dir/releasekey - $devkey/testkey ==> $dir/releasekey - $devkey/media ==> $dir/media - $devkey/shared ==> $dir/shared - $devkey/platform ==> $dir/platform - - where $devkey is the directory part of the value of - default_system_dev_certificate from the input target-files's - META/misc_info.txt. (Defaulting to "build/target/product/security" - if the value is not present in misc_info. - - -d and -k options are added to the set of mappings in the order - in which they appear on the command line. - - -o (--replace_ota_keys) - Replace the certificate (public key) used by OTA package - verification with the one specified in the input target_files - zip (in the META/otakeys.txt file). Key remapping (-k and -d) - is performed on this key. - - -t (--tag_changes) <+tag>,<-tag>,... - Comma-separated list of changes to make to the set of tags (in - the last component of the build fingerprint). Prefix each with - '+' or '-' to indicate whether that tag should be added or - removed. Changes are processed in the order they appear. - Default value is "-test-keys,-dev-keys,+release-keys". - -""" - -import sys - -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." - sys.exit(1) - -import base64 -import cStringIO -import copy -import errno -import os -import re -import shutil -import subprocess -import tempfile -import zipfile - -import add_img_to_target_files -import common - -OPTIONS = common.OPTIONS - -OPTIONS.extra_apks = {} -OPTIONS.key_map = {} -OPTIONS.replace_ota_keys = False -OPTIONS.replace_verity_public_key = False -OPTIONS.replace_verity_private_key = False -OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys") - -def GetApkCerts(tf_zip): - certmap = common.ReadApkCerts(tf_zip) - - # apply the key remapping to the contents of the file - for apk, cert in certmap.iteritems(): - certmap[apk] = OPTIONS.key_map.get(cert, cert) - - # apply all the -e options, overriding anything in the file - for apk, cert in OPTIONS.extra_apks.iteritems(): - if not cert: - cert = "PRESIGNED" - certmap[apk] = OPTIONS.key_map.get(cert, cert) - - return certmap - - -def CheckAllApksSigned(input_tf_zip, apk_key_map): - """Check that all the APKs we want to sign have keys specified, and - error out if they don't.""" - unknown_apks = [] - for info in input_tf_zip.infolist(): - if info.filename.endswith(".apk"): - name = os.path.basename(info.filename) - if name not in apk_key_map: - unknown_apks.append(name) - if unknown_apks: - print "ERROR: no key specified for:\n\n ", - print "\n ".join(unknown_apks) - print "\nUse '-e <apkname>=' to specify a key (which may be an" - print "empty string to not sign this apk)." - sys.exit(1) - - -def SignApk(data, keyname, pw): - unsigned = tempfile.NamedTemporaryFile() - unsigned.write(data) - unsigned.flush() - - signed = tempfile.NamedTemporaryFile() - - common.SignFile(unsigned.name, signed.name, keyname, pw, align=4) - - data = signed.read() - unsigned.close() - signed.close() - - return data - - -def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, - apk_key_map, key_passwords): - - maxsize = max([len(os.path.basename(i.filename)) - for i in input_tf_zip.infolist() - if i.filename.endswith('.apk')]) - rebuild_recovery = False - - tmpdir = tempfile.mkdtemp() - def write_to_temp(fn, attr, data): - fn = os.path.join(tmpdir, fn) - if fn.endswith("/"): - fn = os.path.join(tmpdir, fn) - os.mkdir(fn) - else: - d = os.path.dirname(fn) - if d and not os.path.exists(d): - os.makedirs(d) - - if attr >> 16 == 0xa1ff: - os.symlink(data, fn) - else: - with open(fn, "wb") as f: - f.write(data) - - for info in input_tf_zip.infolist(): - if info.filename.startswith("IMAGES/"): continue - - data = input_tf_zip.read(info.filename) - out_info = copy.copy(info) - - if (info.filename == "META/misc_info.txt" and - OPTIONS.replace_verity_private_key): - ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info, OPTIONS.replace_verity_private_key[1]) - elif (info.filename == "BOOT/RAMDISK/verity_key" and - OPTIONS.replace_verity_public_key): - ReplaceVerityPublicKey(output_tf_zip, OPTIONS.replace_verity_public_key[1]) - elif (info.filename.startswith("BOOT/") or - info.filename.startswith("RECOVERY/") or - info.filename.startswith("META/") or - info.filename == "SYSTEM/etc/recovery-resource.dat"): - write_to_temp(info.filename, info.external_attr, data) - - if info.filename.endswith(".apk"): - name = os.path.basename(info.filename) - key = apk_key_map[name] - if key not in common.SPECIAL_CERT_STRINGS: - print " signing: %-*s (%s)" % (maxsize, name, key) - signed_data = SignApk(data, key, key_passwords[key]) - output_tf_zip.writestr(out_info, signed_data) - else: - # an APK we're not supposed to sign. - print "NOT signing: %s" % (name,) - output_tf_zip.writestr(out_info, data) - elif info.filename in ("SYSTEM/build.prop", - "VENDOR/build.prop", - "RECOVERY/RAMDISK/default.prop"): - print "rewriting %s:" % (info.filename,) - new_data = RewriteProps(data, misc_info) - output_tf_zip.writestr(out_info, new_data) - if info.filename == "RECOVERY/RAMDISK/default.prop": - write_to_temp(info.filename, info.external_attr, new_data) - elif info.filename.endswith("mac_permissions.xml"): - print "rewriting %s with new keys." % (info.filename,) - new_data = ReplaceCerts(data) - output_tf_zip.writestr(out_info, new_data) - elif info.filename in ("SYSTEM/recovery-from-boot.p", - "SYSTEM/bin/install-recovery.sh"): - rebuild_recovery = True - elif (OPTIONS.replace_ota_keys and - info.filename in ("RECOVERY/RAMDISK/res/keys", - "SYSTEM/etc/security/otacerts.zip")): - # don't copy these files if we're regenerating them below - pass - elif (OPTIONS.replace_verity_private_key and - info.filename == "META/misc_info.txt"): - pass - elif (OPTIONS.replace_verity_public_key and - info.filename == "BOOT/RAMDISK/verity_key"): - pass - else: - # a non-APK file; copy it verbatim - output_tf_zip.writestr(out_info, data) - - if OPTIONS.replace_ota_keys: - new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) - if new_recovery_keys: - write_to_temp("RECOVERY/RAMDISK/res/keys", 0755 << 16, new_recovery_keys) - - if rebuild_recovery: - recovery_img = common.GetBootableImage( - "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info) - boot_img = common.GetBootableImage( - "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info) - - def output_sink(fn, data): - output_tf_zip.writestr("SYSTEM/"+fn, data) - - common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img, - info_dict=misc_info) - - shutil.rmtree(tmpdir) - - -def ReplaceCerts(data): - """Given a string of data, replace all occurences of a set - of X509 certs with a newer set of X509 certs and return - the updated data string.""" - for old, new in OPTIONS.key_map.iteritems(): - try: - if OPTIONS.verbose: - print " Replacing %s.x509.pem with %s.x509.pem" % (old, new) - f = open(old + ".x509.pem") - old_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower() - f.close() - f = open(new + ".x509.pem") - new_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower() - f.close() - # Only match entire certs. - pattern = "\\b"+old_cert16+"\\b" - (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE) - if OPTIONS.verbose: - print " Replaced %d occurence(s) of %s.x509.pem with " \ - "%s.x509.pem" % (num, old, new) - except IOError, e: - if (e.errno == errno.ENOENT and not OPTIONS.verbose): - continue - - print " Error accessing %s. %s. Skip replacing %s.x509.pem " \ - "with %s.x509.pem." % (e.filename, e.strerror, old, new) - - return data - - -def EditTags(tags): - """Given a string containing comma-separated tags, apply the edits - specified in OPTIONS.tag_changes and return the updated string.""" - tags = set(tags.split(",")) - for ch in OPTIONS.tag_changes: - if ch[0] == "-": - tags.discard(ch[1:]) - elif ch[0] == "+": - tags.add(ch[1:]) - return ",".join(sorted(tags)) - - -def RewriteProps(data, misc_info): - output = [] - for line in data.split("\n"): - line = line.strip() - original_line = line - if line and line[0] != '#' and "=" in line: - key, value = line.split("=", 1) - if (key in ("ro.build.fingerprint", "ro.vendor.build.fingerprint") - and misc_info.get("oem_fingerprint_properties") is None): - pieces = value.split("/") - pieces[-1] = EditTags(pieces[-1]) - value = "/".join(pieces) - elif (key in ("ro.build.thumbprint", "ro.vendor.build.thumbprint") - and misc_info.get("oem_fingerprint_properties") is not None): - pieces = value.split("/") - pieces[-1] = EditTags(pieces[-1]) - value = "/".join(pieces) - elif key == "ro.build.description": - pieces = value.split(" ") - assert len(pieces) == 5 - pieces[-1] = EditTags(pieces[-1]) - value = " ".join(pieces) - elif key == "ro.build.tags": - value = EditTags(value) - elif key == "ro.build.display.id": - # change, eg, "JWR66N dev-keys" to "JWR66N" - value = value.split() - if len(value) > 1 and value[-1].endswith("-keys"): - value.pop() - value = " ".join(value) - line = key + "=" + value - if line != original_line: - print " replace: ", original_line - print " with: ", line - output.append(line) - return "\n".join(output) + "\n" - - -def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): - try: - keylist = input_tf_zip.read("META/otakeys.txt").split() - except KeyError: - raise common.ExternalError("can't read META/otakeys.txt from input") - - extra_recovery_keys = misc_info.get("extra_recovery_keys", None) - if extra_recovery_keys: - extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem" - for k in extra_recovery_keys.split()] - if extra_recovery_keys: - print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys) - else: - extra_recovery_keys = [] - - mapped_keys = [] - for k in keylist: - m = re.match(r"^(.*)\.x509\.pem$", k) - if not m: - raise common.ExternalError( - "can't parse \"%s\" from META/otakeys.txt" % (k,)) - k = m.group(1) - mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem") - - if mapped_keys: - print "using:\n ", "\n ".join(mapped_keys) - print "for OTA package verification" - else: - devkey = misc_info.get("default_system_dev_certificate", - "build/target/product/security/testkey") - mapped_keys.append( - OPTIONS.key_map.get(devkey, devkey) + ".x509.pem") - print "META/otakeys.txt has no keys; using", mapped_keys[0] - - # recovery uses a version of the key that has been slightly - # predigested (by DumpPublicKey.java) and put in res/keys. - # extra_recovery_keys are used only in recovery. - - p = common.Run(["java", "-jar", - os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] - + mapped_keys + extra_recovery_keys, - stdout=subprocess.PIPE) - new_recovery_keys, _ = p.communicate() - if p.returncode != 0: - raise common.ExternalError("failed to run dumpkeys") - common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", - new_recovery_keys) - - # SystemUpdateActivity uses the x509.pem version of the keys, but - # put into a zipfile system/etc/security/otacerts.zip. - # We DO NOT include the extra_recovery_keys (if any) here. - - tempfile = cStringIO.StringIO() - certs_zip = zipfile.ZipFile(tempfile, "w") - for k in mapped_keys: - certs_zip.write(k) - certs_zip.close() - common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", - tempfile.getvalue()) - - return new_recovery_keys - -def ReplaceVerityPublicKey(targetfile_zip, key_path): - print "Replacing verity public key with %s" % key_path - with open(key_path) as f: - common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", f.read()) - -def ReplaceVerityPrivateKey(targetfile_input_zip, targetfile_output_zip, misc_info, key_path): - print "Replacing verity private key with %s" % key_path - current_key = misc_info["verity_key"] - original_misc_info = targetfile_input_zip.read("META/misc_info.txt") - new_misc_info = original_misc_info.replace(current_key, key_path) - common.ZipWriteStr(targetfile_output_zip, "META/misc_info.txt", new_misc_info) - -def BuildKeyMap(misc_info, key_mapping_options): - for s, d in key_mapping_options: - if s is None: # -d option - devkey = misc_info.get("default_system_dev_certificate", - "build/target/product/security/testkey") - devkeydir = os.path.dirname(devkey) - - OPTIONS.key_map.update({ - devkeydir + "/testkey": d + "/releasekey", - devkeydir + "/devkey": d + "/releasekey", - devkeydir + "/media": d + "/media", - devkeydir + "/shared": d + "/shared", - devkeydir + "/platform": d + "/platform", - }) - else: - OPTIONS.key_map[s] = d - - -def main(argv): - - key_mapping_options = [] - - def option_handler(o, a): - if o in ("-e", "--extra_apks"): - names, key = a.split("=") - names = names.split(",") - for n in names: - OPTIONS.extra_apks[n] = key - elif o in ("-d", "--default_key_mappings"): - key_mapping_options.append((None, a)) - elif o in ("-k", "--key_mapping"): - key_mapping_options.append(a.split("=", 1)) - elif o in ("-o", "--replace_ota_keys"): - OPTIONS.replace_ota_keys = True - elif o in ("-t", "--tag_changes"): - new = [] - for i in a.split(","): - i = i.strip() - if not i or i[0] not in "-+": - raise ValueError("Bad tag change '%s'" % (i,)) - new.append(i[0] + i[1:].strip()) - OPTIONS.tag_changes = tuple(new) - elif o == "--replace_verity_public_key": - OPTIONS.replace_verity_public_key = (True, a) - elif o == "--replace_verity_private_key": - OPTIONS.replace_verity_private_key = (True, a) - else: - return False - return True - - args = common.ParseOptions(argv, __doc__, - extra_opts="e:d:k:ot:", - extra_long_opts=["extra_apks=", - "default_key_mappings=", - "key_mapping=", - "replace_ota_keys", - "tag_changes=", - "replace_verity_public_key=", - "replace_verity_private_key="], - extra_option_handler=option_handler) - - if len(args) != 2: - common.Usage(__doc__) - sys.exit(1) - - input_zip = zipfile.ZipFile(args[0], "r") - output_zip = zipfile.ZipFile(args[1], "w") - - misc_info = common.LoadInfoDict(input_zip) - - BuildKeyMap(misc_info, key_mapping_options) - - apk_key_map = GetApkCerts(input_zip) - CheckAllApksSigned(input_zip, apk_key_map) - - key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) - ProcessTargetFiles(input_zip, output_zip, misc_info, - apk_key_map, key_passwords) - - input_zip.close() - output_zip.close() - - add_img_to_target_files.AddImagesToTargetFiles(args[1]) - - print "done." - - -if __name__ == '__main__': - try: - main(sys.argv[1:]) - except common.ExternalError, e: - print - print " ERROR: %s" % (e,) - print - sys.exit(1) +sign_target_files_apks.py
\ No newline at end of file diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py new file mode 100755 index 0000000..d47cc4f --- /dev/null +++ b/tools/releasetools/sign_target_files_apks.py @@ -0,0 +1,506 @@ +#!/usr/bin/env python +# +# 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. + +""" +Signs all the APK files in a target-files zipfile, producing a new +target-files zip. + +Usage: sign_target_files_apks [flags] input_target_files output_target_files + + -e (--extra_apks) <name,name,...=key> + Add extra APK name/key pairs as though they appeared in + apkcerts.txt (so mappings specified by -k and -d are applied). + Keys specified in -e override any value for that app contained + in the apkcerts.txt file. Option may be repeated to give + multiple extra packages. + + -k (--key_mapping) <src_key=dest_key> + Add a mapping from the key name as specified in apkcerts.txt (the + src_key) to the real key you wish to sign the package with + (dest_key). Option may be repeated to give multiple key + mappings. + + -d (--default_key_mappings) <dir> + Set up the following key mappings: + + $devkey/devkey ==> $dir/releasekey + $devkey/testkey ==> $dir/releasekey + $devkey/media ==> $dir/media + $devkey/shared ==> $dir/shared + $devkey/platform ==> $dir/platform + + where $devkey is the directory part of the value of + default_system_dev_certificate from the input target-files's + META/misc_info.txt. (Defaulting to "build/target/product/security" + if the value is not present in misc_info. + + -d and -k options are added to the set of mappings in the order + in which they appear on the command line. + + -o (--replace_ota_keys) + Replace the certificate (public key) used by OTA package + verification with the one specified in the input target_files + zip (in the META/otakeys.txt file). Key remapping (-k and -d) + is performed on this key. + + -t (--tag_changes) <+tag>,<-tag>,... + Comma-separated list of changes to make to the set of tags (in + the last component of the build fingerprint). Prefix each with + '+' or '-' to indicate whether that tag should be added or + removed. Changes are processed in the order they appear. + Default value is "-test-keys,-dev-keys,+release-keys". + +""" + +import sys + +if sys.hexversion < 0x02070000: + print >> sys.stderr, "Python 2.7 or newer is required." + sys.exit(1) + +import base64 +import cStringIO +import copy +import errno +import os +import re +import shutil +import subprocess +import tempfile +import zipfile + +import add_img_to_target_files +import common + +OPTIONS = common.OPTIONS + +OPTIONS.extra_apks = {} +OPTIONS.key_map = {} +OPTIONS.replace_ota_keys = False +OPTIONS.replace_verity_public_key = False +OPTIONS.replace_verity_private_key = False +OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys") + +def GetApkCerts(tf_zip): + certmap = common.ReadApkCerts(tf_zip) + + # apply the key remapping to the contents of the file + for apk, cert in certmap.iteritems(): + certmap[apk] = OPTIONS.key_map.get(cert, cert) + + # apply all the -e options, overriding anything in the file + for apk, cert in OPTIONS.extra_apks.iteritems(): + if not cert: + cert = "PRESIGNED" + certmap[apk] = OPTIONS.key_map.get(cert, cert) + + return certmap + + +def CheckAllApksSigned(input_tf_zip, apk_key_map): + """Check that all the APKs we want to sign have keys specified, and + error out if they don't.""" + unknown_apks = [] + for info in input_tf_zip.infolist(): + if info.filename.endswith(".apk"): + name = os.path.basename(info.filename) + if name not in apk_key_map: + unknown_apks.append(name) + if unknown_apks: + print "ERROR: no key specified for:\n\n ", + print "\n ".join(unknown_apks) + print "\nUse '-e <apkname>=' to specify a key (which may be an" + print "empty string to not sign this apk)." + sys.exit(1) + + +def SignApk(data, keyname, pw): + unsigned = tempfile.NamedTemporaryFile() + unsigned.write(data) + unsigned.flush() + + signed = tempfile.NamedTemporaryFile() + + common.SignFile(unsigned.name, signed.name, keyname, pw, align=4) + + data = signed.read() + unsigned.close() + signed.close() + + return data + + +def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, + apk_key_map, key_passwords): + + maxsize = max([len(os.path.basename(i.filename)) + for i in input_tf_zip.infolist() + if i.filename.endswith('.apk')]) + rebuild_recovery = False + + tmpdir = tempfile.mkdtemp() + def write_to_temp(fn, attr, data): + fn = os.path.join(tmpdir, fn) + if fn.endswith("/"): + fn = os.path.join(tmpdir, fn) + os.mkdir(fn) + else: + d = os.path.dirname(fn) + if d and not os.path.exists(d): + os.makedirs(d) + + if attr >> 16 == 0xa1ff: + os.symlink(data, fn) + else: + with open(fn, "wb") as f: + f.write(data) + + for info in input_tf_zip.infolist(): + if info.filename.startswith("IMAGES/"): + continue + + data = input_tf_zip.read(info.filename) + out_info = copy.copy(info) + + if (info.filename == "META/misc_info.txt" and + OPTIONS.replace_verity_private_key): + ReplaceVerityPrivateKey(input_tf_zip, output_tf_zip, misc_info, + OPTIONS.replace_verity_private_key[1]) + elif (info.filename == "BOOT/RAMDISK/verity_key" and + OPTIONS.replace_verity_public_key): + new_data = ReplaceVerityPublicKey(output_tf_zip, + OPTIONS.replace_verity_public_key[1]) + write_to_temp(info.filename, info.external_attr, new_data) + elif (info.filename.startswith("BOOT/") or + info.filename.startswith("RECOVERY/") or + info.filename.startswith("META/") or + info.filename == "SYSTEM/etc/recovery-resource.dat"): + write_to_temp(info.filename, info.external_attr, data) + + if info.filename.endswith(".apk"): + name = os.path.basename(info.filename) + key = apk_key_map[name] + if key not in common.SPECIAL_CERT_STRINGS: + print " signing: %-*s (%s)" % (maxsize, name, key) + signed_data = SignApk(data, key, key_passwords[key]) + output_tf_zip.writestr(out_info, signed_data) + else: + # an APK we're not supposed to sign. + print "NOT signing: %s" % (name,) + output_tf_zip.writestr(out_info, data) + elif info.filename in ("SYSTEM/build.prop", + "VENDOR/build.prop", + "RECOVERY/RAMDISK/default.prop"): + print "rewriting %s:" % (info.filename,) + new_data = RewriteProps(data, misc_info) + output_tf_zip.writestr(out_info, new_data) + if info.filename == "RECOVERY/RAMDISK/default.prop": + write_to_temp(info.filename, info.external_attr, new_data) + elif info.filename.endswith("mac_permissions.xml"): + print "rewriting %s with new keys." % (info.filename,) + new_data = ReplaceCerts(data) + output_tf_zip.writestr(out_info, new_data) + elif info.filename in ("SYSTEM/recovery-from-boot.p", + "SYSTEM/bin/install-recovery.sh"): + rebuild_recovery = True + elif (OPTIONS.replace_ota_keys and + info.filename in ("RECOVERY/RAMDISK/res/keys", + "SYSTEM/etc/security/otacerts.zip")): + # don't copy these files if we're regenerating them below + pass + elif (OPTIONS.replace_verity_private_key and + info.filename == "META/misc_info.txt"): + pass + elif (OPTIONS.replace_verity_public_key and + info.filename == "BOOT/RAMDISK/verity_key"): + pass + else: + # a non-APK file; copy it verbatim + output_tf_zip.writestr(out_info, data) + + if OPTIONS.replace_ota_keys: + new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) + if new_recovery_keys: + write_to_temp("RECOVERY/RAMDISK/res/keys", 0o755 << 16, new_recovery_keys) + + if rebuild_recovery: + recovery_img = common.GetBootableImage( + "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info) + boot_img = common.GetBootableImage( + "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info) + + def output_sink(fn, data): + output_tf_zip.writestr("SYSTEM/"+fn, data) + + common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img, + info_dict=misc_info) + + shutil.rmtree(tmpdir) + + +def ReplaceCerts(data): + """Given a string of data, replace all occurences of a set + of X509 certs with a newer set of X509 certs and return + the updated data string.""" + for old, new in OPTIONS.key_map.iteritems(): + try: + if OPTIONS.verbose: + print " Replacing %s.x509.pem with %s.x509.pem" % (old, new) + f = open(old + ".x509.pem") + old_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower() + f.close() + f = open(new + ".x509.pem") + new_cert16 = base64.b16encode(common.ParseCertificate(f.read())).lower() + f.close() + # Only match entire certs. + pattern = "\\b"+old_cert16+"\\b" + (data, num) = re.subn(pattern, new_cert16, data, flags=re.IGNORECASE) + if OPTIONS.verbose: + print " Replaced %d occurence(s) of %s.x509.pem with " \ + "%s.x509.pem" % (num, old, new) + except IOError as e: + if e.errno == errno.ENOENT and not OPTIONS.verbose: + continue + + print " Error accessing %s. %s. Skip replacing %s.x509.pem " \ + "with %s.x509.pem." % (e.filename, e.strerror, old, new) + + return data + + +def EditTags(tags): + """Given a string containing comma-separated tags, apply the edits + specified in OPTIONS.tag_changes and return the updated string.""" + tags = set(tags.split(",")) + for ch in OPTIONS.tag_changes: + if ch[0] == "-": + tags.discard(ch[1:]) + elif ch[0] == "+": + tags.add(ch[1:]) + return ",".join(sorted(tags)) + + +def RewriteProps(data, misc_info): + output = [] + for line in data.split("\n"): + line = line.strip() + original_line = line + if line and line[0] != '#' and "=" in line: + key, value = line.split("=", 1) + if (key in ("ro.build.fingerprint", "ro.vendor.build.fingerprint") + and misc_info.get("oem_fingerprint_properties") is None): + pieces = value.split("/") + pieces[-1] = EditTags(pieces[-1]) + value = "/".join(pieces) + elif (key in ("ro.build.thumbprint", "ro.vendor.build.thumbprint") + and misc_info.get("oem_fingerprint_properties") is not None): + pieces = value.split("/") + pieces[-1] = EditTags(pieces[-1]) + value = "/".join(pieces) + elif key == "ro.build.description": + pieces = value.split(" ") + assert len(pieces) == 5 + pieces[-1] = EditTags(pieces[-1]) + value = " ".join(pieces) + elif key == "ro.build.tags": + value = EditTags(value) + elif key == "ro.build.display.id": + # change, eg, "JWR66N dev-keys" to "JWR66N" + value = value.split() + if len(value) > 1 and value[-1].endswith("-keys"): + value.pop() + value = " ".join(value) + line = key + "=" + value + if line != original_line: + print " replace: ", original_line + print " with: ", line + output.append(line) + return "\n".join(output) + "\n" + + +def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): + try: + keylist = input_tf_zip.read("META/otakeys.txt").split() + except KeyError: + raise common.ExternalError("can't read META/otakeys.txt from input") + + extra_recovery_keys = misc_info.get("extra_recovery_keys", None) + if extra_recovery_keys: + extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem" + for k in extra_recovery_keys.split()] + if extra_recovery_keys: + print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys) + else: + extra_recovery_keys = [] + + mapped_keys = [] + for k in keylist: + m = re.match(r"^(.*)\.x509\.pem$", k) + if not m: + raise common.ExternalError( + "can't parse \"%s\" from META/otakeys.txt" % (k,)) + k = m.group(1) + mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem") + + if mapped_keys: + print "using:\n ", "\n ".join(mapped_keys) + print "for OTA package verification" + else: + devkey = misc_info.get("default_system_dev_certificate", + "build/target/product/security/testkey") + mapped_keys.append( + OPTIONS.key_map.get(devkey, devkey) + ".x509.pem") + print "META/otakeys.txt has no keys; using", mapped_keys[0] + + # recovery uses a version of the key that has been slightly + # predigested (by DumpPublicKey.java) and put in res/keys. + # extra_recovery_keys are used only in recovery. + + p = common.Run(["java", "-jar", + os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] + + mapped_keys + extra_recovery_keys, + stdout=subprocess.PIPE) + new_recovery_keys, _ = p.communicate() + if p.returncode != 0: + raise common.ExternalError("failed to run dumpkeys") + common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", + new_recovery_keys) + + # SystemUpdateActivity uses the x509.pem version of the keys, but + # put into a zipfile system/etc/security/otacerts.zip. + # We DO NOT include the extra_recovery_keys (if any) here. + + temp_file = cStringIO.StringIO() + certs_zip = zipfile.ZipFile(temp_file, "w") + for k in mapped_keys: + certs_zip.write(k) + certs_zip.close() + common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", + temp_file.getvalue()) + + return new_recovery_keys + +def ReplaceVerityPublicKey(targetfile_zip, key_path): + print "Replacing verity public key with %s" % key_path + with open(key_path) as f: + data = f.read() + common.ZipWriteStr(targetfile_zip, "BOOT/RAMDISK/verity_key", data) + return data + +def ReplaceVerityPrivateKey(targetfile_input_zip, targetfile_output_zip, + misc_info, key_path): + print "Replacing verity private key with %s" % key_path + current_key = misc_info["verity_key"] + original_misc_info = targetfile_input_zip.read("META/misc_info.txt") + new_misc_info = original_misc_info.replace(current_key, key_path) + common.ZipWriteStr(targetfile_output_zip, "META/misc_info.txt", new_misc_info) + misc_info["verity_key"] = key_path + +def BuildKeyMap(misc_info, key_mapping_options): + for s, d in key_mapping_options: + if s is None: # -d option + devkey = misc_info.get("default_system_dev_certificate", + "build/target/product/security/testkey") + devkeydir = os.path.dirname(devkey) + + OPTIONS.key_map.update({ + devkeydir + "/testkey": d + "/releasekey", + devkeydir + "/devkey": d + "/releasekey", + devkeydir + "/media": d + "/media", + devkeydir + "/shared": d + "/shared", + devkeydir + "/platform": d + "/platform", + }) + else: + OPTIONS.key_map[s] = d + + +def main(argv): + + key_mapping_options = [] + + def option_handler(o, a): + if o in ("-e", "--extra_apks"): + names, key = a.split("=") + names = names.split(",") + for n in names: + OPTIONS.extra_apks[n] = key + elif o in ("-d", "--default_key_mappings"): + key_mapping_options.append((None, a)) + elif o in ("-k", "--key_mapping"): + key_mapping_options.append(a.split("=", 1)) + elif o in ("-o", "--replace_ota_keys"): + OPTIONS.replace_ota_keys = True + elif o in ("-t", "--tag_changes"): + new = [] + for i in a.split(","): + i = i.strip() + if not i or i[0] not in "-+": + raise ValueError("Bad tag change '%s'" % (i,)) + new.append(i[0] + i[1:].strip()) + OPTIONS.tag_changes = tuple(new) + elif o == "--replace_verity_public_key": + OPTIONS.replace_verity_public_key = (True, a) + elif o == "--replace_verity_private_key": + OPTIONS.replace_verity_private_key = (True, a) + else: + return False + return True + + args = common.ParseOptions(argv, __doc__, + extra_opts="e:d:k:ot:", + extra_long_opts=["extra_apks=", + "default_key_mappings=", + "key_mapping=", + "replace_ota_keys", + "tag_changes=", + "replace_verity_public_key=", + "replace_verity_private_key="], + extra_option_handler=option_handler) + + if len(args) != 2: + common.Usage(__doc__) + sys.exit(1) + + input_zip = zipfile.ZipFile(args[0], "r") + output_zip = zipfile.ZipFile(args[1], "w") + + misc_info = common.LoadInfoDict(input_zip) + + BuildKeyMap(misc_info, key_mapping_options) + + apk_key_map = GetApkCerts(input_zip) + CheckAllApksSigned(input_zip, apk_key_map) + + key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) + ProcessTargetFiles(input_zip, output_zip, misc_info, + apk_key_map, key_passwords) + + input_zip.close() + output_zip.close() + + add_img_to_target_files.AddImagesToTargetFiles(args[1]) + + print "done." + + +if __name__ == '__main__': + try: + main(sys.argv[1:]) + except common.ExternalError, e: + print + print " ERROR: %s" % (e,) + print + sys.exit(1) diff --git a/tools/releasetools/sparse_img.py b/tools/releasetools/sparse_img.py index 820d85b..d2955c3 100644 --- a/tools/releasetools/sparse_img.py +++ b/tools/releasetools/sparse_img.py @@ -14,12 +14,11 @@ import bisect import os -import sys import struct -import pprint from hashlib import sha1 -from rangelib import * +import rangelib + class SparseImage(object): """Wraps a sparse image file (and optional file map) into an image @@ -39,7 +38,6 @@ class SparseImage(object): self.blocksize = blk_sz = header[5] self.total_blocks = total_blks = header[6] total_chunks = header[7] - image_checksum = header[8] if magic != 0xED26FF3A: raise ValueError("Magic should be 0xED26FF3A but is 0x%08X" % (magic,)) @@ -64,7 +62,6 @@ class SparseImage(object): header_bin = f.read(12) header = struct.unpack("<2H2I", header_bin) chunk_type = header[0] - reserved1 = header[1] chunk_sz = header[2] total_sz = header[3] data_sz = total_sz - 12 @@ -102,7 +99,7 @@ class SparseImage(object): raise ValueError("Unknown chunk type 0x%04X not supported" % (chunk_type,)) - self.care_map = RangeSet(care_data) + self.care_map = rangelib.RangeSet(care_data) self.offset_index = [i[0] for i in offset_map] if file_map_fn: @@ -166,7 +163,7 @@ class SparseImage(object): with open(fn) as f: for line in f: fn, ranges = line.split(None, 1) - ranges = RangeSet.parse(ranges) + ranges = rangelib.RangeSet.parse(ranges) out[fn] = ranges assert ranges.size() == ranges.intersect(remaining).size() remaining = remaining.subtract(ranges) @@ -186,7 +183,7 @@ class SparseImage(object): for s, e in remaining: for b in range(s, e): idx = bisect.bisect_right(self.offset_index, b) - 1 - chunk_start, chunk_len, filepos, fill_data = self.offset_map[idx] + chunk_start, _, filepos, fill_data = self.offset_map[idx] if filepos is not None: filepos += (b-chunk_start) * self.blocksize f.seek(filepos, os.SEEK_SET) diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py new file mode 100644 index 0000000..5fdc132 --- /dev/null +++ b/tools/releasetools/test_common.py @@ -0,0 +1,110 @@ +# +# Copyright (C) 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import tempfile +import time +import unittest +import zipfile + +import common + + +def random_string_with_holes(size, block_size, step_size): + data = ["\0"] * size + for begin in range(0, size, step_size): + end = begin + block_size + data[begin:end] = os.urandom(block_size) + return "".join(data) + + +class CommonZipTest(unittest.TestCase): + def _test_ZipWrite(self, contents, extra_zipwrite_args=None): + extra_zipwrite_args = dict(extra_zipwrite_args or {}) + + test_file = tempfile.NamedTemporaryFile(delete=False) + zip_file = tempfile.NamedTemporaryFile(delete=False) + + test_file_name = test_file.name + zip_file_name = zip_file.name + + # File names within an archive strip the leading slash. + arcname = extra_zipwrite_args.get("arcname", test_file_name) + if arcname[0] == "/": + arcname = arcname[1:] + + zip_file.close() + zip_file = zipfile.ZipFile(zip_file_name, "w") + + try: + test_file.write(contents) + test_file.close() + + old_stat = os.stat(test_file_name) + expected_mode = extra_zipwrite_args.get("perms", 0o644) + + time.sleep(5) # Make sure the atime/mtime will change measurably. + + common.ZipWrite(zip_file, test_file_name, **extra_zipwrite_args) + + new_stat = os.stat(test_file_name) + self.assertEqual(int(old_stat.st_mode), int(new_stat.st_mode)) + self.assertEqual(int(old_stat.st_mtime), int(new_stat.st_mtime)) + self.assertIsNone(zip_file.testzip()) + + zip_file.close() + zip_file = zipfile.ZipFile(zip_file_name, "r") + info = zip_file.getinfo(arcname) + + self.assertEqual(info.date_time, (2009, 1, 1, 0, 0, 0)) + mode = (info.external_attr >> 16) & 0o777 + self.assertEqual(mode, expected_mode) + self.assertEqual(zip_file.read(arcname), contents) + self.assertIsNone(zip_file.testzip()) + finally: + os.remove(test_file_name) + os.remove(zip_file_name) + + def test_ZipWrite(self): + file_contents = os.urandom(1024) + self._test_ZipWrite(file_contents) + + def test_ZipWrite_with_opts(self): + file_contents = os.urandom(1024) + self._test_ZipWrite(file_contents, { + "arcname": "foobar", + "perms": 0o777, + "compress_type": zipfile.ZIP_DEFLATED, + }) + + def test_ZipWrite_large_file(self): + kilobytes = 1024 + megabytes = 1024 * kilobytes + gigabytes = 1024 * megabytes + + size = int(2 * gigabytes + 1) + block_size = 4 * kilobytes + step_size = 4 * megabytes + file_contents = random_string_with_holes( + size, block_size, step_size) + self._test_ZipWrite(file_contents, { + "compress_type": zipfile.ZIP_DEFLATED, + }) + + def test_ZipWrite_resets_ZIP64_LIMIT(self): + default_limit = (1 << 31) - 1 + self.assertEqual(default_limit, zipfile.ZIP64_LIMIT) + self._test_ZipWrite('') + self.assertEqual(default_limit, zipfile.ZIP64_LIMIT) diff --git a/tools/signapk/SignApk.java b/tools/signapk/SignApk.java index e661e50..88f486a 100644 --- a/tools/signapk/SignApk.java +++ b/tools/signapk/SignApk.java @@ -35,6 +35,7 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.encoders.Base64; +import java.io.Console; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -166,18 +167,17 @@ class SignApk { } /** - * Reads the password from stdin and returns it as a string. + * Reads the password from console and returns it as a string. * * @param keyFile The file containing the private key. Used to prompt the user. */ private static String readPassword(File keyFile) { - // TODO: use Console.readPassword() when it's available. - System.out.print("Enter password for " + keyFile + " (password will not be hidden): "); - System.out.flush(); - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - try { - return stdin.readLine(); - } catch (IOException ex) { + Console console; + char[] pwd; + if((console = System.console()) != null && + (pwd = console.readPassword("[%s]", "Enter password for " + keyFile)) != null){ + return String.valueOf(pwd); + } else { return null; } } @@ -621,8 +621,12 @@ class SignApk { this.type = new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()); } + /** + * This should actually return byte[] or something similar, but nothing + * actually checks it currently. + */ public Object getContent() { - throw new UnsupportedOperationException(); + return this; } public ASN1ObjectIdentifier getContentType() { diff --git a/tools/signtos/Android.mk b/tools/signtos/Android.mk new file mode 100644 index 0000000..94ab944 --- /dev/null +++ b/tools/signtos/Android.mk @@ -0,0 +1,25 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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) + +# the signtos tool - signs Trusty images +# ============================================================ +include $(CLEAR_VARS) +LOCAL_MODULE := signtos +LOCAL_SRC_FILES := SignTos.java +LOCAL_JAR_MANIFEST := SignTos.mf +LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host bouncycastle-bcpkix-host +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/signtos/SignTos.java b/tools/signtos/SignTos.java new file mode 100644 index 0000000..485ad2f --- /dev/null +++ b/tools/signtos/SignTos.java @@ -0,0 +1,314 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.signtos; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; + +/** + * Signs Trusty images for use with operating systems that support it. + */ +public class SignTos { + /** Size of the signature footer in bytes. */ + private static final int SIGNATURE_BLOCK_SIZE = 256; + + /** Current signature version code we use. */ + private static final int VERSION_CODE = 1; + + /** Size of the header on the file to skip. */ + private static final int HEADER_SIZE = 512; + + private static BouncyCastleProvider sBouncyCastleProvider; + + /** + * Reads the password from stdin and returns it as a string. + * + * @param keyFile The file containing the private key. Used to prompt the user. + */ + private static String readPassword(File keyFile) { + // TODO: use Console.readPassword() when it's available. + System.out.print("Enter password for " + keyFile + " (password will not be hidden): "); + System.out.flush(); + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + try { + return stdin.readLine(); + } catch (IOException ex) { + return null; + } + } + + /** + * Decrypt an encrypted PKCS#8 format private key. + * + * Based on ghstark's post on Aug 6, 2006 at + * http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949 + * + * @param encryptedPrivateKey The raw data of the private key + * @param keyFile The file containing the private key + */ + private static PKCS8EncodedKeySpec decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile) + throws GeneralSecurityException { + EncryptedPrivateKeyInfo epkInfo; + try { + epkInfo = new EncryptedPrivateKeyInfo(encryptedPrivateKey); + } catch (IOException ex) { + // Probably not an encrypted key. + return null; + } + + char[] password = readPassword(keyFile).toCharArray(); + + SecretKeyFactory skFactory = SecretKeyFactory.getInstance(epkInfo.getAlgName()); + Key key = skFactory.generateSecret(new PBEKeySpec(password)); + + Cipher cipher = Cipher.getInstance(epkInfo.getAlgName()); + cipher.init(Cipher.DECRYPT_MODE, key, epkInfo.getAlgParameters()); + + try { + return epkInfo.getKeySpec(cipher); + } catch (InvalidKeySpecException ex) { + System.err.println("signapk: Password for " + keyFile + " may be bad."); + throw ex; + } + } + + /** Read a PKCS#8 format private key. */ + private static PrivateKey readPrivateKey(File file) throws IOException, + GeneralSecurityException { + DataInputStream input = new DataInputStream(new FileInputStream(file)); + try { + byte[] bytes = new byte[(int) file.length()]; + input.read(bytes); + + /* Check to see if this is in an EncryptedPrivateKeyInfo structure. */ + PKCS8EncodedKeySpec spec = decryptPrivateKey(bytes, file); + if (spec == null) { + spec = new PKCS8EncodedKeySpec(bytes); + } + + /* + * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm + * OID and use that to construct a KeyFactory. + */ + ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded())); + PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); + String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId(); + + return KeyFactory.getInstance(algOid).generatePrivate(spec); + } finally { + input.close(); + } + } + + /** + * Tries to load a JSE Provider by class name. This is for custom PrivateKey + * types that might be stored in PKCS#11-like storage. + */ + private static void loadProviderIfNecessary(String providerClassName) { + if (providerClassName == null) { + return; + } + + final Class<?> klass; + try { + final ClassLoader sysLoader = ClassLoader.getSystemClassLoader(); + if (sysLoader != null) { + klass = sysLoader.loadClass(providerClassName); + } else { + klass = Class.forName(providerClassName); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + System.exit(1); + return; + } + + Constructor<?> constructor = null; + for (Constructor<?> c : klass.getConstructors()) { + if (c.getParameterTypes().length == 0) { + constructor = c; + break; + } + } + if (constructor == null) { + System.err.println("No zero-arg constructor found for " + providerClassName); + System.exit(1); + return; + } + + final Object o; + try { + o = constructor.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + return; + } + if (!(o instanceof Provider)) { + System.err.println("Not a Provider class: " + providerClassName); + System.exit(1); + } + + Security.insertProviderAt((Provider) o, 1); + } + + private static String getSignatureAlgorithm(Key key) { + if ("EC".equals(key.getAlgorithm())) { + ECKey ecKey = (ECKey) key; + int curveSize = ecKey.getParams().getOrder().bitLength(); + if (curveSize <= 256) { + return "SHA256withECDSA"; + } else if (curveSize <= 384) { + return "SHA384withECDSA"; + } else { + return "SHA512withECDSA"; + } + } else { + throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm()); + } + } + + /** + * @param inputFilename + * @param outputFilename + */ + private static void signWholeFile(InputStream input, OutputStream output, PrivateKey signingKey) + throws Exception { + Signature sig = Signature.getInstance(getSignatureAlgorithm(signingKey)); + sig.initSign(signingKey); + + byte[] buffer = new byte[8192]; + + /* Skip the header. */ + int skippedBytes = 0; + while (skippedBytes != HEADER_SIZE) { + int bytesRead = input.read(buffer, 0, HEADER_SIZE - skippedBytes); + output.write(buffer, 0, bytesRead); + skippedBytes += bytesRead; + } + + int totalBytes = 0; + for (;;) { + int bytesRead = input.read(buffer); + if (bytesRead == -1) { + break; + } + totalBytes += bytesRead; + sig.update(buffer, 0, bytesRead); + output.write(buffer, 0, bytesRead); + } + + byte[] sigBlock = new byte[SIGNATURE_BLOCK_SIZE]; + sigBlock[0] = VERSION_CODE; + sig.sign(sigBlock, 1, sigBlock.length - 1); + + output.write(sigBlock); + } + + private static void usage() { + System.err.println("Usage: signtos " + + "[-providerClass <className>] " + + " privatekey.pk8 " + + "input.img output.img"); + System.exit(2); + } + + public static void main(String[] args) throws Exception { + if (args.length < 3) { + usage(); + } + + String providerClass = null; + String providerArg = null; + + int argstart = 0; + while (argstart < args.length && args[argstart].startsWith("-")) { + if ("-providerClass".equals(args[argstart])) { + if (argstart + 1 >= args.length) { + usage(); + } + providerClass = args[++argstart]; + ++argstart; + } else { + usage(); + } + } + + /* + * Should only be "<privatekey> <input> <output>" left. + */ + if (argstart != args.length - 3) { + usage(); + } + + sBouncyCastleProvider = new BouncyCastleProvider(); + Security.addProvider(sBouncyCastleProvider); + + loadProviderIfNecessary(providerClass); + + String keyFilename = args[args.length - 3]; + String inputFilename = args[args.length - 2]; + String outputFilename = args[args.length - 1]; + + PrivateKey privateKey = readPrivateKey(new File(keyFilename)); + + InputStream input = new BufferedInputStream(new FileInputStream(inputFilename)); + OutputStream output = new BufferedOutputStream(new FileOutputStream(outputFilename)); + try { + SignTos.signWholeFile(input, output, privateKey); + } finally { + input.close(); + output.close(); + } + + System.out.println("Successfully signed: " + outputFilename); + } +} diff --git a/tools/signtos/SignTos.mf b/tools/signtos/SignTos.mf new file mode 100644 index 0000000..d860296 --- /dev/null +++ b/tools/signtos/SignTos.mf @@ -0,0 +1 @@ +Main-Class: com.android.signtos.SignTos diff --git a/tools/zipalign/Android.mk b/tools/zipalign/Android.mk index 7986798..4194f81 100644 --- a/tools/zipalign/Android.mk +++ b/tools/zipalign/Android.mk @@ -26,7 +26,7 @@ ifeq ($(HOST_OS),linux) LOCAL_LDLIBS += -lrt endif -ifneq ($(strip $(USE_MINGW)),) +ifdef USE_MINGW LOCAL_STATIC_LIBRARIES += libz else LOCAL_LDLIBS += -lz diff --git a/tools/zipalign/README.txt b/tools/zipalign/README.txt index 9c7d07e..0b80b35 100644 --- a/tools/zipalign/README.txt +++ b/tools/zipalign/README.txt @@ -5,6 +5,7 @@ usage: zipalign [-f] [-v] <align> infile.zip outfile.zip -c : check alignment only (does not modify file) -f : overwrite existing outfile.zip + -p : page align stored shared object files -v : verbose output <align> is in bytes, e.g. "4" provides 32-bit alignment infile.zip is an existing Zip archive @@ -33,3 +34,7 @@ By default, zipalign will not overwrite an existing output file. With the You can use the "-c" flag to test whether a zip archive is properly aligned. +The "-p" flag aligns any file with a ".so" extension, and which is stored +uncompressed in the zip archive, to a 4096-byte page boundary. This +facilitates directly loading shared libraries from inside a zip archive. + diff --git a/tools/zipalign/ZipAlign.cpp b/tools/zipalign/ZipAlign.cpp index dc2826b..a2dfd02 100644 --- a/tools/zipalign/ZipAlign.cpp +++ b/tools/zipalign/ZipAlign.cpp @@ -32,20 +32,39 @@ void usage(void) fprintf(stderr, "Zip alignment utility\n"); fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n"); fprintf(stderr, - "Usage: zipalign [-f] [-v] [-z] <align> infile.zip outfile.zip\n" + "Usage: zipalign [-f] [-p] [-v] [-z] <align> infile.zip outfile.zip\n" " zipalign -c [-v] <align> infile.zip\n\n" ); fprintf(stderr, " <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n"); fprintf(stderr, " -c: check alignment only (does not modify file)\n"); fprintf(stderr, " -f: overwrite existing outfile.zip\n"); + fprintf(stderr, " -p: page align stored shared object files\n"); fprintf(stderr, " -v: verbose output\n"); fprintf(stderr, " -z: recompress using Zopfli\n"); } +static int getAlignment(bool pageAlignSharedLibs, int defaultAlignment, + ZipEntry* pEntry) { + + static const int kPageAlignment = 4096; + + if (!pageAlignSharedLibs) { + return defaultAlignment; + } + + const char* ext = strrchr(pEntry->getFileName(), '.'); + if (ext && strcmp(ext, ".so") == 0) { + return kPageAlignment; + } + + return defaultAlignment; +} + /* * Copy all entries from "pZin" to "pZout", aligning as needed. */ -static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli) +static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli, + bool pageAlignSharedLibs) { int numEntries = pZin->getNumEntries(); ZipEntry* pEntry; @@ -75,13 +94,15 @@ static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfl status = pZout->add(pZin, pEntry, padding, &pNewEntry); } } else { + const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry); + /* * Copy the entry, adjusting as required. We assume that the * file position in the new file will be equal to the file * position in the original. */ long newOffset = pEntry->getFileOffset() + bias; - padding = (alignment - (newOffset % alignment)) % alignment; + padding = (alignTo - (newOffset % alignTo)) % alignTo; //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n", // pEntry->getFileName(), (long) pEntry->getFileOffset(), @@ -105,7 +126,7 @@ static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfl * output file exists and "force" wasn't specified. */ static int process(const char* inFileName, const char* outFileName, - int alignment, bool force, bool zopfli) + int alignment, bool force, bool zopfli, bool pageAlignSharedLibs) { ZipFile zin, zout; @@ -136,7 +157,7 @@ static int process(const char* inFileName, const char* outFileName, return 1; } - int result = copyAndAlign(&zin, &zout, alignment, zopfli); + int result = copyAndAlign(&zin, &zout, alignment, zopfli, pageAlignSharedLibs); if (result != 0) { printf("zipalign: failed rewriting '%s' to '%s'\n", inFileName, outFileName); @@ -147,7 +168,8 @@ static int process(const char* inFileName, const char* outFileName, /* * Verify the alignment of a zip archive. */ -static int verify(const char* fileName, int alignment, bool verbose) +static int verify(const char* fileName, int alignment, bool verbose, + bool pageAlignSharedLibs) { ZipFile zipFile; bool foundBad = false; @@ -172,11 +194,12 @@ static int verify(const char* fileName, int alignment, bool verbose) } } else { long offset = pEntry->getFileOffset(); - if ((offset % alignment) != 0) { + const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry); + if ((offset % alignTo) != 0) { if (verbose) { printf("%8ld %s (BAD - %ld)\n", (long) offset, pEntry->getFileName(), - offset % alignment); + offset % alignTo); } foundBad = true; } else { @@ -204,6 +227,7 @@ int main(int argc, char* const argv[]) bool force = false; bool verbose = false; bool zopfli = false; + bool pageAlignSharedLibs = false; int result = 1; int alignment; char* endp; @@ -233,6 +257,9 @@ int main(int argc, char* const argv[]) case 'z': zopfli = true; break; + case 'p': + pageAlignSharedLibs = true; + break; default: fprintf(stderr, "ERROR: unknown flag -%c\n", *cp); wantUsage = true; @@ -260,14 +287,15 @@ int main(int argc, char* const argv[]) if (check) { /* check existing archive for correct alignment */ - result = verify(argv[1], alignment, verbose); + result = verify(argv[1], alignment, verbose, pageAlignSharedLibs); } else { /* create the new archive */ - result = process(argv[1], argv[2], alignment, force, zopfli); + result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs); /* trust, but verify */ - if (result == 0) - result = verify(argv[2], alignment, verbose); + if (result == 0) { + result = verify(argv[2], alignment, verbose, pageAlignSharedLibs); + } } bail: diff --git a/tools/zipalign/ZipEntry.cpp b/tools/zipalign/ZipEntry.cpp index d4d366d..b2270cb 100644 --- a/tools/zipalign/ZipEntry.cpp +++ b/tools/zipalign/ZipEntry.cpp @@ -356,7 +356,7 @@ time_t ZipEntry::getModWhen(void) const */ void ZipEntry::setModWhen(time_t when) { -#ifdef HAVE_LOCALTIME_R +#if !defined(_WIN32) struct tm tmResult; #endif time_t even; @@ -368,7 +368,7 @@ void ZipEntry::setModWhen(time_t when) even = (time_t)(((unsigned long)(when) + 1) & (~1)); /* expand */ -#ifdef HAVE_LOCALTIME_R +#if !defined(_WIN32) ptm = localtime_r(&even, &tmResult); #else ptm = localtime(&even); |