summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/acp/Android.mk3
-rw-r--r--tools/atree/files.cpp9
-rw-r--r--tools/atree/fs.cpp7
-rwxr-xr-xtools/buildinfo.sh7
-rw-r--r--tools/droiddoc/templates-sac/head_tag.cs2
-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)bin3195 -> 3195 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/android.pngbin0 -> 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)bin3633 -> 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)bin3036 -> 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)bin3144 -> 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)bin2960 -> 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)bin2757 -> 2757 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_down.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_down.png)bin180 -> 180 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_bluelink_up.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_bluelink_up.png)bin181 -> 181 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_left_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_off.jpg)bin592 -> 592 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_left_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_left_on.jpg)bin692 -> 692 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_right_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_off.jpg)bin592 -> 592 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/arrow_right_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/arrow_right_on.jpg)bin692 -> 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)bin162 -> 162 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/bg_community_leftDiv.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_community_leftDiv.jpg)bin10692 -> 10692 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_fade.jpg)bin300 -> 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)bin1376 -> 1376 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/bg_images_sprite.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_images_sprite.png)bin2008 -> 2008 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/bg_logo.png)bin1525 -> 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)bin72570 -> 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)bin192 -> 192 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient.png)bin146 -> 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)bin164 -> 164 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/close-grey.pngbin0 -> 379 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.pngbin0 -> 830 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/close-white.pngbin0 -> 292 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.pngbin0 -> 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)bin312 -> 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)bin2170 -> 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)bin2497 -> 2497 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/developers-logo.png)bin10155 -> 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)bin224 -> 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)bin511 -> 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)bin299 -> 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)bin341 -> 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)bin301 -> 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)bin311 -> 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)bin1154 -> 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)bin249 -> 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)bin16512 -> 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)bin15892 -> 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)bin7553 -> 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)bin3576 -> 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)bin11210 -> 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)bin3673 -> 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)bin111790 -> 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)bin27250 -> 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)bin1849 -> 1849 bytes
-rwxr-xr-xtools/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)bin2840 -> 2840 bytes
-rwxr-xr-xtools/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)bin2180 -> 2180 bytes
-rwxr-xr-xtools/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)bin3654 -> 3654 bytes
-rwxr-xr-xtools/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)bin1902 -> 1902 bytes
-rwxr-xr-xtools/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)bin2041 -> 2041 bytes
-rwxr-xr-xtools/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)bin3413 -> 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)bin16630 -> 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)bin1944 -> 1944 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/home/donut-android.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/donut-android.png)bin9386 -> 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)bin11311 -> 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)bin17086 -> 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)bin2739 -> 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)bin11690 -> 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)bin5042 -> 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)bin21315 -> 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)bin13716 -> 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)bin5573 -> 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)bin5739 -> 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)bin5364 -> 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)bin4588 -> 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)bin15002 -> 15002 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/home/io-large.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/io-large.png)bin5522 -> 5522 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/home/io-small.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/home/io-small.png)bin1427 -> 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)bin39756 -> 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)bin3424 -> 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)bin5752 -> 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)bin3134 -> 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)bin1616 -> 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)bin2381 -> 2381 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/hr_gray_main.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_main.jpg)bin378 -> 378 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/hr_gray_side.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/hr_gray_side.jpg)bin344 -> 344 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_contribute.jpg)bin1021 -> 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)bin697 -> 697 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_download.jpg)bin1192 -> 1192 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_download2.jpg)bin653 -> 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)bin44163 -> 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)bin1022 -> 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)bin1098 -> 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)bin10201 -> 10201 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_robot.jpg)bin638 -> 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)bin1406 -> 1406 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/icon_world.jpg)bin511 -> 511 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/left_off.jpg)bin592 -> 592 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/left_on.jpg)bin692 -> 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)bin202 -> 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)bin393 -> 393 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/logo_breadcrumbz.jpg)bin3311 -> 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)bin1055 -> 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)bin1014 -> 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)bin958 -> 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)bin1447 -> 1447 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/open_source.png (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/open_source.png)bin6340 -> 6340 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.pngbin0 -> 880 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.pngbin0 -> 2280 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.pngbin0 -> 670 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.pngbin0 -> 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)bin2251 -> 2251 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/preview.pngbin0 -> 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)bin2951 -> 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)bin1024 -> 1024 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e.gif)bin2713 -> 2713 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e2.gif)bin2680 -> 2680 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-eg.gif)bin3075 -> 3075 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s.gif)bin2617 -> 2617 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.gif)bin2618 -> 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)bin966 -> 966 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/resizable-sg.gif)bin3057 -> 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)bin889 -> 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)bin2095 -> 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)bin2480 -> 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)bin2544 -> 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)bin2155 -> 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)bin15565 -> 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)bin972 -> 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)bin1001 -> 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)bin835 -> 835 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/right_off.jpg)bin592 -> 592 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/right_on.jpg)bin692 -> 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)bin258 -> 258 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_1.jpg)bin3060 -> 3060 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_2.jpg)bin3736 -> 3736 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_3.jpg)bin3151 -> 3151 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_large_1.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_1.jpg)bin19240 -> 19240 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_large_2.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_2.jpg)bin20188 -> 20188 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_large_3.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_large_3.jpg)bin20202 -> 20202 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_off.jpg)bin676 -> 676 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/slide_on.jpg)bin733 -> 733 bytes
-rwxr-xr-xtools/droiddoc/templates-sdk-dev/assets/images/spacer.gif (renamed from tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif)bin96 -> 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)bin198 -> 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)bin1383 -> 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)bin64431 -> 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)bin30679 -> 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)bin39994 -> 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)bin75920 -> 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)bin301931 -> 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)bin57247 -> 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)bin33589 -> 33589 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.pngbin0 -> 13039 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.pngbin0 -> 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)bin238 -> 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)bin229 -> 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)bin228 -> 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)bin221 -> 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)bin262 -> 262 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.pngbin0 -> 1437 bytes
-rw-r--r--tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.pngbin0 -> 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)bin415 -> 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)bin318 -> 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)bin1040 -> 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)bin302 -> 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)bin437 -> 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)bin1037 -> 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)bin286 -> 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)bin3208 -> 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)bin5877 -> 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)bin3338 -> 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)bin6019 -> 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)bin3208 -> 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)bin5877 -> 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)bin3219 -> 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)bin5738 -> 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)bin3017 -> 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)bin5456 -> 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)bin980 -> 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)bin166 -> 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)bin3565 -> 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)bin170 -> 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)bin3567 -> 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)bin5258 -> 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)bin1614 -> 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.cs36
-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.css6706
-rw-r--r--tools/droiddoc/templates-sdk/assets/css/fullscreen.css194
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/android_logo.pngbin0 -> 513 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/android_logo@2x.pngbin0 -> 860 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.pngbin0 -> 4712 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.pngbin0 -> 18596 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/resource-card-default-android.jpgbin15565 -> 12042 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/sprite-2x.pngbin0 -> 7283 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/images/sprite.pngbin0 -> 3121 bytes
-rw-r--r--tools/droiddoc/templates-sdk/assets/js/docs.js1352
-rw-r--r--tools/droiddoc/templates-sdk/class.cs23
-rw-r--r--tools/droiddoc/templates-sdk/classes.cs5
-rw-r--r--tools/droiddoc/templates-sdk/components/masthead.cs504
-rw-r--r--tools/droiddoc/templates-sdk/customizations.cs521
-rw-r--r--tools/droiddoc/templates-sdk/designpage.cs12
-rw-r--r--tools/droiddoc/templates-sdk/docpage.cs87
-rw-r--r--tools/droiddoc/templates-sdk/footer.cs187
-rw-r--r--tools/droiddoc/templates-sdk/head_tag.cs15
-rw-r--r--tools/droiddoc/templates-sdk/nosidenavpage.cs1
-rw-r--r--tools/droiddoc/templates-sdk/package.cs3
-rw-r--r--tools/droiddoc/templates-sdk/packages.cs3
-rw-r--r--tools/droiddoc/templates-sdk/sample.cs8
-rw-r--r--tools/droiddoc/templates-sdk/sampleindex.cs8
-rw-r--r--tools/droiddoc/templates-sdk/sdkpage.cs9
-rw-r--r--tools/droiddoc/templates-sdk/trailer.cs1
-rw-r--r--tools/fs_config/Android.mk66
-rw-r--r--tools/fs_config/default/android_filesystem_config.h44
-rw-r--r--tools/fs_config/fs_config_generate.c128
-rw-r--r--tools/fs_get_stats/Android.mk2
-rwxr-xr-xtools/post_process_props.py19
-rwxr-xr-xtools/product_debug.py1
-rwxr-xr-xtools/releasetools/add_img_to_target_files.py85
-rw-r--r--tools/releasetools/blockimgdiff.py138
-rwxr-xr-xtools/releasetools/build_image.py131
l---------[-rwxr-xr-x]tools/releasetools/check_target_files_signatures442
-rwxr-xr-xtools/releasetools/check_target_files_signatures.py442
-rw-r--r--tools/releasetools/common.py400
-rw-r--r--tools/releasetools/edify_generator.py91
-rwxr-xr-xtools/releasetools/img_from_target_files.py32
l---------[-rwxr-xr-x]tools/releasetools/make_recovery_patch54
-rwxr-xr-xtools/releasetools/make_recovery_patch.py53
l---------[-rwxr-xr-x]tools/releasetools/ota_from_target_files1577
-rwxr-xr-xtools/releasetools/ota_from_target_files.py1631
-rw-r--r--tools/releasetools/pylintrc382
-rw-r--r--tools/releasetools/rangelib.py3
l---------[-rwxr-xr-x]tools/releasetools/sign_target_files_apks499
-rwxr-xr-xtools/releasetools/sign_target_files_apks.py506
-rw-r--r--tools/releasetools/sparse_img.py13
-rw-r--r--tools/releasetools/test_common.py110
-rw-r--r--tools/signapk/SignApk.java22
-rw-r--r--tools/signtos/Android.mk25
-rw-r--r--tools/signtos/SignTos.java314
-rw-r--r--tools/signtos/SignTos.mf1
-rw-r--r--tools/zipalign/Android.mk2
-rw-r--r--tools/zipalign/README.txt5
-rw-r--r--tools/zipalign/ZipAlign.cpp52
-rw-r--r--tools/zipalign/ZipEntry.cpp4
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/android.png b/tools/droiddoc/templates-sdk-dev/assets/images/android.png
new file mode 100644
index 0000000..4040f3f
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/android.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/android_wrench.png b/tools/droiddoc/templates-sdk-dev/assets/images/android_wrench.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-left.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-left.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/arrow-right.png b/tools/droiddoc/templates-sdk-dev/assets/images/arrow-right.png
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_fade.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_fade.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_gradient.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/bg_gradient.jpg
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/bg_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/bg_logo.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/blog-default.png b/tools/droiddoc/templates-sdk-dev/assets/images/blog-default.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/body-gradient.png b/tools/droiddoc/templates-sdk-dev/assets/images/body-gradient.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png
index 407a318..407a318 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/breadcrumb.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/breadcrumb.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png
new file mode 100644
index 0000000..1b0d7f1
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey.png
Binary files differ
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
new file mode 100644
index 0000000..1355507
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-grey_2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png
new file mode 100644
index 0000000..ef02018
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-white.png
Binary files differ
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
new file mode 100644
index 0000000..9b9c41d
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/close-white_2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/close.png b/tools/droiddoc/templates-sdk-dev/assets/images/close.png
index 6ae3391..6ae3391 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/close.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/close.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/dac_logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/dac_logo.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/developers-logo.png b/tools/droiddoc/templates-sdk-dev/assets/images/developers-logo.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-generic.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-generic.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-image.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-image.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-java.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-java.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-manifest.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-manifest.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/file-xml.png b/tools/droiddoc/templates-sdk-dev/assets/images/file-xml.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/folder.png b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png
index 44c6100..44c6100 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/folder.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/folder.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/fullscreen.png b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png
index 01f971c..01f971c 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/fullscreen.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/fullscreen.png
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/GDC2011.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/GDC2011.png
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/home/gingerdroid.png b/tools/droiddoc/templates-sdk-dev/assets/images/home/gingerdroid.png
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_contribute.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_contribute.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_design.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_design.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_download2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_download2.jpg
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_market.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_market.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_more.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_more.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_play.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_play.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_robot.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_robot.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_search.png b/tools/droiddoc/templates-sdk-dev/assets/images/icon_search.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/icon_world.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/icon_world.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/left_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_off.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/left_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/left_on.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/link-out.png b/tools/droiddoc/templates-sdk-dev/assets/images/link-out.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/locale.png b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png
index de3aae7..de3aae7 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/locale.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/locale.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/logo_breadcrumbz.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/logo_breadcrumbz.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_bottom.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_bottom.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_check.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_check.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_mid.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_mid.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/more_top.png b/tools/droiddoc/templates-sdk-dev/assets/images/more_top.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/open_source.png b/tools/droiddoc/templates-sdk-dev/assets/images/open_source.png
index 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
Binary files differ
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
new file mode 100644
index 0000000..5e7e7ba
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey.png
Binary files differ
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
new file mode 100644
index 0000000..3e01635
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-grey_2x.png
Binary files differ
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
new file mode 100644
index 0000000..017d846
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white.png
Binary files differ
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
new file mode 100644
index 0000000..e48c1fd
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/play-circle-white_2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/preliminary.png b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png
index fe0da3d..fe0da3d 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/preliminary.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/preliminary.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dev/assets/images/preview.png b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png
new file mode 100644
index 0000000..e5856db
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/preview.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/quicknav_arrow.png b/tools/droiddoc/templates-sdk-dev/assets/images/quicknav_arrow.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-e2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-e2.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-eg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-eg.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-s2.png b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-s2.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resizable-sg.gif b/tools/droiddoc/templates-sdk-dev/assets/images/resizable-sg.gif
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-article.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-article.png
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-sample.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-sample.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-tutorial.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-tutorial.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/resource-video.png b/tools/droiddoc/templates-sdk-dev/assets/images/resource-video.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/right_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_off.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/right_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/right_on.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/sidenav-rule.png b/tools/droiddoc/templates-sdk-dev/assets/images/sidenav-rule.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_1.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_1.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_2.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_2.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_3.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_3.jpg
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_off.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_off.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/slide_on.jpg b/tools/droiddoc/templates-sdk-dev/assets/images/slide_on.jpg
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif
index f96b355..f96b355 100755
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/spacer.gif
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/spacer.gif
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/callout.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/callout.png
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
new file mode 100644
index 0000000..077a7e6
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square.png
Binary files differ
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
new file mode 100644
index 0000000..e7e1540
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/device_wear_square_small.png
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/styles/gototop.png b/tools/droiddoc/templates-sdk-dev/assets/images/styles/gototop.png
index 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
Binary files differ
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
new file mode 100644
index 0000000..3c2dc1a
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35.png
Binary files differ
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
new file mode 100644
index 0000000..e34be2e
--- /dev/null
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/styles/helpouts-logo-35_2x.png
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-closed.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-closed.png
index 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
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/triangle-opened.png b/tools/droiddoc/templates-sdk-dev/assets/images/triangle-opened.png
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/uiguidelines1.png b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png
index 5ce1611..5ce1611 100644
--- a/tools/droiddoc/templates-sdk-dyn/assets/images/uiguidelines1.png
+++ b/tools/droiddoc/templates-sdk-dev/assets/images/uiguidelines1.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk-dyn/assets/images/video-droid.png b/tools/droiddoc/templates-sdk-dev/assets/images/video-droid.png
index 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
Binary files differ
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()">&nbsp;</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) ?>&nbsp;</td>
+ <td class="jd-descrcol" width="100%">
+ <?cs call:short_descr(attr) ?>&nbsp;
+ <?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) ?>&nbsp;</td>
+ <td class="jd-descrcol" width="100%">
+ <?cs call:short_descr(cl) ?>&nbsp;
+ <?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) ?>&nbsp;</td>
<td class="jd-linkcol"><?cs call:cond_link(field.name, toroot, field.href, cl.included) ?>&nbsp;</td>
- <td class="jd-descrcol" width="100%"><?cs call:short_descr(field) ?>&nbsp;</td>
+ <td class="jd-descrcol" width="100%">
+ <?cs call:short_descr(field) ?>&nbsp;
+ <?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) ?>&nbsp;</td>
+ <td class="jd-descrcol" width="100%">
+ <?cs call:short_descr(cl) ?>&nbsp;
+ <?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 &amp; 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 &amp; 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 ?>
+ , &nbsp;
+ <?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) ?>&nbsp;
+ <?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>
&#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
&#124; <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 @@
&#124; <a href="<?cs var:toroot ?>samples/<?cs var:projectDir ?>/project.html">Project</a>
<?cs /if ?>
&#124; <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 &amp; 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 &amp; 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 &amp; 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
new file mode 100644
index 0000000..5f19215
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/android_logo.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png b/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png
new file mode 100644
index 0000000..04132cc
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/android_logo@2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png
new file mode 100644
index 0000000..3f39f4d
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk.png
Binary files differ
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
new file mode 100644
index 0000000..8081ac5
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/android_logo_ndk@2x.png
Binary files differ
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
index 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
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png b/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png
new file mode 100644
index 0000000..185b7e8
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/sprite-2x.png
Binary files differ
diff --git a/tools/droiddoc/templates-sdk/assets/images/sprite.png b/tools/droiddoc/templates-sdk/assets/images/sprite.png
new file mode 100644
index 0000000..7fef43e
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/images/sprite.png
Binary files differ
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 &amp; 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 &amp; 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 &amp; 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 &amp; 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">&nbsp;</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>&nbsp;&nbsp;|&nbsp;
- <a href="<?cs var:toroot ?>legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
- <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 ?>&nbsp;r<?cs var:sdk.rel.id ?> &mdash; <?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 ?>&nbsp;
<?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">&nbsp;</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">&nbsp;</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 ?>&nbsp;
<?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 &amp; 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">&#42; 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 &amp; 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);