From 22558d0be8210aee1a2ab64b374bb357d4123acd Mon Sep 17 00:00:00 2001 From: Dirk Dougherty Date: Thu, 10 Dec 2009 16:25:06 -0800 Subject: sdk doc change for esr: Add "resources" tab content. Fix links pointing to the old locations. Change Android.mk to output samples files to resources/samples. Misc other fixes. Bug: 2160782 Change-Id: Ib1eb2e9e3fe3a7b2ad16387dbf888646a1195221 --- Android.mk | 38 +- docs/html/guide/basics/what-is-android.jd | 4 +- docs/html/guide/developing/debug-tasks.jd | 2 +- docs/html/guide/developing/tools/adt.jd | 2 +- docs/html/guide/developing/tools/emulator.jd | 2 +- docs/html/guide/guide_toc.cs | 78 -- docs/html/guide/index.jd | 2 +- docs/html/guide/publishing/app-signing.jd | 2 +- docs/html/guide/publishing/versioning.jd | 4 +- docs/html/guide/topics/appwidgets/index.jd | 4 +- docs/html/guide/topics/graphics/opengl.jd | 2 +- docs/html/guide/topics/intents/intents-filters.jd | 4 +- .../topics/manifest/supports-screens-element.jd | 2 +- docs/html/guide/topics/resources/localization.jd | 4 +- docs/html/guide/topics/ui/binding.jd | 12 +- docs/html/guide/topics/ui/custom-components.jd | 12 +- docs/html/guide/topics/ui/declaring-layout.jd | 2 +- docs/html/guide/topics/ui/dialogs.jd | 4 +- docs/html/guide/topics/ui/layout-objects.jd | 8 +- docs/html/guide/topics/ui/menus.jd | 4 +- docs/html/guide/topics/ui/ui-events.jd | 2 +- docs/html/guide/topics/views/custom-views.jd | 2 +- docs/html/intl/ja/guide/basics/what-is-android.jd | 4 +- docs/html/intl/ja/guide/index.jd | 4 +- docs/html/intl/ja/guide/publishing/app-signing.jd | 2 +- docs/html/intl/ja/resources/community-groups.jd | 116 +++ .../intl/ja/resources/tutorials/hello-world.jd | 375 ++++++++++ docs/html/intl/ja/sdk/1.5_r2/installing.jd | 8 +- docs/html/intl/ja/sdk/1.5_r3/installing.jd | 8 +- .../resources/articles/avoiding-memory-leaks.jd | 109 +++ .../resources/articles/backward-compatibility.jd | 238 ++++++ .../resources/articles/can-i-use-this-intent.jd | 69 ++ .../resources/articles/creating-input-method.jd | 235 ++++++ docs/html/resources/articles/drawable-mutations.jd | 91 +++ .../articles/faster-screen-orientation-change.jd | 115 +++ docs/html/resources/articles/future-proofing.jd | 89 +++ docs/html/resources/articles/gestures.jd | 211 ++++++ docs/html/resources/articles/glsurfaceview.jd | 268 +++++++ docs/html/resources/articles/images/File.png | Bin 0 -> 14329 bytes docs/html/resources/articles/images/File_002.png | Bin 0 -> 13623 bytes docs/html/resources/articles/images/JFlubber.png | Bin 0 -> 8824 bytes docs/html/resources/articles/images/WikiNotes.png | Bin 0 -> 58942 bytes .../articles/images/all_drawables_changed.png | Bin 0 -> 60168 bytes docs/html/resources/articles/images/android.png | Bin 0 -> 79299 bytes docs/html/resources/articles/images/buttons.png | Bin 0 -> 4733 bytes docs/html/resources/articles/images/contacts.png | Bin 0 -> 73617 bytes .../articles/images/correct_drawables.png | Bin 0 -> 60746 bytes .../articles/images/ddms_allocation_tracker.png | Bin 0 -> 83383 bytes .../articles/images/ddms_allocation_trackerl.png | Bin 0 -> 514553 bytes docs/html/resources/articles/images/device.png | Bin 0 -> 112261 bytes docs/html/resources/articles/images/device_002.png | Bin 0 -> 97176 bytes docs/html/resources/articles/images/gestures.png | Bin 0 -> 11254 bytes .../resources/articles/images/gestures_002.png | Bin 0 -> 140982 bytes .../resources/articles/images/gestures_003.png | Bin 0 -> 15609 bytes .../resources/articles/images/gestures_004.png | Bin 0 -> 15484 bytes .../resources/articles/images/gestures_005.png | Bin 0 -> 14652 bytes .../resources/articles/images/gestures_006.png | Bin 0 -> 14643 bytes docs/html/resources/articles/images/grid.png | Bin 0 -> 32134 bytes docs/html/resources/articles/images/ime.png | Bin 0 -> 14225 bytes docs/html/resources/articles/images/ime_002.png | Bin 0 -> 14589 bytes docs/html/resources/articles/images/ime_003.png | Bin 0 -> 51163 bytes docs/html/resources/articles/images/ime_004.png | Bin 0 -> 10840 bytes docs/html/resources/articles/images/ime_005.png | Bin 0 -> 13099 bytes docs/html/resources/articles/images/ime_006.png | Bin 0 -> 14041 bytes .../articles/images/layouts_comparison_small.png | Bin 0 -> 132330 bytes docs/html/resources/articles/images/list01.png | Bin 0 -> 81747 bytes docs/html/resources/articles/images/list02.png | Bin 0 -> 85815 bytes .../html/resources/articles/images/list_fade_1.png | Bin 0 -> 44890 bytes .../html/resources/articles/images/list_fade_2.png | Bin 0 -> 136484 bytes .../html/resources/articles/images/list_fade_3.png | Bin 0 -> 105257 bytes .../html/resources/articles/images/list_fade_4.png | Bin 0 -> 190068 bytes docs/html/resources/articles/images/merge1.jpg | Bin 0 -> 49327 bytes docs/html/resources/articles/images/merge2.png | Bin 0 -> 29721 bytes docs/html/resources/articles/images/merge3.png | Bin 0 -> 26044 bytes docs/html/resources/articles/images/merge4.jpg | Bin 0 -> 44128 bytes docs/html/resources/articles/images/merge5.png | Bin 0 -> 35091 bytes .../resources/articles/images/mutated_states.png | Bin 0 -> 60394 bytes .../resources/articles/images/on-screen-inputs.png | Bin 0 -> 44392 bytes .../articles/images/on-screen-inputs_002.png | Bin 0 -> 34148 bytes .../articles/images/on-screen-inputs_003.png | Bin 0 -> 24749 bytes .../articles/images/on-screen-inputs_004.png | Bin 0 -> 55736 bytes .../articles/images/on-screen-inputs_005.png | Bin 0 -> 14092 bytes .../articles/images/on-screen-inputs_006.png | Bin 0 -> 24405 bytes .../articles/images/photostream_landscape.png | Bin 0 -> 104835 bytes .../articles/images/photostream_portrait.png | Bin 0 -> 124993 bytes docs/html/resources/articles/images/qsb.png | Bin 0 -> 34882 bytes docs/html/resources/articles/images/qsb_002.png | Bin 0 -> 246945 bytes docs/html/resources/articles/images/qsb_003.png | Bin 0 -> 43897 bytes .../resources/articles/images/relativelayout_1.png | Bin 0 -> 10385 bytes .../resources/articles/images/relativelayout_2.png | Bin 0 -> 8335 bytes .../resources/articles/images/relativelayout_3.png | Bin 0 -> 8394 bytes .../articles/images/relativelayout_wire_1.png | Bin 0 -> 3554 bytes .../articles/images/relativelayout_wire_2.png | Bin 0 -> 3553 bytes .../articles/images/relativelayout_wire_3.png | Bin 0 -> 3543 bytes docs/html/resources/articles/images/search01.png | Bin 0 -> 132998 bytes docs/html/resources/articles/images/search02.png | Bin 0 -> 115605 bytes .../resources/articles/images/shared_states.png | Bin 0 -> 54451 bytes docs/html/resources/articles/images/shelves2.png | Bin 0 -> 123418 bytes docs/html/resources/articles/images/text_field.png | Bin 0 -> 63949 bytes docs/html/resources/articles/images/ui-1.6.png | Bin 0 -> 14329 bytes docs/html/resources/articles/images/ui-1.6_002.png | Bin 0 -> 13623 bytes docs/html/resources/articles/images/viewstub1.png | Bin 0 -> 123418 bytes docs/html/resources/articles/images/viewstub2.png | Bin 0 -> 112198 bytes docs/html/resources/articles/images/viewstub3.png | Bin 0 -> 30279 bytes docs/html/resources/articles/images/viewstub4.png | Bin 0 -> 46944 bytes docs/html/resources/articles/images/webview.png | Bin 0 -> 14463 bytes .../articles/images/window_background.png | Bin 0 -> 136846 bytes .../articles/images/window_background_null.png | Bin 0 -> 136728 bytes .../articles/images/window_background_root.png | Bin 0 -> 29229 bytes docs/html/resources/articles/index.jd | 9 + .../resources/articles/layout-tricks-efficiency.jd | 177 +++++ .../html/resources/articles/layout-tricks-merge.jd | 198 +++++ .../html/resources/articles/layout-tricks-reuse.jd | 67 ++ .../html/resources/articles/layout-tricks-stubs.jd | 84 +++ .../resources/articles/listview-backgrounds.jd | 86 +++ docs/html/resources/articles/live-folders.jd | 168 +++++ docs/html/resources/articles/on-screen-inputs.jd | 249 +++++++ docs/html/resources/articles/painless-threading.jd | 147 ++++ docs/html/resources/articles/qsb.jd | 151 ++++ docs/html/resources/articles/timed-ui-updates.jd | 149 ++++ docs/html/resources/articles/touch-mode.jd | 138 ++++ docs/html/resources/articles/track-mem.jd | 62 ++ docs/html/resources/articles/tts.jd | 241 ++++++ docs/html/resources/articles/ui-1.5.jd | 48 ++ docs/html/resources/articles/ui-1.6.jd | 130 ++++ docs/html/resources/articles/using-webviews.jd | 61 ++ docs/html/resources/articles/wikinotes-intents.jd | 255 +++++++ docs/html/resources/articles/wikinotes-linkify.jd | 113 +++ docs/html/resources/articles/window-bg-speed.jd | 125 ++++ docs/html/resources/articles/zipalign.jd | 98 +++ docs/html/resources/community-groups.jd | 121 +++ docs/html/resources/community-more.jd | 48 ++ docs/html/resources/faq/commontasks.jd | 821 +++++++++++++++++++++ docs/html/resources/faq/framework.jd | 197 +++++ docs/html/resources/faq/index.jd | 11 + docs/html/resources/faq/licensingandoss.jd | 19 + docs/html/resources/faq/security.jd | 156 ++++ docs/html/resources/faq/troubleshooting.jd | 261 +++++++ docs/html/resources/index.jd | 38 + docs/html/resources/resources_toc.cs | 242 ++++++ .../resources/samples/images/BluetoothChat1.png | Bin 0 -> 16064 bytes .../resources/samples/images/BluetoothChat2.png | Bin 0 -> 15678 bytes .../resources/samples/images/ContactManager1.png | Bin 0 -> 54351 bytes .../resources/samples/images/ContactManager2.png | Bin 0 -> 40027 bytes docs/html/resources/samples/images/HomeSample.png | Bin 0 -> 44416 bytes docs/html/resources/samples/images/JetBoy.png | Bin 0 -> 53801 bytes .../resources/samples/images/MultiResolution.png | Bin 0 -> 96462 bytes .../samples/images/SearchableDictionary1.png | Bin 0 -> 15800 bytes .../samples/images/SearchableDictionary2.png | Bin 0 -> 18114 bytes docs/html/resources/samples/images/Snake.png | Bin 0 -> 5445 bytes .../html/resources/samples/images/SoftKeyboard.png | Bin 0 -> 13426 bytes docs/html/resources/samples/images/Wiktionary.png | Bin 0 -> 23644 bytes .../resources/samples/images/WiktionarySimple.png | Bin 0 -> 61543 bytes .../samples/images/sample_lunarlander.png | Bin 0 -> 27514 bytes docs/html/resources/samples/images/sample_note.png | Bin 0 -> 6011 bytes .../resources/samples/images/sample_notepad.png | Bin 0 -> 6530 bytes docs/html/resources/samples/index.jd | 72 ++ docs/html/resources/tutorials/hello-world.jd | 564 ++++++++++++++ .../resources/tutorials/images/hello_world_0.png | Bin 0 -> 6328 bytes .../resources/tutorials/images/hello_world_1.png | Bin 0 -> 10031 bytes .../resources/tutorials/images/hello_world_2.png | Bin 0 -> 11040 bytes .../resources/tutorials/images/hello_world_3.png | Bin 0 -> 11000 bytes .../resources/tutorials/images/hello_world_4.png | Bin 0 -> 61711 bytes .../resources/tutorials/images/hello_world_5.png | Bin 0 -> 6244 bytes .../resources/tutorials/images/hello_world_8.png | Bin 0 -> 10993 bytes .../resources/tutorials/images/hello_world_9.png | Bin 0 -> 6791 bytes docs/html/resources/tutorials/index.html | 8 + .../html/resources/tutorials/localization/index.jd | 593 +++++++++++++++ .../tutorials/notepad/codelab/NotepadCodeLab.zip | Bin 0 -> 90916 bytes docs/html/resources/tutorials/notepad/index.jd | 142 ++++ .../resources/tutorials/notepad/notepad-ex1.jd | 591 +++++++++++++++ .../resources/tutorials/notepad/notepad-ex2.jd | 647 ++++++++++++++++ .../resources/tutorials/notepad/notepad-ex3.jd | 358 +++++++++ .../tutorials/notepad/notepad-extra-credit.jd | 70 ++ .../resources/tutorials/notepad/notepad-index.jd | 143 ++++ .../tutorials/views/hello-autocomplete.jd | 116 +++ .../resources/tutorials/views/hello-datepicker.jd | 151 ++++ .../resources/tutorials/views/hello-formstuff.jd | 262 +++++++ .../resources/tutorials/views/hello-gallery.jd | 135 ++++ .../resources/tutorials/views/hello-gridview.jd | 129 ++++ .../tutorials/views/hello-linearlayout.jd | 130 ++++ .../resources/tutorials/views/hello-listview.jd | 90 +++ .../resources/tutorials/views/hello-mapview.jd | 273 +++++++ .../tutorials/views/hello-relativelayout.jd | 75 ++ .../resources/tutorials/views/hello-spinner.jd | 106 +++ .../resources/tutorials/views/hello-tablelayout.jd | 118 +++ .../resources/tutorials/views/hello-tabwidget.jd | 124 ++++ .../resources/tutorials/views/hello-timepicker.jd | 159 ++++ .../resources/tutorials/views/hello-webview.jd | 118 +++ .../resources/tutorials/views/images/android.png | Bin 0 -> 693 bytes .../tutorials/views/images/androidmarker.png | Bin 0 -> 702 bytes .../tutorials/views/images/hello-autocomplete.png | Bin 0 -> 4601 bytes .../tutorials/views/images/hello-datepicker.png | Bin 0 -> 7322 bytes .../tutorials/views/images/hello-formstuff.png | Bin 0 -> 4258 bytes .../tutorials/views/images/hello-gallery.png | Bin 0 -> 5593 bytes .../tutorials/views/images/hello-gridview.png | Bin 0 -> 21768 bytes .../tutorials/views/images/hello-linearlayout.png | Bin 0 -> 4207 bytes .../tutorials/views/images/hello-listview.png | Bin 0 -> 6926 bytes .../tutorials/views/images/hello-mapview.png | Bin 0 -> 16922 bytes .../views/images/hello-relativelayout.png | Bin 0 -> 2399 bytes .../tutorials/views/images/hello-spinner.png | Bin 0 -> 2513 bytes .../tutorials/views/images/hello-tablelayout.png | Bin 0 -> 3446 bytes .../tutorials/views/images/hello-tabwidget.png | Bin 0 -> 2117 bytes .../tutorials/views/images/hello-timepicker.png | Bin 0 -> 5644 bytes .../tutorials/views/images/hello-webview.png | Bin 0 -> 5874 bytes docs/html/resources/tutorials/views/index.jd | 118 +++ docs/html/sdk/1.1_r1/upgrading.jd | 2 +- docs/html/sdk/RELEASENOTES.jd | 2 +- docs/html/sdk/android-2.0.1.jd | 7 +- docs/html/sdk/eclipse-adt.jd | 14 +- docs/html/sdk/index.jd | 2 +- docs/html/sdk/installing.jd | 8 +- 212 files changed, 11969 insertions(+), 166 deletions(-) create mode 100644 docs/html/intl/ja/resources/community-groups.jd create mode 100644 docs/html/intl/ja/resources/tutorials/hello-world.jd create mode 100644 docs/html/resources/articles/avoiding-memory-leaks.jd create mode 100644 docs/html/resources/articles/backward-compatibility.jd create mode 100644 docs/html/resources/articles/can-i-use-this-intent.jd create mode 100644 docs/html/resources/articles/creating-input-method.jd create mode 100644 docs/html/resources/articles/drawable-mutations.jd create mode 100644 docs/html/resources/articles/faster-screen-orientation-change.jd create mode 100644 docs/html/resources/articles/future-proofing.jd create mode 100644 docs/html/resources/articles/gestures.jd create mode 100644 docs/html/resources/articles/glsurfaceview.jd create mode 100644 docs/html/resources/articles/images/File.png create mode 100644 docs/html/resources/articles/images/File_002.png create mode 100644 docs/html/resources/articles/images/JFlubber.png create mode 100644 docs/html/resources/articles/images/WikiNotes.png create mode 100644 docs/html/resources/articles/images/all_drawables_changed.png create mode 100644 docs/html/resources/articles/images/android.png create mode 100644 docs/html/resources/articles/images/buttons.png create mode 100644 docs/html/resources/articles/images/contacts.png create mode 100644 docs/html/resources/articles/images/correct_drawables.png create mode 100644 docs/html/resources/articles/images/ddms_allocation_tracker.png create mode 100644 docs/html/resources/articles/images/ddms_allocation_trackerl.png create mode 100644 docs/html/resources/articles/images/device.png create mode 100644 docs/html/resources/articles/images/device_002.png create mode 100644 docs/html/resources/articles/images/gestures.png create mode 100644 docs/html/resources/articles/images/gestures_002.png create mode 100644 docs/html/resources/articles/images/gestures_003.png create mode 100644 docs/html/resources/articles/images/gestures_004.png create mode 100644 docs/html/resources/articles/images/gestures_005.png create mode 100644 docs/html/resources/articles/images/gestures_006.png create mode 100644 docs/html/resources/articles/images/grid.png create mode 100644 docs/html/resources/articles/images/ime.png create mode 100644 docs/html/resources/articles/images/ime_002.png create mode 100644 docs/html/resources/articles/images/ime_003.png create mode 100644 docs/html/resources/articles/images/ime_004.png create mode 100644 docs/html/resources/articles/images/ime_005.png create mode 100644 docs/html/resources/articles/images/ime_006.png create mode 100644 docs/html/resources/articles/images/layouts_comparison_small.png create mode 100644 docs/html/resources/articles/images/list01.png create mode 100644 docs/html/resources/articles/images/list02.png create mode 100644 docs/html/resources/articles/images/list_fade_1.png create mode 100644 docs/html/resources/articles/images/list_fade_2.png create mode 100644 docs/html/resources/articles/images/list_fade_3.png create mode 100644 docs/html/resources/articles/images/list_fade_4.png create mode 100644 docs/html/resources/articles/images/merge1.jpg create mode 100644 docs/html/resources/articles/images/merge2.png create mode 100644 docs/html/resources/articles/images/merge3.png create mode 100644 docs/html/resources/articles/images/merge4.jpg create mode 100644 docs/html/resources/articles/images/merge5.png create mode 100644 docs/html/resources/articles/images/mutated_states.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs_002.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs_003.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs_004.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs_005.png create mode 100644 docs/html/resources/articles/images/on-screen-inputs_006.png create mode 100644 docs/html/resources/articles/images/photostream_landscape.png create mode 100644 docs/html/resources/articles/images/photostream_portrait.png create mode 100644 docs/html/resources/articles/images/qsb.png create mode 100644 docs/html/resources/articles/images/qsb_002.png create mode 100644 docs/html/resources/articles/images/qsb_003.png create mode 100644 docs/html/resources/articles/images/relativelayout_1.png create mode 100644 docs/html/resources/articles/images/relativelayout_2.png create mode 100644 docs/html/resources/articles/images/relativelayout_3.png create mode 100644 docs/html/resources/articles/images/relativelayout_wire_1.png create mode 100644 docs/html/resources/articles/images/relativelayout_wire_2.png create mode 100644 docs/html/resources/articles/images/relativelayout_wire_3.png create mode 100644 docs/html/resources/articles/images/search01.png create mode 100644 docs/html/resources/articles/images/search02.png create mode 100644 docs/html/resources/articles/images/shared_states.png create mode 100644 docs/html/resources/articles/images/shelves2.png create mode 100644 docs/html/resources/articles/images/text_field.png create mode 100644 docs/html/resources/articles/images/ui-1.6.png create mode 100644 docs/html/resources/articles/images/ui-1.6_002.png create mode 100644 docs/html/resources/articles/images/viewstub1.png create mode 100644 docs/html/resources/articles/images/viewstub2.png create mode 100644 docs/html/resources/articles/images/viewstub3.png create mode 100644 docs/html/resources/articles/images/viewstub4.png create mode 100644 docs/html/resources/articles/images/webview.png create mode 100644 docs/html/resources/articles/images/window_background.png create mode 100644 docs/html/resources/articles/images/window_background_null.png create mode 100644 docs/html/resources/articles/images/window_background_root.png create mode 100644 docs/html/resources/articles/index.jd create mode 100644 docs/html/resources/articles/layout-tricks-efficiency.jd create mode 100644 docs/html/resources/articles/layout-tricks-merge.jd create mode 100644 docs/html/resources/articles/layout-tricks-reuse.jd create mode 100644 docs/html/resources/articles/layout-tricks-stubs.jd create mode 100644 docs/html/resources/articles/listview-backgrounds.jd create mode 100644 docs/html/resources/articles/live-folders.jd create mode 100644 docs/html/resources/articles/on-screen-inputs.jd create mode 100644 docs/html/resources/articles/painless-threading.jd create mode 100644 docs/html/resources/articles/qsb.jd create mode 100644 docs/html/resources/articles/timed-ui-updates.jd create mode 100644 docs/html/resources/articles/touch-mode.jd create mode 100644 docs/html/resources/articles/track-mem.jd create mode 100644 docs/html/resources/articles/tts.jd create mode 100644 docs/html/resources/articles/ui-1.5.jd create mode 100644 docs/html/resources/articles/ui-1.6.jd create mode 100644 docs/html/resources/articles/using-webviews.jd create mode 100644 docs/html/resources/articles/wikinotes-intents.jd create mode 100644 docs/html/resources/articles/wikinotes-linkify.jd create mode 100644 docs/html/resources/articles/window-bg-speed.jd create mode 100644 docs/html/resources/articles/zipalign.jd create mode 100644 docs/html/resources/community-groups.jd create mode 100644 docs/html/resources/community-more.jd create mode 100644 docs/html/resources/faq/commontasks.jd create mode 100644 docs/html/resources/faq/framework.jd create mode 100644 docs/html/resources/faq/index.jd create mode 100644 docs/html/resources/faq/licensingandoss.jd create mode 100644 docs/html/resources/faq/security.jd create mode 100644 docs/html/resources/faq/troubleshooting.jd create mode 100644 docs/html/resources/index.jd create mode 100644 docs/html/resources/resources_toc.cs create mode 100644 docs/html/resources/samples/images/BluetoothChat1.png create mode 100644 docs/html/resources/samples/images/BluetoothChat2.png create mode 100644 docs/html/resources/samples/images/ContactManager1.png create mode 100644 docs/html/resources/samples/images/ContactManager2.png create mode 100644 docs/html/resources/samples/images/HomeSample.png create mode 100644 docs/html/resources/samples/images/JetBoy.png create mode 100644 docs/html/resources/samples/images/MultiResolution.png create mode 100644 docs/html/resources/samples/images/SearchableDictionary1.png create mode 100644 docs/html/resources/samples/images/SearchableDictionary2.png create mode 100644 docs/html/resources/samples/images/Snake.png create mode 100644 docs/html/resources/samples/images/SoftKeyboard.png create mode 100644 docs/html/resources/samples/images/Wiktionary.png create mode 100644 docs/html/resources/samples/images/WiktionarySimple.png create mode 100644 docs/html/resources/samples/images/sample_lunarlander.png create mode 100644 docs/html/resources/samples/images/sample_note.png create mode 100644 docs/html/resources/samples/images/sample_notepad.png create mode 100644 docs/html/resources/samples/index.jd create mode 100644 docs/html/resources/tutorials/hello-world.jd create mode 100644 docs/html/resources/tutorials/images/hello_world_0.png create mode 100644 docs/html/resources/tutorials/images/hello_world_1.png create mode 100644 docs/html/resources/tutorials/images/hello_world_2.png create mode 100644 docs/html/resources/tutorials/images/hello_world_3.png create mode 100644 docs/html/resources/tutorials/images/hello_world_4.png create mode 100644 docs/html/resources/tutorials/images/hello_world_5.png create mode 100644 docs/html/resources/tutorials/images/hello_world_8.png create mode 100644 docs/html/resources/tutorials/images/hello_world_9.png create mode 100644 docs/html/resources/tutorials/index.html create mode 100755 docs/html/resources/tutorials/localization/index.jd create mode 100644 docs/html/resources/tutorials/notepad/codelab/NotepadCodeLab.zip create mode 100644 docs/html/resources/tutorials/notepad/index.jd create mode 100644 docs/html/resources/tutorials/notepad/notepad-ex1.jd create mode 100644 docs/html/resources/tutorials/notepad/notepad-ex2.jd create mode 100644 docs/html/resources/tutorials/notepad/notepad-ex3.jd create mode 100644 docs/html/resources/tutorials/notepad/notepad-extra-credit.jd create mode 100644 docs/html/resources/tutorials/notepad/notepad-index.jd create mode 100644 docs/html/resources/tutorials/views/hello-autocomplete.jd create mode 100644 docs/html/resources/tutorials/views/hello-datepicker.jd create mode 100644 docs/html/resources/tutorials/views/hello-formstuff.jd create mode 100644 docs/html/resources/tutorials/views/hello-gallery.jd create mode 100644 docs/html/resources/tutorials/views/hello-gridview.jd create mode 100644 docs/html/resources/tutorials/views/hello-linearlayout.jd create mode 100644 docs/html/resources/tutorials/views/hello-listview.jd create mode 100644 docs/html/resources/tutorials/views/hello-mapview.jd create mode 100644 docs/html/resources/tutorials/views/hello-relativelayout.jd create mode 100644 docs/html/resources/tutorials/views/hello-spinner.jd create mode 100644 docs/html/resources/tutorials/views/hello-tablelayout.jd create mode 100644 docs/html/resources/tutorials/views/hello-tabwidget.jd create mode 100644 docs/html/resources/tutorials/views/hello-timepicker.jd create mode 100644 docs/html/resources/tutorials/views/hello-webview.jd create mode 100755 docs/html/resources/tutorials/views/images/android.png create mode 100755 docs/html/resources/tutorials/views/images/androidmarker.png create mode 100755 docs/html/resources/tutorials/views/images/hello-autocomplete.png create mode 100755 docs/html/resources/tutorials/views/images/hello-datepicker.png create mode 100755 docs/html/resources/tutorials/views/images/hello-formstuff.png create mode 100755 docs/html/resources/tutorials/views/images/hello-gallery.png create mode 100755 docs/html/resources/tutorials/views/images/hello-gridview.png create mode 100755 docs/html/resources/tutorials/views/images/hello-linearlayout.png create mode 100755 docs/html/resources/tutorials/views/images/hello-listview.png create mode 100755 docs/html/resources/tutorials/views/images/hello-mapview.png create mode 100755 docs/html/resources/tutorials/views/images/hello-relativelayout.png create mode 100755 docs/html/resources/tutorials/views/images/hello-spinner.png create mode 100755 docs/html/resources/tutorials/views/images/hello-tablelayout.png create mode 100644 docs/html/resources/tutorials/views/images/hello-tabwidget.png create mode 100755 docs/html/resources/tutorials/views/images/hello-timepicker.png create mode 100755 docs/html/resources/tutorials/views/images/hello-webview.png create mode 100644 docs/html/resources/tutorials/views/index.jd diff --git a/Android.mk b/Android.mk index 8d3d118..6b75bcd 100644 --- a/Android.mk +++ b/Android.mk @@ -357,33 +357,31 @@ sample_dir := development/samples web_docs_sample_code_flags := \ -hdf android.hasSamples 1 \ -samplecode $(sample_dir)/ApiDemos \ - guide/samples/ApiDemos "API Demos" \ - -samplecode $(sample_dir)/BluetoothChat \ - guide/samples/BluetoothChat "Bluetooth Chat" \ - -samplecode $(sample_dir)/ContactManager \ - guide/samples/ContactManager "Contact Manager" \ + resources/samples/ApiDemos "API Demos" \ + -samplecode $(sample_dir)/BluetoothChat \ + resources/samples/BluetoothChat "Bluetooth Chat" \ + -samplecode $(sample_dir)/ContactManager \ + resources/samples/ContactManager "Contact Manager" \ -samplecode $(sample_dir)/Home \ - guide/samples/Home "Home" \ + resources/samples/Home "Home" \ -samplecode $(sample_dir)/JetBoy \ - guide/samples/JetBoy "JetBoy" \ + resources/samples/JetBoy "JetBoy" \ -samplecode $(sample_dir)/LunarLander \ - guide/samples/LunarLander "Lunar Lander" \ - -samplecode $(sample_dir)/MultiResolution \ - guide/samples/MultiResolution "Multiple Resolutions" \ + resources/samples/LunarLander "Lunar Lander" \ + -samplecode $(sample_dir)/MultiResolution \ + resources/samples/MultiResolution "Multiple Resolutions" \ -samplecode $(sample_dir)/NotePad \ - guide/samples/NotePad "Note Pad" \ + resources/samples/NotePad "Note Pad" \ -samplecode $(sample_dir)/SearchableDictionary \ - guide/samples/SearchableDictionary "Searchable Dictionary" \ + resources/samples/SearchableDictionary "Searchable Dictionary" \ -samplecode $(sample_dir)/Snake \ - guide/samples/Snake "Snake" \ + resources/samples/Snake "Snake" \ -samplecode $(sample_dir)/SoftKeyboard \ - guide/samples/SoftKeyboard "Soft Keyboard" \ - -samplecode $(sample_dir)/Wiktionary \ - guide/samples/Wiktionary "Wiktionary" \ - -samplecode $(sample_dir)/WiktionarySimple \ - guide/samples/WiktionarySimple "Wiktionary (Simplified)" - - + resources/samples/SoftKeyboard "Soft Keyboard" \ + -samplecode $(sample_dir)/Wiktionary \ + resources/samples/Wiktionary "Wiktionary" \ + -samplecode $(sample_dir)/WiktionarySimple \ + resources/samples/WiktionarySimple "Wiktionary (Simplified)" ## SDK version identifiers used in the published docs # major[.minor] version for current SDK. (full releases only) diff --git a/docs/html/guide/basics/what-is-android.jd b/docs/html/guide/basics/what-is-android.jd index 668e62e..9393fab 100644 --- a/docs/html/guide/basics/what-is-android.jd +++ b/docs/html/guide/basics/what-is-android.jd @@ -64,7 +64,7 @@ to be replaced by the user.

Underlying all applications is a set of services and systems, including:

For more details and a walkthrough of an application, see the Notepad Tutorial.

+href="{@docRoot}resources/tutorials/notepad/index.html">Notepad Tutorial.

Libraries

diff --git a/docs/html/guide/developing/debug-tasks.jd b/docs/html/guide/developing/debug-tasks.jd index 6b7c27a..3279741 100644 --- a/docs/html/guide/developing/debug-tasks.jd +++ b/docs/html/guide/developing/debug-tasks.jd @@ -60,7 +60,7 @@ D/ActivityManager( 763): Stopping: HistoryRecord{409dbb20 com.android.home.AllAp that expose useful information such as CPU usage and frame rate. See Debug and Test Settings on the Emulator below. -

Also, see the Troubleshooting section +

Also, see the Troubleshooting section of the doc to figure out why your application isn't appearing on the emulator, or why it's not starting.

diff --git a/docs/html/guide/developing/tools/adt.jd b/docs/html/guide/developing/tools/adt.jd index f28b24c..6eee91d 100644 --- a/docs/html/guide/developing/tools/adt.jd +++ b/docs/html/guide/developing/tools/adt.jd @@ -105,7 +105,7 @@ Eclipse components (for example, WST). If you encounter an error when installing ADT, your Eclipse installion might not include those components. For information about how to quickly add the necessary components to your Eclipse installation, see the troubleshooting topic -ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

+ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

For Linux users

If you encounter this error when installing the ADT Plugin for Eclipse: diff --git a/docs/html/guide/developing/tools/emulator.jd b/docs/html/guide/developing/tools/emulator.jd index a9b6914..03a4d1e 100644 --- a/docs/html/guide/developing/tools/emulator.jd +++ b/docs/html/guide/developing/tools/emulator.jd @@ -1754,7 +1754,7 @@ to the current working directory):

For emulators running on Mac OS X, if you see an error "Warning: No DNS servers found" when starting the emulator, check to see whether you have an /etc/resolv.conf file. If not, please run the following line in a command window:

ln -s /private/var/run/resolv.conf /etc/resolv.conf
-

See Frequently Asked Questions for more troubleshooting information.

+

See Frequently Asked Questions for more troubleshooting information.

Emulator Limitations

diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index c08a280..927c3fa 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -364,81 +364,6 @@ - -
  • -

    Tutorials and Sample Code - - - - - - - -

    - - -
  • -
  • Appendix @@ -463,9 +388,6 @@
  • Glossary
  • -
  • - FAQ -
  • diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd index ecbf97b..1674bc8 100644 --- a/docs/html/guide/index.jd +++ b/docs/html/guide/index.jd @@ -77,7 +77,7 @@ understanding of the application framework.

    For additional help, consider joining one or more of the Android discussion groups. Go to the -Community tab above +Community pages for more information.

    diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd index f0febc0..86dd155 100644 --- a/docs/html/guide/publishing/app-signing.jd +++ b/docs/html/guide/publishing/app-signing.jd @@ -268,7 +268,7 @@ in C:\Documents and Settings\\.android\ on Windows XP, and in

    Note that, if your development machine is using a non-Gregorian locale, the build tools may erroneously generate an already-expired debug certificate, so that you get an error when trying to compile your application. For workaround information, see the -troubleshooting topic +troubleshooting topic I can't compile my app because the build tools generated an expired debug certificate.

    diff --git a/docs/html/guide/publishing/versioning.jd b/docs/html/guide/publishing/versioning.jd index e2ee684..216f993 100644 --- a/docs/html/guide/publishing/versioning.jd +++ b/docs/html/guide/publishing/versioning.jd @@ -170,6 +170,6 @@ maximum API Level.

    android:minSdkVersion as an attribute.

    For more information, see the <uses- -sdk> manifest element documentation and the <uses-sdk> +manifest element documentation and the API Levels document.

    diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd index c9df3ba..cf606fd 100644 --- a/docs/html/guide/topics/appwidgets/index.jd +++ b/docs/html/guide/topics/appwidgets/index.jd @@ -339,7 +339,7 @@ without worrying about the AppWidgetProvider closing down due to an sample's AppWidgetProvider for an example of an App Widget running a {@link android.app.Service}.

    Also see the +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html"> ExampleAppWidgetProvider.java sample class.

    @@ -468,7 +468,7 @@ reaching the end, the App Widget host is notified that the configuration was can App Widget will not be added.

    See the +href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html"> ExampleAppWidgetConfigure.java sample class in ApiDemos for an example.

    diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd index 901980d..4d0b223 100644 --- a/docs/html/guide/topics/graphics/opengl.jd +++ b/docs/html/guide/topics/graphics/opengl.jd @@ -28,7 +28,7 @@ ES API. However, it may not be identical, so watch out for deviations.

    For an example of this usage model (based on the classic GL ColorCube), showing how to use it with threads can be found in -com.android.samples.graphics.GLSurfaceViewActivity.java. +com.android.samples.graphics.GLSurfaceViewActivity.java.

    Writing a summary of how to actually write 3D applications using OpenGL is diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd index 962a001..7a7eb70 100644 --- a/docs/html/guide/topics/intents/intents-filters.jd +++ b/docs/html/guide/topics/intents/intents-filters.jd @@ -702,8 +702,8 @@ declared in its manifest file. (If you're working offline in the SDK, you can find all the source files for this sample application, including its manifest file, at {@code <sdk>/samples/NotePad/index.html}. If you're viewing the documentation online, the source files are in the -Tutorials and Sample Code -section here.) +Tutorials and Sample Code +section here.)

    diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd index 5494320..620d3b2 100644 --- a/docs/html/guide/topics/manifest/supports-screens-element.jd +++ b/docs/html/guide/topics/manifest/supports-screens-element.jd @@ -31,7 +31,7 @@ or scale them up by a factor of 1.5 (high dpi screens). The screen density is expressed as dots-per-inch (dpi).

    For more information, see -Multiple Screens Support.

    +Multiple Screens Support.

    attributes:
    diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd index f32f1ac..192695b 100755 --- a/docs/html/guide/topics/resources/localization.jd +++ b/docs/html/guide/topics/resources/localization.jd @@ -51,7 +51,7 @@ defaults.

    See also

    1. Hello, L10N Tutorial
    2. +href="{@docRoot}resources/tutorials/localization/index.html">Hello, L10N Tutorial
    3. Resources
    4. Declaring Layout
    5. Activity Lifecycle
    6. @@ -90,7 +90,7 @@ programmatically. This document does not cover how to localize your Java code.

      The Hello, L10N +href="{@docRoot}resources/tutorials/localization/index.html">Hello, L10N tutorial takes you through the steps of creating a simple localized application that uses locale-specific resources in the way described in this document.

      diff --git a/docs/html/guide/topics/ui/binding.jd b/docs/html/guide/topics/ui/binding.jd index 85aed18..4745a3a 100644 --- a/docs/html/guide/topics/ui/binding.jd +++ b/docs/html/guide/topics/ui/binding.jd @@ -13,9 +13,9 @@ parent.link=index.html

      See also

        -
      1. Hello Spinner tutorial
      2. -
      3. Hello ListView tutorial
      4. -
      5. Hello GridView tutorial
      6. +
      7. Hello Spinner tutorial
      8. +
      9. Hello ListView tutorial
      10. +
      11. Hello GridView tutorial
      @@ -107,7 +107,7 @@ mHistoryView.setOnItemClickListener(mMessageClickedHandler);

      For more discussion on how to create different AdapterViews, read the following tutorials: -Hello Spinner, -Hello ListView, and -Hello GridView. +Hello Spinner, +Hello ListView, and +Hello GridView.

      diff --git a/docs/html/guide/topics/ui/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd index 76d1034..b962f76 100644 --- a/docs/html/guide/topics/ui/custom-components.jd +++ b/docs/html/guide/topics/ui/custom-components.jd @@ -61,7 +61,7 @@ examples of what you could do with them:

    7. You could override the way that an EditText component is rendered on the screen - (the Notepad Tutorial uses this to good effect, + (the Notepad Tutorial uses this to good effect, to create a lined-notepad page).
    8. @@ -318,9 +318,9 @@ Here's a summary of some of the other standard methods that the framework calls

      A Custom View Example

      The CustomView sample in the -API Demos provides an example +API Demos provides an example of a customized View. The custom View is defined in the -LabelView +LabelView class.

      The LabelView sample demonstrates a number of different aspects of custom components:

        @@ -339,7 +339,7 @@ class.

        provided canvas.

      You can see some sample usages of the LabelView custom View in -custom_view_1.xml +custom_view_1.xml from the samples. In particular, you can see a mix of both android: namespace parameters and custom app: namespace parameters. These app: parameters are the custom ones that the LabelView recognizes @@ -446,7 +446,7 @@ you would do with a fully customized component, but by starting with a more specialized class in the View heirarchy, you can also get a lot of behavior for free that probably does exactly what you want.

      For example, the SDK includes a NotePad application in the +href="{@docRoot}resources/samples/NotePad/index.html">NotePad application in the samples. This demonstrates many aspects of using the Android platform, among them is extending an EditText View to make a lined notepad. This is not a perfect example, and the APIs for doing this might change from this early @@ -455,7 +455,7 @@ preview, but it does demonstrate the principles.

      NotePad sample into Eclipse (or just look at the source using the link provided). In particular look at the definition of MyEditText in the NoteEditor.java +href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">NoteEditor.java file.

      Some points to note here

        diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd index 80ad7b8..f965966 100644 --- a/docs/html/guide/topics/ui/declaring-layout.jd +++ b/docs/html/guide/topics/ui/declaring-layout.jd @@ -65,7 +65,7 @@ example, the EditText element has a text attribute that corresponds

        Tip: Learn more about different layout types in Common Layout Objects. There are also a collection of tutorials on building various layouts in the -Hello Views tutorial guide.

        +Hello Views tutorial guide.

        Write the XML

        diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd index 4e4ca14..fa2d916 100644 --- a/docs/html/guide/topics/ui/dialogs.jd +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -47,10 +47,10 @@ for notifications and short activities that directly relate to the application i See Creating a ProgressDialog below.
        {@link android.app.DatePickerDialog}
        A dialog that allows the user to select a date. See the - Hello DatePicker tutorial.
        + Hello DatePicker tutorial.
        {@link android.app.TimePickerDialog}
        A dialog that allows the user to select a time. See the - Hello TimePicker tutorial.
        + Hello TimePicker tutorial.

        If you would like to customize your own dialog, you can extend the diff --git a/docs/html/guide/topics/ui/layout-objects.jd b/docs/html/guide/topics/ui/layout-objects.jd index bb13a18..345e9b3 100644 --- a/docs/html/guide/topics/ui/layout-objects.jd +++ b/docs/html/guide/topics/ui/layout-objects.jd @@ -19,7 +19,7 @@ parent.link=index.html

        This section describes some of the more common types of layout objects to use in your applications. Like all layouts, they are subclasses of {@link android.view.ViewGroup ViewGroup}.

        -

        Also see the Hello Views tutorials for +

        Also see the Hello Views tutorials for some guidance on using more Android View layouts.

        FrameLayout

        @@ -83,7 +83,7 @@ neighboring elements. This can be turned off by setting android:baselineAligned="false" in the layout XML.

        To view other sample code, see the -Hello LinearLayout tutorial.

        +Hello LinearLayout tutorial.

        TableLayout

        @@ -138,7 +138,7 @@ result, with cell borders displayed as dotted lines (added for visual effect). < fits the screen. See the {@link android.widget.TableLayout TableLayout reference} documentation for more details.

        -

        To view sample code, see the Hello +

        To view sample code, see the Hello TableLayout tutorial.

        @@ -208,7 +208,7 @@ refer to the ID using the syntax of a relative resource For example, assigning the parameter toLeft="my_button" to a TextView would place the TextView to the left of the View with the ID my_button (which must be written in the XML before the TextView).

        -

        To view this sample code, see the Hello +

        To view this sample code, see the Hello RelativeLayout tutorial.

        diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd index bae94ca..bad8d65 100644 --- a/docs/html/guide/topics/ui/menus.jd +++ b/docs/html/guide/topics/ui/menus.jd @@ -180,7 +180,7 @@ Then, register a {@link android.view.ContextMenu} for the View, with {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.

        For example, here is some code that can be used with the -Notepad application +Notepad application to add a context menu for each note in the list:

         public void onCreateContextMenu(ContextMenu menu, View v,
        @@ -518,5 +518,5 @@ a <category> element in the intent filter. For example:

        Intents and Intent Filters document.

        For a sample application using this technique, see the -Note Pad +Note Pad sample code.

        diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd index 5628d46..a4dd614 100644 --- a/docs/html/guide/topics/ui/ui-events.jd +++ b/docs/html/guide/topics/ui/ui-events.jd @@ -15,7 +15,7 @@ parent.link=index.html

        See also

          -
        1. Hello Form Stuff tutorial
        2. +
        3. Hello Form Stuff tutorial
        diff --git a/docs/html/guide/topics/views/custom-views.jd b/docs/html/guide/topics/views/custom-views.jd index c5f9346..c255293 100644 --- a/docs/html/guide/topics/views/custom-views.jd +++ b/docs/html/guide/topics/views/custom-views.jd @@ -40,7 +40,7 @@ parent.link=index.html
      1. You could override the way that an EditText component is rendered on the screen - (the Notepad sample uses this to good effect, + (the Notepad sample uses this to good effect, to create a lined-notepad page).
      2. diff --git a/docs/html/intl/ja/guide/basics/what-is-android.jd b/docs/html/intl/ja/guide/basics/what-is-android.jd index 89558a0..fcf670d 100644 --- a/docs/html/intl/ja/guide/basics/what-is-android.jd +++ b/docs/html/intl/ja/guide/basics/what-is-android.jd @@ -39,7 +39,7 @@ page.title=Android とは

        アプリケーションの基盤となるのは、次のサービスとシステムのセットです:

        • アプリケーションの構築を可能にする、拡張可能で豊富なビューのセット。ビューには、リスト、グリッド、テキスト ボックス、ボタンだけでなく、埋め込み可能なウェブブラウザも含まれます。
        • + href="{@docRoot}resources/tutorials/views/index.html">ビューのセット。ビューには、リスト、グリッド、テキスト ボックス、ボタンだけでなく、埋め込み可能なウェブブラウザも含まれます。
        • コンテンツ プロバイダを使用すると、アプリケーションのデータ(たとえば、連絡先アプリケーション)に、別のアプリケーションからアクセスしたり、データを共有させることができます。
        • リソース マネージャは、ローカライズされた文字列、グラフィックス、レイアウト ファイルなどのコード以外のリソースへのアクセスを提供します。
        • {@link android.app.NotificationManager 通知マネージャ}を使用すると、すべてのアプリケーションからステータス バーにカスタマイズした警告を表示することができます。
        • @@ -47,7 +47,7 @@ page.title=Android とは

        アプリケーションの簡単な説明と詳細については、Notepad チュートリアルをご覧ください。

        +href="{@docRoot}resources/tutorials/notepad/index.html">Notepad チュートリアルをご覧ください。

        ライブラリ

        diff --git a/docs/html/intl/ja/guide/index.jd b/docs/html/intl/ja/guide/index.jd index 73ca18a..5d35e0a 100644 --- a/docs/html/intl/ja/guide/index.jd +++ b/docs/html/intl/ja/guide/index.jd @@ -41,12 +41,12 @@ Android 向けプログラム開発の最初のステップは、SDK(ソフト

        -SDK のダウンロード後は、まずはじめにデベロッパー ガイドを参照してください。コードを実際に見てみることから始めたい場合は、簡単な Hello World チュートリアルを参照してください。Android プラットフォーム向けに作成された標準的な「Hello, World」アプリケーションについて説明しています。アプリケーションの基礎ドキュメントは、アプリケーション フレームワークを理解したいユーザーに最適な出発点となります。 +SDK のダウンロード後は、まずはじめにデベロッパー ガイドを参照してください。コードを実際に見てみることから始めたい場合は、簡単な Hello World チュートリアルを参照してください。Android プラットフォーム向けに作成された標準的な「Hello, World」アプリケーションについて説明しています。アプリケーションの基礎ドキュメントは、アプリケーション フレームワークを理解したいユーザーに最適な出発点となります。

        -不明点などがある場合は、Android ディスカッション グループへの参加をおすすめします。詳しくは上部にある [コミュニティ] タブをご覧ください。 +不明点などがある場合は、Android ディスカッション グループへの参加をおすすめします。詳しくは上部にある [コミュニティ] タブをご覧ください。

        デベロッパー ガイドの別のページに移動してから、このページに戻るには、[デベロッパー ガイド] タブをクリックします。

        \ No newline at end of file diff --git a/docs/html/intl/ja/guide/publishing/app-signing.jd b/docs/html/intl/ja/guide/publishing/app-signing.jd index 23d8cf7..710591d 100644 --- a/docs/html/intl/ja/guide/publishing/app-signing.jd +++ b/docs/html/intl/ja/guide/publishing/app-signing.jd @@ -153,7 +153,7 @@ page.title=アプリケーションへの署名

        次にビルドを行うと、ビルド ツールは新しいキーストアとデバッグ キーを再度生成します。

        -

        開発コンピュータがグレゴリオ暦以外のロケールを使用している場合、ビルド ツールが誤って期限切れのデバッグ証明書を生成することがあります。このため、アプリケーションをコンパイルしようとするとエラーが発生します。解決策については、トラブルシューティング トピックの ビルド ツールが期限切れのデバッグ証明書を生成するため、アプリケーションがコンパイルできない をご覧ください。

        +

        開発コンピュータがグレゴリオ暦以外のロケールを使用している場合、ビルド ツールが誤って期限切れのデバッグ証明書を生成することがあります。このため、アプリケーションをコンパイルしようとするとエラーが発生します。解決策については、トラブルシューティング トピックの ビルド ツールが期限切れのデバッグ証明書を生成するため、アプリケーションがコンパイルできない をご覧ください。

        公開リリースへの署名

        diff --git a/docs/html/intl/ja/resources/community-groups.jd b/docs/html/intl/ja/resources/community-groups.jd new file mode 100644 index 0000000..c99b1f8 --- /dev/null +++ b/docs/html/intl/ja/resources/community-groups.jd @@ -0,0 +1,116 @@ +community=true +page.title=コミュニティ +@jd:body + +
        +

        コミュニティ

        +

        Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されているグループの趣意をお読みください。

        + +

        注: Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、オープンソース プロジェクトのメーリング リスト(英語)を参照してください。

        + +

        目次

        +
          +
        1. 質問を投稿する前に
        2. +
        3. アプリケーション デベロッパー メーリング リスト
        4. +
        5. メーリング リストにメールを使用
        6. +
        7. IRC の使用
        8. +
        + +

        質問を投稿する前に

        +

        投稿を作成する前に、下記をお試しください:

        + +
          +
        1. よくある質問を参照します。Android アプリケーションの開発について非常に一般的な質問が、この一覧に記載されており、頻繁に更新されています。
        2. +
        3. Android のメイン サイトの検索バー(このページの上部にあるのと同じもの)に、調べたいキーワードを入力してください。この検索は、サイト、ドキュメント、ブログに含まれるすべてのコンテンツの他に、すべてのグループで以前行われたすべてのディスカッションを網羅しています。誰か他の人が、以前にも同じ問題に遭遇した可能性は大いにあります。
        4. +
        5. メーリング リストのアーカイブを検索して、同じ質問に関するディスカッションが既に存在しないか調べてください。 +
        6. +
        + +

        質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。 +

          +
        1. コミュニティ ガイドラインが記載されているAndroid メーリングリストの趣意をお読みください。 +
        2. +
        3. 質問に最適なメーリング リストを選択してください。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。
        4. +
        5. + 質問の内容を明確に。明確な質問は、回答者と、将来情報を探そうとする人の双方にとって有益です。
        6. +
        7. 投稿は詳しく書いてください。回答者の人たちが問題を理解するのに役立ちます。コードやログのスニペット、スクリーンショットへのリンクを含めることも有用です。質問をわかりやすく表現するための詳しいガイドラインは、賢い質問のしかた(英語)をご覧ください。 +
        8. +
        + + +

        アプリケーション デベロッパー メーリング リスト

        +
          + +
        • Android SDK Japan - Android SDK に関する質問と答え、提案とフィードバックを交換できる場です。 + +
        • + +
        • Android 初心者向け - Android アプリケーションの開発初心者向けです。Android SDK と基本的な Android API の利用方法について学習したい場合は、このメーリング リストから始めてください。このメーリング リストには、SDK を利用するデベロッパーの初歩的なディスカッションの場所です。Android プラットフォームで初めてアプリケーションを作成して実行する際は、非常に有益な情報を得ることができるでしょう。開発環境のインストール方法についての質問を投稿したり、Android 開発の初歩(初めて作成するユーザー インターフェース、権限、Android ファイルシステムでのファイル、Android マーケットでのアプリケーションなど)について教えてもらうことができます。新たに質問する前に、必ず最初にアーカイブを確認してください。高度な内容の質問の場合はここでは質問せず、android-developers メーリング リストで質問してください。また使用に関する質問は、android-discuss メーリング リストの方が適しています。 + +
        • + +
        • Android デベロッパー向け - Android アプリケーション デベロッパーとして経験を積むにつれ、Android アプリケーション開発の基本を把握して、SDK を使いこなせるようになります。今度は、より高度な内容について質問する必要があります。アプリケーションのトラブルシューティング、実装へのアドバイス、アプリケーションのパフォーマンスやユーザー エクスペリエンスを改良するテクニックに関する質問には、次のメーリング リストが役立ちます。使用に関する問題(android-discuss をご利用ください)や、Android SDK を使用する際の初歩的質問(android-beginners をご利用ください)についてのディスカッションの場所ではありません。 + +
        • + +
        • Android ディスカッション - Android に関する「井戸端会議」です。ここでは、Android プラットフォームへのアイデア、自分のアプリケーションの公表、Android 携帯端末に関するディスカッション、コミュニティ リソースなど、Android に関することなら何でも投稿可能です。ただし他のメーリング リストに該当する内容の場合は、そのメーリング リストに投稿することをおすすめします。質問のテーマが限定されている場所の方が、より多くの回答を得ることができるでしょう。 + +
        • + +
        • Android セキュリティ ディスカッション - 安全な開発、新たに発生したセキュリティの問題、Android デベロッパー向けの Android デベロッパーによるベスト プラクティスについて自由にディスカッションを行える場所です。メーリング リストで脆弱性を直接公開することは、すべての Android ユーザーを危険にさらすことになるので、避けてください。 + +
        • + +
        • Android セキュリティに関する発表 - Android セキュリティ チームがセキュリティ関連の発表を行う、小規模なグループです。 + +
        • + +
        • Android マーケット ヘルプフォーラム - Android マーケットに関する質問や問題の報告をするための、ウェブベースのディスカッション フォーラムです。 + +
        • + +
        + + + +

        メーリング リストにメールを使用

        +

        Google グループ のサイトを使用する代わりに、メール クライアントを使用して、メーリング リストに投稿することも可能です。

        +

        Google グループのサイトを使用せずに、グループに登録するには、上記の「メールで登録」のリンクを使用します。

        +

        メーリング リストへの投稿をメールで受信するように設定する方法は、次のとおりです:

        + +
        1. Google グループ サイトから、グループにログインします。たとえば android-framework グループには http://groups.google.com/group/android-framework?hl=ja にアクセスします。
        2. +
        3. 右側の [メンバーステータスを編集] をクリックします。
        4. +
        5. [このグループの閲覧方法] で、メール オプションのいずれかを選択します。
        6. +
        + +

        IRC の使用

        +

        Android コミュニティは irc.freenode.net サーバーの #android チャンネルを使用しています。 +

        + + + + + + + +
        diff --git a/docs/html/intl/ja/resources/tutorials/hello-world.jd b/docs/html/intl/ja/resources/tutorials/hello-world.jd new file mode 100644 index 0000000..c12965c --- /dev/null +++ b/docs/html/intl/ja/resources/tutorials/hello-world.jd @@ -0,0 +1,375 @@ +page.title=Hello, World +@jd:body + + + +

        デベロッパーにとって、開発フレームワークの第一印象は、どれだけ簡単に「Hello, World」を記述できるかで決まります。Android では、非常に簡単に記述できます。総合開発環境として Eclipse を使用している場合には、開発は特に簡単です。プロジェクトの作成と管理に使用できる便利なプラグインが用意されており、開発サイクルを大幅にスピードアップできるためです。

        + +

        Eclipse を使用していない場合でも問題ありません。Developing in Other IDEsに慣れてから、このチュートリアルに戻り、Eclipse に関する部分以外を参考にしてください。

        + +

        開始する前に、最新の SDK がインストールされている必要があります。また、Eclipse を使用する場合には、ADT プラグインもインストールされている必要があります。これらのプログラムがインストールされていない場合は、「Installing the Android SDK」を参考にインストールを実行して、完了後にこのチュートリアルに戻ってください。

        + +

        AVD の作成

        + + + +

        このチュートリアルでは、開発したアプリケーションを Android エミュレータで実行します。エミュレータを起動するには、事前に Android 仮想デバイス(AVD)を作成する必要があります。AVD は、エミュレータが使用するシステム イメージとデバイスの設定を定義するものです。

        + +

        AVD を作成するには、Android SDK に含まれている「android」ツールを使用します。コマンド プロンプトまたはターミナルを開き、SDK パッケージの中の tools/ ディレクトリに移動して、次のコマンドを実行します。 +

        +android create avd --target 2 --name my_avd
        +
        + +

        カスタム ハードウェア プロファイルを作成するかどうかを尋ねられます。ここではひとまず、リターン キーを押してスキップします(デフォルトの回答は「No」となっています)以上で AVD の作成は終了です。この作業により、Android 1.5 プラットフォームを使用する「my_avd」という名前の AVD が構成されました。これで、AVD をエミュレータで使用できる状態になりました。

        + +

        上記のコマンドで使用した --target オプションは、エミュレータを実行する配備ターゲットを指定するもので、必須オプションです。--name オプションは新規 AVD の名前を定義するもので、これも必須オプションです。

        + + +

        新規 Android プロジェクトを作成する

        + +

        AVD を作成したら、次は Eclipse 内で新規 Android プロジェクトを開始します。

        + +
          +
        1. Eclipse で、[[]ファイル(File)] > [[]新規(New)] > [[]プロジェクト(Project)] を選択します。 +

          ADT Plugin for Eclipse が正常にインストールされていれば、表示されるダイアログに、「Android」というラベルの付いたフォルダと、その中の「Android プロジェクト(Android Project)」が表示されます(1 つまたは複数の Android プロジェクトを作成した後は、「Android XML File」というエントリも表示されるようになります)。

          +
        2. + +
        3. 「Android プロジェクト(Android Project)」を選択して、[[]次へ(Next)] をクリックします。
          +
        4. + +
        5. プロジェクトの詳細項目に以下の値を入力します。 +
            +
          • プロジェクト名(Project name): HelloAndroid
          • +
          • アプリケーション名(Application name): Hello, Android
          • +
          • パッケージ名(Package name): com.example.helloandroid(または自分のプライベート ネームスペース)
          • +
          • アクティビティを作成(Create Activity): HelloAndroid
          • +
          • SDK の最小バージョン(Min SDK Version): 2
          • +
          +

          [[]完了(Finish)] をクリックします。

          + + + +

          各フィールドの説明は以下のとおりです。

          + +
          +
          プロジェクト名(Project Name)
          +
          Eclipse のプロジェクト名。プロジェクト ファイルを格納するディレクトリの名前です。
          +
          アプリケーション名(Application Name)
          +
          アプリケーション名はユーザーにわかりやすいアプリケーションのタイトルにします。この名前が Android 携帯端末に表示されます。
          +
          パッケージ名(Package Name)
          +
          作成したすべてのソース コードを格納するパッケージ ネームスペースです(Java プログラミング言語で作成するパッケージと同じルールに従います)。また、これにより、スタブ Activity が生成されるパッケージの名前も設定されます。 +

          パッケージ名は Android システムにインストールされたすべてのパッケージに共通して固有のものでなければなりません。このため、作成するアプリケーションに標準的なドメイン スタイルのパッケージを使用することが非常に重要です。上記の例では、「com.example」というネームスペースを使用しています。これはサンプル ドキュメント用のネームスペースです。実際にアプリケーションを作成する際には、所属する組織または法人に適切なネームスペースを使用します。

          +
          アクティビティを作成(Create Activity)
          +
          プラグインによって生成されるクラス スタブの名前です。クラス スタブは Android の {@link android.app.Activity} クラスのサブクラスとなります。アクティビティとは単に、実行して何らかの処理を行うことができるクラスを意味します。選択に応じて UI を作成することもできます(ただし必須ではありません)。チェックボックスになっていることからわかるように、これは任意選択の項目です。しかし、実際にはほとんどのアプリケーションでは、アクティビティをアプリケーションの基盤として使用しています。
          +
          SDK の最小バージョン(Min SDK Version)
          +
          作成するアプリケーションが必要とする最小 API レベルを指定する値です。ここに入力した API レベルが、選択可能なターゲットのいずれかで提供される API レベルと一致する場合は、ビルド ターゲットが自動的に選択されます(この例では、API レベルに「2」と入力するとターゲット Android 1.1 が選択されます)。Android システム イメージと Android SDK それぞれの新しいバージョンでは、API に追加または変更が加えられている可能性があります。追加または変更が加えられている場合、新しい API レベルがシステム イメージに割り当てられ、どのアプリケーションの実行を許可するかが規制されます。アプリケーションで必要な API レベルがデバイスでサポートされるレベルよりも高い場合、アプリケーションはインストールされません。
          +
          + +

          その他のフィールド: 「デフォルト ロケーションの使用」チェックボックスでは、プロジェクトのファイルが生成され保存されるディスク上の場所を変更することができます。「ビルド ターゲット」は、作成するアプリケーションがコンパイルされるときにターゲットとするプラットフォームです(この項目は [[]SDK の最小バージョン(Min SDK Version)] の入力値に基づいて自動的に選択されます)。

          + +

          ここで、選択した「ビルド ターゲット」で Android 1.1 プラットフォームが使用されることに注目してください。これは、作成するアプリケーションが Android 1.1 プラットフォーム ライブラリをターゲットとしてコンパイルされることを意味します。先ほど作成した AVD は Android 1.5 プラットフォームで実行されます。バージョンの数字が一致しませんが、Android アプリケーションには上方互換性があるため、1.1 プラットフォーム ライブラリをターゲットとして構築されたアプリケーションでも 1.5 プラットフォームで正常に動作します。ただしその逆の場合は正常に動作しません。

          +
        6. +
        + +

        さて、これで Android プロジェクトを使用できる状態になりました。プロジェクトは左側のパッケージ エクスプローラー(Package Explorer)で表示できます。「HelloAndroid」 > 「src」 > 「com.example.helloandroid」 の中にある HelloAndroid.java ファイルを開きます。ファイルの内容は次のようになっています。

        + +
        +package com.example.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        クラスが {@link android.app.Activity} クラスに基づいていることに注目してください。アクティビティ(Activity)とは、処理を実行するために使用される単体のアプリケーション エンティティです。1 つのアプリケーションにはいくつものアクティビティが含まれる場合がありますが、ユーザーが一度に操作するのは 1 つのアクティビティです。アクティビティが開始すると、Android システムによって {@link android.app.Activity#onCreate(Bundle) onCreate()} メソッドが呼び出されます。このタイミングですべての初期化と UI セットアップを実行します。アクティビティにユーザー インターフェースは必須ではありませんが、通常はユーザー インターフェースを装備します。

        + +

        では、コードを変更してみましょう。

        + + +

        UI を構築する

        + +

        下記の変更済みのコードを参照して、お手元の HelloAndroid クラスに同じ変更を加えてみてください。太字の部分が追加された行です。

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +import android.widget.TextView;
        +
        +public class HelloAndroid extends Activity {
        +   /** Called when the activity is first created. */
        +   @Override
        +   public void onCreate(Bundle savedInstanceState) {
        +       super.onCreate(savedInstanceState);
        +       TextView tv = new TextView(this);
        +       tv.setText("Hello, Android");
        +       setContentView(tv);
        +   }
        +}
        + +

        ヒント: プロジェクトにインポート パッケージを簡単に追加できる方法として、Ctrl+Shift+O(Mac では コマンド+Shift+O)を押す方法があります。これは、コードの記述に基づいて足りないパッケージを特定して追加する Eclipse のショートカット キーです。

        + +

        Android のユーザー インターフェースは、「ビュー(Views)」と呼ばれるオブジェクトの階層で構成されています。{@link android.view.View} は、UI レイアウト内でボタン、画像、または(このサンプルのように)テキスト ラベルといった要素として使用される、描画可能なオブジェクトです。これらのオブジェクトのそれぞれが View クラスのサブクラスであり、テキストを処理するサブクラスは {@link android.widget.TextView} です。

        + +

        この変更では、クラス コンストラクタを使用して TextView を作成します。このクラス コンストラクタは、パラメータとして Android {@link android.content.Context} インスタンスを受け入れます。Context とは、システムへのハンドルであり、リソースの解決、データベースや設定へのアクセスの取得などのサービスを提供します。Activity クラスは Context を継承します。作成する HelloAndroid クラスは、Activity のサブクラスであるため、Context でもあります。したがって、this を Context 参照として TextView に引き渡すことができます。

        + +

        次に、{@link android.widget.TextView setText(CharSequence) setText()} を使用してテキスト コンテンツを定義します。

        + +

        最後に、そのコンテンツが Activity UI のコンテンツとして表示されるように、TextView を {@link android.app.Activity#setContentView(View) setContentView()} に引き渡します。Activity によってこのメソッドが呼び出されなければ、UI は表示されず、空白の画面が表示されます。

        + +

        これで、Android で「Hello, World」が表示されるようになりました。次の手順はもちろん、アプリケーションの実行です。

        + + +

        アプリケーションを実行する

        + +

        Eclipse プラグインでは、非常に簡単にアプリケーションを実行できます。

        + +
          +
        1. [[]実行] > [[]実行] を選択します。
        2. +
        3. 「Android Application」を選択します。
        4. +
        + + + +

        Eclipse ADT によって自動的にプロジェクトの新規起動構成が作成され、Android エミュレータが自動的に起動します。エミュレータが起動した後、少し経つとアプリケーションが表示されます。次のような画面が表示されます。

        + + + +

        グレーのバーに表示されている「Hello, Android」は、アプリケーションのタイトルです。このタイトルは Eclipse プラグインによって自動的に作成されます(文字列は res/values/strings.xml ファイル内で定義され、AndroidManifest.xml によって参照されます)。タイトルの下のテキストは、先ほど TextView オブジェクトで作成した実際のテキストです。

        + +

        これで「Hello World」についての基本的なチュートリアルは終了ですが、この続きもぜひ読んでください。Android アプリケーションの開発に関するさらに有益な情報を紹介しています。

        + + +

        UI を XML レイアウトにアップグレードする

        + +

        先ほど作成した「Hello, World」のサンプルは、「プログラマティック」と呼ばれる UI レイアウトを使用しています。「プログラマティック」とは、アプリケーションの UI を直接ソース コードで作成および構築することを意味します。UI プログラミングの経験が豊富な方であればおそらく、このようなアプローチが時にいかに脆弱になり得るかをよくご存じでしょう。レイアウトの軽微な変更のたびに、ソース コード全体に関わる大きな問題が発生する可能性があるからです。また、複数のビューを適切に結びつけることも忘れられがちであるため、これによりレイアウトにエラーが発生し、コードのデバッグで時間が無駄になる場合があります。

        + +

        その理由から、Android では、XML ベースのレイアウト ファイルを使用する別の UI 構築モデルを用意しています。この概念を簡単に説明するには、サンプルを紹介するのが一番です。ここに示すのは、上記の「プログラマティック」に構築したサンプルと同じように動作する XML レイアウト ファイルです。

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        +  android:layout_width="fill_parent"
        +  android:layout_height="fill_parent"
        +  android:text="@string/hello"/>
        + +

        Android XML レイアウト ファイルの全般的な構造はシンプルです。XML 要素がツリー構造になっており、含まれた各ノードが View クラスの名前を表しています(このサンプルでは View 要素が 1 つのみですが)。XML レイアウト内の要素として、{@link android.view.View} を拡張する任意のクラスの名前を使用できます。これには作成するコードの中で定義するカスタム View クラスも含まれます。この構造により、プログラマティックなレイアウトよりもシンプルな構造と構文を使用して、迅速な UI 構築を非常に簡単に行うことができます。このモデルは、アプリケーションの表示(つまり UI)を、データの取得と入力に使用されるアプリケーション ロジックから切り離すことができる Web 開発モデルからヒントを得て考案されました。

        + +

        上記の XML サンプルには、TextView という View 要素 1 つのみが含まれています。この要素は 4 つの XML 属性を持っています。下表に、これらの 4 つの属性の説明をまとめました。

        + + + + + + + + + + + + + + + + + + + + + + + + +
        + 属性 + + 説明 +
        + xmlns:android + + Android ネームスペースで定義された共通の属性を参照することを Android ツールに伝える XML ネームスペース宣言です。すべての Android レイアウト ファイル内の最初と最後のタグはこの属性を持つ必要があります。
        +
        + android:layout_width + + 該当の View が画面の利用可能な幅のうちどれくらいを占めるかを定義します。このサンプルでは、この View しかないため、「fill_parent」という値を使用して画面全体を占めることにします。
        +
        + android:layout_height + + android:layout_width とよく似た属性で、幅ではなく高さを表します。 +
        + android:text + + TextView が表示するテキストを設定します。このサンプルでは、ハードコード記述された文字列値ではなく文字列リソースを使用します。文字列「hello」は res/values/strings.xml ファイル内で定義されます。アプリケーションに文字列を挿入する場合にはこの方法が推奨されます。レイアウト ファイルのハードコードを直接変更する必要がないため、アプリケーションの他の言語へのローカライズがスムーズに進むからです。詳しくは、「リソースと国際化」を参照してください。 +
        + + +

        これらの XML レイアウト ファイルは、作成するプロジェクトの res/layout/ ディレクトリ内に置かれます。「res」は「resources」の略で、アプリケーションに必要なコード以外のすべてのアセットがこのディレクトリに格納されます。リソースには、レイアウト ファイルの他に、画像、音声、ローカライズされた文字列などのアセットがあります。

        + + + +

        Eclipse プラグインでは、このようなレイアウト ファイルの 1 つである「main.xml」が自動的に作成されます。先ほど「Hello World」アプリケーションを作成した際には、このファイルは無視してプログラマティックにレイアウトを作成しました。この作成方法は Android フレームワークについてより深く理解していただくことを意図したもので、実際にはほとんどの場合レイアウトはコードではなく XML ファイルで定義します。以下の手順では、既存のアプリケーションを変更して XML レイアウトが使用されるようにする方法を説明します。

        + +
          +
        1. Eclipse のパッケージ エクスプローラー(Package Explorer)で、/res/layout/ フォルダを展開し、main.xml を開きます(開いた後、場合によっては XML ソースを見るのにウィンドウ下部にある「main.xml」タブをクリックする必要があります)。ファイルの内容を以下の XML に置き換えます。 + +
          <?xml version="1.0" encoding="utf-8"?>
          +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          +  android:layout_width="fill_parent"
          +  android:layout_height="fill_parent"
          +  android:text="@string/hello"/>
          +

          ファイルを保存します。

          +
        2. + +
        3. res/values/ フォルダ内の strings.xml を開きます。このファイルは、作成するユーザー インターフェースのためのすべてのデフォルトのテキスト文字列を保存するものです。Eclipse を使用している場合、ADT によってあらかじめ helloapp_name という 2 つの文字列が用意された状態になります。hello を何か別の文字列に書き換えてみましょう。たとえば「Hello, Android! I am a string resource!」としてみましょう。変更後のファイルの全体は次のようになります。 +
          +<?xml version="1.0" encoding="utf-8"?>
          +<resources>
          +    <string name="hello">Hello, Android! I am a string resource!</string>
          +    <string name="app_name">Hello, Android</string>
          +</resources>
          +
          +
        4. + +
        5. 次に、HelloAndroid クラスを開いて、XML レイアウトを使用して変更します。ファイルを編集して次のような内容にします。 +
          +package com.example.helloandroid;
          +
          +import android.app.Activity;
          +import android.os.Bundle;
          +
          +public class HelloAndroid extends Activity {
          +    /** Called when the activity is first created. */
          +    @Override
          +    public void onCreate(Bundle savedInstanceState) {
          +        super.onCreate(savedInstanceState);
          +        setContentView(R.layout.main);
          +    }
          +}
          + +

          この変更を行う際に、コードを手入力してコード補完機能を試してみましょう。「R.layout.main」と入力しようとすると、プラグインによって入力候補が表示されます。この機能の便利さは、開発中に何回も実感すると思います。

          + +

          View オブジェクトに setContentView() を引き渡す代わりに、レイアウト リソースへの参照を付与します。リソースは R.layout.main として識別されます。これは、/res/layout/main.xml で定義されたレイアウトを、コンパイルされたオブジェクトで表したものです。Eclipse プラグインでは、この参照がプロジェクトの R.java クラス内に自動的に作成されます。Eclipse を使用していない場合、Ant を実行してアプリケーションのビルドを行う際に R.java クラスが生成されます(R クラスについて詳しくは後ほど説明します)。

          +
        6. +
        + +

        ここで、アプリケーションを再実行します。起動構成は作成済みであるため、ここでは緑色の矢印アイコンをクリックして実行するか、または [[]実行(Run)] > [[]ヒストリーの実行(Run History)] > [[]Android Activity] を選択するだけです。TextView 文字列に加えた変更を除けば、アプリケーションは同じに見えます。ここでポイントとなるのは、2 つの異なるレイアウト編集方法を使用して同じ結果が得られるということです。

        + +

        ヒント: ショートカット キーCtrl+F11(Mac では コマンド+Shift+F11)を使用して、現在表示されているアプリケーションを実行することができます。

        + +

        ここからは、デバッグの基礎知識と、他の総合開発環境に関する補足情報について説明します。さらに詳しく学習したい場合は、「アプリケーションの基礎」を参照してください。Android アプリケーションが動作するためのすべての要素について説明しています。また、「デベロッパー ガイド」の導入ページを参照して、デベロッパー ガイド ドキュメントの概要を確認してください。

        + + +
        +

        R クラス

        +

        Eclipse で、R.java という名前のファイル(gen/(「生成された Java ファイル(Generated Java Files)」フォルダ内)を開きます。ファイルの内容は次のようになっています。

        + +
        +package com.example.helloandroid;
        +
        +public final class R {
        +    public static final class attr {
        +    }
        +    public static final class drawable {
        +        public static final int icon=0x7f020000;
        +    }
        +    public static final class layout {
        +        public static final int main=0x7f030000;
        +    }
        +    public static final class string {
        +        public static final int app_name=0x7f040001;
        +        public static final int hello=0x7f040000;
        +    }
        +}
        +
        + +

        プロジェクトの R.java ファイルは、ファイル内で定義されたすべてのリソースへのインデックスです。ソース コード内では、プロジェクトに含めたすべてのリソースを参照するための簡略形式としてこのクラスを使用します。これは、Eclipse などの総合開発環境のコード補完機能とともに使用すると特に便利です。探している特定の参照をすばやくインタラクティブに見つけることができるからです。

        + +

        お手元のファイルはこれとは若干異なる可能性があります(おそらく 16 進値が異なるためです)。ここでは、「layout」という名前の内部クラスと、そのメンバーであるフィールド「main」に注目します。Eclipse プラグインにより main.xml という名前の XML レイアウト ファイルが認識され、ここにそのためのクラスが生成されたものです。プロジェクトに他のリソース(res/values/string.xml ファイル内の文字列や res/drawable/ ディレクトリ内の描画可能オブジェクトなど)を追加すると、R.java に最新の変更が反映されます。

        +

        Eclipse を使用していない場合は、(Ant ツールを使用した)ビルド時にこのクラス ファイルが生成されます。

        +

        くれぐれもこのファイルを手動で編集しないようにしてください。

        +
        + +

        プロジェクトをデバッグする

        + +

        Android Plugin for Eclipse は、Eclipse のデバッガと優れた連動性を発揮します。このメリットを確認するため、作成したコードにバグを埋め込んでみましょう。作成した HelloAndroid ソース コードを次のように変更します。

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        Object o = null;
        +        o.toString();
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        この変更は、単にコードに NullPointerException を発生させるものです。アプリケーションを再度実行すると、最終的に次のような画面が表示されます。

        + + + +

        「強制終了」を押してアプリケーションを終了し、エミュレータ ウィンドウを閉じます。

        + +

        エラーの詳細を確認するには、ソース コード内の Object o = null; 行にブレークポイントを設定します(該当するソース コード行の横にあるマーカー バーをダブルクリックします)。次に、メニューから [[]実行(Run)] > [[]デバッグ ヒストリー(Debug History)] > [[]Hello, Android] を選択して、デバッグ モードに入ります。エミュレータでアプリケーションが再起動されますが、今度は、先ほど設定したブレークポイントに到達した時点で中断されます。その後 Eclipse のデバッグ パースペクティブ(Debug Perspective)で、他のアプリケーションで通常行うように、コードの内容を確認できます。

        + + + + +

        Eclipse を使用せずにプロジェクトを作成する

        + +

        Eclipse を使用していない場合(普段から使用している総合開発環境がある場合や、シンプルにテキスト エディタやコマンド ライン ツールを使用している場合など)は、Eclipse プラグインを利用することはできません。しかし心配は無用です。Eclipse を使用していないからといって何らかの機能が失われることはありません。

        + +

        Android Plugin for Eclipse は、単に Android SDK に含まれるツール セットをまとめたものに過ぎません(エミュレータ、aapt、adb、ddms などの個別のツールについては、こちらで別途説明しています)。このため、これらのツールを別のツール、たとえば「Ant」のビルド ファイルなどでまとめることも可能です。

        + +

        Android SDK には、「android」という名前のツールが含まれています。このツールを使用すると、作成するプロジェクトのソース コードとディレクトリ スタブすべて、および Ant と互換性のある build.xml ファイルを作成することができます。これにより、プロジェクトをコマンド ラインで作成したり、普段使用している総合開発環境と統合したりすることができます。

        + +

        たとえば、Eclipse で作成されるものと同様の HelloAndroid プロジェクトを作成するには、次のコマンドを使用します。

        + +
        +android create project \
        +    --package com.android.helloandroid \
        +    --activity HelloAndroid \ 
        +    --target 2 \
        +    --path <path-to-your-project>/HelloAndroid 
        +
        + +

        これにより、path で定義された場所に、プロジェクトに必要なフォルダとファイルが作成されます。

        + +

        SDK ツールを使用してプロジェクトを作成および構築する方法について詳しくは、「Developing in Other IDEs」を参照してください。

        diff --git a/docs/html/intl/ja/sdk/1.5_r2/installing.jd b/docs/html/intl/ja/sdk/1.5_r2/installing.jd index a587b1a..789fc26 100644 --- a/docs/html/intl/ja/sdk/1.5_r2/installing.jd +++ b/docs/html/intl/ja/sdk/1.5_r2/installing.jd @@ -130,7 +130,7 @@ page.title=Android SDK のインストール

        その他のインストール エラー

        -

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        +

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        Linux ユーザーの場合

        Eclipse 用 ADT プラグインのインストール時に、次のエラーが発生する場合があります。 @@ -166,15 +166,15 @@ JKS

      3. サンプル コードの参照

          -
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • -
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • +
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • +
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • <sdk>/platforms/<platfrom>/samples に収められている他のサンプル アプリケーションのいずれかを新しいプロジェクトとして作成し、自分の開発環境でコンパイルし、実行します。

        Android デベロッパー グループへのアクセス

        • [コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        • + href="{@docRoot}resources/community-groups.html">コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        diff --git a/docs/html/intl/ja/sdk/1.5_r3/installing.jd b/docs/html/intl/ja/sdk/1.5_r3/installing.jd index a587b1a..789fc26 100644 --- a/docs/html/intl/ja/sdk/1.5_r3/installing.jd +++ b/docs/html/intl/ja/sdk/1.5_r3/installing.jd @@ -130,7 +130,7 @@ page.title=Android SDK のインストール

        その他のインストール エラー

        -

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        +

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        Linux ユーザーの場合

        Eclipse 用 ADT プラグインのインストール時に、次のエラーが発生する場合があります。 @@ -166,15 +166,15 @@ JKS

        サンプル コードの参照

          -
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • -
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • +
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • +
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • <sdk>/platforms/<platfrom>/samples に収められている他のサンプル アプリケーションのいずれかを新しいプロジェクトとして作成し、自分の開発環境でコンパイルし、実行します。

        Android デベロッパー グループへのアクセス

        • [コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        • + href="{@docRoot}resources/community-groups.html">コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        diff --git a/docs/html/resources/articles/avoiding-memory-leaks.jd b/docs/html/resources/articles/avoiding-memory-leaks.jd new file mode 100644 index 0000000..3361bc1 --- /dev/null +++ b/docs/html/resources/articles/avoiding-memory-leaks.jd @@ -0,0 +1,109 @@ +page.title=Avoiding Memory Leaks +@jd:body + + +

        Android applications are, at least on the T-Mobile G1, limited +to 16 MB of heap. It's both a lot of memory for a phone and yet very +little for what some developers want to achieve. Even if you do not +plan on using all of this memory, you should use as little as possible +to let other applications run without getting them killed. The more +applications Android can keep in memory, the faster it will be for the +user to switch between his apps. As part of my job, I ran into memory +leaks issues in Android applications and they are most of the time due +to the same mistake: keeping a long-lived reference to a +{@link android.content.Context Context}.

        + +

        On Android, a Context is used for many operations + but mostly to load and access resources. This is why all the widgets +receive a Context parameter in their constructor. In a +regular Android application, you usually have two kinds of +Context, {@link android.app.Activity} and +{@link android.app.Application}. It's usually the first one that +the developer passes to classes and methods that need a Context:

        + +
        @Override
        +protected void onCreate(Bundle state) {
        +  super.onCreate(state);
        +  
        +  TextView label = new TextView(this);
        +  label.setText("Leaks are bad");
        +  
        +  setContentView(label);
        +}
        +
        + +

        This means that views have a reference to the entire activity and +therefore to anything your activity is holding onto; usually the entire +View hierarchy and all its resources. Therefore, if you leak the Context +("leak" meaning you keep a reference to it thus preventing the GC from +collecting it), you leak a lot of memory. Leaking an entire activity +can be really easy if you're not careful.

        + +

        When the screen orientation changes the system will, by default, +destroy the current activity and create a new one while preserving its +state. In doing so, Android will reload the application's UI from the +resources. Now imagine you wrote an application with a large bitmap +that you don't want to load on every rotation. The easiest way to keep +it around and not having to reload it on every rotation is to keep in a +static field:

        + +
        private static Drawable sBackground;
        +  
        +@Override
        +protected void onCreate(Bundle state) {
        +  super.onCreate(state);
        +  
        +  TextView label = new TextView(this);
        +  label.setText("Leaks are bad");
        +  
        +  if (sBackground == null) {
        +    sBackground = getDrawable(R.drawable.large_bitmap);
        +  }
        +  label.setBackgroundDrawable(sBackground);
        +  
        +  setContentView(label);
        +}
        +
        + +

        This code is very fast and also very wrong; it leaks the first activity +created upon the first screen orientation change. When a +{@link android.graphics.drawable.Drawable Drawable} is attached to a view, the view is set as a +{@link android.graphics.drawable.Drawable#setCallback(android.graphics.drawable.Drawable.Callback) callback} +on the drawable. In the code snippet above, this means the drawable has a +reference to the TextView which itself has a reference to the +activity (the Context) which in turns has references to +pretty much anything (depending on your code.)

        + +

        This example is one of the simplest cases of leaking the +Context and you can see how we worked around it in the +Home screen's source code +(look for the unbindDrawables() method) by setting the stored +drawables' callbacks to null when the activity is destroyed. Interestingly +enough, there are cases where you can create a chain of leaked contexts, +and they are bad. They make you run out of memory rather quickly.

        + +

        There are two easy ways to avoid context-related memory leaks. The most +obvious one is to avoid escaping the context outside of its own scope. The +example above showed the case of a static reference but inner classes and +their implicit reference to the outer class can be equally dangerous. The +second solution is to use the Application context. This +context will live as long as your application is alive and does not depend +on the activities life cycle. If you plan on keeping long-lived objects +that need a context, remember the application object. You can obtain it +easily by calling +{@link android.content.Context#getApplicationContext() Context.getApplicationContext()} +or {@link android.app.Activity#getApplication() Activity.getApplication()}.

        + +

        In summary, to avoid context-related memory leaks, remember the following:

        +
          +
        • Do not keep long-lived references to a context-activity (a reference +to an activity should have the same life cycle as the activity itself)
        • +
        • Try using the context-application instead of a context-activity
        • +
        • Avoid non-static inner classes in an activity if you don't control +their life cycle, use a static inner class and make a weak reference to +the activity inside. The solution to this issue is to use a static inner +class with a {@link java.lang.ref.WeakReference WeakReference} to the +outer class, as done in ViewRoot +and its W inner class for instance
        • +
        • A garbage collector is not an insurance against memory leaks
        • +
        diff --git a/docs/html/resources/articles/backward-compatibility.jd b/docs/html/resources/articles/backward-compatibility.jd new file mode 100644 index 0000000..9f0ddf5 --- /dev/null +++ b/docs/html/resources/articles/backward-compatibility.jd @@ -0,0 +1,238 @@ +page.title=Backward Compatibility for Applications +@jd:body + +

        A variety of Android-powered devices are now available to consumers from carriers +in geographies around the world. Across those devices, a range of Android +platform versions are in use, some running the latest version of the platform, +others running older versions. As a developer, you need to consider the approach +to backward compatibility that you will take in your application — do you +want to allow your application to run on all devices, or just those running the +latest software? In some cases it will be useful to employ the newer APIs on +devices that support them, while continuing to support older devices.

        + +

        Setting the minSdkVersion

        +

        If the use of a new API is integral to the application — perhaps you +need to record video using an API introduced in Android 1.5 (API Level 3) +— you should add a <android:minSdkVersion> + to the application's manifest, to ensure your app won't +be installed on older devices. For example, if your application depends on an +API introduced in API Level 3, you would specify "3" as the value of the minimum +SDK version:

        + +
          <manifest>
        +   ...
        +   <uses-sdk android:minSdkVersion="3" />
        +   ...
        +  </manifest>
        + +

        However, if you want to add a useful but non-essential feature, such as +popping up an on-screen keyboard even when a hardware keyboard is available, you +can write your program in a way that allows it to use the newer features without +failing on older devices.

        + +

        Using reflection

        + +

        Suppose there's a simple new call you want to use, like {@link +android.os.Debug#dumpHprofData(java.lang.String) +android.os.Debug.dumpHprofData(String filename)}. The {@link android.os.Debug} +class has existed since Android 1.0, but the method is new in Anroid 1.5 (API +Level 3). If you try to call it directly, your app will fail to run on devices +running Android 1.1 or earlier.

        + +

        The simplest way to call the method is through reflection. This requires +doing a one-time lookup and caching the result in a Method object. +Using the method is a matter of calling Method.invoke and un-boxing +the result. Consider the following:

        + +
        public class Reflect {
        +   private static Method mDebug_dumpHprofData;
        +
        +   static {
        +       initCompatibility();
        +   };
        +
        +   private static void initCompatibility() {
        +       try {
        +           mDebug_dumpHprofData = Debug.class.getMethod(
        +                   "dumpHprofData", new Class[] { String.class } );
        +           /* success, this is a newer device */
        +       } catch (NoSuchMethodException nsme) {
        +           /* failure, must be older device */
        +       }
        +   }
        +
        +   private static void dumpHprofData(String fileName) throws IOException {
        +       try {
        +           mDebug_dumpHprofData.invoke(null, fileName);
        +       } catch (InvocationTargetException ite) {
        +           /* unpack original exception when possible */
        +           Throwable cause = ite.getCause();
        +           if (cause instanceof IOException) {
        +               throw (IOException) cause;
        +           } else if (cause instanceof RuntimeException) {
        +               throw (RuntimeException) cause;
        +           } else if (cause instanceof Error) {
        +               throw (Error) cause;
        +           } else {
        +               /* unexpected checked exception; wrap and re-throw */
        +               throw new RuntimeException(ite);
        +           }
        +       } catch (IllegalAccessException ie) {
        +           System.err.println("unexpected " + ie);
        +       }
        +   }
        +
        +   public void fiddle() {
        +       if (mDebug_dumpHprofData != null) {
        +           /* feature is supported */
        +           try {
        +               dumpHprofData("/sdcard/dump.hprof");
        +           } catch (IOException ie) {
        +               System.err.println("dump failed!");
        +           }
        +       } else {
        +           /* feature not supported, do something else */
        +           System.out.println("dump not supported");
        +       }
        +   }
        +}
        + +

        This uses a static initializer to call initCompatibility, +which does the method lookup. If that succeeds, it uses a private +method with the same semantics as the original (arguments, return +value, checked exceptions) to do the call. The return value (if it had +one) and exception are unpacked and returned in a way that mimics the +original. The fiddle method demonstrates how the +application logic would choose to call the new API or do something +different based on the presence of the new method.

        + +

        For each additional method you want to call, you would add an additional +private Method field, field initializer, and call wrapper to the +class.

        + +

        This approach becomes a bit more complex when the method is declared in a +previously undefined class. It's also much slower to call +Method.invoke() than it is to call the method directly. These +issues can be mitigated by using a wrapper class.

        + +

        Using a wrapper class

        + +

        The idea is to create a class that wraps all of the new APIs exposed by a new +or existing class. Each method in the wrapper class just calls through to the +corresponding real method and returns the same result.

        + +

        If the target class and method exist, you get the same behavior you would get +by calling the class directly, with a small amount of overhead from the +additional method call. If the target class or method doesn't exist, the +initialization of the wrapper class fails, and your application knows that it +should avoid using the newer calls.

        + +

        Suppose this new class were added:

        public class NewClass {
        +   private static int mDiv = 1;
        +
        +   private int mMult;
        +
        +   public static void setGlobalDiv(int div) {
        +       mDiv = div;
        +   }
        +
        +   public NewClass(int mult) {
        +       mMult = mult;
        +   }
        +
        +   public int doStuff(int val) {
        +       return (val * mMult) / mDiv;
        +   }
        +}
        + +

        We would create a wrapper class for it:

        + +
        class WrapNewClass {
        +   private NewClass mInstance;
        +
        +   /* class initialization fails when this throws an exception */
        +   static {
        +       try {
        +           Class.forName("NewClass");
        +       } catch (Exception ex) {
        +           throw new RuntimeException(ex);
        +       }
        +   }
        +
        +   /* calling here forces class initialization */
        +   public static void checkAvailable() {}
        +
        +   public static void setGlobalDiv(int div) {
        +       NewClass.setGlobalDiv(div);
        +   }
        +
        +   public WrapNewClass(int mult) {
        +       mInstance = new NewClass(mult);
        +   }
        +
        +   public int doStuff(int val) {
        +       return mInstance.doStuff(val);
        +   }
        +}
        + +

        This has one method for each constructor and method in the original, plus a +static initializer that tests for the presence of the new class. If the new +class isn't available, initialization of WrapNewClass fails, +ensuring that the wrapper class can't be used inadvertently. The +checkAvailable method is used as a simple way to force class +initialization. We use it like this:

        + +
        public class MyApp {
        +   private static boolean mNewClassAvailable;
        +
        +   /* establish whether the "new" class is available to us */
        +   static {
        +       try {
        +           WrapNewClass.checkAvailable();
        +           mNewClassAvailable = true;
        +       } catch (Throwable t) {
        +           mNewClassAvailable = false;
        +       }
        +   }
        +
        +   public void diddle() {
        +       if (mNewClassAvailable) {
        +           WrapNewClass.setGlobalDiv(4);
        +           WrapNewClass wnc = new WrapNewClass(40);
        +           System.out.println("newer API is available - " + wnc.doStuff(10));
        +       } else {
        +           System.out.println("newer API not available");
        +       }
        +   }
        +}
        + +

        If the call to checkAvailable succeeds, we know the new class is +part of the system. If it fails, we know the class isn't there, and adjust our +expectations accordingly. It should be noted that the call to +checkAvailable will fail before it even starts if the bytecode +verifier decides that it doesn't want to accept a class that has references to a +nonexistent class. The way this code is structured, the end result is the same +whether the exception comes from the verifier or from the call to +Class.forName.

        + +

        When wrapping an existing class that now has new methods, you only need to +put the new methods in the wrapper class. Invoke the old methods directly. The +static initializer in WrapNewClass would be augmented to do a +one-time check with reflection.

        + +

        Testing is key

        + +

        You must test your application on every version of the Android framework that +is expected to support it. By definition, the behavior of your application will +be different on each. Remember the mantra: if you haven't tried it, it doesn't +work.

        + +

        You can test for backward compatibility by running your application in an +emulator that uses an older version of the platform. The Android SDK allows you +to do this easily by creating "Android Virtual Devices" with different API +levels. Once you create the AVDs, you can test your application with old and new +versions of the system, perhaps running them side-by-side to see the +differences. More information about emulator AVDs can be found in the AVD documentation and +from emulator -help-virtual-device.

        \ No newline at end of file diff --git a/docs/html/resources/articles/can-i-use-this-intent.jd b/docs/html/resources/articles/can-i-use-this-intent.jd new file mode 100644 index 0000000..a726189 --- /dev/null +++ b/docs/html/resources/articles/can-i-use-this-intent.jd @@ -0,0 +1,69 @@ +page.title=Can I Use this Intent? +@jd:body + +

        Android offers a very powerful and yet easy-to-use message type called +an intents. +You can use intents to turn applications into high-level libraries and +make code modular and reusable. The Android Home screen and AnyCut +applications, for instance, use intents extensively to create shortcuts.

        + +

        While it is nice to be able to make use of a loosely coupled +API, there is no guarantee that the intent you send will be received by +another application. This happens in particular with third-party apps, like +Panoramio +and its RADAR intent.

        + +

        This article describes a technique you can use to find out whether the system +contains any application capable of responding to the intent you want to use. +The example below shows a helper method that queries the system package manager +to determine whether there's an app that can respond to a specified intent. Your +application can pass an intent to the method and then, for example, show or hide +user options that the user would normally use to trigger the intent.

        + +
        /**
        + * Indicates whether the specified action can be used as an intent. This
        + * method queries the package manager for installed packages that can
        + * respond to an intent with the specified action. If no suitable package is
        + * found, this method returns false.
        + *
        + * @param context The application's environment.
        + * @param action The Intent action to check for availability.
        + *
        + * @return True if an Intent with the specified action can be sent and
        + *         responded to, false otherwise.
        + */
        +public static boolean isIntentAvailable(Context context, String action) {
        +    final PackageManager packageManager = context.getPackageManager();
        +    final Intent intent = new Intent(action);
        +    List<ResolveInfo> list =
        +            packageManager.queryIntentActivities(intent,
        +                    PackageManager.MATCH_DEFAULT_ONLY);
        +    return list.size() > 0;
        +}
        +
        + +

        Here is how you could use the helper method:

        + +
        @Override
        +public boolean onPrepareOptionsMenu(Menu menu) {
        +    final boolean scanAvailable = isIntentAvailable(this,
        +        "com.google.zxing.client.android.SCAN");
        +
        +    MenuItem item;
        +    item = menu.findItem(R.id.menu_item_add);
        +    item.setEnabled(scanAvailable);
        +
        +    return super.onPrepareOptionsMenu(menu);
        +}
        +
        + +

        In this example, the menu is grayed out if the Barcode Scanner +application is not installed.

        + +

        Another, simpler, way to do this is to catch the +ActivityNotFoundException when calling startActivity() +but it only lets you react to the problem, you cannot predict it and update the +UI accordingly to prevent the user from doing something that won't work. The +technique described here can also be used at startup time to ask the user +whether he'd like to install the missing package, you can then simply redirect +him to the Android Market by using the appropriate URI.

        \ No newline at end of file diff --git a/docs/html/resources/articles/creating-input-method.jd b/docs/html/resources/articles/creating-input-method.jd new file mode 100644 index 0000000..5a92970 --- /dev/null +++ b/docs/html/resources/articles/creating-input-method.jd @@ -0,0 +1,235 @@ +page.title=Creating an Input Method +@jd:body + + +

        To create an input method (IME) for entering text into text fields +and other Views, you need to extend the {@link android.inputmethodservice.InputMethodService}. +class. This class provides much of the basic implementation for an input +method, in terms of managing the state and visibility of the input method and +communicating with the currently visible activity.

        + +

        A good starting point would be the SoftKeyboard sample code provided as part +of the SDK. You can modify the sample code to start building your own input +method.

        + +

        An input method is packaged like any other application or service. In the +AndroidManifest.xml file, you declare the input method as a +service, with the appropriate intent filter and any associated meta data:

        + +
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        +        package="com.example.fastinput">
        +
        +    <application android:label="@string/app_label">
        + <!-- Declares the input method service --> + <service android:name="FastInputIME" + android:label="@string/fast_input_label" + android:permission="android.permission.BIND_INPUT_METHOD"> + <intent-filter> + <action android:name="android.view.InputMethod" /> + </intent-filter> + <meta-data android:name="android.view.im" android:resource="@xml/method" /> + </service> + + <!-- Optional activities. A good idea to have some user settings. --> + <activity android:name="FastInputIMESettings" android:label="@string/fast_input_settings"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + </intent-filter> + </activity> + </application> +</manifest>
        + +

        If your input method allows the user to tweak some settings, you should +provide a settings activity that can be launched from the Settings application. +This is optional and you may choose to provide all user settings directly in +your IME's UI.

        + +

        The typical life-cycle of an InputMethodService looks like +this:

        + +

        + +

        Visual Elements

        + +

        There are two main visual elements for an input method—the input view and the +candidates view. You don't have to follow this style though, if one of them is +not relevant to your input method experience.

        + +

        Input View

        + +

        This is where the user can input text either in the form of keypresses, +handwriting or other gestures. When the input method is displayed for the first +time, InputMethodService.onCreateInputView() will be called. Create +and return the view hierarchy that you would like to display in the input method +window.

        + +

        Candidates View

        + +

        This is where potential word corrections or completions are presented to the +user for selection. Again, this may or may not be relevant to your input method +and you can return null from calls to +InputMethodService.onCreateCandidatesView(), which is the default +behavior.

        + +

        Designing for the different Input Types

        + +

        An application's text fields can have different input types specified on +them, such as free form text, numeric, URL, email address and search. When you +implement a new input method, you need to be aware of the different input types. +Input methods are not automatically switched for different input types and so +you need to support all types in your IME. However, the IME is not responsible +for validating the input sent to the application. That's the responsibility of +the application.

        + +

        For example, the LatinIME provided with the Android platform provides +different layouts for text and phone number entry:

        + +

        + +

        InputMethodService.onStartInputView() is called with an +EditorInfo object that contains details about the input type and other +attributes of the application's text field.

        (EditorInfo.inputType +& EditorInfo.TYPE_CLASS_MASK) can be one of many different values, +including:

        + +
          +
        • TYPE_CLASS_NUMBER
        • +
        • TYPE_CLASS_DATETIME
        • +
        • TYPE_CLASS_PHONE
        • +
        • TYPE_CLASS_TEXT
        • +
        + +

        See android.text.InputType for more details.

        + +

        EditorInfo.inputType can contain other masked bits that +indicate the class variation and other flags. For example, +TYPE_TEXT_VARIATION_PASSWORD or TYPE_TEXT_VARIATION_URI +or TYPE_TEXT_FLAG_AUTO_COMPLETE.

        + +

        Password fields

        + +

        Pay +specific attention when sending text to password fields. Make sure that +the password is not visible within your UI — neither in the input +view or the candidates view. Also, do not save the password anywhere without +explicitly informing the user.

        + +

        Landscape vs. portrait

        + +

        The UI needs to be able to scale between landscape and portrait orientations. +In non-fullscreen IME mode, leave sufficient space for the application to show +the text field and any associated context. Preferably, no more than half the +screen should be occupied by the IME. In fullscreen IME mode this is not an +issue.

        + +

        Sending text to the application

        + +

        There are two ways to send text to the application. You can either send +individual key events or you can edit the text around the cursor in the +application's text field.

        + +

        To send a key event, you can simply construct KeyEvent objects and call +InputConnection.sendKeyEvent(). Here are some examples:

        + +
        InputConnection ic = getCurrentInputConnection();
        +long eventTime = SystemClock.uptimeMillis();
        +ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
        +    KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
        +    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
        +ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
        +    KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
        +    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
        + +

        Or use the convenience method:

        + +
        InputMethodService.sendDownUpKeyEvents(keyEventCode);
        + +

        Note: +It is recommended to use the above method for certain fields such as +phone number fields because of filters that may be applied to the text +after each key press. Return key and delete key should also be sent as +raw key events for certain input types, as applications may be watching +for specific key events in order to perform an action.

        + +

        When editing text in a text field, some of the more useful methods on +android.view.inputmethod.InputConnection are:

        + +
          +
        • getTextBeforeCursor()
        • +
        • getTextAfterCursor()
        • +
        • deleteSurroundingText()
        • +
        • commitText()
        • +
        + +

        For example, let's say the text "Fell" is to the left of the cursor +and you want to replace it with "Hello!":

        + +
        InputConnection ic = getCurrentInputConnection();
        +ic.deleteSurroundingText(4, 0);
        +ic.commitText("Hello", 1);
        +ic.commitText("!", 1);
        + +

        Composing text before committing

        + +

        If your input method does some kind of text prediction or requires multiple +steps to compose a word or glyph, you can show the progress in the text field +until the user commits the word and then you can replace the partial composition +with the completed text. The text that is being composed will be highlighted in +the text field in some fashion, such as an underline.

        + +
        InputConnection ic = getCurrentInputConnection();
        +ic.setComposingText("Composi", 1);
        +...
        +ic.setComposingText("Composin", 1);
        +...
        +ic.commitText("Composing ", 1);
        + +

        + +

        + +

        Intercepting hard key events

        + +

        Even though the input method window doesn't have explicit focus, it receives +hard key events first and can choose to consume them or forward them along to +the application. For instance, you may want to consume the directional keys to +navigate within your UI for candidate selection during composition. Or you may +want to trap the back key to dismiss any popups originating from the input +method window. To intercept hard keys, override +InputMethodService.onKeyDown() and +InputMethodService.onKeyUp(). Remember to call +super.onKey* if you don't want to consume a certain key +yourself.

        + +

        Other considerations

        + +
          +
        • Provide a way for the user to easily bring up any associated settings +directly from the input method UI
        • +
        • Provide +a way for the user to switch to a different input method (multiple +input methods may be installed) directly from the input method UI.
        • +
        • Bring +up the UI quickly - preload or lazy-load any large resources so that +the user sees the input method quickly on tapping on a text field. And +cache any resources and views for subsequent invocations of the input +method.
        • +
        • On the flip side, any large memory allocations should +be released soon after the input method window is hidden so that +applications can have sufficient memory to run. Consider using a +delayed message to release resources if the input method is in a hidden +state for a few seconds.
        • +
        • Make sure that most common characters +can be entered using the input method, as users may use punctuation in +passwords or user names and they shouldn't be stuck in a situation +where they can't enter a certain character in order to gain access into +a password-locked device.
        • +
        + +

        Samples

        + +

        For a real world example, with support for multiple input types and text +prediction, see the LatinIME source code. The +Android SDK also includes a SoftKeyboard sample as well.

        diff --git a/docs/html/resources/articles/drawable-mutations.jd b/docs/html/resources/articles/drawable-mutations.jd new file mode 100644 index 0000000..f979829 --- /dev/null +++ b/docs/html/resources/articles/drawable-mutations.jd @@ -0,0 +1,91 @@ +page.title=Drawable Mutations +@jd:body + +

        Android's drawables are extremely useful to easily build applications. A +{@link android.graphics.drawable.Drawable Drawable} is a pluggable drawing +container that is usually associated with a View. For instance, a +{@link android.graphics.drawable.BitmapDrawable BitmapDrawable} is used to display +images, a {@link android.graphics.drawable.ShapeDrawable ShapeDrawable} to draw +shapes and gradients, and so on. You can even combine them to create complex +renderings.

        + +

        Drawables allow you to easily customize the rendering of the widgets without +subclassing them. As a matter of fact, they are so convenient that most of the +default Android apps and widgets are built using drawables; there are about 700 +drawables used in the core Android framework. Because drawables are used so +extensively throughout the system, Android optimizes them when they are loaded +from resources. For instance, every time you create a +{@link android.widget.Button Button}, a new drawable is loaded from the framework +resources (android.R.drawable.btn_default). This means all buttons +across all the apps use a different drawable instance as their background. +However, all these drawables share a common state, called the "constant state." +The content of this state varies according to the type of drawable you are +using, but it usually contains all the properties that can be defined by a +resource. In the case of a button, the constant state contains a bitmap image. +This way, all buttons across all applications share the same bitmap, which saves +a lot of memory.

        + +

        The following diagram shows what entities are +created when you assign the same image resource as the background of +two different views. As you can see, two drawables are created but they +both share the same constant state, hence the same bitmap:

        + + + +

        This state sharing feature is great to avoid wasting memory but it can cause +problems when you try to modify the properties of a drawable. Imagine an +application with a list of books. Each book has a star next to its name, totally +opaque when the user marks the book as a favorite, and translucent when the book +is not a favorite. To achieve this effect, you would probably write the +following code in your list adapter's getView() method:

        + +
        Book book = ...;
        +TextView listItem = ...;
        +
        +listItem.setText(book.getTitle());
        +
        +Drawable star = context.getResources().getDrawable(R.drawable.star);
        +if (book.isFavorite()) {
        +  star.setAlpha(255); // opaque
        +} else {
        +  star.setAlpha(70); // translucent
        +}
        + +

        Unfortunately, this piece of code yields a rather strange result: +all of the drawables have the same opacity:

        + + + +

        This +result is explained by the constant state. Even though we are getting a +new drawable instance for each list item, the constant state remains +the same and, in the case of BitmapDrawable, the opacity is part of the +constant state. Thus, changing the opacity of one drawable instance +changes the opacity of all the other instances. Even worse, working +around this issue was not easy with Android 1.0 and 1.1.

        + +

        Android 1.5 and higher offers a very easy way to solve this issue +with the new {@link android.graphics.drawable.Drawable#mutate()} method. +When you invoke this method on a drawable, the constant state of the +drawable is duplicated to allow you to change any property without +affecting other drawables. Note that bitmaps are still shared, even +after mutating a drawable. The diagram below shows what happens when +you invoke mutate() on a drawable:

        + + + +

        Let's update our previous piece of code to make use of mutate():

        + +
        Drawable star = context.getResources().getDrawable(R.drawable.star);
        +if (book.isFavorite()) {
        +  star.mutate().setAlpha(255); // opaque
        +} else {
        +  star. mutate().setAlpha(70); // translucent
        +}
        + +

        For convenience, mutate() +returns the drawable itself, which allows to chain method calls. It +does not however create a new drawable instance. With this new piece of +code, our application now behaves correctly:

        + + diff --git a/docs/html/resources/articles/faster-screen-orientation-change.jd b/docs/html/resources/articles/faster-screen-orientation-change.jd new file mode 100644 index 0000000..c500035 --- /dev/null +++ b/docs/html/resources/articles/faster-screen-orientation-change.jd @@ -0,0 +1,115 @@ +page.title=Faster Screen Orientation Change +@jd:body + +

        Android is designed to run efficiently on a wide +array of devices, with very different hardware configurations. Some +devices, like the T-Mobile G1, can change their hardware configuration +at runtime. For instance, when you open the keyboard, the screen change +from the portrait orientation to the landscape orientation. + +

        + +

        To make +Android app development easier, the Android system automatically handles +configuration change events and restarts the current activity with the new +configuration. This is the default behavior that lets you declare +resources like layouts and drawables based on the orientation, screen +size, locale, etc.

        + +

        While this behavior is really powerful, since your application adapts +automatically to the device's configuration at runtime, it is sometimes +confusing for new Android developers, who wonder why their activity is +destroyed and recreated.

        + +

        Facing this "issue," some developers choose to handle configuration changes +themselves which is, in general, a short-term solution that will only complicate +their lives later. On the other hand, the system's automatic resource handling +is a very efficient and easy way to adapt an application's user interface to +various devices and devices configurations. It sometimes comes at a price, +though.

        + +

        When your application displays a lot of data, or data that is expensive to fetch, +the automatic destruction/creation of the activities can be lead to a +painful user experience. Take the example of Photostream, +a simple Flickr browsing application. After you launch the application and choose a Flickr account, the +application downloads a set of 6 photos (on a T-Mobile G1) from the +Flickr servers and displays them on screen. To improve the user +experience, the application uses slightly different layouts and drawables in +portrait and landscape modes and this is what the result looks like:

        + +

        + +

        + +

        Photostream lets Android take care of the configuration change when the +screen is rotated. However, can you imagine how painful it would be for the user +to see all the images being downloaded again? The obvious solution to this +problem is to temporarily cache the images. They could be cached on the SD card +(if there's one), in the Application object, in a static field, etc. None of +these techniques is adapted to the current situation: why should we bother +caching the images when the screen is not rotated? Fortunately for us, Android +offers a great API exactly for that purpose.

        + +

        The Activity class has a special method called +{@link android.app.Activity#onRetainNonConfigurationInstance()}. This method +can be used to pass an arbitrary object your future self and Android +is smart enough to call this method only when needed. In the case of Photostream, +the application used this method +to pass the downloaded images to the future activity on orientation change. +The implementation can be summarized like so:

        + +
        @Override
        +public Object onRetainNonConfigurationInstance() {
        +    final LoadedPhoto[] list = new LoadedPhoto[numberOfPhotos];
        +    keepPhotos(list);
        +    return list;
        +}
        +
        + +

        In the new activity, in onCreate(), all you have to do to +get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}. +In Photostream, this method is invoked +and if the returned value is not null, the grid is loaded with the list of +photos from the previous activity:

        + +
        private void loadPhotos() {
        +    final Object data = getLastNonConfigurationInstance();
        +    
        +    // The activity is starting for the first time, load the photos from Flickr
        +    if (data == null) {
        +        mTask = new GetPhotoListTask().execute(mCurrentPage);
        +    } else {
        +        // The activity was destroyed/created automatically, populate the grid
        +        // of photos with the images loaded by the previous activity
        +        final LoadedPhoto[] photos = (LoadedPhoto[]) data;
        +        for (LoadedPhoto photo : photos) {
        +            addPhoto(photo);
        +        }
        +    }
        +}
        +
        + +

        Be very careful with the object you pass through +onRetainNonConfigurationChange(), though. If the object you +pass is for some reason tied to the Activity/Context, you will leak +all the views and resources of the activity. This means you should +never pass a View, a Drawable, an Adapter, etc. Photostream for +instance extracts the bitmaps from the drawables and pass the bitmaps +only, not the drawables. Finally, remember that +onRetainNonConfigurationChange() should be used only to retain +data that is expensive to load. Otherwise, keep it simple and let Android +do everything.

        diff --git a/docs/html/resources/articles/future-proofing.jd b/docs/html/resources/articles/future-proofing.jd new file mode 100644 index 0000000..ee98186 --- /dev/null +++ b/docs/html/resources/articles/future-proofing.jd @@ -0,0 +1,89 @@ +page.title=Future-Proofing Your Apps +@jd:body + +

        It's important to implement your application so that it will not break as new +versions of the Android platform are loaded onto the users device. The list +below is based on our observations of five ways that we've seen bad apps fail. +You can think of these as "anti-patterns" (that is, techniques to avoid) for +Android development.

        + +

        If your application uses any of the dubious techniques below, break out +your IDE and duct tape, spackle, and patch up the app.

        + +

        Technique to Avoid, #1: Using Internal APIs

        + +

        Even +though we've always strongly advised against doing so, some developers +have chosen to use unsupported or internal APIs. For instance, many +developers are using the internal brightness control and bluetooth +toggle APIs that were present in 1.0 and 1.1. A bug -- which was +fixed in Android 1.5 -- allowed apps to use those APIs without +requesting permission. As a result, apps that used those APIs broke +on 1.5. If you've used internal APIs in your apps, you need to update +your apps to stop doing so.

        + +

        Technique to Avoid, #2: Directly Manipulating Settings

        + +

        Strictly speaking this one isn't evil, since this is a change in +behavior that we made to Android itself. But we made it because some +developers were doing naughty things: a number of apps were changing +system settings silently without even notifying the user. For instance, +some apps turn on GPS without asking the user, and others might turn on +data roaming.

        + +

        As a result, applications can no longer directly +manipulate the values of certain system Settings, even if they +previously had permission to do so. For instance, apps can no longer +directly turn on or off GPS. These apps won't crash, but the APIs in +question now have no effect, and do nothing. Instead, apps will need to +issue an Intent to launch the appropriate Settings configuration +screen, so that the user can change these settings manually. For +details, see the android.provider.Settings.Secure class, which you can +find in the 1.5_pre SDK documentation (and later). Note that only +Settings that were moved to the Settings.Secure class are affected. +Other, less sensitive, settings will continue to have the same behavior +as in Android 1.1.

        + +

        Technique to Avoid, #3: Going Overboard with Layouts

        + +

        Due to changes in the View rendering infrastructure, unreasonably deep +(more than 10 or so) or broad (more than 30 total) View hierarchies in +layouts are now likely to cause crashes. This was always a risk for +excessively complex layouts, but you can think of Android 1.5 as being +better than 1.1 at exposing this problem. Most developers won't need to +worry about this, but if your app has very complicated layouts, you'll +need to put it on a diet. You can simplify your layouts using the more +advanced layout classes like FrameLayout and TableLayout.

        + +

        Technique to Avoid, #4: Bad Hardware Assumptions

        + +

        Android 1.5 includes support for soft keyboards, and there will soon be many +devices that run Android but do not have physical keyboards. If your +application assumes the presence of a physical keyboard (such as if you +have created a custom View that sinks keypress events) you should make +sure it degrades gracefully on devices that only have soft keyboards. +For more information on this, keep on eye on this blog as we'll be +posting more detailed information about handling the new soft keyboards.

        + +

        Technique to Avoid, #5: Incautious Rotations

        + +

        Devices running Android 1.5 and later can automatically rotate the screen, +depending on how the user orients the device. Some 1.5 devices will do +this by default, and on all others it can be turned on by the user. +This can sometimes result in unpredictable behavior from applications +that do their own reorientations (whether using the accelerometer, or +something else.) This often happens when applications assume that the +screen can only rotate if the physical keyboard is exposed; if the +device lacks a physical keyboard, these apps do not expect to be +reoriented, which is a coding error. Developers should be sure that +their applications can gracefully handle being reoriented at any time.

        + +

        Also, apps that use the accelerometer directly to reorient themselves +sometimes compete with the system doing the same thing, with odd +results. And finally, some apps that use the accelerometer to detect +things like shaking motions and that don't lock their orientation to +portrait or landscape, often end up flipping back and forth between +orientations. This can be irritating to the user. (You can lock your +app's orientation to portrait or landscape using the +android:screenOrientation attribute in the manifest file.)

        + diff --git a/docs/html/resources/articles/gestures.jd b/docs/html/resources/articles/gestures.jd new file mode 100644 index 0000000..8711645 --- /dev/null +++ b/docs/html/resources/articles/gestures.jd @@ -0,0 +1,211 @@ +page.title=Gestures +@jd:body + +

        Touch screens are a great way to interact with applications on +mobile devices. With a touch screen, users can easily tap, drag, fling, +or slide to quickly perform actions in their favorite applications. +For app developers. the Android framework makes it's easy to +recognize simple actions, like a swipe, but it has been more +difficult to handle complicated gestures, sometimes requiring +developers to write a lot of code.

        + +

        That's why we introduced a new gestures API in Android 1.6. This API, located +in the new package {@link android.gesture}, lets you store, load, draw, and +recognize gestures. This article will show you how you can use the +android.gesture API in your applications. Before going any further, +you should download the source code +of the examples.

        + +

        Creating a gestures library

        + +

        Android 1.6 and higher SDK platforms include a new application pre-installed +on the emulator, called Gestures Builder. You can use this application to create +a set of pre-defined gestures for your own application. It also serves as an +example of how to let the user define his own gestures in your applications. You +can find the source code of Gestures Builders in the samples directory of each +SDK platform. In our example we will use Gestures Builder to generate a set of +gestures for us (make sure to create an AVD with an SD card image to use +Gestures Builder.) The screenshot below shows what the application looks like +after adding a few gestures:

        + + + +

        As you can see, a gesture is always associated with a name. That name is very +important because it identifies each gesture within your application. The names +do not have to be unique. Actually it can be very useful to have several +gestures with the same name to increase the precision of the recognition. Every +time you add or edit a gesture in the Gestures Builder, a file is generated on +the emulator's SD card, /sdcard/gestures. This file contains the +description of all the gestures, and you will need to package it inside your +application inside the resources directory, in +/res/raw.

        + +

        Loading the gestures library

        + +

        Now that you have a set of pre-defined gestures, you must load it inside your +application. This can be achieved in several ways but the easiest is to use the +GestureLibraries class:

        + +
        mLibrary = GestureLibraries.fromRawResource(this, R.raw.spells);
        +if (!mLibrary.load()) {
        +    finish();
        +}
        + +

        In this example, the gesture library is loaded from the file +/res/raw/spells. You can easily load libraries from other sources, +like the SD card, which is very important if you want your application to be +able to save the library; a library loaded from a raw resource is read-only and +cannot be modified. The following diagram shows the structure of a library:

        + + + +

        Recognizing gestures

        + +

        To start recognizing gestures in your application, all you have to do +is add a GestureOverlayView to your XML layout:

        + +
        <android.gesture.GestureOverlayView
        +    android:id="@+id/gestures"
        +    android:layout_width="fill_parent" 
        +    android:layout_height="0dip"
        +    android:layout_weight="1.0" />
        + +

        Notice that the GestureOverlayView +is not part of the usual android.widget package. Therefore, you must +use its fully qualified name. A gesture overlay acts as a simple +drawing board on which the user can draw his gestures. You can tweak +several visual properties, like the color and the width of the stroke +used to draw gestures, and register various listeners to follow what +the user is doing. The most commonly used listener is +GestureOverlayView.OnGesturePerformedListener, +which fires whenever a user is done drawing a gesture:

        + +
        GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
        +gestures.addOnGesturePerformedListener(this);
        + +

        When the listener fires, you can ask the GestureLibrary +to try to recognize the gesture. In return, you will get a list of +Prediction instances, each with a name - the same name you entered in +the Gestures Builder - and a score. The list is sorted by descending +scores; the higher the score, the more likely the associated gesture is +the one the user intended to draw. The following code snippet +demonstrates how to retrieve the name of the first prediction:

        + +
        public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
        +    ArrayList<prediction> predictions = mLibrary.recognize(gesture);
        +
        +    // We want at least one prediction
        +    if (predictions.size() > 0) {
        +        Prediction prediction = predictions.get(0);
        +        // We want at least some confidence in the result
        +        if (prediction.score > 1.0) {
        +            // Show the spell
        +            Toast.makeText(this, prediction.name, Toast.LENGTH_SHORT).show();
        +        }
        +    }
        +}
        + +

        In this example, the first prediction is taken into account only if it's +score is greater than 1.0. The threshold you use is entirely up to you +but know that scores lower than 1.0 are typically poor matches. And +this is all the code you need to create a simple application that can +recognize pre-defined gestures (see the source code of the project +GesturesDemo):

        + + + +

        Gestures overlay

        + +

        In the example above, the GestureOverlayView was used +as a normal view, embedded inside a LinearLayout. +However, as its name suggests, it can also be used as an overlay on top +of other views. This can be useful to recognize gestures in a game or +just anywhere in the UI of an application. In the second example, +called GesturesListDemo, we'll create an overlay on top of a list of +contacts. We start again in Gestures Builder to create a new set of +pre-defined gestures:

        + +

        + +

        And here is what the XML layout looks like:

        + +
        <android.gesture.GestureOverlayView
        +    xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:id="@+id/gestures"
        +    android:layout_width="fill_parent"
        +    android:layout_height="fill_parent"
        +    
        +    android:gestureStrokeType="multiple"
        +    android:eventsInterceptionEnabled="true"
        +    android:orientation="vertical">
        +
        +    <ListView
        +        android:id="@android:id/list"  
        +        android:layout_width="fill_parent" 
        +        android:layout_height="fill_parent"  />
        +
        +</android.gesture.GestureOverlayView>
        + +

        In this application, the gestures view is an overlay on top of a regular +ListView. The overlay also specifies a few properties that we did not +need before:

        + +
          +
        • gestureStrokeType: indicates +whether we want to recognize gestures made of a single stroke or +multiple strokes. Since one of our gestures is the "+" symbol, we need +multiple strokes
        • +
        • eventsInterceptionEnabled: when +set to true, this property tells the overlay to steal the events from +its children as soon as it knows the user is really drawing a gesture. +This is useful when there's a scrollable view under the overlay, to +avoid scrolling the underlying child as the user draws his gesture
        • +
        • orientation: +indicates the scroll orientation of the views underneath. In this case +the list scrolls vertically, which means that any horizontal gestures +(like action_delete) can immediately be recognized as a +gesture. Gestures that start with a vertical stroke must contain at +least one horizontal component to be recognized. In other words, a +simple vertical line cannot be recognized as a gesture since it would +conflict with the list's scrolling.
        • +
        + +

        The code used to load and set up the gestures library and overlay is exactly +the same as before. The only difference is that we now check the name of the +predictions to know what the user intended to do:

        + +
        public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
        +    ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
        +    if (predictions.size() > 0 && predictions.get(0).score > 1.0) {
        +        String action = predictions.get(0).name;
        +        if ("action_add".equals(action)) {
        +            Toast.makeText(this, "Adding a contact", Toast.LENGTH_SHORT).show();
        +        } else if ("action_delete".equals(action)) {
        +            Toast.makeText(this, "Removing a contact", Toast.LENGTH_SHORT).show();
        +        } else if ("action_refresh".equals(action)) {
        +            Toast.makeText(this, "Reloading contacts", Toast.LENGTH_SHORT).show();
        +        }
        +    }
        +}
        + +

        The user is now able to draw his gestures on top of the list without +interfering with the scrolling:

        + + + +

        The overlay even gives visual clues as to whether the gesture is considered +valid for recognition. In the case of a vertical overlay, for instance, +a single vertical stroke cannot be recognized as a gesture and is +therefore drawn with a translucent color:

        + + + +

        It's your turn

        + +

        Adding support for gestures in your application is easy and can be a valuable +addition. The gestures API does not even have to be used to recognize complex +shapes; it will work equally well to recognize simple swipes. We are very +excited by the possibilities the gestures API offers, and we're eager to see +what cool applications the community will create with it.

        diff --git a/docs/html/resources/articles/glsurfaceview.jd b/docs/html/resources/articles/glsurfaceview.jd new file mode 100644 index 0000000..57403ea --- /dev/null +++ b/docs/html/resources/articles/glsurfaceview.jd @@ -0,0 +1,268 @@ +page.title=Introducing GLSurfaceView +@jd:body + + +

        The {@link android android.opengl.GLSurfaceView} class makes it +easier for you to use OpenGL ES rendering in your applications by:

        + +
          +
        • Providing the glue code to connect OpenGL ES to the {@link +android.view.View} system.
        • +
        • Providing the glue code to make OpenGL ES work with the {@link +android.app.Activity} life-cycle.
        • +
        • Making it easy to choose an appropriate frame buffer pixel format.
        • +
        • Creating and managing a separate rendering thread, to enable smooth +animation.
        • +
        • Providing easy-to-use debugging tools for tracing OpenGL ES API calls and +checking for errors.
        • +
        + +

        GLSurfaceView is a good base for building an application that uses OpenGL ES +for part or all of its rendering. A 2D or 3D action game would be a good +candidate, as would a 2D or 3D data visualization application such as Google Maps StreetView.

        + +

        A simple GLSurfaceView application

        + +

        Here's the source code to the simplest possible OpenGL ES application:

        + +
        package com.example.android.apis.graphics;
        +
        +import javax.microedition.khronos.egl.EGLConfig;
        +import javax.microedition.khronos.opengles.GL10;
        +
        +import android.app.Activity;
        +import android.opengl.GLSurfaceView;
        +import android.os.Bundle;
        +
        +public class ClearActivity extends Activity {
        +    @Override
        +    protected void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        mGLView = new GLSurfaceView(this);
        +        mGLView.setRenderer(new ClearRenderer());
        +        setContentView(mGLView);
        +    }
        +
        +    @Override
        +    protected void onPause() {
        +        super.onPause();
        +        mGLView.onPause();
        +    }
        +
        +    @Override
        +    protected void onResume() {
        +        super.onResume();
        +        mGLView.onResume();
        +    }
        +
        +    private GLSurfaceView mGLView;
        +}
        +
        +class ClearRenderer implements GLSurfaceView.Renderer {
        +    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        +        // Do nothing special.
        +    }
        +
        +    public void onSurfaceChanged(GL10 gl, int w, int h) {
        +        gl.glViewport(0, 0, w, h);
        +    }
        +
        +    public void onDrawFrame(GL10 gl) {
        +        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        +    }
        +}
        + +

        This program doesn't do much: it clears the screen to black on every frame. +But it is a complete OpenGL application that correctly implements the +Android activity life-cycle. It pauses rendering when the activity is +paused, and resumes it when the activity is resumed. You could use this +application as the basis for non-interactive demonstration programs. +Just add more OpenGL calls to the ClearRenderer.onDrawFrame() method. +Notice that you don't even need to subclass the GLSurfaceView view.

        + +

        The {@link android.opengl.GLSurfaceView.Renderer} interface has three methods:

        + +
          +
        • The +onSurfaceCreated() method is called at the start of rendering, and +whenever the OpenGL ES drawing context has to be recreated. (The +drawing context is typically lost and recreated when the activity is +paused and resumed.) OnSurfaceCreated() is a good place to create +long-lived OpenGL resources such as textures.
        • +
        • The onSurfaceChanged() +method is called when the surface changes size. It's a good place to +set your OpenGL viewport. You may also want to set your camera here, if +it's a fixed camera that doesn't move around the scene.
        • +
        • The onDrawFrame() method is called every frame, and is +responsible for drawing the scene. You would typically start by calling +glClear to clear the framebuffer, followed by other OpenGL ES calls +to draw the current scene.
        • +
        + +

        How about user input?

        + +

        If you want an interactive application (such as a game), you will typically +subclass GLSurfaceView, because that's an easy way of obtaining +input events. Here's a slightly longer example showing how to do that:

        + +
        package com.google.android.ClearTest;
        +
        +import javax.microedition.khronos.egl.EGLConfig;
        +import javax.microedition.khronos.opengles.GL10;
        +
        +import android.app.Activity;
        +import android.content.Context;
        +import android.opengl.GLSurfaceView;
        +import android.os.Bundle;
        +import android.view.MotionEvent;
        +
        +public class ClearActivity extends Activity {
        +    @Override
        +    protected void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        mGLView = new ClearGLSurfaceView(this);
        +        setContentView(mGLView);
        +    }
        +
        +    @Override
        +    protected void onPause() {
        +        super.onPause();
        +        mGLView.onPause();
        +    }
        +
        +    @Override
        +    protected void onResume() {
        +        super.onResume();
        +        mGLView.onResume();
        +    }
        +
        +    private GLSurfaceView mGLView;
        +}
        +
        +class ClearGLSurfaceView extends GLSurfaceView {
        +    public ClearGLSurfaceView(Context context) {
        +        super(context);
        +        mRenderer = new ClearRenderer();
        +        setRenderer(mRenderer);
        +    }
        +
        +    public boolean onTouchEvent(final MotionEvent event) {
        +        queueEvent(new Runnable(){
        +            public void run() {
        +                mRenderer.setColor(event.getX() / getWidth(),
        +                        event.getY() / getHeight(), 1.0f);
        +            }});
        +            return true;
        +        }
        +
        +        ClearRenderer mRenderer;
        +}
        +
        +class ClearRenderer implements GLSurfaceView.Renderer {
        +    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        +        // Do nothing special.
        +    }
        +
        +    public void onSurfaceChanged(GL10 gl, int w, int h) {
        +        gl.glViewport(0, 0, w, h);
        +    }
        +
        +    public void onDrawFrame(GL10 gl) {
        +        gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
        +        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        +    }
        +
        +    public void setColor(float r, float g, float b) {
        +        mRed = r;
        +        mGreen = g;
        +        mBlue = b;
        +    }
        +
        +    private float mRed;
        +    private float mGreen;
        +    private float mBlue;
        +}
        + +

        This application clears the screen for every frame. When you tap on the +screen, it sets the clear color based on the (x,y) coordinates of your touch +event. Note the use of queueEvent() in +ClearGLSurfaceView.onTouchEvent(). The queueEvent() +method is used to safely communicate between the UI thread and the rendering +thread. If you prefer, you can use some other Java cross-thread communication +technique, such as synchronized methods on the Renderer class +itself. However, queueing events is often the simplest way of dealing with +cross-thread communication.

        + +

        Other GLSurfaceView samples

        + +

        Tired +of just clearing the screen? You can find more interesting samples in +the API Demos sample included in the Android SDK. All the OpenGL ES samples have been +converted to use the GLSurfaceView view:

        + +
          +
        • GLSurfaceView - a spinning triangle
        • +
        • Kube - a cube puzzle demo
        • +
        • Translucent GLSurfaceView - shows how to display 3D graphics on a translucent background
        • +
        • Textured Triangle - shows how to draw a textured 3D triangle
        • +
        • Sprite Text - shows how to draw text into a texture and then composite it into a 3D scene
        • +
        • Touch Rotate - shows how to rotate a 3D object in response to user input.
        • +
        + +

        Choosing a surface

        + +

        GLSurfaceView +helps you choose the type of surface to render to. Different Android +devices support different types of surfaces, with no common subset. +This makes it tricky problem to choose the best available surface on +each device.

        + +

        By default, GLSurfaceView tries to find a surface that's as +close as possible to a 16-bit RGB frame buffer with a 16-bit depth +buffer. Depending upon your application's needs you may want to change +this behavior. For example, the Translucent GLSurfaceView sample needs +an Alpha channel in order to render translucent data. GLSurfaceView +provides an overloaded setEGLSurfaceChooser() method to give +you control over which surface type is chosen:

        + +
        +
        setEGLConfigChooser(boolean needDepth)
        +
        Choose a config that's closest to R5G6B5 with or without a 16-bit framebuffer
        +
        setEGLConfigChooser(int redSize, int greenSize,int blueSize, +int alphaSize,int depthSize, int stencilSize)
        +
        Choose the config with the fewest number of bits per pixel that has at least +as many bits-per-channel as specified in the constructor.
        +
        setEGLConfigChooser(EGLConfigChooser configChooser)
        +
        Allow total control over choosing a configuration. You pass in your own +implementation of EGLConfigChooser, which gets to inspect the +device's capabilities and choose a configuration.
        +
        + +

        Continuous rendering versus render-when-dirty

        + +

        Most 3D applications, such as games or simulations, are continuously +animated. But some 3D applications are more reactive: they wait passively until +the user does something, and then react to it. For those types of applications, +the default GLSurfaceView behavior of continuously redrawing the +screen is a waste of time. If you are developing a reactive application, you can +call GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY), which +turns off the continuous animation. Then you call +GLSurfaceView.requestRender() whenever you want to re-render.

        + +

        Help With debugging

        + +

        GLSurfaceView has a handy built-in feature for debugging OpenGL ES +applications: the GLSurfaceView.setDebugFlags() method can be used +to enable logging and/or error checking your OpenGL ES calls. Call this method +in your GLSurfaceView's constructor, before calling +setRenderer():

        + +
        public ClearGLSurfaceView(Context context) {
        +    super(context);
        +    // Turn on error-checking and logging
        +    setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
        +    mRenderer = new ClearRenderer();
        +    setRenderer(mRenderer);
        +}
        \ No newline at end of file diff --git a/docs/html/resources/articles/images/File.png b/docs/html/resources/articles/images/File.png new file mode 100644 index 0000000..bc5a2b8 Binary files /dev/null and b/docs/html/resources/articles/images/File.png differ diff --git a/docs/html/resources/articles/images/File_002.png b/docs/html/resources/articles/images/File_002.png new file mode 100644 index 0000000..39254b30 Binary files /dev/null and b/docs/html/resources/articles/images/File_002.png differ diff --git a/docs/html/resources/articles/images/JFlubber.png b/docs/html/resources/articles/images/JFlubber.png new file mode 100644 index 0000000..d95e32b Binary files /dev/null and b/docs/html/resources/articles/images/JFlubber.png differ diff --git a/docs/html/resources/articles/images/WikiNotes.png b/docs/html/resources/articles/images/WikiNotes.png new file mode 100644 index 0000000..d52c4fc Binary files /dev/null and b/docs/html/resources/articles/images/WikiNotes.png differ diff --git a/docs/html/resources/articles/images/all_drawables_changed.png b/docs/html/resources/articles/images/all_drawables_changed.png new file mode 100644 index 0000000..04ec4a2 Binary files /dev/null and b/docs/html/resources/articles/images/all_drawables_changed.png differ diff --git a/docs/html/resources/articles/images/android.png b/docs/html/resources/articles/images/android.png new file mode 100644 index 0000000..6dc88cc Binary files /dev/null and b/docs/html/resources/articles/images/android.png differ diff --git a/docs/html/resources/articles/images/buttons.png b/docs/html/resources/articles/images/buttons.png new file mode 100644 index 0000000..8c220b9 Binary files /dev/null and b/docs/html/resources/articles/images/buttons.png differ diff --git a/docs/html/resources/articles/images/contacts.png b/docs/html/resources/articles/images/contacts.png new file mode 100644 index 0000000..d8b067d Binary files /dev/null and b/docs/html/resources/articles/images/contacts.png differ diff --git a/docs/html/resources/articles/images/correct_drawables.png b/docs/html/resources/articles/images/correct_drawables.png new file mode 100644 index 0000000..516309b Binary files /dev/null and b/docs/html/resources/articles/images/correct_drawables.png differ diff --git a/docs/html/resources/articles/images/ddms_allocation_tracker.png b/docs/html/resources/articles/images/ddms_allocation_tracker.png new file mode 100644 index 0000000..b9fa0a1 Binary files /dev/null and b/docs/html/resources/articles/images/ddms_allocation_tracker.png differ diff --git a/docs/html/resources/articles/images/ddms_allocation_trackerl.png b/docs/html/resources/articles/images/ddms_allocation_trackerl.png new file mode 100644 index 0000000..5ac8d2a Binary files /dev/null and b/docs/html/resources/articles/images/ddms_allocation_trackerl.png differ diff --git a/docs/html/resources/articles/images/device.png b/docs/html/resources/articles/images/device.png new file mode 100644 index 0000000..186b960 Binary files /dev/null and b/docs/html/resources/articles/images/device.png differ diff --git a/docs/html/resources/articles/images/device_002.png b/docs/html/resources/articles/images/device_002.png new file mode 100644 index 0000000..4bc3b0c Binary files /dev/null and b/docs/html/resources/articles/images/device_002.png differ diff --git a/docs/html/resources/articles/images/gestures.png b/docs/html/resources/articles/images/gestures.png new file mode 100644 index 0000000..fe8f7cd Binary files /dev/null and b/docs/html/resources/articles/images/gestures.png differ diff --git a/docs/html/resources/articles/images/gestures_002.png b/docs/html/resources/articles/images/gestures_002.png new file mode 100644 index 0000000..b20da98 Binary files /dev/null and b/docs/html/resources/articles/images/gestures_002.png differ diff --git a/docs/html/resources/articles/images/gestures_003.png b/docs/html/resources/articles/images/gestures_003.png new file mode 100644 index 0000000..a295939 Binary files /dev/null and b/docs/html/resources/articles/images/gestures_003.png differ diff --git a/docs/html/resources/articles/images/gestures_004.png b/docs/html/resources/articles/images/gestures_004.png new file mode 100644 index 0000000..3fe5fb1 Binary files /dev/null and b/docs/html/resources/articles/images/gestures_004.png differ diff --git a/docs/html/resources/articles/images/gestures_005.png b/docs/html/resources/articles/images/gestures_005.png new file mode 100644 index 0000000..3efc519 Binary files /dev/null and b/docs/html/resources/articles/images/gestures_005.png differ diff --git a/docs/html/resources/articles/images/gestures_006.png b/docs/html/resources/articles/images/gestures_006.png new file mode 100644 index 0000000..399c31d Binary files /dev/null and b/docs/html/resources/articles/images/gestures_006.png differ diff --git a/docs/html/resources/articles/images/grid.png b/docs/html/resources/articles/images/grid.png new file mode 100644 index 0000000..4713de5 Binary files /dev/null and b/docs/html/resources/articles/images/grid.png differ diff --git a/docs/html/resources/articles/images/ime.png b/docs/html/resources/articles/images/ime.png new file mode 100644 index 0000000..57f6df1 Binary files /dev/null and b/docs/html/resources/articles/images/ime.png differ diff --git a/docs/html/resources/articles/images/ime_002.png b/docs/html/resources/articles/images/ime_002.png new file mode 100644 index 0000000..3ec00b2 Binary files /dev/null and b/docs/html/resources/articles/images/ime_002.png differ diff --git a/docs/html/resources/articles/images/ime_003.png b/docs/html/resources/articles/images/ime_003.png new file mode 100644 index 0000000..a3f57bb Binary files /dev/null and b/docs/html/resources/articles/images/ime_003.png differ diff --git a/docs/html/resources/articles/images/ime_004.png b/docs/html/resources/articles/images/ime_004.png new file mode 100644 index 0000000..efeddf0 Binary files /dev/null and b/docs/html/resources/articles/images/ime_004.png differ diff --git a/docs/html/resources/articles/images/ime_005.png b/docs/html/resources/articles/images/ime_005.png new file mode 100644 index 0000000..a7394e0 Binary files /dev/null and b/docs/html/resources/articles/images/ime_005.png differ diff --git a/docs/html/resources/articles/images/ime_006.png b/docs/html/resources/articles/images/ime_006.png new file mode 100644 index 0000000..0b55c79 Binary files /dev/null and b/docs/html/resources/articles/images/ime_006.png differ diff --git a/docs/html/resources/articles/images/layouts_comparison_small.png b/docs/html/resources/articles/images/layouts_comparison_small.png new file mode 100644 index 0000000..0ba4cb8 Binary files /dev/null and b/docs/html/resources/articles/images/layouts_comparison_small.png differ diff --git a/docs/html/resources/articles/images/list01.png b/docs/html/resources/articles/images/list01.png new file mode 100644 index 0000000..e1b7fa8 Binary files /dev/null and b/docs/html/resources/articles/images/list01.png differ diff --git a/docs/html/resources/articles/images/list02.png b/docs/html/resources/articles/images/list02.png new file mode 100644 index 0000000..7f72a3f Binary files /dev/null and b/docs/html/resources/articles/images/list02.png differ diff --git a/docs/html/resources/articles/images/list_fade_1.png b/docs/html/resources/articles/images/list_fade_1.png new file mode 100644 index 0000000..43013d6 Binary files /dev/null and b/docs/html/resources/articles/images/list_fade_1.png differ diff --git a/docs/html/resources/articles/images/list_fade_2.png b/docs/html/resources/articles/images/list_fade_2.png new file mode 100644 index 0000000..160d3ff Binary files /dev/null and b/docs/html/resources/articles/images/list_fade_2.png differ diff --git a/docs/html/resources/articles/images/list_fade_3.png b/docs/html/resources/articles/images/list_fade_3.png new file mode 100644 index 0000000..70dca64 Binary files /dev/null and b/docs/html/resources/articles/images/list_fade_3.png differ diff --git a/docs/html/resources/articles/images/list_fade_4.png b/docs/html/resources/articles/images/list_fade_4.png new file mode 100644 index 0000000..7619fca Binary files /dev/null and b/docs/html/resources/articles/images/list_fade_4.png differ diff --git a/docs/html/resources/articles/images/merge1.jpg b/docs/html/resources/articles/images/merge1.jpg new file mode 100644 index 0000000..114eed6 Binary files /dev/null and b/docs/html/resources/articles/images/merge1.jpg differ diff --git a/docs/html/resources/articles/images/merge2.png b/docs/html/resources/articles/images/merge2.png new file mode 100644 index 0000000..b4a8d4c Binary files /dev/null and b/docs/html/resources/articles/images/merge2.png differ diff --git a/docs/html/resources/articles/images/merge3.png b/docs/html/resources/articles/images/merge3.png new file mode 100644 index 0000000..61ed983 Binary files /dev/null and b/docs/html/resources/articles/images/merge3.png differ diff --git a/docs/html/resources/articles/images/merge4.jpg b/docs/html/resources/articles/images/merge4.jpg new file mode 100644 index 0000000..17b6c20 Binary files /dev/null and b/docs/html/resources/articles/images/merge4.jpg differ diff --git a/docs/html/resources/articles/images/merge5.png b/docs/html/resources/articles/images/merge5.png new file mode 100644 index 0000000..289f47e Binary files /dev/null and b/docs/html/resources/articles/images/merge5.png differ diff --git a/docs/html/resources/articles/images/mutated_states.png b/docs/html/resources/articles/images/mutated_states.png new file mode 100644 index 0000000..50518b6 Binary files /dev/null and b/docs/html/resources/articles/images/mutated_states.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs.png b/docs/html/resources/articles/images/on-screen-inputs.png new file mode 100644 index 0000000..b8b3cf7 Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs_002.png b/docs/html/resources/articles/images/on-screen-inputs_002.png new file mode 100644 index 0000000..a5d21c7 Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs_002.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs_003.png b/docs/html/resources/articles/images/on-screen-inputs_003.png new file mode 100644 index 0000000..81ee257 Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs_003.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs_004.png b/docs/html/resources/articles/images/on-screen-inputs_004.png new file mode 100644 index 0000000..651b72a Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs_004.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs_005.png b/docs/html/resources/articles/images/on-screen-inputs_005.png new file mode 100644 index 0000000..75185ff Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs_005.png differ diff --git a/docs/html/resources/articles/images/on-screen-inputs_006.png b/docs/html/resources/articles/images/on-screen-inputs_006.png new file mode 100644 index 0000000..b653d75 Binary files /dev/null and b/docs/html/resources/articles/images/on-screen-inputs_006.png differ diff --git a/docs/html/resources/articles/images/photostream_landscape.png b/docs/html/resources/articles/images/photostream_landscape.png new file mode 100644 index 0000000..ad4a0c5 Binary files /dev/null and b/docs/html/resources/articles/images/photostream_landscape.png differ diff --git a/docs/html/resources/articles/images/photostream_portrait.png b/docs/html/resources/articles/images/photostream_portrait.png new file mode 100644 index 0000000..3794f63 Binary files /dev/null and b/docs/html/resources/articles/images/photostream_portrait.png differ diff --git a/docs/html/resources/articles/images/qsb.png b/docs/html/resources/articles/images/qsb.png new file mode 100644 index 0000000..4e40af1 Binary files /dev/null and b/docs/html/resources/articles/images/qsb.png differ diff --git a/docs/html/resources/articles/images/qsb_002.png b/docs/html/resources/articles/images/qsb_002.png new file mode 100644 index 0000000..8c2f772 Binary files /dev/null and b/docs/html/resources/articles/images/qsb_002.png differ diff --git a/docs/html/resources/articles/images/qsb_003.png b/docs/html/resources/articles/images/qsb_003.png new file mode 100644 index 0000000..069b6cd Binary files /dev/null and b/docs/html/resources/articles/images/qsb_003.png differ diff --git a/docs/html/resources/articles/images/relativelayout_1.png b/docs/html/resources/articles/images/relativelayout_1.png new file mode 100644 index 0000000..3360ad8 Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_1.png differ diff --git a/docs/html/resources/articles/images/relativelayout_2.png b/docs/html/resources/articles/images/relativelayout_2.png new file mode 100644 index 0000000..8e71bb2 Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_2.png differ diff --git a/docs/html/resources/articles/images/relativelayout_3.png b/docs/html/resources/articles/images/relativelayout_3.png new file mode 100644 index 0000000..16a9767 Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_3.png differ diff --git a/docs/html/resources/articles/images/relativelayout_wire_1.png b/docs/html/resources/articles/images/relativelayout_wire_1.png new file mode 100644 index 0000000..9cb241d Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_wire_1.png differ diff --git a/docs/html/resources/articles/images/relativelayout_wire_2.png b/docs/html/resources/articles/images/relativelayout_wire_2.png new file mode 100644 index 0000000..4243812 Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_wire_2.png differ diff --git a/docs/html/resources/articles/images/relativelayout_wire_3.png b/docs/html/resources/articles/images/relativelayout_wire_3.png new file mode 100644 index 0000000..04ce1ce Binary files /dev/null and b/docs/html/resources/articles/images/relativelayout_wire_3.png differ diff --git a/docs/html/resources/articles/images/search01.png b/docs/html/resources/articles/images/search01.png new file mode 100644 index 0000000..4160a76 Binary files /dev/null and b/docs/html/resources/articles/images/search01.png differ diff --git a/docs/html/resources/articles/images/search02.png b/docs/html/resources/articles/images/search02.png new file mode 100644 index 0000000..6300018 Binary files /dev/null and b/docs/html/resources/articles/images/search02.png differ diff --git a/docs/html/resources/articles/images/shared_states.png b/docs/html/resources/articles/images/shared_states.png new file mode 100644 index 0000000..81bec09 Binary files /dev/null and b/docs/html/resources/articles/images/shared_states.png differ diff --git a/docs/html/resources/articles/images/shelves2.png b/docs/html/resources/articles/images/shelves2.png new file mode 100644 index 0000000..2de239f Binary files /dev/null and b/docs/html/resources/articles/images/shelves2.png differ diff --git a/docs/html/resources/articles/images/text_field.png b/docs/html/resources/articles/images/text_field.png new file mode 100644 index 0000000..b9dedec Binary files /dev/null and b/docs/html/resources/articles/images/text_field.png differ diff --git a/docs/html/resources/articles/images/ui-1.6.png b/docs/html/resources/articles/images/ui-1.6.png new file mode 100644 index 0000000..bc5a2b8 Binary files /dev/null and b/docs/html/resources/articles/images/ui-1.6.png differ diff --git a/docs/html/resources/articles/images/ui-1.6_002.png b/docs/html/resources/articles/images/ui-1.6_002.png new file mode 100644 index 0000000..39254b30 Binary files /dev/null and b/docs/html/resources/articles/images/ui-1.6_002.png differ diff --git a/docs/html/resources/articles/images/viewstub1.png b/docs/html/resources/articles/images/viewstub1.png new file mode 100644 index 0000000..2de239f Binary files /dev/null and b/docs/html/resources/articles/images/viewstub1.png differ diff --git a/docs/html/resources/articles/images/viewstub2.png b/docs/html/resources/articles/images/viewstub2.png new file mode 100644 index 0000000..6e6feb9 Binary files /dev/null and b/docs/html/resources/articles/images/viewstub2.png differ diff --git a/docs/html/resources/articles/images/viewstub3.png b/docs/html/resources/articles/images/viewstub3.png new file mode 100644 index 0000000..5e793e6 Binary files /dev/null and b/docs/html/resources/articles/images/viewstub3.png differ diff --git a/docs/html/resources/articles/images/viewstub4.png b/docs/html/resources/articles/images/viewstub4.png new file mode 100644 index 0000000..cffb9c6 Binary files /dev/null and b/docs/html/resources/articles/images/viewstub4.png differ diff --git a/docs/html/resources/articles/images/webview.png b/docs/html/resources/articles/images/webview.png new file mode 100644 index 0000000..92472af Binary files /dev/null and b/docs/html/resources/articles/images/webview.png differ diff --git a/docs/html/resources/articles/images/window_background.png b/docs/html/resources/articles/images/window_background.png new file mode 100644 index 0000000..58f4f7e Binary files /dev/null and b/docs/html/resources/articles/images/window_background.png differ diff --git a/docs/html/resources/articles/images/window_background_null.png b/docs/html/resources/articles/images/window_background_null.png new file mode 100644 index 0000000..83f7b45 Binary files /dev/null and b/docs/html/resources/articles/images/window_background_null.png differ diff --git a/docs/html/resources/articles/images/window_background_root.png b/docs/html/resources/articles/images/window_background_root.png new file mode 100644 index 0000000..95a47c0 Binary files /dev/null and b/docs/html/resources/articles/images/window_background_root.png differ diff --git a/docs/html/resources/articles/index.jd b/docs/html/resources/articles/index.jd new file mode 100644 index 0000000..3080453 --- /dev/null +++ b/docs/html/resources/articles/index.jd @@ -0,0 +1,9 @@ +page.title=Technical Articles +@jd:body + + +
        +
        Using Text-to-Speech
        +
        The text-to-speech API lets your application "speak" to users, in any of several languages. This article provides an overview of the TTS API and how you use to add speech capabilities to your application.
        +
        + diff --git a/docs/html/resources/articles/layout-tricks-efficiency.jd b/docs/html/resources/articles/layout-tricks-efficiency.jd new file mode 100644 index 0000000..b7b5761 --- /dev/null +++ b/docs/html/resources/articles/layout-tricks-efficiency.jd @@ -0,0 +1,177 @@ +page.title=Layout Tricks: Creating Efficient Layouts +@jd:body + +

        The Android UI toolkit offers several layout managers that are +rather easy to use and, most of the time, you only need the basic +features of these layout managers to implement a user interface.

        + +

        Sticking to the basic features is unfortunately not the most efficient +way to create user interfaces. A common example is the abuse of +{@link android.widget.LinearLayout}, which leads to a proliferation of +views in the view hierarchy. Every view — or worse, every layout +manager — that you add to your application comes at a cost: +initialization, layout and drawing become slower. The layout pass can be +especially expensive when you nest several LinearLayout +that use the {@link android.R.attr#layout_weight weight} +parameter, which requires the child to be measured twice.

        + +

        Let's consider a very simple and common example of a layout: a list item +with an icon on the left, a title at the top and an optional description +underneath the title. Here is what such an item looks like:

        + +
        Simple list item
        + +

        To clearly understand how the views, one {@link android.widget.ImageView} and +two {@link android.widget.TextView}, are positioned with respect to each other, +here is the wireframe of the layout as captured by HierarchyViewer:

        + +
        Wireframe of the simple list item
        + +

        Implementing this layout is straightforward with LinearLayout. +The item itself is a horizontal LinearLayout with an +ImageView and a vertical LinearLayout, which contains +the two TextView. Here's the source code of this layout:

        + +
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:layout_width="fill_parent"
        +    android:layout_height="?android:attr/listPreferredItemHeight"
        +    
        +    android:padding="6dip">
        +    
        +    <ImageView
        +        android:id="@+id/icon"
        +        
        +        android:layout_width="wrap_content"
        +        android:layout_height="fill_parent"
        +        android:layout_marginRight="6dip"
        +        
        +        android:src="@drawable/icon" />
        +
        +    <LinearLayout
        +        android:orientation="vertical"
        +    
        +        android:layout_width="0dip"
        +        android:layout_weight="1"
        +        android:layout_height="fill_parent">
        +
        +        <TextView
        +            android:layout_width="fill_parent"
        +            android:layout_height="0dip"
        +            android:layout_weight="1"
        +                    
        +            android:gravity="center_vertical"
        +            android:text="My Application" />
        +            
        +        <TextView  
        +            android:layout_width="fill_parent"
        +            android:layout_height="0dip"
        +            android:layout_weight="1" 
        +            
        +            android:singleLine="true"
        +            android:ellipsize="marquee"
        +            android:text="Simple application that shows how to use RelativeLayout" />
        +            
        +    </LinearLayout>
        +
        +</LinearLayout>
        + +

        This layout works but can be wasteful if you instantiate it for every list +item of a {@link android.widget.ListView}. The same layout can be rewritten +using a single {@link android.widget.RelativeLayout}, thus saving one view, and +even better one level in view hierarchy, per list item. The implementation of +the layout with a RelativeLayout remains simple:

        + +
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:layout_width="fill_parent"
        +    android:layout_height="?android:attr/listPreferredItemHeight"
        +    
        +    android:padding="6dip">
        +    
        +    <ImageView
        +        android:id="@+id/icon"
        +        
        +        android:layout_width="wrap_content"
        +        android:layout_height="fill_parent"
        +        
        +        android:layout_alignParentTop="true"
        +        android:layout_alignParentBottom="true"
        +        android:layout_marginRight="6dip"
        +        
        +        android:src="@drawable/icon" />
        +
        +    <TextView  
        +        android:id="@+id/secondLine"
        +
        +        android:layout_width="fill_parent"
        +        android:layout_height="26dip" 
        +        
        +        android:layout_toRightOf="@id/icon"
        +        android:layout_alignParentBottom="true"
        +        android:layout_alignParentRight="true"
        +        
        +        android:singleLine="true"
        +        android:ellipsize="marquee"
        +        android:text="Simple application that shows how to use RelativeLayout" />
        +
        +    <TextView
        +        android:layout_width="fill_parent"
        +        android:layout_height="wrap_content"
        +        
        +        android:layout_toRightOf="@id/icon"
        +        android:layout_alignParentRight="true"
        +        android:layout_alignParentTop="true"
        +        android:layout_above="@id/secondLine"
        +        android:layout_alignWithParentIfMissing="true"
        +                
        +        android:gravity="center_vertical"
        +        android:text="My Application" />
        +
        +</RelativeLayout>
        + +

        This new implementation behaves exactly the same way as the previous +implementation, except in one case. The list item we want to display has two +lines of text: the title and an optional description. When a +description is not available for a given list item, the application would simply +set the visibility of the second TextView to +{@link android.view.View#GONE}. This works perfectly with the LinearLayout +implementation but not with the RelativeLayout version:

        + +
        RelativeLayout and description GONE
        +
        RelativeLayout and description GONE
        + +

        In a RelativeLayout, views are aligned with their parent, with the +RelativeLayout itself, or with other views. For instance, we declared that +the description is aligned with the bottom of the RelativeLayout and +that the title is positioned above the description and anchored to the +parent's top. With the description GONE, RelativeLayout doesn't know +where to position the title's bottom edge. To solve this problem, you +can use a very special layout parameter called +{@link android.R.attr#layout_alignWithParentIfMissing}. +

        + +

        This boolean parameter simply tells RelativeLayout to use its own edges as +anchors when a constraint target is missing. For instance, if you position a +view to the right of a GONE view and set alignWithParentIfMissing +to true, RelativeLayout will instead anchor the view +to its left edge. In our case, using alignWithParentIfMissing will +cause RelativeLayout to align the title's bottom with its own +bottom. The result is the following:

        + +
        RelativeLayout, description GONE and alignWithParentIfMissing
        +
        RelativeLayout, description GONE and alignWithParentIfMissing
        + +

        The +behavior of our layout is now perfect, even when the description is +GONE. Even better, the hierarchy is simpler and because we are not +using LinearLayout's weights it's also more efficient. The difference +between the two implementations becomes obvious when comparing the view +hierarchies in HierarchyViewer:

        + +
        LinearLayout vs RelativeLayout
        + +

        Again, the difference will be much more important when you use such a layout +for every item in a ListView for instance. Hopefully this simple +example showed you that getting to know your layouts is the best way to +learn how to optimize your UI.

        diff --git a/docs/html/resources/articles/layout-tricks-merge.jd b/docs/html/resources/articles/layout-tricks-merge.jd new file mode 100644 index 0000000..3e165d2 --- /dev/null +++ b/docs/html/resources/articles/layout-tricks-merge.jd @@ -0,0 +1,198 @@ +page.title=Layout Tricks: Merging Layouts +@jd:body + +

        The articles showed you how to use the <include /> tag in XML layouts, to reuse and share your layout code. This article explains the <merge /> tag and how it complements the <include /> tag.

        + +

        The <merge /> tag was created for the purpose of +optimizing Android layouts by reducing the number of levels in view trees. It's +easier to understand the problem this tag solves by looking at an example. The +following XML layout declares a layout that shows an image with its title on top +of it. The structure is fairly simple; a {@link android.widget.FrameLayout} is +used to stack a {@link android.widget.TextView} on top of an +{@link android.widget.ImageView}:

        + +
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:layout_width="fill_parent"
        +    android:layout_height="fill_parent">
        +
        +    <ImageView  
        +        android:layout_width="fill_parent" 
        +        android:layout_height="fill_parent" 
        +    
        +        android:scaleType="center"
        +        android:src="@drawable/golden_gate" />
        +    
        +    <TextView
        +        android:layout_width="wrap_content" 
        +        android:layout_height="wrap_content" 
        +        android:layout_marginBottom="20dip"
        +        android:layout_gravity="center_horizontal|bottom"
        +
        +        android:padding="12dip"
        +        
        +        android:background="#AA000000"
        +        android:textColor="#ffffffff"
        +        
        +        android:text="Golden Gate" />
        +
        +</FrameLayout>
        + +

        This layout renders nicely and nothing seems wrong with it:

        + +
        A FrameLayout is used to overlay a title on top of an image
        + +

        Things get more interesting when you inspect the result with HierarchyViewer. +If you look closely at the resulting tree, you will notice that the +FrameLayout defined in our XML file (highlighted in blue below) is +the sole child of another FrameLayout:

        + +
        A layout with only one child of same dimensions can be removed
        + +

        Since our FrameLayout has the same dimension as its parent, by +the virtue of using the fill_parent constraints, and does not +define any background, extra padding or a gravity, it is totally +useless. We only made the UI more complex for no good reason. But how could +we get rid of this FrameLayout? After all, XML documents require a +root tag and tags in XML layouts always represent view instances.

        + +

        That's where the <merge /> tag comes in handy. When the +{@link android.view.LayoutInflater} encounters this tag, it skips it and adds +the <merge /> children to the <merge /> +parent. Confused? Let's rewrite our previous XML layout by replacing the +FrameLayout with <merge />:

        + +
        <merge xmlns:android="http://schemas.android.com/apk/res/android">
        +
        +    <ImageView  
        +        android:layout_width="fill_parent" 
        +        android:layout_height="fill_parent" 
        +    
        +        android:scaleType="center"
        +        android:src="@drawable/golden_gate" />
        +    
        +    <TextView
        +        android:layout_width="wrap_content" 
        +        android:layout_height="wrap_content" 
        +        android:layout_marginBottom="20dip"
        +        android:layout_gravity="center_horizontal|bottom"
        +
        +        android:padding="12dip"
        +        
        +        android:background="#AA000000"
        +        android:textColor="#ffffffff"
        +        
        +        android:text="Golden Gate" />
        +
        +</merge>
        + +

        With this new version, both the TextView and the +ImageView will be added directly to the top-level +FrameLayout. The result will be visually the same but the view +hierarchy is simpler:

        + +
        Optimized view hierarchy using the merge tag
        + +

        Obviously, using <merge /> works in this case because the +parent of an activity's content view is always a FrameLayout. You +could not apply this trick if your layout was using a LinearLayout +as its root tag for instance. The <merge /> can be useful in +other situations though. For instance, it works perfectly when combined with the +<include /> tag. You can also use <merge +/> when you create a custom composite view. Let's see how we can use +this tag to create a new view called OkCancelBar which simply shows +two buttons with customizable labels. You can also download the complete +source code of this example. Here is the XML used to display this custom +view on top of an image:

        + +
        <merge
        +    xmlns:android="http://schemas.android.com/apk/res/android"
        +    xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">
        +
        +    <ImageView  
        +        android:layout_width="fill_parent" 
        +        android:layout_height="fill_parent" 
        +    
        +        android:scaleType="center"
        +        android:src="@drawable/golden_gate" />
        +    
        +    <com.example.android.merge.OkCancelBar
        +        android:layout_width="fill_parent" 
        +        android:layout_height="wrap_content" 
        +        android:layout_gravity="bottom"
        +
        +        android:paddingTop="8dip"
        +        android:gravity="center_horizontal"
        +        
        +        android:background="#AA000000"
        +        
        +        okCancelBar:okLabel="Save"
        +        okCancelBar:cancelLabel="Don't save" />
        +
        +</merge>
        + +

        This new layout produces the following result on a device:

        + +
        Creating a custom view with the merge tag
        + +

        The source code of OkCancelBar is very simple because the two +buttons are defined in an external XML file, loaded using a +LayoutInflate. As you can see in the following snippet, the XML +layout R.layout.okcancelbar is inflated with the +OkCancelBar as the parent:

        + +
        public class OkCancelBar extends LinearLayout {
        +    public OkCancelBar(Context context, AttributeSet attrs) {
        +        super(context, attrs);
        +        setOrientation(HORIZONTAL);
        +        setGravity(Gravity.CENTER);
        +        setWeightSum(1.0f);
        +        
        +        LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
        +        
        +        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
        +        
        +        String text = array.getString(R.styleable.OkCancelBar_okLabel);
        +        if (text == null) text = "Ok";
        +        ((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
        +        
        +        text = array.getString(R.styleable.OkCancelBar_cancelLabel);
        +        if (text == null) text = "Cancel";
        +        ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
        +        
        +        array.recycle();
        +    }
        +}
        + +

        The two buttons are defined in the following XML layout. As you can see, we +use the <merge /> tag to add the two buttons directly to the +OkCancelBar. Each button is included from the same external XML +layout file to make them easier to maintain; we simply override their id:

        + +
        <merge xmlns:android="http://schemas.android.com/apk/res/android">
        +    <include
        +        layout="@layout/okcancelbar_button"
        +        android:id="@+id/okcancelbar_ok" />
        +        
        +    <include
        +        layout="@layout/okcancelbar_button"
        +        android:id="@+id/okcancelbar_cancel" />
        +</merge>
        + +

        We have created a flexible and easy to maintain custom view that generates +an efficient view hierarchy:

        + +
        The resulting hierarchy is simple and efficient
        + +

        The <merge /> tag is extremely useful and can do wonders +in your code. However, it suffers from a couple of limitations:

        + +
          +
        • <merge /> can only be used as the root tag of an XML layout
        • +
        • When inflating a layout starting with a <merge />, you must +specify a parent ViewGroup and you must set attachToRoot to +true (see the documentation for +{@link android.view.LayoutInflater#inflate(int, android.view.ViewGroup, boolean)} method)
        • +
        + diff --git a/docs/html/resources/articles/layout-tricks-reuse.jd b/docs/html/resources/articles/layout-tricks-reuse.jd new file mode 100644 index 0000000..072ba89 --- /dev/null +++ b/docs/html/resources/articles/layout-tricks-reuse.jd @@ -0,0 +1,67 @@ +page.title=Layout Tricks: Creating Reusable UI Components +@jd:body + +

        The Android platform offers a wide variety of UI widgets, small +visual construction blocks that you can glue together to present users with +complex and useful interfaces. However applications often need higher-level +visual components. To meet that need, and to do so efficiently, you can +combine multiple standard widgets into a single, reusable component.

        + +

        For example, you could create a reusable component that contains a progress +bar and a cancel button, a panel containing two buttons (positive and negative +actions), a panel with an icon, a title and a description, and so on. You can +create UI components easily by writing a custom View, but you can +do it even more easily using only XML.

        + +

        In Android XML layout files, each tag is mapped to an actual class instance +(the class is always a subclass of {@link android.view.View} The UI toolkit lets +you also use three special tags that are not mapped to a View +instance: <requestFocus />, <merge /> and +<include />. This article shows how to use <include +/> to create pure XML visual components. For information about how to +use <merge />, which can be particularly powerful when +combined with <include />see the Merging Layouts +article.

        + +

        The <include /> element does exactly what its name +suggests; it includes another XML layout. Using this tag is straightforward as +shown in the following example, taken straight from the source code of the Home application +that ships with Android:

        + +
        <com.android.launcher.Workspace
        +    android:id="@+id/workspace"
        +    android:layout_width="fill_parent"
        +    android:layout_height="fill_parent"
        +
        +    launcher:defaultScreen="1">
        +
        +    <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
        +    <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
        +    <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
        +
        +</com.android.launcher.Workspace>
        + +

        In the <include /> only the layout attribute +is required. This attribute, without the android namespace prefix, +is a reference to the layout file you wish to include. In this example, the same +layout is included three times in a row. This tag also lets you override a few +attributes of the included layout. The above example shows that you can use +android:id to specify the id of the root view of the included +layout; it will also override the id of the included layout if one is defined. +Similarly, you can override all the layout parameters. This means that any +android:layout_* attribute can be used with the <include +/> tag. Here is an example:

        + +
        <include android:layout_width="fill_parent" layout="@layout/image_holder" />
        +<include android:layout_width="256dip" layout="@layout/image_holder" />
        +
        + +

        This tag is particularly useful when you need to customize only part of your +UI depending on the device's configuration. For instance, the main layout of +your activity can be placed in the layout/ directory and can +include another layout which exists in two flavors, in layout-land/ +and layout-port/. This allows you to share most of the UI in +portrait and landscape.

        \ No newline at end of file diff --git a/docs/html/resources/articles/layout-tricks-stubs.jd b/docs/html/resources/articles/layout-tricks-stubs.jd new file mode 100644 index 0000000..e494a54 --- /dev/null +++ b/docs/html/resources/articles/layout-tricks-stubs.jd @@ -0,0 +1,84 @@ +page.title=Layout Tricks: Using ViewStubs +@jd:body + +

        Sharing and reusing UI components is very easy with Android, thanks to the <include /> tag. Sometimes it's so +easy to create complex UI constructs that your UI ends up with a large number of +views, some of which are rarely used. Thankfully, Android offers a very special +widget called {@link android.view.ViewStub}, which brings you all the benefits +of the <include /> without polluting your user interface with +rarely used views.

        + +

        A ViewStub is a dumb and lightweight view. It has no dimension, +it does not draw anything and does not participate in the layout in any way. +This means that a ViewStub is very cheap to inflate and very cheap +to keep in a view hierarchy. A ViewStub can be best described as a +lazy include. The layout referenced by a ViewStub is +inflated and added to the user interface only when you decide so.

        + +

        The following screenshot comes from the Shelves application. The main purpose of +the activity shown in the screenshot is to present the user with a browsable +list of books:

        + + + +

        The same activity is also used when the user adds or imports new books. +During such an operation, Shelves shows extra bits of user interface. +The screenshot below shows the progress bar and cancel button that +appear at the bottom of the screen during an import:

        + + + +

        Because importing books is not a common operation, at least when compared to +browsing the list of books, the import panel is originally represented +by a ViewStub:

        + + + +

        When the user initiates the import process, the ViewStub is +inflated and replaced by the content of the layout file it references:

        + + + +

        To use a ViewStub, all you need is to specify an +android:id attribute, to later inflate the stub, and an +android:layout attribute, to reference what layout file +to include and inflate. A stub lets you use a third attribute, +android:inflatedId, which can be used to override the +id of the root of the included file. Finally, the layout +parameters specified on the stub will be applied to the roof of the +included layout. Here is an example:

        + +
        <ViewStub
        +  android:id="@+id/stub_import"
        +  android:inflatedId="@+id/panel_import"
        +
        +  android:layout="@layout/progress_overlay"
        +
        +  android:layout_width="fill_parent"
        +  android:layout_height="wrap_content"
        +  android:layout_gravity="bottom" />
        + +

        When you are ready to inflate the stub, simply invoke the +{@link android.view.ViewStub#inflate()} method. You can also simply change the +visibility of the stub to {@link android.view.View#VISIBLE} or +{@link android.view.View#INVISIBLE} and the stub will inflate. Note however that the +inflate() method has the benefit of returning the root +View of the inflate layout:

        + +
        ((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
        +// or
        +View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
        + +

        It is very important to remember that after the stub is inflated, the stub is +removed from the view hierarchy. As such, it is unnecessary to keep a +long-lived reference, for instance in an class instance field, to a +ViewStub.

        + +

        A ViewStub is a great compromise between ease of programming and +efficiency. Instead of inflating views manually and adding them at runtime to +your view hierarchy, simply use a ViewStub. It's cheap and easy. +The only drawback of ViewStub is that it currently does +not support the <merge /> +tag.

        diff --git a/docs/html/resources/articles/listview-backgrounds.jd b/docs/html/resources/articles/listview-backgrounds.jd new file mode 100644 index 0000000..f4c6998 --- /dev/null +++ b/docs/html/resources/articles/listview-backgrounds.jd @@ -0,0 +1,86 @@ +page.title=ListView Backgrounds: An Optimization +@jd:body + +

        {@link android.widget.ListView} is one of Android's most widely used widgets. +It is rather easy to use, very flexible, and incredibly powerful. +ListView can also be difficult to understand at times.

        + +

        One of the most common issues with ListView happens when you try +to use a custom background. By default, like many Android widgets, +ListView has a transparent background which means that you can see +through the default window's background, a very dark gray +(#FF191919 with the current dark theme.) Additionally, +ListView enables the fading edges by default, as you can +see at the top of the following screenshot — the first text item gradually +fades to black. This technique is used throughout the system to indicate that +the container can be scrolled.

        + +
        Android's default ListView
        + +

        The fade effect is implemented using a combination of +{@link android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int) Canvas.saveLayerAlpha()} +and the {@link android.graphics.PorterDuff.Mode#DST_OUT Porter-Duff Destination Out blending mode}.

        + +

        Unfortunately, things start to get ugly when you try to use a custom +background on the ListView or when you change the window's +background. The following two screenshots show what happens in an application +when you change the window's background. The left image shows what the list +looks like by default and the right image shows what the list looks like during +a scroll initiated with a touch gesture:

        + +
        +Dark fade +Dark list
        + +

        This rendering issue is caused by an optimization of the Android framework +enabled by default on all instances of ListView. I mentioned +earlier that the fade effect is implemented using a Porter-Duff blending mode. +This implementation works really well but is unfortunately very costly and can +bring down drawing performance by quite a bit as it requires to capture a +portion of the rendering in an offscreen bitmap and then requires extra blending +(which implies readbacks from memory.)

        + +

        Since ListView is most of the time displayed on a solid +background, there is no reason to go down that expensive route. That's why we +introduced an optimization called the "cache color hint." The cache color hint +is an RGB color set by default to the window's background color, that is #191919 +in Android's dark theme. When this hint is set, ListView (actually, +its base class View) knows it will draw on a solid background and +therefore replaces th expensive saveLayerAlpha()/Porter-Duff +rendering with a simple gradient. This gradient goes from fully transparent to +the cache color hint value and this is exactly what you see on the image above, +with the dark gradient at the bottom of the list. However, this still does not +explain why the entire list turns black during a scroll.

        + +

        As mentioned before, ListView has a transparent/translucent +background by default, and so all default widgets in the Android UI toolkit. +This implies that when ListView redraws its children, it has to +blend the children with the window's background. Once again, this requires +costly readbacks from memory that are particularly painful during a scroll or a +fling when drawing happens dozen of times per second.

        + +

        To improve drawing performance during scrolling operations, the Android +framework reuses the cache color hint. When this hint is set, the framework +copies each child of the list in a Bitmap filled with the hint +value (assuming that another optimization, called scrolling cache, is +not turned off). ListView then blits these bitmaps directly on +screen and because these bitmaps are known to be opaque, no blending is +required. Also, since the default cache color hint is #191919, you +get a dark background behind each item during a scroll.

        + +

        To fix this issue, all you have to do is either disable the cache color hint +optimization, if you use a non-solid color background, or set the hint to the +appropriate solid color value. You can do this from code (see +{@link android.widget.AbsListView#setCacheColorHint(int)}) or preferably from +XML, by using the android:cacheColorHint attribute. To disable the +optimization, simply use the transparent color #00000000. The +following screenshot shows a list with +android:cacheColorHint="#00000000" set in the XML layout file:

        + +
        Fade on a custom background
        + +

        As you can see, the fade works perfectly against the custom wooden +background. The cache color hint feature is interesting because it +shows how optimizations can make your life more difficult in +some situations. In this particular case, however, the benefit of the +default behavior outweighs the added complexity..

        diff --git a/docs/html/resources/articles/live-folders.jd b/docs/html/resources/articles/live-folders.jd new file mode 100644 index 0000000..be974f4 --- /dev/null +++ b/docs/html/resources/articles/live-folders.jd @@ -0,0 +1,168 @@ +page.title=Live Folders +@jd:body + +

        Live folders, introduced in Android 1.5 (API Level 3), let you display any source of data +on the Home screen without forcing the user to launch an application. A live +folder is simply a real-time view of a {@link android.content.ContentProvider}. +As such, a live folder can be used to display all of the user's contacts or +bookmarks, email, playlists, an RSS feed, and so on. The possibilities are +endless!

        + +

        The platform includes several standard folders for displaying contacts. For +instance, the screenshot below shows the content of the live folders that +displays all contacts with a phone number:

        + + + +

        If a contacts sync happens in the background while the user is browsing this live +folder, the user will see the change happen in real-time. Live folders are not +only useful, but they are also easy to add to to your application and data. + +This articles shows how to add a live folder to an example application called +Shelves. To better understand how live folders work, you can download the source code of the +application and modify it by following the instructions below.

        + +

        To give the user the option to create a new live folder for an application, +you first need to create a new activity with an intent filter whose action is +android.intent.action.CREATE_LIVE_FOLDER. To do so, simply open +AndroidManifest.xml and add something similar to this:

        + +
        <activity
        +    android:name=".activity.BookShelfLiveFolder"
        +    android:label="BookShelf">
        +    <intent-filter>	
        +        <action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
        +        <category android:name="android.intent.category.DEFAULT" />
        +    </intent-filter>
        +</activity>
        + +

        The label and icon of this activity are what the user will see on the Home +screen when choosing a live folder to create:

        + + + +

        Since you just need an intent filter, it is possible, and sometimes advised, +to reuse an existing activity. In the case of Shelves, we will create a new +activity, org.curiouscreature.android.shelves.activity.BookShelfLiveFolder. +The role of this activity is to send an Intent result to Home +containing the description of the live folder: its name, icon, display mode and +content URI. The content URI is very important as it describes what +ContentProvider will be used to populate the live folder. The code +of the activity is very simple as you can see here:

        + +
        public class BookShelfLiveFolder extends Activity {
        +    public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books");
        +
        +    @Override
        +    protected void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +
        +        final Intent intent = getIntent();
        +        final String action = intent.getAction();
        +
        +        if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
        +            setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI,
        +                    "Books", R.drawable.ic_live_folder));
        +        } else {
        +            setResult(RESULT_CANCELED);
        +        }
        +
        +        finish();
        +    }
        +
        +    private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) {
        +        final Intent intent = new Intent();
        +
        +        intent.setData(uri);
        +        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
        +        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
        +                Intent.ShortcutIconResource.fromContext(context, icon));
        +        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);
        +
        +        return intent;
        +    }
        +}
        + +

        This activity, when invoked with theACTION_CREATE_LIVE_FOLDER +intent, returns an intent with a URI, +content://shelves/live_folders/books, and three extras to describe +the live folder. There are other extras and constants you can use and you should +refer to the documentation of android.provider.LiveFolders for more +details. When Home receives this intent, a new live folder is created on the +user's desktop, with the name and icon you provided. Then, when the user clicks +on the live folder to open it, Home queries the content provider referenced by +the provided URI.

        + +

        Live folders' content providers must obey specific naming rules. The +Cursor returned by the query() method must have at +least two columns named LiveFolders._ID and +LiveFolders.NAME. The first one is the unique identifier of each +item in the live folder and the second one is the name of the item. There are +other column names you can use to specify an icon, a description, the intent to +associate with the item (fired when the user clicks that item), etc. Again, +refer to the documentation of android.provider.LiveFolders for more +details.

        In our example, all we need to do is modify the existing provider +in Shelves called +org.curiouscreature.android.shelves.provider.BooksProvider. First, +we need to modify the URI_MATCHER to recognize our +content://shelves/live_folders/books content URI:

        + +
        private static final int LIVE_FOLDER_BOOKS = 4;
        +// ...
        +URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS);
        + +

        Then we need to create a new projection map for the cursor. A projection map +can be used to "rename" columns. In our case, we will replace +BooksStore.Book._ID, BooksStore.Book.TITLE and +BooksStore.Book.AUTHORS with LiveFolders._ID, +LiveFolders.TITLE and LiveFolders.DESCRIPTION:

        + +
        private static final HashMap<string, string=""> LIVE_FOLDER_PROJECTION_MAP;
        +static {
        +    LIVE_FOLDER_PROJECTION_MAP = new HashMap<string, string="">();
        +    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID +
        +            " AS " + LiveFolders._ID);
        +    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE +
        +            " AS " + LiveFolders.NAME);
        +    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS +
        +            " AS " + LiveFolders.DESCRIPTION);
        +}
        + +

        Because we are providing a title and a description for each row, Home will +automatically display each item of the live folder with two lines of text. +Finally, we implement the query() method by supplying our +projection map to the SQL query builder:

        + +
        public Cursor query(Uri uri, String[] projection, String selection,
        +        String[] selectionArgs, String sortOrder) {
        +
        +    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        +
        +    switch (URI_MATCHER.match(uri)) {
        +        // ...
        +        case LIVE_FOLDER_BOOKS:
        +            qb.setTables("books");
        +            qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP);
        +            break;
        +        default:
        +            throw new IllegalArgumentException("Unknown URI " + uri);
        +    }
        +
        +    SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        +    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER);
        +    c.setNotificationUri(getContext().getContentResolver(), uri);
        +
        +    return c;
        +}
        + +

        You can now compile and deploy the application, go to the Home screen and +try to add a live folder. You can add a books live folder to your Home screen +and when you open it, see the list of all of your books, with their +titles and authors, and all it took was a few lines of code:

        + +

        + +

        The live folders API is extremely simple and relies only on intents and +content URI. If you want to see more examples of live folders +implementation, you can read the source code of the Contacts application and of the Contacts provider.

        You can also download the result of our exercise, the modified version of Shelves with live folders support.

        \ No newline at end of file diff --git a/docs/html/resources/articles/on-screen-inputs.jd b/docs/html/resources/articles/on-screen-inputs.jd new file mode 100644 index 0000000..057325a --- /dev/null +++ b/docs/html/resources/articles/on-screen-inputs.jd @@ -0,0 +1,249 @@ +page.title=Onscreen Input Methods +@jd:body + + +

        Starting from Android 1.5, the Android platform offers an Input Method +Framework (IMF) that lets you create on-screen input methods such as software +keyboards. This article provide an overview of what Android input method editors +(IMEs) are and what an application needs to do to work well with them. The IMF +is designed to support new classes of Android devices, such as those without +hardware keyboards, so it is important that your application works well with the +IMF and offers a great experience for users.

        + +

        What is an input method?

        + +

        The Android IMF is designed to support a variety of IMEs, including soft +keyboard, hand-writing recognizers, and hard keyboard translators. Our focus, +however, will be on soft keyboards, since this is the kind of input method that +is currently part of the platform.

        + +

        A user will usually access the current IME by tapping on a text view to +edit, as shown here in the home screen:

        + + + + +

        The soft keyboard is positioned at the bottom of the screen over the +application's window. To organize the available space between the application +and IME, we use a few approaches; the one shown here is called pan and +scan, and simply involves scrolling the application window around so that +the currently focused view is visible. This is the default mode, since it is the +safest for existing applications.

        + +

        Most often the preferred screen layout is a resize, where the +application's window is resized to be entirely visible. An example is shown +here, when composing an e-mail message:

        + + + + +

        The size of the application window is changed so that none of it is hidden by +the IME, allowing full access to both the application and IME. This of course +only works for applications that have a resizeable area that can be reduced to +make enough space, but the vertical space in this mode is actually no less than +what is available in landscape orientation, so very often an application can +already accommodate it.

        + +

        The final major mode is fullscreen or extract +mode. This is used when the IME is too large to reasonably share space +with the underlying application. With the standard IMEs, you will only +encounter this situation when the screen is in a landscape orientation, +although other IMEs are free to use it whenever they desire. In this +case the application window is left as-is, and the IME simply displays +fullscreen on top of it, as shown here:

        + + + + +

        Because the IME is covering the application, it has its own editing area, +which shows the text actually contained in the application. There are also some +limited opportunities the application has to customize parts of the IME (the +"done" button at the top and enter key label at the bottom) to improve the user +experience.

        + +

        Basic XML attributes for controlling IMEs

        + +

        There are a number of things the system does to try to help existing +applications work with IMEs as well as possible, such as:

        + +
          +
        • Use pan and scan mode by default, unless it can reasonably guess that +resize mode will work by the existence of lists, scroll views, etc.
        • +
        • Analyze the various existing TextView attributes to guess at the kind of +content (numbers, plain text, etc) to help the soft keyboard display an +appropriate key layout.
        • +
        • Assign a few default actions to the fullscreen IME, such as "next field" +and "done".
        • +
        + +

        There are also some simple things you can do in your application that will +often greatly improve its user experience. Except where explicitly mentioned, +these will work in any Android platform version, even those previous to Android +1.5 (since they will simply ignore these new options).

        + +

        Specifying each EditText control's input type

        + +

        The most important thing for an application to do is to use the new +android:inputType +attribute on each EditText. The attribute provides much richer +information +about the text content. This attribute actually replaces many existing +attributes (android:password, +android:singleLine, +android:numeric, +android:phoneNumber, +android:capitalize, +android:autoText, and +android:editable). If you specify the older attributes +and the new android:inputType attribute, the system uses +android:inputType and ignores the others.

        + +

        The android:inputType attribute has three pieces:

        + +
          +
        • The class is the overall interpretation of characters. The +currently supported classes are text (plain text), +number (decimal number), phone (phone number), and +datetime (a date or time).
        • +
        • The variation is a further refinement on the class. In the +attribute you will normally specify the class and variant together, with the +class as a prefix. For example, textEmailAddress is a text field +where the user will enter something that is an e-mail address (foo@bar.com) so +the key layout will have an '@' character in easy access, and +numberSigned is a numeric field with a sign. If only the class is +specified, then you get the default/generic variant.
        • +
        • Additional flags can be specified that supply further refinement. +These flags are specific to a class. For example, some flags for the +text class are textCapSentences, +textAutoCorrect, and textMultiline.
        • +
        + +

        As an example, here is the new EditText for the IM application's message text view:

        + +
            <EditText android:id="@+id/edtInput"
        +        android:layout_width="0dip"
        +        android:layout_height="wrap_content"
        +        android:layout_weight="1"
        +        android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
        +        android:imeOptions="actionSend|flagNoEnterAction"
        +        android:maxLines="4"
        +        android:maxLength="2000"
        +        android:hint="@string/compose_hint"/>
        + +

        A full description of all of the input types can be found in the +documentation. It is important to make use of the correct input types that are +available, so that the soft keyboard can use the optimal keyboard layout for the +text the user will be entering.

        + +

        Enabling resize mode and other window features

        + +

        The second most important thing for your app to do is to specify the overall +behavior of your window in relation to the input method. The most visible aspect +of this is controlling resize vs. pan and scan mode, but there are other things +you can do as well to improve your user experience.

        + +

        You will usually control this behavior through the +android:windowSoftInputMode attribute on each +<activity> definition in your +AndroidManifest.xml. Like the input type, there are a couple +different pieces of data that can be specified here by combining them +together:

        + +
          +
        • The window adjustment mode is specified with either +adjustResize or adjustPan. It is highly recommended +that you always specify one or the other.
        • +
        • You can further control whether the IME will be shown automatically when +your activity is displayed and other situations where the user moves to it. The +system won't automatically show an IME by default, but in some cases it can be +convenient for the user if an application enables this behavior. You can request +this with stateVisible. There are also a number of other state +options for finer-grained control that you can find in the documentation.
        • +
        + +

        A typical example of this field can be see in the edit contact activity, +which ensures it is resized and automatically displays the IME for the user:

        + +
            <activity name="EditContactActivity"
        +        android:windowSoftInputMode="stateVisible|adjustResize">
        +        ...
        +    </activity>
        + +

        Note:Starting from Android 1.5 (API Level 3), +the platform offers a new method, +{@link android.view.Window#setSoftInputMode(int mode)}, +that non-Activity windows can use to control their behavior. Calling this method +in your will make your application incompatible with previous versions of the +Android platform.

        + +

        Controlling the action buttons

        + +

        The final customization we will look at is the "action" buttons in the IME. +There are currently two types of actions:

        + +
          +
        • The enter key on a soft keyboard is typically bound to an action when not +operating on a mult-line edit text. For example, on the G1 pressing the hard +enter key will typically move to the next field or the application will +intercept it to execute an action; with a soft keyboard, this overloading of the +enter key remains, since the enter button just sends an enter key event.
        • +
        • When in fullscreen mode, an IME may also put an additional action button to +the right of the text being edited, giving the user quick access to a common +application operation.
        • +
        + +

        These options are controlled with the android:imeOptions +attribute on TextView. The value you supply here can be any +combination of:

        + +
          +
        • One of the pre-defined action constants (actionGo, +actionSearch, actionSend, actionNext, +actionDone). If none of these are specified, the system will infer +either actionNext or actionDone depending on whether +there is a focusable field after this one; you can explicitly force no action +with actionNone.
        • +
        • The flagNoEnterAction option tells the IME that the action +should not be available on the enter key, even if the text itself is +not multi-line. This avoids having unrecoverable actions like (send) that can be +accidentally touched by the user while typing.
        • +
        • The flagNoAccessoryAction removes the action button from the +text area, leaving more room for text.
        • The flagNoExtractUi +completely removes the text area, allowing the application to be seen behind +it.
        • +
        + +

        The previous IM application message view also provides an example of an +interesting use of imeOptions, to specify the send action but not +let it be shown on the enter key:

        + +
        android:imeOptions="actionSend|flagNoEnterAction"
        + +

        APIs for controlling IMEs

        + +

        For more advanced control over the IME, there are a variety of new APIs you +can use. Unless special care is taken (such as by using reflection), using these +APIs will cause your application to be incompatible with previous versions of +Android, and you should make sure you specify +android:minSdkVersion="3" in your manifest. For more information, +see the documentation for the <uses-sdk> manifest element.

        + +

        The primary API is the new android.view.inputmethod.InputMethodManager class, which you can retrieve with Context.getSystemService(). +It allows you to interact with the global input method state, such as +explicitly hiding or showing the current IME's input area.

        + +

        There are also new window flags controlling input method interaction, which you can control through the existing Window.addFlags() method and new Window.setSoftInputMode() method. The PopupWindow +class has grown corresponding methods to control these options on its +window. One thing in particular to be aware of is the new WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM constant, which is used to control whether a window is on top of or behind the current IME.

        + +

        Most of the interaction between an active IME and application is done through the android.view.inputmethod.InputConnection +class. This is the API an application implement, which an IME calls to +perform the appropriate edit operations on the application. You won't +normally need to worry about this, since TextView provides its own implementation for itself.

        + +

        There are also a handful of new View APIs, the most important of these being onCreateInputConnection() which creates a new InputConnection for an IME (and fills in an android.view.inputmethod.EditorInfo +structure with your input type, IME options, and other data); again, +most developers won't need to worry about this, since TextView takes +care of it for you.

        \ No newline at end of file diff --git a/docs/html/resources/articles/painless-threading.jd b/docs/html/resources/articles/painless-threading.jd new file mode 100644 index 0000000..921f4df --- /dev/null +++ b/docs/html/resources/articles/painless-threading.jd @@ -0,0 +1,147 @@ +page.title=Painless Threading +@jd:body + +

        This article discusses the threading model used by Android applications and how applications can ensure best UI performance by spawning worker threads to handle long-running operations, rather than handling them in the main thread. The article also explains the API that your application can use to interact with Android UI toolkit components running on the main thread and spawn managed worker threads.

        + +

        The UI thread

        + +

        When an application is launched, the system creates a thread called +"main" for the application. The main thread, also called the UI +thread, is very important because it is in charge of dispatching the +events to the appropriate widgets, including drawing events. +It is also the thread where your application interacts with running +components of the Android UI toolkit.

        + +

        For instance, if you touch the a button on screen, the UI thread dispatches +the touch event to the widget, which in turn sets its pressed state and +posts an invalidate request to the event queue. The UI thread dequeues +the request and notifies the widget to redraw itself.

        + +

        This single-thread model can yield poor performance unless your application +is implemented properly. Specifically, if everything is happening in a single +thread, performing long operations such as network access or database +queries on the UI thread will block the whole user interface. No event +can be dispatched, including drawing events, while the long operation +is underway. From the user's perspective, the application appears hung. +Even worse, if the UI thread is blocked for more than a few seconds +(about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog.

        + +

        If you want to see how bad this can look, write a simple application +with a button that invokes Thread.sleep(2000) in its +OnClickListener. +The button will remain in its pressed state for about 2 seconds before +going back to its normal state. When this happens, it is very easy for +the user to perceive the application as slow.

        + +

        To summarize, it's vital to the responsiveness of your application's UI to +keep the UI thread unblocked. If you have long operations to perform, you should +make sure to do them in extra threads (background or worker +threads).

        + +

        Here's an example of a click listener downloading an image over the +network and displaying it in an ImageView:

        + +
        public void onClick(View v) {
        +  new Thread(new Runnable() {
        +    public void run() {
        +      Bitmap b = loadImageFromNetwork();
        +      mImageView.setImageBitmap(b);
        +    }
        +  }).start();
        +}
        + +

        At first, this code seems to be a good solution to your problem, as it does +not block the UI thread. Unfortunately, it violates the single-threaded model +for the UI: the Android UI toolkit is not thread-safe and must always +be manipulated on the UI thread. In this piece of code above, the +ImageView is manipulated on a worker thread, which can cause really +weird problems. Tracking down and fixing such bugs can be difficult and +time-consuming.

        + +

        Android offers several ways to access the UI +thread from other threads. You may already be familiar with some of +them but here is a comprehensive list:

        + +
          +
        • {@link android.app.Activity#runOnUiThread(java.lang.Runnable) Activity.runOnUiThread(Runnable)}
        • +
        • {@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}
        • +
        • {@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable, long)}
        • +
        • {@link android.os.Handler}
        • +
        + +

        You can use any of these classes and methods to correct the previous code example:

        + +
        public void onClick(View v) {
        +  new Thread(new Runnable() {
        +    public void run() {
        +      final Bitmap b = loadImageFromNetwork();
        +      mImageView.post(new Runnable() {
        +        public void run() {
        +          mImageView.setImageBitmap(b);
        +        }
        +      });
        +    }
        +  }).start();
        +}
        + +

        Unfortunately, +these classes and methods could also tend to make your code more complicated +and more difficult to read. It becomes even worse when your implement +complex operations that require frequent UI updates.

        + +

        To remedy this problem, Android 1.5 and later platforms offer a utility class +called {@link android.os.AsyncTask}, that simplifies the creation of +long-running tasks that need to communicate with the user interface.

        + +

        An AsyncTask equivalent is also available for applications that +will run on Android 1.0 and 1.1. The name of the class is UserTask. It offers the +exact same API and all you have to do is copy its source code in your +application.

        + +

        The goal of AsyncTask is to take care of thread management for +you. Our previous example can easily be rewritten with +AsyncTask:

        + +
        public void onClick(View v) {
        +  new DownloadImageTask().execute("http://example.com/image.png");
        +}
        +
        +private class DownloadImageTask extends AsyncTask<string, void,="" bitmap=""> {
        +     protected Bitmap doInBackground(String... urls) {
        +         return loadImageFromNetwork(urls[0]);
        +     }
        +
        +     protected void onPostExecute(Bitmap result) {
        +         mImageView.setImageBitmap(result);
        +     }
        + }
        + +

        As you can see, AsyncTask must be used by subclassing +it. It is also very important to remember that an AsyncTask +instance has to be created on the UI thread and can be executed only once. You +can read the +AsyncTask documentation for a full understanding on how to use this class, +but here is a quick overview of how it works:

        + + + +

        In addition to the official documentation, you can read several complex examples in the source code of Shelves (ShelvesActivity.java and AddBookActivity.java) and Photostream (LoginActivity.java, PhotostreamActivity.java and ViewPhotoActivity.java). We highly recommend reading the source code of Shelves to see how to persist tasks across configuration changes and how to cancel them properly when the activity is destroyed.

        + +

        Regardless of whether or not you use AsyncTask, +always remember these two rules about the single thread model:

        + +
          +
        1. Do not block the UI thread, and +
        2. Make sure that you access the Android UI toolkit only on the UI thread. +
        + +

        AsyncTask just makes it easier to do both of these things.

        diff --git a/docs/html/resources/articles/qsb.jd b/docs/html/resources/articles/qsb.jd new file mode 100644 index 0000000..1249f21 --- /dev/null +++ b/docs/html/resources/articles/qsb.jd @@ -0,0 +1,151 @@ +page.title=Quick Search Box +@jd:body + +

        + +

        Starting with Android 1.6, the platform includes support for Quick Search +Box (QSB), a powerful, system-wide search framework. Quick Search Box makes it +possible for users to quickly and easily find what they're looking for, both on +their devices and on the web. It suggests content on your device as you type, +like apps, contacts, browser history, and music. It also offers results from the +web search suggestions, local business listings, and other info from +Google, such as stock quotes, weather, and flight status. All of this is +available right from the home screen, by tapping on Quick Search Box.

        + +

        What +we're most excited about with this new feature is the ability for you, +the developers, to leverage the QSB framework to provide quicker and +easier access to the content inside your apps. Your apps can provide +search suggestions that will surface to users in QSB alongside other +search results and suggestions. This makes it possible for users to +access your application's content from outside your application—for +example, from the home screen.

        + +

        Note: The code fragments in this document are +related to a sample app called Searchable Dictionary. The app is +available for Android 1.6 and later platforms.

        + +

        The story before now: searching within your app

        + +

        Platform releases versions previous to Android 1.6 already provided a mechanism +that let you expose search and search suggestions in your app, as described in +the docs for {@link android.app.SearchManager}. That mechanism has not changed +and requires the following two things in your +AndroidManifest.xml:

        + +

        1) In your <activity>, an intent filter, and a reference +to a searchable.xml file (described below):

        + +
        <intent-filter>
        +    <action android:name="android.intent.action.SEARCH" />
        +    <category android:name="android.intent.category.DEFAULT" />
        +</intent-filter>
        +            
        +<meta-data android:name="android.app.searchable"
        +       android:resource="@xml/searchable" />
        + +

        2) A content provider that can provide search suggestions according to the +URIs and column formats specified by the +Search Suggestions +section of the SearchManager docs:

        + +
        <!-- Provides search suggestions for words and their definitions. -->
        +<provider android:name="DictionaryProvider"
        +       android:authorities="dictionary"
        +       android:syncable="false" />
        + +

        In the searchable.xml file, you specify a few things about how +you want the search system to present search for your app, including the +authority of the content provider that provides suggestions for the user as they +type. Here's an example of the searchable.xml of an Android app +that provides search suggestions within its own activities:

        + +
        <searchable xmlns:android="http://schemas.android.com/apk/res/android"
        +        android:label="@string/search_label"
        +        android:searchSuggestAuthority="dictionary"
        +        android:searchSuggestIntentAction="android.intent.action.VIEW">
        +</searchable>
        + +

        Note that the android:searchSuggestAuthority attribute refers to +the authority of the content provider we declared in +AndroidManifest.xml.

        + +

        For more details on this, see the +Searchability Metadata +section of the of the SearchManager docs.

        + +

        Including your app in Quick Search Box

        + + + +

        In Android 1.6, we added a new attribute to the metadata for searchables: +android:includeInGlobalSearch. By specifying this as +"true" in your searchable.xml, you allow QSB to pick +up your search suggestion content provider and include its suggestions along +with the rest (if the user enables your suggestions from the system search +settings).

        + +

        You should also specify a string value for +android:searchSettingsDescription, which describes to users what +sorts of suggestions your app provides in the system settings for search.

        + +
        <searchable xmlns:android="http://schemas.android.com/apk/res/android"
        +       android:label="@string/search_label"
        +       android:searchSettingsDescription="@string/settings_description"
        +       android:includeInGlobalSearch="true"
        +       android:searchSuggestAuthority="dictionary"
        +       android:searchSuggestIntentAction="android.intent.action.VIEW">
        +</searchable>
        + +

        These new attributes are supported only in Android 1.6 and later.

        + +

        What to expect

        + +

        The +first and most important thing to note is that when a user installs an +app with a suggestion provider that participates in QSB, this new app +will not be enabled for QSB by default. The user can choose +to enable particular suggestion sources from the system settings for +search (by going to "Search" > "Searchable items" in settings).

        + +

        You +should consider how to handle this in your app. Perhaps show a notice +that instructs the user to visit system settings and enable your app's +suggestions.

        + +

        Once the user enables your searchable item, the +app's suggestions will have a chance to show up in QSB, most likely +under the "more results" section to begin with. As your app's +suggestions are chosen more frequently, they can move up in the list.

        + + + + +

        Shortcuts

        + +

        One +of our objectives with QSB is to make it faster for users to access the +things they access most often. One way we've done this is by +'shortcutting' some of the previously chosen search suggestions, so +they will be shown immediately as the user starts typing, instead of +waiting to query the content providers. Suggestions from your app may +be chosen as shortcuts when the user clicks on them.

        + +

        For dynamic suggestions that may wish to change their content (or become invalid) +in the future, you can provide a 'shortcut id'. This tells QSB to query +your suggestion provider for up-to-date content for a suggestion after +it has been displayed. For more details on how to manage shortcuts, see +the Shortcuts section +within the SearchManager docs.

        diff --git a/docs/html/resources/articles/timed-ui-updates.jd b/docs/html/resources/articles/timed-ui-updates.jd new file mode 100644 index 0000000..863387c --- /dev/null +++ b/docs/html/resources/articles/timed-ui-updates.jd @@ -0,0 +1,149 @@ +page.title=Updating the UI from a Timer +@jd:body + + + +

        Background: While developing my first useful +(though small) application for Android, which was a port of an existing +utility I use when podcasting, I needed a way of updating a clock +displayed on the UI at regular intervals, but in a lightweight and CPU +efficient way.

        + +

        Problem: In the original application I used +java.util.Timer to update the clock, but that class is not such a good +choice on Android. Using a Timer introduces a new thread into the +application for a relatively minor reason. Thinking in terms of mobile +applications often means re-considering choices that you might make +differently for a desktop application with relatively richer resources +at its disposal. We would like to find a more efficient way of updating +that clock.

        + +

        The Application: The original application is a +Java Swing and SE application. It is like a stopwatch with a lap timer +that we use when recording podcasts; when you start the recording, you +start the stopwatch. Then for every mistake that someone makes, you hit +the flub button. At the end you can save out the bookmarked mistakes +which can be loaded into the wonderful +Audacity +audio editor as a labels track. You can then see where all of the mistakes +are in the recording and edit them out.

        + +

        The article describing it is: http://www.developer.com/java/ent/print.php/3589961

        + +

        In the original version, the timer code looked like this:

        + +
        class UpdateTimeTask extends TimerTask {
        +   public void run() {
        +       long millis = System.currentTimeMillis() - startTime;
        +       int seconds = (int) (millis / 1000);
        +       int minutes = seconds / 60;
        +       seconds     = seconds % 60;
        +
        +       timeLabel.setText(String.format("%d:%02d", minutes, seconds));
        +   }
        +}

        And in the event listener to start this update, the following Timer() instance is used: +

        if(startTime == 0L) {
        +   startTime = evt.getWhen();
        +   timer = new Timer();
        +   timer.schedule(new UpdateTimeTask(), 100, 200);
        +}
        + +

        In particular, note the 100, 200 parameters. The first parameter +means wait 100 ms before running the clock update task the first time. +The second means repeat every 200ms after that, until stopped. 200 ms +should not be too noticeable if the second resolution happens to fall +close to or on the update. If the resolution was a second, you could +find the clock sometimes not updating for close to 2 seconds, or +possibly skipping a second in the counting, it would look odd).

        + +

        When I ported the application to use the Android SDKs, this code +actually compiled in Eclipse, but failed with a runtime error because +the Timer() class was not available at runtime (fortunately, this was +easy to figure out from the error messages). On a related note, the +String.format method was also not available, so the eventual solution +uses a quick hack to format the seconds nicely as you will see.

        + +

        Fortunately, the role of Timer can be replaced by the +android.os.Handler class, with a few tweaks. To set it up from an event +listener:

        + +
        private Handler mHandler = new Handler();
        +
        +...
        +
        +OnClickListener mStartListener = new OnClickListener() {
        +   public void onClick(View v) {
        +       if (mStartTime == 0L) {
        +            mStartTime = System.currentTimeMillis();
        +            mHandler.removeCallbacks(mUpdateTimeTask);
        +            mHandler.postDelayed(mUpdateTimeTask, 100);
        +       }
        +   }
        +};
        + +

        A couple of things to take note of here. First, the event doesn't +have a .getWhen() method on it, which we handily used to set the start +time for the timer. Instead, we grab the System.currentTimeMillis(). +Also, the Handler.postDelayed() method only takes one time parameter, +it doesn't have a "repeating" field. In this case we are saying to the +Handler "call mUpdateTimeTask() after 100ms", a sort of fire and forget +one time shot. We also remove any existing callbacks to the handler +before adding the new handler, to make absolutely sure we don't get +more callback events than we want.

        + +

        But we want it to repeat, until we tell it to stop. To do this, just +put another postDelayed at the tail of the mUpdateTimeTask run() +method. Note also that Handler requires an implementation of Runnable, +so we change mUpdateTimeTask to implement that rather than extending +TimerTask. The new clock updater, with all these changes, looks like +this:

        + +
        private Runnable mUpdateTimeTask = new Runnable() {
        +   public void run() {
        +       final long start = mStartTime;
        +       long millis = SystemClock.uptimeMillis() - start;
        +       int seconds = (int) (millis / 1000);
        +       int minutes = seconds / 60;
        +       seconds     = seconds % 60;
        +
        +       if (seconds < 10) {
        +           mTimeLabel.setText("" + minutes + ":0" + seconds);
        +       } else {
        +           mTimeLabel.setText("" + minutes + ":" + seconds);            
        +       }
        +     
        +       mHandler.postAtTime(this,
        +               start + (((minutes * 60) + seconds + 1) * 1000));
        +   }
        +};
        + +

        and can be defined as a class member field.

        + +

        The if statement is just a way to make sure the label is set to +10:06 instead of 10:6 when the seconds modulo 60 are less than 10 +(hopefully String.format() will eventually be available). At the end of +the clock update, the task sets up another call to itself from the +Handler, but instead of a hand-wavy 200ms before the update, we can +schedule it to happen at a particular wall-clock time — the line: start ++ (((minutes * 60) + seconds + 1) * 1000) does this.

        + +

        All we need now is a way to stop the timer when the stop button +is pressed. Another button listener defined like this:

        + +
        OnClickListener mStopListener = new OnClickListener() {
        +   public void onClick(View v) {
        +       mHandler.removeCallbacks(mUpdateTimeTask);
        +   }
        +};
        + +

        will make sure that the next callback is removed when the stop button +is pressed, thus interrupting the tail iteration.

        + +

        Handler is actually a better choice than Timer for another reason +too. The Handler runs the update code as a part of your main thread, +avoiding the overhead of a second thread and also making for easy +access to the View hierarchy used for the user interface. Just remember +to keep such tasks small and light to avoid slowing down the user +experience.

        + + diff --git a/docs/html/resources/articles/touch-mode.jd b/docs/html/resources/articles/touch-mode.jd new file mode 100644 index 0000000..e340062 --- /dev/null +++ b/docs/html/resources/articles/touch-mode.jd @@ -0,0 +1,138 @@ +page.title=Touch Mode +@jd:body + +

        This article explains the touch mode, one of the most +important principles of Android's UI toolkit.

        + +

        The touch mode is a state of the view hierarchy that depends solely on the +user interaction with the phone. By itself, the touch mode is something very +easy to understand as it simply indicates whether the last user interaction was +performed with the touch screen. For example, if you are using an +Android-powered device, selecting a widget with the trackball will take you out +of touch mode; however, if you touch a button on the screen with your finger, +you will enter touch mode. When the user is not in touch mode, we talk about the +trackball mode, navigation mode or keyboard navigation, so do not be surprised +if you encounter these terms.

        + +

        There is only one API directly related to touch mode, +{@link android.view.View#isInTouchMode() View.isInTouchMode()}.

        + +

        Sounds easy enough, right? Oddly enough, touch mode is deceivingly simple and +the consequences of entering touch mode are far greater than you might +think. Let's look at some of the reasons why.

        + +

        Touch Mode, Selection, and Focus

        + +

        Designing a UI toolkit for mobile devices is difficult because of the various +interaction mechanisms they provide. Some devices offer only 12 keys, some have +a touch screen, some require a stylus, some have both a touch screen and a +keyboard. Based on the hardware capabilities of the he user can interact with +your application using different mechanisms, so we had to think very hard about +all the possible issues that could arise. One issue led us to create the touch +mode.

        + +

        Imagine a simple application, ApiDemos +for example, that shows a list of text items. The user can freely +navigate through the list using the trackball but also, alternatively, scroll +and fling the list using the touch screen. The issue in this scenario is +how to handle the selection properly when the user manipulates the list +through the touch screen.

        + +

        In this case, if the user selects an item at the top of the list and then +flings the list towards the bottom, what should happen to the selection? Should +it remain on the item and scroll off the screen? What should happen if the user +then decided to move the selection with the trackball? Or worse, what should +happen if the user presses the trackball to act upon the currently selected +item, which is not shown on screen anymore?

        + +

        After careful consideration, we decided to remove the selection altogether, +when the user manipulates the UI through the touch screen.

        + +

        In touch mode, there is no focus and no selection. Any selected item in a +list of in a grid becomes unselected as soon as the user enters touch +mode. Similarly, any focused widgets become unfocused when the user +enters touch mode. The image below illustrates what happens when the +user touches a list after selecting an item with the trackball.

        + + + + +

        To +make things more natural for the user, the framework knows how to +resurrect the selection/focus whenever the user leaves touch mode. For +instance, in the example above, if the user were to use the trackball +again, the selection would reappear on the previously-selected item. +This is why some developers are confused when they create a custom view +and start receiving key events only after moving the trackball once: +their application is in touch mode, and they need to use the trackball +to exit touch mode and resurrect the focus.

        + +

        The relationship between touch mode, selection, and focus means you must not +rely on selection and/or focus to exist in your application. A very common +problem with new Android developers is to rely on +{@link android.widget.AdapterView#getSelectedItemPosition() ListView.getSelectedItemPosition()}. +In touch mode, this method will return +{@link android.widget.AdapterView#INVALID_POSITION INVALID_POSITION}. + You should instead use click listeners (see +{@link android.widget.AdapterView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)}) +or the choice mode (see +{@link android.widget.ListView#setChoiceMode(int)}).

        + +

        Focusable in Touch Mode

        + +

        In general, focus doesn't exist in touch mode. However, focus can exist in +touch mode in a very special way called focusable. This special mode +was created for widgets that receive text input, such as +{@link android.widget.EditText} or, when filtering is enabled, +{@link android.widget.ListView}. The focusable mode is what lets the user enter text +inside a text field on the screen, without first selecting it with the trackball +or their finger.

        + +

        When a user +touches the screen, the application will enter touch mode if it wasn't +in touch mode already. What happens during the transition to +touch mode depends on what the user touched, and what currently has +focus. If the user touches a widget that is focusable in touch +mode, that widget will receive focus. Otherwise, any currently +focused widget will not retain focus unless it is focusable in touch +mode. For instance, in the picture below, when the user touches +the screen, the input text field receives the focus.

        + + + +

        Fousable in touch mode (see +{@link android.view.View#setFocusableInTouchMode(boolean) View.setFocusableInTouchMode}) + is a property that you can set yourself, either from code or from XML. +However, you should use it sparingly and only in very specific situations, +because it breaks consistency with the normal behavior of the Android UI. A game +is a good example of an application that could make good use of the focusable in +touch mode property. MapView, if used in fullscreen as in Google Maps, is +another good example of where you can use focusable in touch mode correctly.

        + +

        Below is another example of a focusable in touch mode widget. When the user +taps an AutoCompleteTextView suggestion with his finger, the focus +remains on the input text field:

        + + + + +

        Developers new to Android often think that focusable in touch mode is the +solution they need to "fix" the problem of "disappearing" selection/focus. We +really encourage you to think very hard before using it. If used incorrectly, it +can make your application behave differently from the rest of the system and +simply throw off the user's habits. The Android framework contains all the tools +you need to handle user interactions without using focusable in touch mode. For +example, instead of trying to make ListView always keep its +selection, simply use the appropriate choice mode, as shown in +{@link android.widget.ListView#setChoiceMode(int)}. + +

        Touch Mode Cheat Sheet

        + +

        Do:

        +
          +
        • Remain consistent with the core applications
        • Use the appropriate feature if you need persistent selection (radio button, check box, the ListView choice mode, etc.)
        • +
        • Use focusable in touch mode if you write a game
        • +
        + +

        Don't:

        +
        • Do not try to keep the focus or selection in touch mode
        diff --git a/docs/html/resources/articles/track-mem.jd b/docs/html/resources/articles/track-mem.jd new file mode 100644 index 0000000..d580e82 --- /dev/null +++ b/docs/html/resources/articles/track-mem.jd @@ -0,0 +1,62 @@ +page.title=Tracking Memory Allocations +@jd:body + +

        Writing efficient mobile applications is not always straightforward. In +particular, Android applications rely on automatic memory management handled by +Dalvik's garbage collector, which can sometimes cause performance issues if you +are not careful with memory allocations.

        + +

        In a performance-sensitive code path, such as the layout or drawing method of +a view or the logic code of a game, any allocation comes at a price. After too +many allocations, the garbage collector will kick in and stop your application +to let it free some memory. Most of the time, garbage collections happen fast +enough for you not to notice. However, if a collection happens while you are +scrolling through a list of items or while you are trying to defeat a foe in a +game, you may suddenly see a drop in performance/responsiveness of the +application. It's not unusual for a garbage collection to take 100 to 200 ms. +For comparison, a smooth animation needs to draw each frame in 16 to 33 ms. If +the animation is suddenly interrupted for 10 frames, you can be certain that +your users will notice.

        + +

        Most of the time, garbage collection occurs because of tons of small, +short-lived objects and some garbage collectors, like generational garbage +collectors, can optimize the collection of these objects so that the application +does not get interrupted too often. The Android garbage collector is +unfortunately not able to perform such optimizations and the creation of +short-lived objects in performance critical code paths is thus very costly for +your application.

        + +

        To help you avoid frequent garbage collections, the Android SDK ships with a +very useful tool called allocation tracker. This tool is part of DDMS, +which you must have already used for debugging purposes. To start using the +allocation tracker, you must first launch the standalone version of DDMS, which +can be found in the tools/ directory of the SDK. The version of +DDMS included in the Eclipse plugin does not offer you ability to use the +allocation tracker yet.

        + +

        Once DDMS is running, simply select your application process and then click +the Allocation Tracker tab. In the new view, click Start +Tracking and then use your application to make it execute the code paths +you want to analyze. When you are ready, click Get Allocations. A list +of allocated objects will be shown in the first table. By clicking on a line you +can see, in the second table, the stack trace that led to the allocation. Not +only you will know what type of object was allocated, but also in which thread, +in which class, in which file and at which line. The following screenshot shows +the allocations performed by Shelves while scrolling a +ListView.

        + + + + + + +

        Even though it is not necessary — and sometimes not possible — to +remove all allocations for your performance critical code paths. the allocation +tracker will help you identify important issues in your code. For instance, a +common mistake I have seen in many applications is to create a new +Paint object on every draw. Moving the paint into an instance field +is a simple fix that helps performance a lot. I highly encourage you to peruse +the Android source code to see how we +reduce allocations in performance-critical code paths. You will also thus +discover the APIs Android provide to help you reuse objects.

        diff --git a/docs/html/resources/articles/tts.jd b/docs/html/resources/articles/tts.jd new file mode 100644 index 0000000..e3fad91 --- /dev/null +++ b/docs/html/resources/articles/tts.jd @@ -0,0 +1,241 @@ +page.title=Using Text-to-Speech +@jd:body + +

        Starting with Android 1.6 (API Level 4), the Android platform includes a new +Text-to-Speech (TTS) capability. Also known as "speech synthesis", TTS enables +your Android device to "speak" text of different languages.

        + +

        Before we explain how to use the TTS API itself, let's first review a few +aspects of the engine that will be important to your TTS-enabled application. We +will then show how to make your Android application talk and how to configure +the way it speaks.

        + +

        Languages and resources

        + +

        The TTS engine that ships with the Android platform supports a number of +languages: English, French, German, Italian and Spanish. Also, depending on +which side of the Atlantic you are on, American and British accents for English +are both supported.

        + +

        The TTS engine needs to know which language to speak, as a word like "Paris", +for example, is pronounced differently in French and English. So the voice and +dictionary are language-specific resources that need to be loaded before the +engine can start to speak.

        + +

        Although all Android-powered devices that support the TTS functionality ship +with the engine, some devices have limited storage and may lack the +language-specific resource files. If a user wants to install those resources, +the TTS API enables an application to query the platform for the availability of +language files and can initiate their download and installation. So upon +creating your activity, a good first step is to check for the presence of the +TTS resources with the corresponding intent:

        + +
        Intent checkIntent = new Intent();
        +checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        +startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
        + +

        A successful check will be marked by a CHECK_VOICE_DATA_PASS +result code, indicating this device is ready to speak, after the creation of +our +{@link android.speech.tts.TextToSpeech} object. If not, we need to let the user +know to install the data that's required for the device to become a +multi-lingual talking machine! Downloading and installing the data is +accomplished by firing off the ACTION_INSTALL_TTS_DATA intent, which will take +the user to Android Market, and will let her/him initiate the download. +Installation of the data will happen automatically once the download completes. +Here is an example of what your implementation of +onActivityResult() would look like:

        + +
        private TextToSpeech mTts;
        +protected void onActivityResult(
        +        int requestCode, int resultCode, Intent data) {
        +    if (requestCode == MY_DATA_CHECK_CODE) {
        +        if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
        +            // success, create the TTS instance
        +            mTts = new TextToSpeech(this, this);
        +        } else {
        +            // missing data, install it
        +            Intent installIntent = new Intent();
        +            installIntent.setAction(
        +                TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
        +            startActivity(installIntent);
        +        }
        +    }
        +}
        + +

        In the constructor of the TextToSpeech instance we pass a +reference to the Context to be used (here the current Activity), +and to an OnInitListener (here our Activity as well). This listener +enables our application to be notified when the Text-To-Speech engine is fully +loaded, so we can start configuring it and using it.

        + +

        Languages and Locale

        + +

        At Google I/O 2009, we showed an example of TTS where it was used to speak the result of a +translation from and to one of the 5 languages the Android TTS engine currently +supports. Loading a language is as simple as calling for instance:

        + +
        mTts.setLanguage(Locale.US);

        to load and set the language to +English, as spoken in the country "US". A locale is the preferred way to specify +a language because it accounts for the fact that the same language can vary from +one country to another. To query whether a specific Locale is supported, you can +use isLanguageAvailable(), which returns the level of support for +the given Locale. For instance the calls:

        + +
        mTts.isLanguageAvailable(Locale.UK))
        +mTts.isLanguageAvailable(Locale.FRANCE))
        +mTts.isLanguageAvailable(new Locale("spa", "ESP")))
        + +

        will return TextToSpeech.LANG_COUNTRY_AVAILABLE to indicate that the language +AND country as described by the Locale parameter are supported (and the data is +correctly installed). But the calls:

        + +
        mTts.isLanguageAvailable(Locale.CANADA_FRENCH))
        +mTts.isLanguageAvailable(new Locale("spa"))
        + +

        will return TextToSpeech.LANG_AVAILABLE. In the first example, +French is supported, but not the given country. And in the second, only the +language was specified for the Locale, so that's what the match was made on.

        + +

        Also note that besides the ACTION_CHECK_TTS_DATA intent to check +the availability of the TTS data, you can also use +isLanguageAvailable() once you have created your +TextToSpeech instance, which will return +TextToSpeech.LANG_MISSING_DATA if the required resources are not +installed for the queried language.

        + +

        Making the engine speak an Italian string while the engine is set to the +French language will produce some pretty interesting results, but it will +not exactly be something your user would understand So try to match the +language of your application's content and the language that you loaded in your +TextToSpeech instance. Also if you are using +Locale.getDefault() to query the current Locale, make sure that at +least the default language is supported.

        + +

        Making your application speak

        + +

        Now that our TextToSpeech instance is properly initialized and +configured, we can start to make your application speak. The simplest way to do +so is to use the speak() method. Let's iterate on the following +example to make a talking alarm clock:

        + +
        String myText1 = "Did you sleep well?";
        +String myText2 = "I hope so, because it's time to wake up.";
        +mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, null);
        +mTts.speak(myText2, TextToSpeech.QUEUE_ADD, null);
        + +

        The TTS engine manages a global queue of all the entries to synthesize, which +are also known as "utterances". Each TextToSpeech instance can +manage its own queue in order to control which utterance will interrupt the +current one and which one is simply queued. Here the first speak() +request would interrupt whatever was currently being synthesized: the queue is +flushed and the new utterance is queued, which places it at the head of the +queue. The second utterance is queued and will be played after +myText1 has completed.

        + +

        Using optional parameters to change the playback stream type

        + +

        On Android, each audio stream that is played is associated with one stream +type, as defined in +{@link android.media.AudioManager android.media.AudioManager}. For a talking +alarm clock, we would like our text to be played on the +AudioManager.STREAM_ALARM stream type so that it respects the alarm +settings the user has chosen on the device. The last parameter of the speak() +method allows you to pass to the TTS engine optional parameters, specified as +key/value pairs in a HashMap. Let's use that mechanism to change the stream type +of our utterances:

        + +
        HashMap<String, String> myHashAlarm = new HashMap();
        +myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
        +        String.valueOf(AudioManager.STREAM_ALARM));
        +mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
        +mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
        + +

        Using optional parameters for playback completion callbacks

        + +

        Note that speak() calls are asynchronous, so they will return +well before the text is done being synthesized and played by Android, regardless +of the use of QUEUE_FLUSH or QUEUE_ADD. But you might +need to know when a particular utterance is done playing. For instance you might +want to start playing an annoying music after myText2 has finished +synthesizing (remember, we're trying to wake up the user). We will again use an +optional parameter, this time to tag our utterance as one we want to identify. +We also need to make sure our activity implements the +TextToSpeech.OnUtteranceCompletedListener interface:

        + +
        mTts.setOnUtteranceCompletedListener(this);
        +myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
        +        String.valueOf(AudioManager.STREAM_ALARM));
        +mTts.speak(myText1, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
        +myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
        +        "end of wakeup message ID");
        +// myHashAlarm now contains two optional parameters
        +mTts.speak(myText2, TextToSpeech.QUEUE_ADD, myHashAlarm);
        + +

        And the Activity gets notified of the completion in the implementation +of the listener:

        + +
        public void onUtteranceCompleted(String uttId) {
        +    if (uttId == "end of wakeup message ID") {
        +        playAnnoyingMusic();
        +    } 
        +}
        + +

        File rendering and playback

        + +

        While the speak() method is used to make Android speak the text +right away, there are cases where you would want the result of the synthesis to +be recorded in an audio file instead. This would be the case if, for instance, +there is text your application will speak often; you could avoid the synthesis +CPU-overhead by rendering only once to a file, and then playing back that audio +file whenever needed. Just like for speak(), you can use an +optional utterance identifier to be notified on the completion of the synthesis +to the file:

        + +
        HashMap<String, String> myHashRender = new HashMap();
        +String wakeUpText = "Are you up yet?";
        +String destFileName = "/sdcard/myAppCache/wakeUp.wav";
        +myHashRender.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, wakeUpText);
        +mTts.synthesizeToFile(wakuUpText, myHashRender, destFileName);
        + +

        Once you are notified of the synthesis completion, you can play the output +file just like any other audio resource with +{@link android.media.MediaPlayer android.media.MediaPlayer}.

        + +

        But the TextToSpeech class offers other ways of associating +audio resources with speech. So at this point we have a WAV file that contains +the result of the synthesis of "Wake up" in the previously selected language. We +can tell our TTS instance to associate the contents of the string "Wake up" with +an audio resource, which can be accessed through its path, or through the +package it's in, and its resource ID, using one of the two +addSpeech() methods:

        + +
        mTts.addSpeech(wakeUpText, destFileName);
        + +

        This way any call to speak() for the same string content as +wakeUpText will result in the playback of +destFileName. If the file is missing, then speak will behave as if +the audio file wasn't there, and will synthesize and play the given string. But +you can also take advantage of that feature to provide an option to the user to +customize how "Wake up" sounds, by recording their own version if they choose +to. Regardless of where that audio file comes from, you can still use the same +line in your Activity code to ask repeatedly "Are you up yet?":

        + +
        mTts.speak(wakeUpText, TextToSpeech.QUEUE_ADD, myHashAlarm);
        + +

        When not in use...

        The text-to-speech functionality relies on a +dedicated service shared across all applications that use that feature. When you +are done using TTS, be a good citizen and tell it "you won't be needing its +services anymore" by calling mTts.shutdown(), in your Activity +onDestroy() method for instance.

        + +

        Conclusion

        + +

        Android now talks, and so can your apps. Remember that in order for +synthesized speech to be intelligible, you need to match the language you select +to that of the text to synthesize. Text-to-speech can help you push your app in +new directions. Whether you use TTS to help users with disabilities, to enable +the use of your application while looking away from the screen, or simply to +make it cool, we hope you'll enjoy this new feature.

        \ No newline at end of file diff --git a/docs/html/resources/articles/ui-1.5.jd b/docs/html/resources/articles/ui-1.5.jd new file mode 100644 index 0000000..c10cf52 --- /dev/null +++ b/docs/html/resources/articles/ui-1.5.jd @@ -0,0 +1,48 @@ +page.title=UI Framework Changes in Android 1.5 +@jd:body + + +

        Android 1.5 offers a different default look for +the Android UI framework, in relation to Android 1.0 and 1.1. The +screenshots below show the same activity (creating a new contact) on +Android 1.1 and Android 1.5:

        + + + +

        You +can see in this example that the buttons and checkboxes have a new +appearance. Even though these changes do not affect binary nor source +compatibility, they might still break the UI of your apps. As part of +the UI refresh, the minimum size of some of the widgets has changed. +For instance, Android 1.1 buttons have a minimum size of 44x48 pixels +whereas Android 1.5 buttons now have a minimum size of 24x48 pixels. +The image below compares the sizes of Android 1.1 buttons with Android +1.5 buttons:

        + + + +

        If you rely on the button's minimum size, then the layout of your application +may not be the same in Android 1.5 as it was in Android 1.1 because of this +change. This would happen for instance if you created a grid of buttons using +LinearLayout and relying on the minimum size yielded by +wrap_content to align the buttons properly:

        + + + +

        This layout could easily be fixed by using the +android:layout_weight attribute or by replacing the +LinearLayout containers with a TableLayout.

        + +

        This example is probably the worst-case UI issue you may encounter when +running your application on Android 1.5. Other changes introduced in Android +1.5, especially bug fixes in the layout views, may also impact your +application—especially if it is relying on faulty/buggy behavior of the UI +framework.

        + +

        If you encounter issues when running your application on Android 1.5, please +join us on the Android +developer groups or IRC so that we and the +Android community can help you fix your application.

        + +

        Happy coding!

        diff --git a/docs/html/resources/articles/ui-1.6.jd b/docs/html/resources/articles/ui-1.6.jd new file mode 100644 index 0000000..10cb524 --- /dev/null +++ b/docs/html/resources/articles/ui-1.6.jd @@ -0,0 +1,130 @@ +page.title=UI Framework Changes in Android 1.6 +@jd:body + +

        Android 1.6 introduces numerous enhancements and bug fixes in the UI +framework. This article highlights two improvements in particular: more flexible +and robust RelativeLayout and easier click listeners.

        + +

        More flexible, more robust RelativeLayout

        + +

        RelativeLayout is the most versatile layout offered by the Android UI toolkit +and can be successfully used to reduce the number of views created by your +applications. This layout used to suffer from various bugs and limitations, +sometimes making it difficult to use without having some knowledge of its +implementation. To make your life easier, Android 1.6 comes with a revamped +RelativeLayout.

        + +

        This new implementation not only fixes all known bugs in +RelativeLayout but also addresses its major limitation: the +fact that views had to be declared in a particular order. Consider the following +XML layout:

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +
        +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:layout_width="fill_parent"
        +    android:layout_height="64dip"
        +    android:padding="6dip">
        +
        +    <TextView
        +        android:id="@+id/band"  
        +        android:layout_width="fill_parent" 
        +        android:layout_height="26dip" 
        +
        +        android:layout_below="@+id/track"
        +        android:layout_alignLeft="@id/track"
        +        android:layout_alignParentBottom="true"
        +
        +        android:gravity="top"
        +        android:text="The Airborne Toxic Event" />
        +
        +    <TextView
        +        android:id="@id/track"  
        +        android:layout_marginLeft="6dip"
        +        android:layout_width="fill_parent"
        +        android:layout_height="26dip"
        +
        +        android:layout_toRightOf="@+id/artwork"
        +
        +        android:textAppearance="?android:attr/textAppearanceMedium"
        +        android:gravity="bottom"
        +        android:text="Sometime Around Midnight" />
        +        
        +    <ImageView
        +        android:id="@id/artwork"
        +        android:layout_width="56dip"
        +        android:layout_height="56dip"
        +        android:layout_gravity="center_vertical"
        +
        +        android:src="@drawable/artwork" />
        +        
        +</RelativeLayout>
        + +

        This code builds a very simple layout—an image on the left with two lines of +text stacked vertically. This XML layout is perfectly fine and contains no +errors. Unfortunately, Android 1.5's RelativeLayout is incapable of rendering it +correctly, as shown in the screenshot below.

        + + + +

        The problem is that this layout uses forward references. For instance, the +"band" TextView is positioned below the "track" TextView but "track" is declared +after "band" and, in Android 1.5, RelativeLayout does not know how to handle +this case. Now look at the exact same layout running on Android 1.6:

        + + + +

        As you can see Android 1.6 is now better able to handle forward reference. +The result on screen is exactly what you would expect when writing the +layout.

        + +

        Easier click listeners

        + +

        Setting up a click listener on a button is very common task, but +it requires quite a bit of boilerplate code:

        + +
        findViewById(R.id.myButton).setOnClickListener(new View.OnClickListener() {
        +    public void onClick(View v) {
        +        // Do stuff
        +    }
        +});
        + +

        One way to reduce the amount of boilerplate is to share a single click +listener between several buttons. While this technique reduces the +number of classes, it still requires a fair amount of code and it still +requires giving each button an id in your XML layout file:

        + +
        View.OnClickListener handler = View.OnClickListener() {
        +    public void onClick(View v) {
        +        switch (v.getId()) {
        +            case R.id.myButton: // doStuff
        +                break;
        +            case R.id.myOtherButton: // doStuff
        +                break;
        +        }
        +    }
        +}
        +
        +findViewById(R.id.myButton).setOnClickListener(handler);
        +findViewById(R.id.myOtherButton).setOnClickListener(handler);
        + +

        With Android 1.6, none of this is necessary. All you have to do is +declare a public method in your Activity to handle the click +(the method must have one View argument):

        + +
        class MyActivity extends Activity {
        +    public void myClickHandler(View target) {
        +        // Do stuff
        +    }
        +}
        + +

        And then reference this method from your XML layout:

        + +
        <Button android:onClick="myClickHandler" />
        + +

        This new feature reduces both the amount of Java and XML you have to write, +leaving you more time to concentrate on your application.

        + +

        The Android team is committed to helping you write applications in the +easiest and most efficient way possible. We hope you find these improvements +useful and we're excited to see your applications on Android Market.

        diff --git a/docs/html/resources/articles/using-webviews.jd b/docs/html/resources/articles/using-webviews.jd new file mode 100644 index 0000000..3a1f34c --- /dev/null +++ b/docs/html/resources/articles/using-webviews.jd @@ -0,0 +1,61 @@ +page.title=Using WebViews +@jd:body + +

        A small application called WebViewDemo shows how you can add web content to your +application. You can find it in the apps-for-android project. +This application demonstrates how you can embed a {@link android.webkit.WebView} +into an activity and also how you can have two way communication between your +application and the web content.

        + +

        A +WebView uses the same rendering and JavaScript engine as the browser, +but it runs under the control of your application. The WebView can be +full screen or you can mix it with other Views. The content for your +WebView can come from anywhere. The WebView can download content from +the web, or it can come from local files stored in your assets +directory. The content can even be dynamically generated by your +application code. For this example, the HTML comes from a local file +called demo.html.

        + +

        This application does not do very much: when you click on the +android, he raises his arm.

        + +
        + +

        This +could, of course, easily be accomplished with a little bit of +JavaScript. Instead, though, WebViewDemo takes a slightly more +complicated path to illustrate two very powerful features of WebView.

        + +

        First, +JavaScript running inside the WebView can call out to code in your +Activity. You can use this to have your JavaScript trigger actions like +starting a new activity, or it can be used to fetch data from a +database or {@link android.content.ContentProvider}. The API for this +is very simple: just call the +{@link android.webkit.WebView#addJavascriptInterface(java.lang.Object, java.lang.String) addJavascriptInterface()} +method on your WebView. You pass an object whose methods you want to +expose to JavaScript and the name to use when making calls. You can see +the exact syntax in WebViewDemo. +java. Here we are making our DemoJavascriptInterface object available to +JavaScript where it will be called "window.demo".

        + +

        Second, your Activity can invoke JavaScript methods. All you have to do +is call the {@link android.webkit.WebView#loadUrl(java.lang.String) loadUrl} +method with the appropriate JavaScript call:

        + +

        mWebView.loadUrl("javascript:wave()");

        + +

        Our WebViewDemo uses both techniques: when you click on the +android, it calls out to the activity, which then turns around and calls back +into the JavaScript. WebViews are very powerful, and they may be a valuable tool +to help you build your application – especially if you already have a lot of +HTML content. As it happens, we've used exactly this approach in some of the +applications we've written.

        diff --git a/docs/html/resources/articles/wikinotes-intents.jd b/docs/html/resources/articles/wikinotes-intents.jd new file mode 100644 index 0000000..bc64544 --- /dev/null +++ b/docs/html/resources/articles/wikinotes-intents.jd @@ -0,0 +1,255 @@ +page.title=WikiNotes: Routing Intents +@jd:body + + +

        In the Linkify! article, we talked about +using Linkify to turn wiki words (those that match a regular expression that we +have defined) into a content: URI and defining a path to data that +matched a note belonging to that wiki word. As an example, a matching word like +ToDoList would be turned into a URI such as +content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList + and then acted upon using the VIEW action from the Linkify class.

        + +

        This article examines how the Android system takes this combination of +VIEW action and content: URI and finds the correct +activity to fire in order to do something with the data. It will also explain +how the other default links created by Linkify, such as web URLs and telephone +numbers, also result in the correct activity to handle that data type being +fired. Finally, this article will start to examine the custom +ContentProvider that has been created to handle WikiNotes data. The +full description of the ContentProvider and what it does will span a couple more +articles as well, because there is a lot to cover.

        + +

        The Linkify-calls-intent Workflow

        + +

        At a high level, the steps for Linkify to invoke an intent, and for the +resulting activity (if any) to handle it, look like this:

        + +
          +
        1. Linkify is invoked on a TextView to turn matching text patterns into Intent links.
        2. +
        3. Linkify takes over monitoring for those Intent links being selected by the user.
        4. +
        5. When the user selects a link, Linkify calls the VIEW action using the content: URI associated with the link.
        6. +
        7. Android takes the content: URI that represents the data, and looks for a +ContentProvider registered in the system that matches the URI.
        8. +
        9. If a match is found, Android queries the ContentProvider using the URI, +and asks what MIME type the data that will be returned from the URI is.
        10. +
        11. Android then looks for an activity registered in the system with an +intent-filter that matches both the VIEW action, and the MIME type for +the data represented by the content: URI.
        12. +
        13. Assuming a match is found, Linkify then invokes the intent for +the URI, at which point the activity takes over, and is handed +the content: URI.
        14. +
        15. The activity can then use the URI to retrieve the data and act on +it.
        16. +
        + +

        This is actually a simpler process than it +sounds, and it is quite lightweight as well. Perhaps a more +understandable statement about how it works might be:

        + +

        Linkify is used to turn matching text into hot-links. When the user +selects a hot-link, Android takes the data locator represented by the +hot-link and looks for a data handler for that data locator. If it +finds one, it asks for what type of data is returned for that locator. +It then looks for something registered with the system that handles +that type of data for the VIEW action, and starts it, including the +data locator in the request.

        + +

        The real key here is the MIME type. MIME stands for Multipurpose Internet Mail +Extensions — a standard for sending attachments over email. The MIME +type (which is the part Android uses) is a way of describing certain kinds of +data. That type is then used to look for an Activity that can do something with +that data type. In this way, ContentProviders and Activities (or other +IntentReceivers) are decoupled, meaning that a given Content URI might have a +different ContentProvider to handle it, but could still use the same MIME type +meaning that the same activity could be called upon to handle the resulting +data.

        + +

        Linkify on a wiki word

        + +

        Using the above workflow, let's take a look at exactly how the process +works in WikiNotes for Android:

        + +

        First, Linkify is used to turn text matching the wiki word regular expression +into a link that provides a Content URI for that wiki word, for example +content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList.

        + +

        When the user clicks on the wiki word link, Linkify invokes the VIEW +action on the Content URI. At this point, the Android system takes over +getting the Intent request to the correct activity.

        + +

        Next, Android looks for a ContentProvider that has been registered +with the system to handle URIs matching our Content URI format.

        + +

        In our case, we have a definition inside +our application's AndroidManifest.xml +file that reads:

        + +
        <provider name="com.google.android.wikinotes.db.WikiNotesProvider" 
        +    android:authorities="com.google.android.wikinotes.db.wikinotes" />
        + +

        This establishes that we have a ContentProvider defined in our application +that provides the "root authority": +com.google.android.wikinotes.db.wikinotes. This is the first part +of the Content URI that we create for a wiki word link. Root Authority is just +another way of thinking about a descriptor that is registered with Android to +allow requests for certain URLs to be routed to the correct class.

        + +

        So, the whole definition is that a class called +com.google.android.wikinotes.db.WikiNotesProvider is registered +with the system as able to handle the +com.google.android.wikinotes.db.wikinotes root authority (i.e. URIs +starting with that identifier).

        + +

        From here, Android takes the rest of the URI and presents it to that +ContentProvider. If you look at the +WikiNotesProvider +class and scroll to the very bottom, in the static block there, you can see +the pattern definitions to match the rest of the URL.

        + +

        In particular, take a look at the two lines:

        + +
        URI_MATCHER.addURI(WikiNote.WIKINOTES_AUTHORITY, "wikinotes", NOTES);
        +URI_MATCHER.addURI(WikiNote.WIKINOTES_AUTHORITY, "wikinotes/*", NOTE_NAME);
        + +

        These are the definitions of URIs that our ContentProvider recognizes and can +handle. The first recognizes a full URI of +content://com.google.android.wikinotes.db.wikinotes/wikinotes and +associates that with a constant called NOTES. This is used elsewhere in the +ContentProvider to provide a list of all of the wiki notes in the database when +the URI is requested.

        + +

        The second line uses a wildcard — '*' — to match a request of the +form that Linkify will create, e.g. +content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList +. In this example, the * matches the ToDoList part of the URI and is +available to the handler of the request, so that it can fish out the matching +note for ToDoList and return it as the data. This also associates that match +with a constant called NOTE_NAME, which again is used as an identifier elsewhere +in the ContentProvider.

        + +

        The other matches in this static block are related to forms of +searching that have been implemented in the WikiNotes for Android +application, and will be covered in later articles. Likewise, how the +data is obtained from this matching pattern will be the subject of the +next article.

        + +

        For right now we are concerned with the MIME type for the URI. This is +defined in the getType() method also in the +WikiNotesProvider +class (about halfway through the file). Take a quick look at this. The key +parts for now are:

        + +
        case NOTES:
        +    return "vnd.android.cursor.dir/vnd.google.wikinote";
        + +

        and

        + +
        case NOTE_NAME:
        +    return "vnd.android.cursor.item/vnd.google.wikinote";
        + +

        These are the same constant names we defined in our pattern +matchers. In the first case, that of the all notes URI, the MIME type +returned is vnd.android.cursor.dir/vnd.google.wikinote +which is like saying an Android list (dir) of Google wiki notes (the +vnd bit is MIME-speak for "vendor specific definition"). Likewise, in +the case of a NOTE_NAME match, the MIME type returned is +vnd.android.cursor.item/vnd.google.wikinote which is +like saying an Android item of Google wiki notes.

        + +

        Note that if you define your own MIME data types like this, the +vnd.android.cursor.dir and vnd.android.cursor.item +categories should be retained, since they have meaning to the Android +system, but the actual item types should be changed to reflect your +particular data type.

        + +

        So far Android has been able to find a ContentProvider that handles +the Content URI supplied by the Linkify Intent call, and has queried +the ContentProvider to find out the MIME types for that URI. The final +step is to find an activity that can handle the VIEW action for that +MIME type. Take a look in the the +AndroidManifest.xml file +again. Inside the WikiNotes activity definition, you will see:

        + +
        <intent-filter>
        +    <action name="android.intent.action.VIEW"/>
        +    <category name="android.intent.category.DEFAULT"/>
        +    <category name="android.intent.category.BROWSABLE"/>
        +    <data mimetype="vnd.android.cursor.item/vnd.google.wikinote"/>
        +</intent-filter>
        + +

        This is the correct combination of matches for the VIEW action on a +WikiNote type that is requested from the LINKIFY class. The DEFAULT +category indicates that the WikiNotes activity should be treated as a +default handler (a primary choice) for this kind of data, and the +BROWSABLE category means it can be invoked from a "browser", in this +case the marked-up Linkified text.

        + +

        Using this information, Android can match up the VIEW action request +for the WikiNotes data type with the WikiNotes activity, and can then +use the WikiNotes activity to handle the request.

        + +

        Why do it like this?

        + +

        It's quite a trip through the system, and there is a lot to absorb +here, but this is one of the main reasons I wanted to write WikiNotes +in the first place. If you follow and understand the steps here, you'll +have a good grasp of the whole Intents mechanism in Android, and how it +helps loosely coupled activities cooperate to get things done.

        + +

        In this case, we could have found another way to detect wiki words +based on a regular expression, and maybe written our own handler to +intercept clicks within the TextView and dig out the right data and +display it. This would seem to accomplish the same functionality just +as easily as using intents, so what is the advantage to using the full +Intents mechanism?

        + +

        In fact there are several advantages:

        + +

        The most obvious is that because we are using the standard Intent +based approach, we are not limited to just linking and navigating to +other wiki notes. We get similar behavior to a number of other data +types as well. For example, a telephone number or web URL in a wiki +note will be marked up by Linkify, and using this same mechanism (VIEW +action on the linked data type) the browser or dialer activities will +be automatically fired.

        + +

        It also means that each operation on a wiki note can be treated as a +separate life cycle by our activity. We are not dealing with swapping +data in and out of an existing activity - each activity works on a +particular wiki note and that's all you have to worry about.

        + +

        Another advantage is that we now have a public activity to handle +VIEW actions in WikiNotes no matter where the request comes from. +Another application could request to view a wiki note (perhaps without +even knowing what kind of data it is) and our activity could start up +and handle it.

        + +

        The backstack is automatically maintained for you too. As you +forward navigate through WikiNotes, Android maintains the history of +notes visited, and so when you hit the back button you go back to the +last note you were on. All this is free because we rely on the Android +intents mechanism.

        + +

        Finally, if you run WikiNotes for Android and then start DDMS to +take a look at the Activity threads in the WikiNotes application while +it is running, you can see that despite what you might think, letting +Android manage the navigation is very efficient. Create a few linked +notes, as many links deep as you like, and then follow them. If you +follow links hundreds of notes deep, you will still only see a handful +of WikiNotes activities. Android is managing the activities, closing +the older ones as necessary and using the life cycle to swap data in +and out.

        + +

        Next Time

        + +

        This was a long article, but necessarily so. It demonstrates the +importance of the Intents mechanism and to reinforce the notion that it +should be used whenever possible for forward navigation, even within a +single application. Illustrating this is one of the primary reasons I +wrote WikiNotes for Android in the first place.

        + +

        In the next article we will look deeper into the ContentProvider and +examine how it turns a Content URI into a row (or several rows) of data +that can be used by an activity.

        diff --git a/docs/html/resources/articles/wikinotes-linkify.jd b/docs/html/resources/articles/wikinotes-linkify.jd new file mode 100644 index 0000000..21b1f13 --- /dev/null +++ b/docs/html/resources/articles/wikinotes-linkify.jd @@ -0,0 +1,113 @@ +page.title=WikiNotes: Linkify your Text! +@jd:body + +Linkify example + +

        This article introduces WikiNotes for Android, part of the Apps for Android +project. It covers the use of Linkify to turn ordinary text views +into richer, link-oriented content that causes Android intents to fire +when a link is selected.

        + +

        Linkify: The {@link android.text.util.Linkify} class in the +framework is perfect for creating a wiki note pad. It lets you specify a regular expression +» +to match, and a scheme to prepend. The scheme is a string that, when +the matched text is added, forms a Content URI to allow the correct +data to be looked up.

        + +

        For example, in our case we want to look for a regular expression match for a +WikiWord (that is, a word with camel case » and no +spaces). Linkify can then turn this into a Content URI — something like +content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord, +which can then be used to locate the correct wiki page from a +{@link android.content.ContentProvider}.

        + +

        As a bonus, the Linkify class also defines several default matches, +in particular it is able to turn web URLs, email addresses and +telephone numbers into active links which fire Android intents +automatically.

        + +

        Linkify can be passed any TextView in your application, and will +take care of creating the links and enabling their "clickability" for +you.

        + +

        Default Linkify: Using the set of default active +link options is very straightforward. Simply pass it a handle to a +TextView with content in it, and the Linkify.ALL flag:

        + +
        TextView noteView = (TextView) findViewById(R.id.noteview);
        +noteView.setText(someContent);
        +Linkify.addLinks(noteView, Linkify.ALL);
        + +

        and that's it. The Linkify.ALL flag applies all of the predefined +link actions, and the TextView will be immediately updated with a set +of active links which, if you select them, fire default intents for the +actions (e.g. a web URL will start the browser with that URL, a +telephone number will bring up the phone dialer with that number ready +to call, etc.).

        + +

        Custom Linkify: So what about our WikiWord? There is no +pre-defined action for that, so it needs to be defined and associated with a +scheme.

        + +

        The first task is to define a regular expression that matches the kind of +WikiWords we want to find. The regex in this case is:

        + +
        \b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\b
        + +

        Obvious, no? Well actually this is equivalent to the following +description: "Starting with a word boundary (the \b) find at least one +upper case letter, followed by at least one lower case letter or a +numeric digit, followed by another upper case letter, and then any mix +of upper case, lower case or numeric until the next word boundary (the +final \b)". Regular expressions are not very pretty, but they are an +extremely concise and accurate way of specifying a search pattern.

        + +

        We also need to tell Linkify what to do with a match to the +WikiWord. Linkify will automatically append whatever is matched to a +scheme that is supplied to it, so for the sake of argument let's assume +we have a {@link android.content.ContentProvider} that matches the +following content URI:

        + +
        content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord
        + +

        The WikiWord part will be appended by Linkify when it finds a match, so we +just need the part before that as our scheme.

        + +

        Now that we have these two things, we use Linkify to connect them up:

        + +
        Pattern wikiWordMatcher = Pattern.compile("\\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\\b");
        +String wikiViewURL =    "content://com.google.android.wikinotes.db.wikinotes/wikinotes/";
        +Linkify.addLinks(noteView, wikiWordMatcher, wikiViewURL);
        + +

        Note that the \b's had to be escaped with double backslashes for the Java +Pattern.compile line.

        + +

        Linkify can be used multiple times on the same view to add more +links, so using this after the Default Linkify call means that the +existing active links will be maintained and the new WikiWords will be +added. You could define more Linkify actions and keep applying them to +the same TextView if you wanted to.

        + +

        Now, if we have a WikiWord in the TextView, let's say +MyToDoList, Linkify will turn it into an active link with the +content URI:

        + +
        content://com.google.android.wikinotes.db.wikinotes/wikinotes/MyToDoList
        + +

        and if you click on it, Android will fire the default intent for that content +URI.

        + +

        For this to all work, you will need a ContentProvider that +understands that Content URI, and you will need a default activity +capable of doing something with the resulting data. I plan to cover +these in future blog entries (and soon). In fact, the whole Wiki Note +Pad application is currently undergoing some clean up and review, and +will then hopefully be released as a sample application.

        diff --git a/docs/html/resources/articles/window-bg-speed.jd b/docs/html/resources/articles/window-bg-speed.jd new file mode 100644 index 0000000..bd7a303 --- /dev/null +++ b/docs/html/resources/articles/window-bg-speed.jd @@ -0,0 +1,125 @@ +page.title=Window Backgrounds & UI Speed +@jd:body + +

        Some Android applications require to squeeze every bit of performance out of +the UI toolkit and there are many ways to do so. In this article, you will +discover how to speed up the drawing and the perceived startup time of +your activities. Both these techniques rely on a single feature, the window's +background drawable.

        + +

        The term window background is a bit misleading, however. When you +setup your user interface by calling setContentView() on an +{@link android.app.Activity}, Android adds your views to the Activity's +window. The window however does not contain only your views, but a few others +created for you. The most important one is, in the current implementation used +on the T-Mobile G1, the DecorView, highlighted in the view +hierarchy below:

        + +
        A typical Android view hierarchy
        + +

        The DecorView is the view that actually holds the +window's background drawable. Calling +{@link android.view.Window#setBackgroundDrawable(android.graphics.drawable.Drawable) getWindow().setBackgroundDrawable()} +from your Activity changes the background of the window by changing +the DecorView's background drawable. As mentioned before, this +setup is very specific to the current implementation of Android and can change +in a future version or even on another device.

        + +

        If you are using the standard Android themes, a default background drawable +is set on your activities. The standard theme currently used on the T-Mobile G1 +uses for instance a {@link android.graphics.drawable.ColorDrawable}. For most +applications, this background drawable works just fine and can be left alone. It +can however impacts your application's drawing performance. Let's take the +example of an application that always draws a full screen opaque picture:

        + +
        An opaque user interface doesn't need a window background
        + +

        You can see on this screenshot that the window's background is invisible, +entirely covered by an ImageView. This application is setup to +redraw as fast as it can and draws at about 44 frames per second, or 22 +milliseconds per frame (note: the number of frames per second +used in this article were obtained on a T-Mobile G1 with my finger on the screen +so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An +easy way to make such an application draw faster is to remove the +background drawable. Since the user interface is entirely opaque, drawing the +background is simply wasteful. Removing the background improves the performance +quite nicely:

        + +
        Remove the background for faster drawing
        + +

        In this new version of the application, the drawing speed went up to 51 +frames per second, or 19 milliseconds per frame. The difference of 3 +milliseconds per is easily explained by the speed of the memory bus on the +T-Mobile G1: it is exactly the time it takes to move the equivalent of a +screenful of pixels on the bus. The difference could be even greater if the +default background was using a more expensive drawable.

        + +

        Removing the window's background can be achieved very easily by using +a custom theme. To do so, first create a file called +res/values/theme.xml containing the following:

        + +
        <resources>
        +    <style name="Theme.NoBackground" parent="android:Theme">
        +        <item name="android:windowBackground">@null</item>
        +    </style>
        +</resources>
        + +

        You then need to apply the theme to your activity by adding the attribute +android:theme="@style/Theme.NoBackground" to your +<activity /> or <application /> tag. This +trick comes in very handy for any app that uses a MapView, a +WebView or any other full screen opaque view.

        + +

        Opaque views and Android: this optimization is currently +necessary because the Android UI toolkit is not smart enough to prevent the +drawing of views hidden by opaque children. The main reason why this +optimization was not implemented is simply because there are usually very few +opaque views in Android applications. This is however something that I +definitely plan on implementing as soon as possible and I can only apologize for +not having been able to do this earlier.

        Using a theme to change the +window's background is also a fantastic way to improve the perceived +startup performance of some of your activities. This particular trick can only +be applied to activities that use a custom background, like a texture or a logo. +The Shelves application is a good +example:

        + +
        Textured backgrounds are good candidates for window's background
        + +

        If this application simply set the wooden background in the XML layout or in +onCreate() the user would see the application startup with the +default theme and its dark background. The wooden texture would only appear +after the inflation of the content view and the first layout/drawing pass. This +causes a jarring effect and gives the user the impression that the application +takes time to load (which can actually be the case.) Instead, the application +defines the wooden background in a theme, picked up by the system as soon as the +application starts. The user never sees the default theme and gets the +impression that the application is up and running right away. To limit the +memory and disk usage, the background is a tiled texture defined in +res/drawable/background_shelf.xml:

        + +
        <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:src="@drawable/shelf_panel"
        +    android:tileMode="repeat" />

        This drawable is simply referenced by the theme:

        + +
        <resources>
        +    <style name="Theme.Shelves" parent="android:Theme">
        +        <item name="android:windowBackground">@drawable/background_shelf</item>
        +        <item name="android:windowNoTitle">true</item>
        +    </style>
        +</resources>
        + +

        The same exact trick is used in the Google Maps application that ships +with the T-Mobile G1. When the application is launched, the user immediately +sees the loading tiles of MapView. This is only a trick, the theme +is simply using a tiled background that looks exactly like the loading tiles of +MapView.

        + +

        Sometimes the best tricks are also the simplest, so the next time you create +an activity with an opaque UI or a custom background, remember to change the +window's background.

        + +

        Download the source code of the first example.

        + +

        Download the source code of Shelves.

        + + diff --git a/docs/html/resources/articles/zipalign.jd b/docs/html/resources/articles/zipalign.jd new file mode 100644 index 0000000..013d0fe --- /dev/null +++ b/docs/html/resources/articles/zipalign.jd @@ -0,0 +1,98 @@ +page.title=Zipalign: an Easy Optimization +@jd:body + +

        The Android SDK includes a tool called zipalign +that optimizes the way an application is packaged. Running zipalign against your +application enables Android to interact it more efficiently at run time and thus +has the potential to make it and the overall system run faster. We strongly +encourage you to use zipalign on both new and already published +applications and to make the optimized version available — even if your +application targets a previous version of Android. This article describes how +zipalign helps performance and how to use it to optimize your +app.

        + +

        In Android, data files stored in each application's apk are accessed by +multiple processes: the installer reads the manifest to handle the +permissions associated with that application; the Home application +reads resources to get the application's name and icon; the system +server reads resources for a variety of reasons (e.g. to display that +application's notifications); and last but not least, the resource +files are obviously used by the application itself.

        + +

        The resource-handling code in Android can efficiently access resources when +they're aligned on 4-byte boundaries by memory-mapping them. But for resources +that are not aligned (that is, when zipalign hasn't been run on an +apk), it has to fall back to explicitly reading them — which is slower and +consumes additional memory.

        + +

        For an application developer, this fallback mechanism is very +convenient. It provides a lot of flexibility by allowing for several +different development methods, including those that don't include +aligning resources as part of their normal flow.

        + +

        Unfortunately, for users the situation is reversed — reading resources +from unaligned apks is slow and takes a lot of memory. In the best case, the +only visible result is that both the Home application and the unaligned +application launch slower than they otherwise should. In the worst case, +installing several applications with unaligned resources increases memory +pressure, thus causing the system to thrash around by having to constantly start +and kill processes. The user ends up with a slow device with a poor battery +life.

        + +

        Luckily, it's very easy for you to align the resources in your application:

        + +
          +
        • Using ADT:
        • +
        • +
            +
          • The ADT plugin for Eclipse (starting from version 0.9.3) will automatically +align release application packages if the export wizard is used to create them. +To use the wizard, right click the project and choose "Android Tools" > +"Export Signed Application Package..." It can also be accessed from the first +page of the AndroidManifest.xml editor.
          • +
          +
        • +
        • Using Ant:
        • + +
            +
          • The Ant build script (starting from Android 1.6) can align +application packages. Targets for older versions of the Android platform are not +aligned by the Ant build script and need to be manually aligned.
          • +
          • Starting from the Android 1.6 SDK, Ant aligns and signs packages automatically, +when building in debug mode.
          • +
          • In release mode, Ant aligns packages only if it has enough +information to sign the packages, since aligning has to happen after signing. In +order to be able to sign packages, and therefore to align them, Ant +needs to know the location of the keystore and the name of the key in +build.properties. The name of the properties are +key.store and key.alias respectively. If those +properties are present, the signing tool will prompt to enter the store/key +passwords during the build, and the script will sign and then align the apk +file. If the properties are missing, the release package will not be signed, and +therefore will not get aligned either.
          • +
          +
        • +
        • Manually:
        • +
        • +
            +
          • In order to manually align a package, zipalign +is in the tools/ folder of Android 1.6 and later SDKs. You can use +it to align application packages targeting any version of Android. You should run +it only after signing the apk file, using the following command: +
            zipalign -v 4 source.apk destination.apk
          • +
          +
        • +
        • Verifying alignment:
        • +
        • +
            +
          • The following command verifies that a package is aligned:
            zipalign -c -v 4 application.apk +
          • +
          +
        • +
        + +

        We encourage you manually run zipalign +on your currently published applications and to make the newly aligned +versions available to users. Also, don't forget to align any new +applications going forward!

        diff --git a/docs/html/resources/community-groups.jd b/docs/html/resources/community-groups.jd new file mode 100644 index 0000000..61fbcc8 --- /dev/null +++ b/docs/html/resources/community-groups.jd @@ -0,0 +1,121 @@ +community=true +page.title=Android Developer Groups +@jd:body + +

        Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the Groups Charter that covers the community guidelines.

        + +

        Note: If you are seeking discussion about Android source code (not application development), +then please refer to the Open Source Project Mailing lists.

        + +

        Contents

        +
          +
        1. Before you post
        2. +
        3. Application developer mailing lists
        4. +
        5. Using email with the mailing lists
        6. +
        + +

        Before you post

        +

        Before writing a post, please try the following:

        + +
          +
        1. Read the FAQs The most common questions about developing Android applications are addressed in this frequently updated list.
        2. +
        3. Type in keywords of your questions in the main Android site's search bar (such as the one above). This search encompasses all previous discussions, across all groups, as well as the full contents of the site, documentation, and blogs. Chances are good that somebody has run into the same issue before.
        4. +
        5. Search the mailing list archives to see whether your questions have already been discussed. +
        6. +
        + +

        If you can't find your answer, then we encourage you to address the community. +As you write your post, please do the following: +

          +
        1. Read +the mailing list charter that covers the community guidelines. +
        2. +
        3. Select the most appropriate mailing list for your question. There are several different lists for +developers, described below.
        4. +
        5. + Be very clear about your question +in the subject -- it helps everyone, both those trying to answer your +question as well as those who may be looking for information in the +future.
        6. +
        7. Give plenty of details in your post to +help others understand your problem. Code or log snippets, as well as +pointers to screenshots, may also be helpful. For a great guide to +phrasing your questions, read How To Ask Questions The Smart Way. +
        8. +
        + + +

        Application developer mailing lists

        +
          +
        • Android beginners - You're new to Android application development. You want to figure out how to get started with the Android SDK and the basic Android APIs? Start here. This list is open to any discussion around beginner-type questions for developers using the SDK; this is a great way to get up and running with your new application on the Android platform. Ask about getting your development environment set up, get help with the first steps of Android development (your first User Interface, your first permission, your first file on the Android filesystem, your first app on the Android Market...). Be sure to check the archives first before asking new questions. Please avoid advanced subjects, which belong on android-developers, and user questions, which will get a better reception on android-discuss. + +
        • + +
        • Android developers - You're now an experienced Android application developer. You've grasped the basics of Android app development, you're comfortable using the SDK, now you want to move to advanced topics. Get help here with troubleshooting applications, advice on implementation, and strategies for improving your application's performance and user experience. This is the not the right place to discuss user issues (use android-discuss for that) or beginner questions with the Android SDK (use android-beginners for that). + +
        • + +
        • Android discuss - The "water cooler" of Android discussion. You can discuss just about anything Android-related here, ideas for the Android platform, announcements about your applications, discussions about Android devices, community resources... As long as your discussion is related to Android, it's on-topic here. However, if you have a discussion here that could belong on another list, you are probably not reaching all of your target audience here and may want to consider shifting to a more targeted list. + +
        • + +
        • Android ndk - A place for discussing the Android NDK and topics related to using native code in Android applications. + +
        • + +
        • Android security discuss - A place for open discussion on secure development, emerging security concerns, and best practices for and by android developers. Please don't disclose vulnerabilities directly on this list, you'd be putting all Android users at risk. + +
        • + +
        • Android security announce - A low-volume group for security-related announcements by the Android Security Team. + +
        • + +
        • Android Market Help Forum - A web-based discussion forum where you can ask questions or report issues relating to Android Market. + +
        • + +
        + + + +

        Using email with the mailing lists

        +

        Instead of using the Google Groups site, you can use your email client of choice to participate in the mailing lists.

        +

        To subscribe to a group without using the Google Groups site, use the link under "subscribe via email" in the lists above.

        +

        To set up how you receive mailing list postings by email:

        + +
        1. Sign into the group via the Google Groups site. For example, for the android-framework group you would visit http://groups.google.com/group/android-framework.
        2. +
        3. Click "Edit +my membership" on the right side.
        4. +
        5. Under "How do +you want to read this group?" select one of the email options.
        6. +
        + + + + + + + + + diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd new file mode 100644 index 0000000..2be015a --- /dev/null +++ b/docs/html/resources/community-more.jd @@ -0,0 +1,48 @@ +community=true +page.title=IRC and Twitter +@jd:body + +

        In addition to the Android developer groups, you can also participate in the Android developer community through IRC, and you can also follow us on Twitter.

        + +

        IRC

        + +

        Several IRC channels are available for discussions about developing Android applications.

        + + + + + + + + + + + + + + + +
        ChannelHostDescription
        #androidirc.freenode.netGeneral discussion about Android (and Android development).
        #android-devirc.freenode.netDiscussion focused on developing Android apps.
        + +

        If you haven't used IRC before, check http://en.wikipedia.org/wiki/List_of_IRC_clients » for a helpful list of IRC clients. Alternatively, you could also use this web interface », which does not require any installation, to join discussions on the Android IRC channels.

        + +

        Here are some tips for using IRC: + +

          +
        • Set your nickname before you join the channel.
        • +
        • Registering your nickname prevents others from using your nickname or impersonating you later: +
          /nick <yournickname>
          +/msg nickserv register <password> <email>
          +

          Afterwards, when you connect, you'll need to supply a password:

          +
          /connect irc.freenode.net
          +/nick <yournickname>
          +/msg nickserv identify <password>
          +/join #android-dev
          +
        • +
        + +

        Twitter

        +

        You can follow us on Twitter at this account:

        + +

        http://twitter.com/androiddev

        + diff --git a/docs/html/resources/faq/commontasks.jd b/docs/html/resources/faq/commontasks.jd new file mode 100644 index 0000000..fa487f7 --- /dev/null +++ b/docs/html/resources/faq/commontasks.jd @@ -0,0 +1,821 @@ +page.title=Common Tasks and How to Do Them in Android +parent.title=FAQs, Tips, and How-to +parent.link=index.html +@jd:body + + +

        The ApiDemos sample application includes many, many examples of common +tasks and UI features. See the code inside +<sdk>samples/ApiDemos and the other sample applications +under the samples/ folder in the SDK.

        + + +

        Creating an Android Application using the Eclipse Plugin

        + +

        Using the Android Eclipse plugin is the fastest and easiest way +to start creating a new Android application. The plugin automatically generates +the correct project structure for your application, and keeps the resources +compiled for you automatically.

        + +

        It is still a good idea to know what is going on though. Take a look at Application Fundamentals +to understand the basics of how an Android application works.

        + +

        You should also take a look at the ApiDemos application and the other sample +applications included in the SDK, in the <sdk>/samples/ +folder in the SDK.

        + +

        Finally, a great way to started with Android development in Eclipse is to +follow both the Hello, +World and Notepad code +tutorials. In particular, the start of the Hello Android tutorial is an +excellent introduction to creating a new Android application in Eclipse.

        + +

        Creating an Android Application without the Eclipse Plugin

        + +

        This topic describes the manual steps in creating an Android application. +Before reading this, you should read Application Fundamentals +to understand the basics of how an Android application works. You might also +want to look at the sample code included with the Android SDK, in the +<sdk>/samples/ directory.

        + +

        Here is a list of the basic steps in building an application.

        +
          +
        1. Create your required resource files   This includes + the AndroidManifest.xml global description file, string files that your application + needs, and layout files describing your user interface. A full list of optional + and required files and syntax details for each is given in File + List for an Android Application.
        2. +
        3. Design your user interface   See User Interface for + details on elements of the Android screen.
        4. +
        5. Implement your Activity (this page)   You + will create one class/file for each screen in your application. Screens will + inherit from an {@link android.app android.app} class, typically {@link android.app.Activity + android.app.Activity} for basic screens, {@link android.app.ListActivity + android.app.ListActivity} for list screens, or {@link android.app.Dialog + android.app.Dialog} for dialog boxes. You will implement the required callbacks + that let you draw your screen, query data, and commit changes, and also perform + any required tasks such as opening additional screens or reading data from + the device. Common tasks, such as opening a new screen or reading data from + the device, are described below. + The list of files you'll need for your application are described in List + of Files for an Android Application.
        6. +
        7. Build and install your + package. The Android SDK has some nice tools for generating + projects and debugging code.
        8. +
        + +

        Adding an External Library (.jar) using Eclipse

        +

        +You can use a third party JAR in your application by adding it to your Eclipse project as follows: +

        +
          +
        1. +In the Package Explorer panel, right-click on your project and select Properties. +
        2. +Select Java Build Path, then the tab Libraries. +
        3. +Press the Add External JARs... button and select the JAR file. +
        +

        +Alternatively, if you want to include third party JARs with your package, create a new directory for them within your project and select Add Library... instead.

        +

        +It is not necessary to put external JARs in the assets folder. +

        + + +

        Implementing Activity Callbacks

        +

        Android calls a number of callbacks to let you draw your screen, store data before + pausing, and refresh data after closing. You must implement at least some of + these methods. See Lifecycles + discussion in Application Fundamentals to learn when and in what order these methods + are called. Here are some of the standard types of screen classes that Android provides:

        +
          +
        • {@link android.app.Activity android.app.Activity} - This is a standard screen, + with no specialization.
        • +
        • {@link android.app.ListActivity android.app.ListActivity} - This is a screen + that is used to display a list of something. It hosts a ListView object, + and exposes methods to let you identify the selected item, receive callbacks + when the selected item changes, and perform other list-related actions.
        • +
        • {@link android.app.Dialog android.app.Dialog} - This is a small, popup dialog-style + window that isn't intended to remain in the history stack. (It is not resizeable + or moveable by the user.)
        • +
        + +

        Opening a New Screen

        +

        Your Activity will often need to open another Activity screen as it progresses. + This new screen can be part of the same application or part of another application, + the new screen can be floating or full screen, it can return a result, and you + can decide whether to close this screen and remove it from the history stack + when you are done with it, or to keep the screen open in history. These next + sections describe all these options.

        +

        Floating or full?

        +

        When you open a new screen you can decide whether to make it transparent or floating, + or full-screen. The choice of new screen affects the event sequence of events + in the old screen (if the new screen obscures the old screen, a different + series of events is called in the old screen). See Lifecycles discussion + in Application Fundamentals for details.

        +

        Transparent or floating windows are implemented in three + standard ways:

        +
          +
        • Create an {@link android.app.Dialog app.Dialog} class
        • +
        • Create an {@link android.app.AlertDialog app.AlertDialog} class
        • +
        • Set the {@link android.R.style#Theme_Dialog} theme attribute to @android:style/Theme.Dialog + in your AndroidManifest.xml file. For example: +
        +
        +
        <activity class="AddRssItem" android:label="Add an item" android:theme="@android:style/Theme.Dialog"/>
        +
        +
        +

        Calling startActivity() or startActivityForResult() will open a new screen in whatever + way it defines itself (if it uses a floating theme it will be floating, + otherwise it will be full screen).

        +

        Opening a Screen

        +

        When you want to open a new screen, you can either explicitly specify the activity + class to open, or you can let the operating system decide which screen to open, + based upon the data and various parameters you pass in. A screen is opened by + calling {@link android.app.Activity#startActivity(android.content.Intent) startActivity} + and passing in an {@link android.content.Intent Intent} object, which specifies + the criteria for the handling screen. To specify a specific screen, call Intent.setClass + or setClassName with the exact activity class to open. Otherwise, set a variety + of values and data, and let Android decide which screen is appropriate to open. + Android will find one or zero Activities that match the specified requirements; + it will never open multiple activities for a single request. More information + on Intents and how Android resolves them to a specific class is given in the + {@link android.content.Intent Intent} topic.

        +

        Some Intent examples

        +

        The following snippet loads the com.android.samples.Animation1 class, and + passes it some arbitrary data.:

        +
        Intent myIntent = new Intent();
        +myIntent.setClassName("com.android.samples", "com.android.samples.Animation1");
        +myIntent.putExtra("com.android.samples.SpecialValue", "Hello, Joe!"); // key/value pair, where key needs current package prefix.
        +startActivity(myIntent);    
        +

        The next snippet requests that a Web page be opened by specifying the VIEW action, + and a URI data string starting with "http://" schema:

        +
        Intent myIntent = new Intent(Intent.VIEW_ACTION, Uri.parse("http://www.google.com"));
        +

        Here is the intent filter from the AndroidManifest.xml file for com.android.browser:

        +
        <intent-filter>
        +    <action android:name="android.intent.action.VIEW" />
        +    <category android:name="android.intent.category.DEFAULT" />
        +    <scheme android:name="http" />
        +    <scheme android:name="https" />
        +    <scheme android:name="file" />
        +</intent-filter> 
        +

        Android defines a number of standard values, for instance the action constants + defined by {@link android.content.Intent}. You can define custom values, but + both the caller and handler must use them. See the <intent-filter> + tag description in The AndroidManifest.xml + File for more information on the manifest syntax for the handling + application.

        +

        Returning a Result from a Screen

        +

        A window can return a result after it closes. This result will be passed back + into the calling Activity's {@link android.app.Activity#onActivityResult(int,int,android.content.Intent) + onActivityResult()} method, which can supply an Intent containing arbitrary data, along with + the request code passed to startActivityForResult(). Note that you must call the {@link + android.app.Activity#startActivityForResult(android.content.Intent,int) startActivityForResult()} + method that accepts a request code parameter to get this callback. The following + code demonstrates opening a new screen and retrieving a result.

        +
        // Open the new screen.
        +public void onClick(View v){
        +    // Start the activity whose result we want to retrieve.  The
        +    // result will come back with request code GET_CODE.
        +    Intent intent = new Intent(this, com.example.app.ChooseYourBoxer.class);
        +    startActivityForResult(intent, CHOOSE_FIGHTER);
        +}
        +
        +// Listen for results.
        +protected void onActivityResult(int requestCode, int resultCode, Intent data){
        +    // See which child activity is calling us back.
        +    switch (resultCode) {
        +        case CHOOSE_FIGHTER:
        +            // This is the standard resultCode that is sent back if the
        +            // activity crashed or didn't doesn't supply an explicit result.
        +            if (resultCode == RESULT_CANCELED){
        +                myMessageboxFunction("Fight cancelled");
        +            } 
        +            else {
        +                myFightFunction(data);
        +            }
        +        default:
        +            break;
        +    }
        +}
        +
        +// Class SentResult
        +// Temporary screen to let the user choose something.
        +    private OnClickListener mLincolnListener = new OnClickListener(){
        +        public void onClick(View v) {
        +            Bundle stats = new Bundle();
        +            stats.putString("height","6\'4\""); 
        +            stats.putString("weight", "190 lbs");
        +            stats.putString("reach", "74\"");
        +            setResult(RESULT_OK, "Lincoln", stats);
        +            finish();
        +        }
        +    };
        +
        +    private OnClickListener mWashingtonListener = new OnClickListener() {
        +        public void onClick(View v){
        +            Bundle stats = new Bundle();
        +            stats.putString("height","6\'2\""); 
        +            stats.putString("weight", "190 lbs");
        +            stats.putString("reach", "73\"");
        +            setResult(RESULT_OK, "Washington", Bundle);
        +            finish();
        +        }
        +    };
        +	
        +

        Lifetime of the new screen

        +

        An activity can remove itself from the history stack by calling {@link android.app.Activity#finish() + Activity.finish()} on itself, or the activity that opened the screen can call + {@link android.app.Activity#finishActivity(int) Activity.finishActivity()} + on any screens that it opens to close them.

        +

        Listening for Button Clicks

        +

        Button click and other UI event capturing are covered in Handling UI Events on the UI Design page.

        +

        Configuring General Window Properties

        +

        You can set a number of general window properties, such as whether to display + a title, whether the window is floating, and whether it displays an icon, by + calling methods on the {@link android.view.Window Window} member + of the underlying View object for the window. Examples include calling {@link + android.app.Activity#getWindow() getWindow().requestFeature()} (or the convenience + method {@link android.app.Activity#requestWindowFeature(int) requestWindowFeature(some_feature)}) + to hide the title. Here is an example of hiding the title bar:

        +
        //Hide the title bar
        +requestWindowFeature(Window.FEATURE_NO_TITLE);
        +
        +

        A better way to achieve the same end is to specify a theme in your Android +Manifest file:

        +
        <application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
        +
        +

        This is preferable because it tells the system not to show a title bar while +your application is starting up. With the explicit method call, your application +will have a title bar visible to the user until onCreate runs.

        +

        (Note that this can be applied to either the <application> +tag or to individual <activity> tags.)

        +

        Referring to localhost from the emulated environment

        +

        +If you need to refer to your host computer's localhost, such as when you +want the emulator client to contact a server running on the same host, use the alias +10.0.2.2 to refer to the host computer's loopback interface. +From the emulator's perspective, localhost (127.0.0.1) refers to its own +loopback interface. +

        +

        Storing and Retrieving State

        +

        If your application is dumped from memory because of space concerns, it will lose + all user interface state information such as checkbox state and text box values + as well as class member values. Android calls {@link android.app.Activity#onSaveInstanceState(android.os.Bundle) + Activity.onSaveInstanceState} before it pauses the application. This method hands in a {@link + android.os.Bundle Bundle} that can be used to store name/value pairs that will + persist and be handed back to the application even if it is dropped from memory. + Android will pass this Bundle back to you when it calls {@link android.app.Activity#onCreate(android.os.Bundle) + onCreate()}. This Bundle only exists while the application is still in the history + stack (whether or not it has been removed from memory) and will be lost when + the application is finalized. See the topics for {@link android.app.Activity#onSaveInstanceState} and + {@link android.app.Activity#onCreate} for + examples of storing and retrieving state.

        +

        Read more about the lifecycle of an application in Application Fundamentals.

        +

        Storing and Retrieving Larger or More Complex Persistent Data

        +

        Your application can store files or complex collection objects, and reserve them + for private use by itself or other activities in the application, or it can expose + its data to all other applications on the device. See Storing, + Retrieving, and Exposing Data to learn how to store and retrieve private data, + how to store and retrieve common data from the device, and how to expose your + private data to other applications.

        +

        Playing Media Files

        +

        Please see the document Audio and Video for more details.

        +

        Listening For and Broadcasting Global Messages, and Setting Alarms

        +

        You can create a listening class that can be notified or even instantiated whenever + a specific type of system message is sent. +

        +

        The listening classes, called broadcast receivers, extend {@link android.content.BroadcastReceiver + BroadcastReceiver}. If you want Android to instantiate the object whenever an appropriate + intent notification is sent, define the receiver with a <receiver> element + in the AndroidManifext.xml file. If the caller is expected to instantiate the + object in preparation to receive a message, this is not required. The receiver + will get a call to their {@link android.content.BroadcastReceiver#onReceive(android.content.Context,android.content.Intent) + BroadcastReceiver.onReceive()} method. A receiver can define an <intent-filter> tag + that describes the types of messages it will receive. Just as Android's IntentResolver + will look for appropriate Activity matches for a startActivity() call, it will + look for any matching Receivers (but it will send the message to all matching + receivers, not to the "best" match).

        +

        To send a notification, the caller creates an {@link android.content.Intent Intent} + object and calls {@link android.app.Activity#sendBroadcast(android.content.Intent) + Context.sendBroadcast()} with that Intent. Multiple recipients can receive + the same message. You can broadcast an Intent message to an intent receiver in + any application, not only your own. If the receiving class is not registered + using <receiver> in its manifest, you can dynamically instantiate + and register a receiver by calling {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,android.content.IntentFilter) + Context.registerReceiver()}.

        +

        Receivers can include intent filters to specify what kinds of intents they are + listening for. Alternatively, if you expect a single known caller to contact + a single known receiver, the receiver does not specify an intent filter, and + the caller specifies the receiver's class name in the Intent by calling {@link + android.content.Intent#setClassName(java.lang.String, java.lang.String) Intent.setClassName()} + with the recipient's class name. The recipient receives a {@link android.content.Context + Context} object that refers to its own package, not to the package of the sender.

        +

        Note:   If a receiver or broadcaster + enforces permissions, your application might need to request permission + to send or receive messages from that object. You can request permission by using + the <uses-permission> tag in the manifest.

        +

        Here is a code snippet of a sender and receiver. This example does not demonstrate + registering receivers dynamically. For a full code example, see the AlarmService + class in the ApiDemos project.

        +

        Sending the message

        +
        // We are sending this to a specific recipient, so we will
        +// only specify the recipient class name. 
        +Intent intent = new Intent(this, AlarmReceiver.class);
        +intent.putExtra("message","Wake up.");
        +sendBroadcast(intent);
        +
        +

        Receiving the message

        +

        Receiver AndroidManifest.xml (because there is no intent filter + child, this class will only receive a broadcast when the receiver class is specified + by name, as is done in this example):

        +
        +<receiver class=".AlarmReceiver" />
        +

        Receiver Java code:

        +
        +public class AlarmReceiver extends BroadcastReceiver{
        +    // Display an alert that we've received a message.    
        +    @Override 
        +    public void onReceive(Context context, Intent intent){
        +	    // Send a text notification to the screen.
        +        NotificationManager nm = (NotificationManager)
        +        context.getSystemService(Context.NOTIFICATION_SERVICE);
        +        nm.notifyWithText(R.id.alarm,
        +                          "Alarm!!!",
        +                          NotificationManager.LENGTH_SHORT,
        +                          null);
        +   }
        +}   
        +

        Other system messages

        +

        You can listen for other system messages sent by Android as well, such as USB + connection/removal messages, SMS arrival messages, and timezone changes. See + {@link android.content.Intent} for a list of broadcast messages to listen for. + Messages are marked "Broadcast Action" in the documentation.

        +

        Listening for phone events

        +

        The {@link android.telephony android.telephony} package overview page describes how to + register to listen for phone events.

        +

        Setting Alarms

        +

        Android provides an {@link android.app.AlarmManager AlarmManager} service that + will let you specify an Intent to send at a designated time. This intent is typically + used to start an application at a preset time. (Note: If you want to send + a notification to a sleeping or running application, use {@link android.os.Handler + Handler} instead.)

        +

        Displaying Alerts

        +

        There are two major kinds of alerts that you may display to the user: +(1) Normal alerts are displayed in response to a user action, such as +trying to perform an action that is not allowed. (2) Out-of-band alerts, +called notifications, are +displayed as a result of something happening in the background, such as the +user receiving new e-mail.

        + +

        Normal Alerts

        + +

        Android provides a number of ways for you to show popup notifications to your + user as they interact with your application.

        + + + + + + + + + + + + + + + + + + + + + +
        ClassDescription
        {@link android.app.Dialog app.Dialog}A generic floating dialog box with a layout that you design.

        {@link android.app.AlertDialog app.AlertDialog}

        A popup alert dialog with two buttons (typically OK and Cancel) that + take callback handlers. See the section after this table for more details.
        {@link android.app.ProgressDialog ProgressDialog} A dialog box used to indicate progress of an operation with a known progress + value or an indeterminate length (setProgress(bool)). See Views > Progress Bar in + ApiDemos for examples.
        ActivityBy setting the theme of an activity to + {@link android.R.style#Theme_Dialog + android:theme="@android:style/Theme.Dialog"}, + your activity will take on + the appearance of a normal dialog, floating on top of whatever was + underneath it. You usually set the theme through the + {@link android.R.attr#theme android:theme} attribute in your AndroidManifest.xml. + The advantage of this + over Dialog and AlertDialog is that Application has a much better managed + life cycle than dialogs: if a dialog goes to the background and is killed, + you cannot recapture state, whereas Application exposes a {@link android.os.Bundle + Bundle} of saved values in onCreate() to help you maintain state.
        +

        AlertDialog

        +

        This is a basic warning dialog box that lets you configure a message, button text, + and callback. You can create one by calling using the {@link + android.app.AlertDialog.Builder} class, as shown here.

        +
        private Handler mHandler = new Handler() {
        +    public void handleMessage(Message msg) {
        +        switch (msg.what) {
        +            case ACCEPT_CALL:
        +            answer(msg.obj);
        +            break;
        +    
        +            case BOUNCE_TO_VOICEMAIL:
        +            voicemail(msg.obj);
        +            break;
        +    
        +        }
        +    }
        +};
        +
        +
        +private void IncomingMotherInlawCall(Connection c) {
        +    String Text;
        +    
        +    // "Answer" callback.
        +    Message acceptMsg = Message.obtain();
        +    acceptMsg.target = mHandler;
        +    acceptMsg.what = ACCEPT_CALL;
        +    acceptMsg.obj = c.getCall();
        +    
        +    // "Cancel" callback.
        +    final Message rejectMsg = Message.obtain();
        +    rejectMsg.target = mHandler;
        +    rejectMsg.what = BOUNCE_TO_VOICEMAIL;
        +    rejectMsg.obj = c.getCall();
        +
        +    new AlertDialog.Builder(this)
        +      .setMessage("Phyllis is calling")
        +      .setPositiveButton("Answer", acceptMsg)
        +      .setOnCanceListener(new OnCancelListener() {
        +        public void onCancel(DialogInterface dialog) {
        +          rejectMsg.sendToTarget();
        +        }});
        +      .show();
        +}    
        + +

        Notifications

        + +

        Out-of-band alerts should always be displayed using the +{@link android.app.NotificationManager}, which allows you to tell the user +about something they may be interested in without disrupting what they are +currently doing. A notification can be anything from a brief pop-up box +informing the user of the new information, through displaying a persistent +icon in the status bar, to vibrating, playing sounds, or flashing lights to +get the user's attention. In all cases, the user must explicitly shift their +focus to the notification before they can interact with it.

        + +

        The following code demonstrates using NotificationManager to display a basic text + popup when a new SMS message arrives in a listening service, and provides the + current message count. You can see several more examples in the ApiDemos application, + under app/ (named notification*.java).

        +
        static void setNewMessageIndicator(Context context, int messageCount){
        +   // Get the static global NotificationManager object.
        +   NotificationManager nm = NotificationManager.getDefault();

        + + // If we're being called because a new message has been received, + // then display an icon and a count. Otherwise, delete the persistent + // message. + if (messageCount > 0) { + nm.notifyWithText(myApp.NOTIFICATION_GUID, // ID for this notification. + messageCount + " new message" + messageCount > 1 ? "s":"", // Text to display. + NotificationManager.LENGTH_SHORT); // Show it for a short time only. + } +}
        +

        To display a notification in the status bar and have it launch an intent when + the user selects it (such as the new text message notification does), call {@link + android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}, + and pass in vibration patterns, status bar icons, or Intents to associate with + the notification.

        +

        Displaying a Progress Bar

        +

        An activity can display a progress bar to notify the user that something is happening. + To display a progress bar in a screen, call {@link android.app.Activity#requestWindowFeature(int) + Activity.requestWindowFeature(Window.FEATURE_PROGRESS)}. To set the value + of the progress bar, call {@link android.view.Window#setFeatureInt(int,int) + Activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, level)}. + Progress bar values are from 0 to 9,999, or set the value to 10,000 to make the + progress bar invisible.

        +

        You can also use the {@link android.app.ProgressDialog ProgressDialog} class, + which enables a dialog box with an embedded progress bar to send a "I'm working + on it" notification to the user.

        +

        Adding Items to the Screen Menu

        +

        See Creating Menus.

        + +

        Display a Web Page

        +

        Use the {@link android.webkit.WebView webkit.WebView} object.

        +

        Binding to Data

        +

        You can bind a ListView to a set of underlying data by using a shim class called + {@link android.widget.ListAdapter ListAdapter} (or a subclass). ListAdapter subclasses + bind to a variety of data sources, and expose a common set of methods such as + getItem() and getView(), and uses them to pick View items to display in its list. + You can extend ListAdapter and override getView() to create your own custom list + items. There are essentially only two steps you need to perform to bind to data:

        +
          +
        1. Create a ListAdapter object and specify its data source
        2. +
        3. Give the ListAdapter to your ListView object.
        4. +
        +

        That's it!

        +

        Here's an example of binding a ListActivity screen to the results from a cursor + query. (Note that the setListAdapter() method shown is a convenience method that + gets the page's ListView object and calls setAdapter() on it.)

        +
        // Run a query and get a Cursor pointing to the results.
        +Cursor c = People.query(this.getContentResolver(), null);
        +startManagingCursor(c);
        +
        +// Create the ListAdapter. A SimpleCursorAdapter lets you specify two interesting things:
        +// an XML template for your list item, and
        +// The column to map to a specific item, by ID, in your template.
        +ListAdapter adapter = new SimpleCursorAdapter(this,  
        +                android.R.layout.simple_list_item_1,  // Use a template that displays a text view
        +                c,                                    // Give the cursor to the list adapter
        +                new String[] {People.NAME} ,          // Map the NAME column in the people database to...
        +                new String[] {"text1"});              // The "text1" view defined in the XML template
        +setListAdapter(adapter);
        +

        See view/List4 in the ApiDemos project for an example of extending ListAdapter + for a new data type.

        + + + +

        Getting a Handle to a Screen Element

        +

        You can get a handle to a screen element by calling {@link +android.app.Activity#findViewById(int) Activity.findViewById}. You can then use +the handle to set or retrieve any values exposed by the object.

        +

        Capture Images from the Phone Camera

        +

        You can hook into the device's camera onto your own Canvas object by using the + {@link android.hardware.Camera Camera} class. See that class's documentation, + and the ApiDemos project's Camera Preview application (Graphics/Camera Preview) + for example code.

        + + +

        Handling Expensive Operations in the UI Thread

        +

        Avoid performing long-running operations (such as network I/O) directly in the UI thread — +the main thread of an application where the UI is run — or your application may be blocked +and become unresponsive. Here is a brief summary of the recommended approach for handling expensive operations:

        +
          +
        1. Create a Handler object in your UI thread
        2. +
        3. Spawn off worker threads to perform any required expensive operations
        4. +
        5. Post results from a worker thread back to the UI thread's handler either through a Runnable or a {@link android.os.Message}
        6. +
        7. Update the views on the UI thread as needed
        8. +
        + +

        The following outline illustrates a typical implementation:

        + +
        +public class MyActivity extends Activity {
        +
        +    [ . . . ]
        +    // Need handler for callbacks to the UI thread
        +    final Handler mHandler = new Handler();
        +
        +    // Create runnable for posting
        +    final Runnable mUpdateResults = new Runnable() {
        +        public void run() {
        +            updateResultsInUi();
        +        }
        +    };
        +
        +    @Override
        +    protected void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +
        +        [ . . . ]
        +    }
        +
        +    protected void startLongRunningOperation() {
        +
        +        // Fire off a thread to do some work that we shouldn't do directly in the UI thread
        +        Thread t = new Thread() {
        +            public void run() {
        +                mResults = doSomethingExpensive();
        +                mHandler.post(mUpdateResults);
        +            }
        +        };
        +        t.start();
        +    }
        +
        +    private void updateResultsInUi() {
        +
        +        // Back in the UI thread -- update our UI elements based on the data in mResults
        +        [ . . . ]
        +    }
        +}
        +
        + +

        For further discussions on this topic, see +Designing for Responsiveness +and the {@link android.os.Handler} documentation.

        + +

        Selecting, Highlighting, or Styling Portions of Text

        +

        You can highlight or style the formatting of strings or substrings of text in + a TextView object. There are two ways to do this:

        +
          +
        • If you use a string resource, + you can add some simple styling, such as bold or italic using HTML notation. + The currently supported tags are: B (bold), + I (italic), U (underline), + TT (monospace), BIG, SMALL, + SUP (superscript), SUB (subscript), + and STRIKE (strikethrough). + So, for example, in res/values/strings.xml you could declare this:
          + <resource>
          +     <string>id="@+id/styled_welcome_message">We + are <b><i>so</i></b> glad to see you.</string>
          + </resources>
        • +
        • To style text on the fly, or to add highlighting or more complex styling, + you must use the Spannable object as described next.
        • +
        +

        To style text on the fly, you must make sure the TextView is using {@link android.text.Spannable} + storage for the text (this will always be true if the TextView is an EditText), + retrieve its text with {@link android.widget.TextView#getText}, and call {@link + android.text.Spannable#setSpan}, passing in a new style class from the {@link + android.text.style} package and the selection range.

        +

        The following code snippet demonstrates creating a string with a highlighted section, + italic section, and bold section, and adding it to an EditText object.

        +
        // Get our EditText object.
        +EditText vw = (EditText)findViewById(R.id.text);
        +
        +// Set the EditText's text.
        +vw.setText("Italic, highlighted, bold.");
        +
        +// If this were just a TextView, we could do:
        +// vw.setText("Italic, highlighted, bold.", TextView.BufferType.SPANNABLE);
        +// to force it to use Spannable storage so styles can be attached.
        +// Or we could specify that in the XML.
        +
        +// Get the EditText's internal text storage
        +Spannable str = vw.getText();
        +
        +// Create our span sections, and assign a format to each.
        +str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        +str.setSpan(new BackgroundColorSpan(0xFFFFFF00), 8, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        +str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, str.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        +
        + +

        Utilizing attributes in a Map query

        +

        +When using a search intent to ask the Maps activity to search for something, the Maps activity responds to the following attributes in the optional context bundle: +

        +
        +               float "centerLatitude" default 0.0f
        +               float "centerLongitude" default 0.0f
        +               float "latitudeSpan" default 0.0f
        +               float "longitudeSpan" default 0.0f
        +               int "zoomLevel" default 10
        +
        +

        +This context information is used to center the search result in a particular area, and is equivalent to adjusting the Map activity to the described location and zoom level before issuing the query. +

        +

        +If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent, then it is undefined which one takes precedence. +

        + +

        List of Files for an Android Application

        +

        The following list describes the structure and files of an Android application. + Many of these files can be built for you (or stubbed out) by the android tool + shipped in the tools/ menu of the SDK.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        MyApp/
         
            AndroidManifest.xml(required) Advertises the screens that this application provides, + where they can be launched (from the main program menu or elsewhere), + any content providers it implements and what kind of data they handle, + where the implementation classes are, and other application-wide + information. Syntax details for this file are described in The AndroidManifest.xml File.
            src/
        +         /myPackagePath/.../MyClass.java
        (required) This folder holds all the source code files for your + application, inside the appropriate package subfolders.
            res/(required) This folder holds all the resources for + your application. Resources are external data files or description files + that are compiled into your code at build time. Files in different folders + are compiled differently, so you must put the proper resource into the + proper folder. (See Resources for details.)
                anim/
        +                animation1.xml
        +                         ...
        (optional) Holds any animation XML description files that the + application uses. The format of these files is described in Resources.
                drawable/
        +                       some_picture.png
        +                       some_stretchable.9.png
        +                       some_background.xml
        +                                     ...
        (optional) Zero or more files that will be compiled to {@link + android.graphics.drawable android.graphics.drawable} resources. Files + can be image files (png, gif, or other) or XML files describing other + graphics such as bitmaps, stretchable bitmaps, or gradients. Supported + bitmap file formats are PNG (preferred), JPG, and GIF (discouraged), + as well as the custom 9-patch stretchable bitmap format. These formats + are described in Resources.
                layout/
        +                       screen_1_layout.xml
        +                                  ...
        (optional) Holds all the XML files describing screens or parts + of screens. Although you could create a screen in Java, defining them + in XML files is typically easier. A layout file is similar in concept + to an HTML file that describes the screen layout and components. See User Interface for more information about designing screens, and Available Resource Types for the syntax of these files.
                values/
        +                       arrays
        +                       classes.xml
        +                       colors.xml
        +                       dimens.xml
        +                      strings.xml
        +                       styles.xml
        +                       values.xml

        (optional) XML files describing additional resources + such as strings, colors, and styles. The naming, quantity, and number + of these files are not enforced--any XML file is compiled, but these + are the standard names given to these files. However, the syntax + of these files is prescribed by Android, and described in Resources.

        +
                xml/(optional) XML files that can be read at run time on the device.
                raw/(optional) Any files to be copied directly to the device.
        + + + +

        Print Messages to a Log File

        + +

        To write log messages from your application:

        +
        1. Import android.util.Log.
        2. +
        3. Use Log.v(), Log.d(), Log.i(), + Log.w(), or Log.e() to log messages. + (See the {@link android.util.Log} class.)
          E.g., + Log.e(this.toString(), "error: " + err.toString())
        4. +
        5. Launch DDMS from a terminal + by executing ddms in your Android SDK /tools path.
        6. +
        7. Run your application in the Android emulator.
        8. +
        9. From the DDMS application, select the emulator + (e.g., "emulator-5554") and click Device > Run logcat... + to view all the log data.
        10. +
        +

        Note: If you are running Eclipse and +encounter a warning about the VM debug port when opening DDMS, you can ignore it +if you're only interested in logs. However, if you want to further inspect and +control your processes from DDMS, then you should close Eclipse before launching DDMS so that +it may use the VM debugging port.

        + + diff --git a/docs/html/resources/faq/framework.jd b/docs/html/resources/faq/framework.jd new file mode 100644 index 0000000..f4b8db0 --- /dev/null +++ b/docs/html/resources/faq/framework.jd @@ -0,0 +1,197 @@ +page.title=Android Application Framework FAQ +parent.title=FAQs, Tips, and How-to +parent.link=index.html +@jd:body + + + + + + +

        Do all the Activities and Services of an application run in a +single process?

        + +

        All Activities and Services in an application run in a single process by +default. If needed, you can declare an android:process attribute +in your manifest file, to explicitly place a component (Activity/Service) in +another process.

        + + + + + +

        Do all Activities run in the main thread of an application +process?

        + +

        By default, all of the application code in a single process runs +in the main UI thread. This is the same thread +that also handles UI events. The only exception is the code that handles +IPC calls coming in from other processes. The system maintains a +separate pool of transaction threads in each process to dispatch all +incoming IPC calls. The developer should create separate threads for any +long-running code, to avoid blocking the main UI thread.

        + + + + + +

        How do I pass data between Activities/Services within a single +application?

        + +

        It depends on the type of data that you want to share:

        + +

        Primitive Data Types

        + +

        To share primitive data between Activities/Services in an +application, use Intent.putExtras(). For passing primitive data that +needs to persist use the + +Preferences storage mechanism.

        + +

        Non-Persistent Objects

        + +

        For sharing complex non-persistent user-defined objects for short +duration, the following approaches are recommended: +

        +

        The android.app.Application class

        +

        The android.app.Application is a base class for those who need to +maintain global application state. It can be accessed via +getApplication() from any Activity or Service. It has a couple of +life-cycle methods and will be instantiated by Android automatically if +your register it in AndroidManifest.xml.

        + +

        A public static field/method

        +

        An alternate way to make data accessible across Activities/Services is to use public static +fields and/or methods. You can access these static fields from any other +class in your application. To share an object, the activity which creates your object sets a +static field to point to this object and any other activity that wants to use +this object just accesses this static field.

        + +

        A HashMap of WeakReferences to Objects

        +

        You can also use a HashMap of WeakReferences to Objects with Long +keys. When an activity wants to pass an object to another activity, it +simply puts the object in the map and sends the key (which is a unique +Long based on a counter or time stamp) to the recipient activity via +intent extras. The recipient activity retrieves the object using this +key.

        + +

        A Singleton class

        +

        There are advantages to using a static Singleton, such as you can +refer to them without casting getApplication() to an +application-specific class, or going to the trouble of hanging an +interface on all your Application subclasses so that your various +modules can refer to that interface instead.

        +

        But, the life cycle of a static is not well under your control; so +to abide by the life-cycle model, the application class should initiate and +tear down these static objects in the onCreate() and onTerminate() methods +of the Application Class

        +

        + +

        Persistent Objects

        + +

        Even while an application appears to continue running, the system +may choose to kill its process and restart it later. If you have data +that you need to persist from one activity invocation to the next, you +need to represent that data as state that gets saved by an activity when +it is informed that it might go away.

        + +

        For sharing complex persistent user-defined objects, the +following approaches are recommended: +

          +
        • Application Preferences
        • +
        • Files
        • +
        • contentProviders
        • +
        • SQLite DB
        • +
        +

        + +

        If the shared data needs to be retained across points where the application +process can be killed, then place that data in persistent storage like +Application Preferences, SQLite DB, Files or ContentProviders. Please refer to +the Data Storage +for further details on how to use these components.

        + + + + + + +

        How can I check if an Activity is already running before starting +it?

        + +

        The general mechanism to start a new activity if its not running— +or to bring the activity stack to the front if is already running in the +background— is the to use the NEW_TASK_LAUNCH flag in the startActivity() +call.

        + + + + + +

        If an Activity starts a remote service, is there any way for the +Service to pass a message back to the Activity?

        + +

        The remote service can define a callback interface and register it with the +clients to callback into the clients. The +{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to +register and unregister clients with the service, and send and receive +messages.

        + +

        The sample code for remote service callbacks is given in ApiDemos/RemoteService

        + + + + + +

        How to avoid getting the Application not responding dialog?

        + +

        Please read the Designing for Responsiveness +document.

        + + + + + + +

        How does an application know if a package is added or removed? +

        + +

        Whenever a package is added, an intent with PACKAGE_ADDED action +is broadcast by the system. Similarly when a package is removed, an +intent with PACKAGE_REMOVED action is broadcast. To receive these +intents, you should write something like this: +

        +       <receiver android:name ="com.android.samples.app.PackageReceiver">
        +            <intent-filter>
        +             <action android:name="android.intent.action.PACKAGE_ADDED"/>
        +              <action android:name="android.intent.action.PACKAGE_REMOVED"/>            
        +            
        +              <data android:scheme="package" />
        +            </intent-filter>
        +        </receiver>
        +  
        +
        +Here PackageReceiver is a BroadcastReceiver class.Its onReceive() +method is invoked, every time an application package is installed or +removed. + +

        + + + diff --git a/docs/html/resources/faq/index.jd b/docs/html/resources/faq/index.jd new file mode 100644 index 0000000..9a2614b --- /dev/null +++ b/docs/html/resources/faq/index.jd @@ -0,0 +1,11 @@ +page.title=Android FAQs +@jd:body + +
        +
        Application Framework FAQ
        +
        Common questions about the Android Application Framework.
        +
        Open Source Licensing FAQ
        +
        Common topics around licensing and Android Open Source
        +
        Android Security FAQ
        +
        Answers to common questions about Android security.
        +
        diff --git a/docs/html/resources/faq/licensingandoss.jd b/docs/html/resources/faq/licensingandoss.jd new file mode 100644 index 0000000..c267fe8 --- /dev/null +++ b/docs/html/resources/faq/licensingandoss.jd @@ -0,0 +1,19 @@ +page.title=Android Open Source Licensing FAQ +parent.title=FAQs, Tips, and How-to +parent.link=index.html +@jd:body + + + +

        Where can I find the open source components of Android?

        +

        The source code for the full Android stack is available from the Android Open Source Project site. + +

        Other mirrored GPL and LGPL'd components are available at http://code.google.com/p/android/downloads/list.

        +

        Notices for other licenses can be found within the SDK.

        + +

        Why are you releasing the code under the Apache License instead of GPLv2?

        +

        One of the best explanations for the reasoning behind releasing code under Apache2 can be found in a ArsTechnica article by Ryan Paul.

        diff --git a/docs/html/resources/faq/security.jd b/docs/html/resources/faq/security.jd new file mode 100644 index 0000000..b0d832b --- /dev/null +++ b/docs/html/resources/faq/security.jd @@ -0,0 +1,156 @@ +page.title=Android Security FAQ +parent.title=FAQs, Tips, and How-to +parent.link=index.html +@jd:body + + + + +

        Is Android secure?

        + +

        The security and privacy of our users' data is of primary importance to the +Android Open Source Project. We are dedicated to building and maintaining one +of the most secure mobile platforms available while still fulfilling our goal +of opening the mobile device space to innovation and competition.

        + +

        The Android Platform provides a rich security model +that allows developers to request the capabilities, or access, needed by their +application and to define new capabilities that other applications can request. +The Android user can choose to grant or deny an application's request for +certain capabilities on the handset.

        + +

        We have made great efforts to secure the Android platform, but it is +inevitable that security bugs will be found in any system of this complexity. +Therefore, the Android team works hard to find new bugs internally and responds +quickly and professionally to vulnerability reports from external researchers. +

        + + +

        I think I found a security flaw. How do I +report it?

        + +

        You can reach the Android security team at security@android.com. If you like, you +can protect your message using our PGP +key.

        + +

        We appreciate researchers practicing responsible disclosure by emailing us +with a detailed summary of the issue and keeping the issue confidential while +users are at risk. In return, we will make sure to keep the researcher informed +of our progress in issuing a fix and will properly credit the reporter(s) when +we announce the patch. We will always move swiftly to mitigate or fix an +externally-reported flaw and will publicly announce the fix once patches are +available to users.

        + + +

        How can I stay informed of Android +security announcements?

        + +

        An important part of sustainably securing a platform, such as, Android is +keeping the user and security community informed of bugs and fixes. We will +publicly announce security bugs when the fixes are available via postings to +the android-security-announce +group on Google Groups. You can subscribe to this group as you would a mailing +list and view the archives here.

        + +

        For more general discussion of Android platform security, or how to use +security features in your Android application, please subscribe to android-security-discuss. +

        + + +

        How do I securely use my Android phone?

        + +

        As an open platform, Android allows users to load software from any +developer onto a device. As with a home PC, the user must be +aware of who is providing the software they are downloading and must decide +whether they want to grant the application the capabilities it requests. +This decision can be informed by the user's judgment of the software +developer's trustworthiness, and where the software came from.

        + +

        Despite the security protections in Android, it is important +for users to only download and install software from developers they trust. +More details on how Android users can make smart security decisions will be +released when consumer devices become available.

        + + +

        I think I found malicious software being +distributed for Android. How can I help?

        + +

        Like any other open platform, it will be possible for unethical developers +to create malicious software, known as malware, for Android. If you +think somebody is trying to spread malware, please let us know at security@android.com. Please include as +much detail about the application as possible, with the location it is +being distributed from and why you suspect it of being malicious software.

        + +

        The term malicious software is subjective, and we cannot make an +exhaustive definition. Some examples of what the Android Security Team believes +to be malicious software is any application that: +

          +
        • drains the device's battery very quickly;
        • +
        • shows the user unsolicited messages (especially messages urging the + user to buy something);
        • +
        • resists (or attempts to resist) the user's effort to uninstall it;
        • +
        • attempts to automatically spread itself to other devices;
        • +
        • hides its files and/or processes;
        • +
        • discloses the user's private information to a third party, without the + user's knowledge and consent;
        • +
        • destroys the user's data (or the device itself) without the user's + knowledge and consent;
        • +
        • impersonates the user (such as by sending email or buying things from a + web store) without the user's knowledge and consent; or
        • +
        • otherwise degrades the user's experience with the device.
        • +
        +

        + + +

        How will Android-powered devices receive security +fixes?

        + +

        The manufacturer of each device is responsible for distributing software +upgrades for it, including security fixes. Many devices will update themselves +automatically with software downloaded "over the air", while some devices +require the user to upgrade them manually.

        + +

        When Android-powered devices are publicly available, this FAQ will provide links how +Open Handset Alliance members release updates.

        + +

        Can I get a fix directly from the +Android Platform Project?

        + +

        Android is a mobile platform that will be released as open source and +available for free use by anybody. This means that there will be many +Android-based products available to consumers, and most of them will be created +without the knowledge or participation of the Android Open Source Project. Like +the maintainers of other open source projects, we cannot build and release +patches for the entire ecosystem of products using Android. Instead, we will +work diligently to find and fix flaws as quickly as possible and to distribute +those fixes to the manufacturers of the products.

        + +

        In addition, We will add security fixes to the open source distribution of +Android and publicly announce the changes on android-security-announce. +

        + +

        If you are making an Android-powered device and would like to know how you can +properly support your customers by keeping abreast of software updates, please +contact us at info@openhandsetalliance.com.

        diff --git a/docs/html/resources/faq/troubleshooting.jd b/docs/html/resources/faq/troubleshooting.jd new file mode 100644 index 0000000..0cf1ab0 --- /dev/null +++ b/docs/html/resources/faq/troubleshooting.jd @@ -0,0 +1,261 @@ +page.title=Troubleshooting +parent.title=FAQs, Tips, and How-to +parent.link=index.html +@jd:body + + +

        Here are some tips and tricks for common Android errors. Don't forget to use the + ddms logcat capability to get a deeper view when errors occur. See Debugging for more debugging tips.

        + + +

        ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

        +

        +The "Android Editors" feature of the ADT Plugin requires specific Eclipse components, such as WST. If you +encounter this error message during ADT installation, you need to install the +required Eclipse components and then try the ADT installation again. Follow the steps below to install the required components for the +Android Editors feature, based on the version of Eclipse that you are using.

        + + + + + + + +
        Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
        +
          +
        1. From the dialog where you select the Update sites to visit, select the checkboxes for both the +ADT site, and the Callisto/Europa/Ganymede Discovery Site (you may want to +check Automatically select mirrors at the bottom).
        2. +
        3. Click Finish.
        4. +
        5. In the Next dialog, select the Android Plugins.
        6. +
        7. Now, expand the tree item of the discovery site. It seems that if you +don't do it, it doesn't load the content of the discovery site.
        8. +
        9. On the right, click Select required. This will select all the components +that are required to install the Android plugin (wst, emf, etc...).
        10. +
        11. Click Next, accept the agreement, click Install All, and restart Eclipse.
        12. +
        +
        +
          +
        1. Select Help > Software Updates...
        2. +
        3. Select the Installed Software tab.
        4. +
        5. Click Update...
        6. +
        7. If an update for ADT is available, select it and click Finish.
        8. +
        +
        + + +

        +

        ADB reports "no device" when an emulator is running

        +

        Try restarting adb by stopping it (adb + kill-server) then any other adb command to restart it.

        + +

        My new application/activity isn't showing up in the + applications list

        +
          +
        • You often must restart your device or emulator before a new activity shows + up in the applications list. This is particularly true when it is a completely + new application with a new AndroidManifest.xml file.
        • +
        • If this is for a new activity in an existing AndroidManifest.xml file, did + you include an <activity> tag for your app (or a <service> tag + for a service, or a <receiver> tag for a receiver, etc.)?
        • +
        • Make sure that your AndroidManifest.xml file is valid. Errors in attribute + values, such as the value attribute in <action value="<something>"> + will often not be caught by compilers, but will prevent your application + from being displayed because the intent filter will not be matched. Extra + spaces or other characters can often sneak into these strings.
        • +
        • Did you send your .apk file to the device (adb install)?
        • +
        • Run logcat on your device (adb logcat) + and then install your .apk file. Check the logcat output to see whether the + application is being installed and recognized properly. Here's sample output + from a successful installation: +
          I/FileObserver( 414): *** onEvent wfd: 3 mask: 8 path: MyRSSReader.apk
          +D/PackageManager( 414): Scanning package: /data/app/MyRSSReader.apk
          +D/PackageManager( 414): Adding package com.example.codelab.rssexample
          +D/PackageManager( 414): Registered content provider: my_rss_item, className = com.example.codelab.rssexample.RssContentProvider, isSyncable = false
          +D/PackageManager( 414): Providers: com.example.codelab.rssexample.RssContentProvider
          +D/PackageManager( 414): Activities: com.example.codelab.rssexample.MyRssReader com.example.codelab.rssexample.MyRssReader2 
          +
        • +
        • If logcat shows that the package manager is having problems loading the manifest + file, force your manifest to be recompiled by adding a space in the file and + compiling it.
        • +
        +

        I updated my app, but the updates don't seem to be showing up on the device

        +

        Did you remember to send your .apk file to the device (adb + install)?

        + +

        I'm getting a "Binary XML file line #2: You must supply a layout_wilih + attribute" error + when I start an application (but I declare a layout_wilih attribute right + there!!!)

        +
          +
        • Make sure that the SDK you are building with is the same version as the Android + OS that you are running on.
        • +
        • Make sure that you're calling setContentView() early in your onCreate() method. + Calling other methods, such as setListAdapter() before calling setContentView() + can sometimes create odd errors when Android tries to access screen elements + that haven't been set before.
        • +
        +

        My request to (make a call, catch an incoming SMS, +receive a notification, send an intent to an Android application) is being +ignored

        +

        You might not have permission (or might not have requested permission) to + call this activity or receive this intent. Many standard Android activities, + such as making a call, have a permission assigned to it to prevent arbitrary + applications from sending or receiving requests. See Security and + Permissions for more information on permissions, and + {@link android.Manifest.permission Manifest.permission} for a list of + standard permissions supported by the Android platform. +

        +

        Help! My project won't build in Eclipse

        +

        If your project doesn't build, you may notice symptoms such as new +resources added in the res/ sub-folders not showing up in the R class, +the emulator not being started, not being able to run the application, or even seeming to run an old version of the application.

        +

        To troubleshoot these types of problems, first try:

        +
          +
        1. Switch to the DDMS view in Eclipse (if you don't already have it open): +
            +
          1. From the menu select Window > Open Perspective > Other
          2. +
          3. Select DDMS from the list and hit OK
          4. +
          +
        2. +
        3. In the Devices panel (top right panel by default), click on the down triangle + to bring up the panel menu
        4. +
        5. Select Reset ADB from the menu, and then try running the + application again
        6. +
        +

        If the above still doesn't work, you can try these steps:

        +
          +
        1. + Check the console and problems tabs at the bottom of the Eclipse UI +
        2. +
        3. + If there are problems listed in either place, they should give you a clue + what is wrong +
        4. +
        5. + If you aren't sure if the problems are fresh or stale, clear the console + with a right click > Clear, then clean the project +
        6. +
        7. + To clean the project (a good idea with any kind of build error), select + Project > Clean from the eclipse main menu, then select the project you + are working on (or clean all) +
        8. +
        +

        Eclipse isn't talking to the emulator

        +

        When communication doesn't seem to be happening between Eclipse and the emulator, symptoms can include: nothing happening when you press run, the emulator hanging waiting +for a debugger to connect, or errors that Eclipse reports about not being able +to find the emulator or shell. By far the most common symptom is that when you press run, the emulator starts (or +is already running), but the application doesn't start.

        +

        +You may find any of these steps will fix the problem and with practice you +probably can figure out which one you need to do for your particular issue, but +to start with, the safest option is to run through all of them in order:

        +
          +
        1. + Quit the emulator if it is running +
        2. +
        3. + Check that any emulator processes are killed (sometimes they can hang, use ps on unix or mac, or task manager in the process view on + windows). +
        4. +
        5. + Quit Eclipse +
        6. +
        7. + From the command line, type: +
          adb kill-server 
          +
        8. +
        9. + Start Eclipse and try again +
        10. +
        + +

        When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.

        +

        This error is displayed if you are using an older version of the JDK. Please make sure you are using JDK version 5 or 6.

        + +

        I can't install ApiDemos apps in my IDE because of a signing error

        + +

        The Android system requires that all applications be signed, as described in + Signing Your Applications. The ApiDemos +applications included with the SDK are preinstalled on the emulator and for that reason have been +compiled and signed with a private key.

        + +If you want to modify or run one of the ApiDemos apps from Eclipse/ADT or other IDE, you can do so +so only after you uninstall the preinstalled version of the app from the emulator. If +you try to run an ApiDemos apps from your IDE without removing the preinstalled version first, +you will get errors similar to:

        + +
        [2008-08-13 15:14:15 - ApiDemos] Re-installation failed due to different application signatures.
        +[2008-08-13 15:14:15 - ApiDemos] You must perform a full uninstall of the application. WARNING: ...This will remove the application data!
        +[2008-08-13 15:14:15 - ApiDemos] Please execute 'adb uninstall com.android.samples' in a shell.
        + +

        The error occurs because, in this case, you are attempting to install another copy of ApiDemos +onto the emulator, a copy that is signed with a different certificate (the Android IDE tools will +have signed the app with a debug certificate, where the existing version was already signed with +a private certificate). The system does not allow this type of reinstallation.

        + +

        To resolve the issue, you need to fully uninstall the preinstalled and then reinstall it using +the adb tool. Here's how to do that:

        + +
          +
        1. In a terminal, change to the tools directory of the SDK.
        2. +
        3. If no emulator instance is running, start an emulator using using the command emulator &.
        4. +
        5. Uninstall the preinstalled app using the command adb uninstall com.android.samples.
        6. +
        7. Reinstall the app using the command adb install <path to the ApiDemos.apk>. If you are + working in Eclipse/ADT, you can just compile and run the app in the normal way.
        8. +
        + +

        Note that if multiple emulator instances are running, you need to direct your uninstall/install +commands to the emulator instance that you are targeting. To do that you can add the +-s <serialNumber> to the command, for example:

        + +
        adb -s emulator-5556 install
        + +

        For more information about adb, see the Android Debug Bridge +documentation.

        + + +

        I can't compile my app because the build tools generated an expired debug certificate

        + +

        If your development machine uses a locale that has a non-Gregorian calendar, you may encounter problems when first trying to compile and run your application. Specifically, you may find that the Android build tools won't compile your application because the debug key is expired.

        + +

        The problem occurs because the Keytool utility — included in the JDK and used by the Android build tools — fails to properly handle non-Gregorian locales and may create validity dates that are in the past. That is, it may generate a debug key that is already expired, which results in the compile error.

        + +

        If you encounter this problem, follow these steps to work around it:

        + +
          +
        1. First, delete the debug keystore/key already generated by the Android build tools. Specifically, delete the debug.keystore file. On Linux/Mac OSX, the file is stored in ~/.android. On Windows XP, the file is stored in +C:\Documents and Settings\<user>\.android. On Windows Vista, the file is stored in +C:\Users\<user>\.android
        2. +
        3. Next, you can either +
            +
          • Temporarily change your development machine's locale (date and time) to one that uses a Gregorian calendar, for example, United States. Once the locale is changed, use the Android build tools to compile and install your app. The build tools will regenerate a new keystore and debug key with valid dates. Once the new debug key is generated, you can reset your development machine to the original locale.
          • +
          • Alternatively, if you do not want to change your machine's locale settings, you can generate the keystore/key on any machine using the Gregorian calendar, then copy the debug.keystore file from that computer to the proper location on your development machine.
          • +
          +
        4. +
        + +

        This problem has been verified on Windows and may apply to other platforms.

        + +

        For general information about signing Android applications, see +Signing Your Applications.

        + diff --git a/docs/html/resources/index.jd b/docs/html/resources/index.jd new file mode 100644 index 0000000..5174dee --- /dev/null +++ b/docs/html/resources/index.jd @@ -0,0 +1,38 @@ +page.title=Developer Resources +@jd:body + +

        +This section provides technical articles, tutorials, sample code, and other +information to help you quickly implement the features you want in your +application. +

        + +
        +
        Technical Articles
        +
        Focused discussions about Android development subjects, including +optimizations, tips, interesting implementations, +and so on. Most of the articles provide "how-to" instructions for adding +features or functionality to your app. The articles are drawn from posts to the +Android Developers Blog. +
        + +
        Tutorials
        +
        Step-by-step instructions demonstrating how to build an Android application +that has the specific features you want.
        + +
        Sample Code
        +
        Fully-functioning sample applications that you can look at or build and run, +to learn about how Android works. Feel free to reuse any of the code or +techniques that you find in the samples!
        + +
        Community
        +
        Links to the Android discussion groups and information about other ways to +collaborate with other developers.
        + +
        More
        +
        Quick development tips, troubleshooting information, and frequently asked +questions (FAQs).
        +
        + +

        To return to this page later, just click the "Resources" tab while any +Resources page is loaded.

        \ No newline at end of file diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs new file mode 100644 index 0000000..60d044a --- /dev/null +++ b/docs/html/resources/resources_toc.cs @@ -0,0 +1,242 @@ + + + diff --git a/docs/html/resources/samples/images/BluetoothChat1.png b/docs/html/resources/samples/images/BluetoothChat1.png new file mode 100644 index 0000000..f87da6a Binary files /dev/null and b/docs/html/resources/samples/images/BluetoothChat1.png differ diff --git a/docs/html/resources/samples/images/BluetoothChat2.png b/docs/html/resources/samples/images/BluetoothChat2.png new file mode 100644 index 0000000..6218eff Binary files /dev/null and b/docs/html/resources/samples/images/BluetoothChat2.png differ diff --git a/docs/html/resources/samples/images/ContactManager1.png b/docs/html/resources/samples/images/ContactManager1.png new file mode 100644 index 0000000..5bfd27b Binary files /dev/null and b/docs/html/resources/samples/images/ContactManager1.png differ diff --git a/docs/html/resources/samples/images/ContactManager2.png b/docs/html/resources/samples/images/ContactManager2.png new file mode 100644 index 0000000..0a11ec3 Binary files /dev/null and b/docs/html/resources/samples/images/ContactManager2.png differ diff --git a/docs/html/resources/samples/images/HomeSample.png b/docs/html/resources/samples/images/HomeSample.png new file mode 100644 index 0000000..990bebb Binary files /dev/null and b/docs/html/resources/samples/images/HomeSample.png differ diff --git a/docs/html/resources/samples/images/JetBoy.png b/docs/html/resources/samples/images/JetBoy.png new file mode 100644 index 0000000..3da0448 Binary files /dev/null and b/docs/html/resources/samples/images/JetBoy.png differ diff --git a/docs/html/resources/samples/images/MultiResolution.png b/docs/html/resources/samples/images/MultiResolution.png new file mode 100644 index 0000000..8b245d9 Binary files /dev/null and b/docs/html/resources/samples/images/MultiResolution.png differ diff --git a/docs/html/resources/samples/images/SearchableDictionary1.png b/docs/html/resources/samples/images/SearchableDictionary1.png new file mode 100644 index 0000000..ebb4604 Binary files /dev/null and b/docs/html/resources/samples/images/SearchableDictionary1.png differ diff --git a/docs/html/resources/samples/images/SearchableDictionary2.png b/docs/html/resources/samples/images/SearchableDictionary2.png new file mode 100644 index 0000000..34746cd Binary files /dev/null and b/docs/html/resources/samples/images/SearchableDictionary2.png differ diff --git a/docs/html/resources/samples/images/Snake.png b/docs/html/resources/samples/images/Snake.png new file mode 100644 index 0000000..c5211d8 Binary files /dev/null and b/docs/html/resources/samples/images/Snake.png differ diff --git a/docs/html/resources/samples/images/SoftKeyboard.png b/docs/html/resources/samples/images/SoftKeyboard.png new file mode 100644 index 0000000..8a4ec63 Binary files /dev/null and b/docs/html/resources/samples/images/SoftKeyboard.png differ diff --git a/docs/html/resources/samples/images/Wiktionary.png b/docs/html/resources/samples/images/Wiktionary.png new file mode 100644 index 0000000..eae5da5 Binary files /dev/null and b/docs/html/resources/samples/images/Wiktionary.png differ diff --git a/docs/html/resources/samples/images/WiktionarySimple.png b/docs/html/resources/samples/images/WiktionarySimple.png new file mode 100644 index 0000000..a23226b Binary files /dev/null and b/docs/html/resources/samples/images/WiktionarySimple.png differ diff --git a/docs/html/resources/samples/images/sample_lunarlander.png b/docs/html/resources/samples/images/sample_lunarlander.png new file mode 100644 index 0000000..a2ff75a Binary files /dev/null and b/docs/html/resources/samples/images/sample_lunarlander.png differ diff --git a/docs/html/resources/samples/images/sample_note.png b/docs/html/resources/samples/images/sample_note.png new file mode 100644 index 0000000..8fc9dcc Binary files /dev/null and b/docs/html/resources/samples/images/sample_note.png differ diff --git a/docs/html/resources/samples/images/sample_notepad.png b/docs/html/resources/samples/images/sample_notepad.png new file mode 100644 index 0000000..46f2211 Binary files /dev/null and b/docs/html/resources/samples/images/sample_notepad.png differ diff --git a/docs/html/resources/samples/index.jd b/docs/html/resources/samples/index.jd new file mode 100644 index 0000000..7fbbea1 --- /dev/null +++ b/docs/html/resources/samples/index.jd @@ -0,0 +1,72 @@ +guide=true +page.title=Sample Code +@jd:body + + +

        Sometimes, the best way to learn how things are done is to look at some code. +Here, you can browse the source of some sample Android applications that are included +in the Android SDK.

        + +

        Each version of the Android platform available for the SDK includes a full set of sample +applications (which may vary between different versions of the platform). +You can find the samples in your SDK at:

        + +

        +<sdk>/platforms/android-<version>/samples/ +

        + +

        You can easily create new Android projects with these samples, modify them +if you'd like, then run them on an emulator or device. For example, to create +a project for the API Demos app from Eclipse, +start a new Android Project, select "Create project from existing source", then select +{@code ApiDemos} in the {@code samples/} directory. To create the API Demos project +using the {@code android} tool, execute:

        +
        +android update project -s -n API Demos -t <target_ID> -p <path-to-platform>/samples/ApiDemos/
        +
        + +

        The pages below provide an overview of each sample application (available with most +platforms) and allow you to view the source files in your browser.

        + +
        + +
        API Demos
        +
        A variety of small applications that demonstrate an extensive collection of + framework topics.
        + +
        Home
        +
        An application for saving notes. Similar (but not identical) to the + Notepad tutorial.
        + +
        JetBoy
        +
        JetBoy is a game that demonstrates the SONiVOX JET interactive music technology, + with {@link android.media.JetPlayer}.
        + +
        Lunar Lander
        +
        A classic Lunar Lander game.
        + +
        Note Pad
        +
        An application for saving notes. Similar (but not identical) to the + Notepad tutorial.
        + +
        Searchable Dictionary
        +
        A sample application that demonstrates Android's search framework, + including how to provide search suggestions for Quick Search Box.
        + +
        Snake
        +
        An implementation of the classic game "Snake."
        + +
        Soft Keyboard
        +
        An example of writing an input method for a software keyboard.
        + +
        + + +
        +

        For more sample applications, check out +apps-for-android, a +collection of open source applications that demonstrate various Android APIs. +

        +
        + + diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd new file mode 100644 index 0000000..58d1a16 --- /dev/null +++ b/docs/html/resources/tutorials/hello-world.jd @@ -0,0 +1,564 @@ +page.title=Hello, World +@jd:body + + + +

        As a developer, you know that the first impression +of a development framework is how easy it is to write "Hello, +World." Well, on Android, it's pretty easy. +It's particularly easy if you're using Eclipse as your IDE, because we've provided a +great plugin that handles your project creation and management to greatly speed-up your +development cycles.

        + +

        If you're not using Eclipse, that's okay. Familiarize yourself with +Developing in Other IDEs. +You can then return to this tutorial and ignore anything about Eclipse.

        + +

        Before you start, you should already have the very latest SDK installed, and if you're using +Eclipse, you should have installed the ADT plugin as well. If you have not installed these, see +Installing the Android SDK and return +here when you've completed the installation.

        + +

        Create an AVD

        + + + +

        In this tutorial, you will run your application in the Android Emulator. +Before you can launch the emulator, you must create an +Android Virtual Device (AVD). An AVD defines the system image and +device settings used by the emulator.

        + +

        To create an AVD, use the "android" tool provided in the Android SDK. +Open a command prompt or terminal, navigate to the +tools/ directory in the SDK package and execute: +

        +android create avd --target 2 --name my_avd
        +
        + +

        The tool now asks if you would like to create a custom hardware profile. +For the time being, press Return to skip it ("no" is the default response). +That's it. This configures an AVD named "my_avd" that uses the Android 1.5 +platform. The AVD is now ready for use in the emulator.

        + +

        In the above command, the --target option is required +and specifies the deployment target to run on the emulator. +The --name option is also required and defines the +name for the new AVD.

        + + +

        Create a New Android Project

        + +

        After you've created an AVD, the next step is to start a new +Android project in Eclipse.

        + +
          +
        1. From Eclipse, select File > New > Project. +

          If the ADT + Plugin for Eclipse has been successfully installed, the resulting dialog + should have a folder labeled "Android" which should contain + "Android Project". (After you create one or more Android projects, an entry for + "Android XML File" will also be available.)

          +
        2. + +
        3. Select "Android Project" and click Next.
          + +
        4. + +
        5. Fill in the project details with the following values: +
            +
          • Project name: HelloAndroid
          • +
          • Application name: Hello, Android
          • +
          • Package name: com.example.helloandroid (or your own private namespace)
          • +
          • Create Activity: HelloAndroid
          • +
          • Min SDK Version: 2
          • +
          +

          Click Finish.

          + + + +

          Here is a description of each field:

          + +
          +
          Project Name
          +
          This is the Eclipse Project name — the name of the directory + that will contain the project files.
          +
          Application Name
          +
          This is the human-readable title for your application — the name that + will appear on the Android device.
          +
          Package Name
          +
          This is the package namespace (following the same rules as for + packages in the Java programming language) that you want all your source code to + reside under. This also sets the package name under which the stub + Activity will be generated. +

          Your package name must be unique across + all packages installed on the Android system; for this reason, it's very + important to use a standard domain-style package for your + applications. The example above uses the "com.example" namespace, which is + a namespace reserved for example documentation — + when you develop your own applications, you should use a namespace that's + appropriate to your organization or entity.

          +
          Create Activity
          +
          This is the name for the class stub that will be generated by the plugin. + This will be a subclass of Android's {@link android.app.Activity} class. An + Activity is simply a class that can run and do work. It can create a UI if it + chooses, but it doesn't need to. As the checkbox suggests, this is optional, but an + Activity is almost always used as the basis for an application.
          +
          Min SDK Version
          +
          This value specifies the minimum API Level required by your application. If the API Level + entered here matches the API Level provided by one of the available targets, + then that Build Target will be automatically selected (in this case, entering + "2" as the API Level will select the Android 1.1 target). With each new + version of the Android system image and Android SDK, there have likely been + additions or changes made to the APIs. When this occurs, a new API Level is assigned + to the system image to regulate which applications are allowed to be run. If an + application requires an API Level that is higher than the level supported + by the device, then the application will not be installed.
          +
          + +

          Other fields: The checkbox for "Use default location" allows you to change + the location on disk where the project's files will be generated and stored. "Build Target" + is the platform target that your application will be compiled against + (this should be selected automatically, based on your Min SDK Version).

          + +

          Notice that the "Build Target" you've selected uses the Android 1.1 + platform. This means that your application will be compiled against the Android 1.1 + platform library. If you recall, the AVD created above runs on the Android 1.5 platform. + These don't have to match; Android applications are forward-compatible, so an application + built against the 1.1 platform library will run normally on the 1.5 platform. The reverse + is not true.

          +
        6. +
        + +

        Your Android project is now ready. It should be visible in the Package +Explorer on the left. +Open the HelloAndroid.java file, located inside HelloAndroid > src > +com.example.helloandroid). It should look like this:

        + +
        +package com.example.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        Notice that the class is based on the {@link android.app.Activity} class. An Activity is a +single application entity that is used to perform actions. An application may have many separate +activities, but the user interacts with them one at a time. The +{@link android.app.Activity#onCreate(Bundle) onCreate()} method +will be called by the Android system when your Activity starts — +it is where you should perform all initialization and UI setup. An activity is not required to +have a user interface, but usually will.

        + +

        Now let's modify some code!

        + + +

        Construct the UI

        + +

        Take a look at the revised code below and then make the same changes to your HelloAndroid class. +The bold items are lines that have been added.

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +import android.widget.TextView;
        +
        +public class HelloAndroid extends Activity {
        +   /** Called when the activity is first created. */
        +   @Override
        +   public void onCreate(Bundle savedInstanceState) {
        +       super.onCreate(savedInstanceState);
        +       TextView tv = new TextView(this);
        +       tv.setText("Hello, Android");
        +       setContentView(tv);
        +   }
        +}
        + +

        Tip: An easy way to add import packages to your project is +to press Ctrl-Shift-O (Cmd-Shift-O, on Mac). This is an Eclipse +shortcut that identifies missing packages based on your code and adds them for you.

        + +

        An Android user interface is composed of hierarchies of objects called +Views. A {@link android.view.View} is a drawable object used as an element in your UI layout, +such as a button, image, or (in this case) a text label. Each of these objects is a subclass +of the View class and the subclass that handles text is {@link android.widget.TextView}.

        + +

        In this change, you create a TextView with the class constructor, which accepts +an Android {@link android.content.Context} instance as its parameter. A +Context is a handle to the system; it provides services like +resolving resources, obtaining access to databases and preferences, and so +on. The Activity class inherits from Context, and because your +HelloAndroid class is a subclass of Activity, it is also a Context. So, you can +pass this as your Context reference to the TextView.

        + +

        Next, you define the text content with +{@link android.widget.TextView setText(CharSequence) setText()}.

        + +

        Finally, you pass the TextView to +{@link android.app.Activity#setContentView(View) setContentView()} in order to +display it as the content for the Activity UI. If your Activity doesn't +call this method, then no UI is present and the system will display a blank +screen.

        + +

        There it is — "Hello, World" in Android! The next step, of course, is +to see it running.

        + + +

        Run the Application

        + +

        The Eclipse plugin makes it very easy to run your applications:

        + +
          +
        1. Select Run > Run.
        2. +
        3. Select "Android Application".
        4. +
        + + + +

        The Eclipse ADT will automatically create a new run configuration for your project +and the Android Emulator will automatically launch. Once the emulator is booted up, +your application will appear after a moment. You should now see something like this:

        + + + +

        The "Hello, Android" you see in the grey bar is actually the application title. The Eclipse plugin +creates this automatically (the string is defined in the res/values/strings.xml file and referenced +by your AndroidManifest.xml file). The text below the title is the actual text that you have +created in the TextView object.

        + +

        That concludes the basic "Hello World" tutorial, but you should continue reading for some more +valuable information about developing Android applications.

        + + +

        Upgrade the UI to an XML Layout

        + +

        The "Hello, World" example you just completed uses what is called a "programmatic" +UI layout. This means that you constructed and built your application's UI +directly in source code. If you've done much UI programming, you're +probably familiar with how brittle that approach can sometimes be: small +changes in layout can result in big source-code headaches. It's also very +easy to forget to properly connect Views together, which can result in errors in +your layout and wasted time debugging your code.

        + +

        That's why Android provides an alternate UI construction model: XML-based +layout files. The easiest way to explain this concept is to show an +example. Here's an XML layout file that is identical in behavior to the +programmatically-constructed example:

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        +  android:layout_width="fill_parent"
        +  android:layout_height="fill_parent"
        +  android:text="@string/hello"/>
        + +

        The general structure of an Android XML layout file is simple: it's a tree +of XML elements, wherein each node is the name of a View class +(this example, however, is just one View element). You can use the +name of any class that extends {@link android.view.View} as an element in your XML layouts, +including custom View classes you define in your own code. This +structure makes it very easy to quickly build up UIs, using a more simple +structure and syntax than you would use in a programmatic layout. This model is inspired +by the web development model, wherein you can separate the presentation of your +application (its UI) from the application logic used to fetch and fill in data.

        + +

        In the above XML example, there's just one View element: the TextView, +which has four XML attributes. Here's a summary of what they mean:

        + + + + + + + + + + + + + + + + + + + + + + + + +
        + Attribute + + Meaning +
        + xmlns:android + + This is an XML namespace declaration that tells the Android tools that you are going to refer to common attributes defined in the Android namespace. The outermost tag in every Android layout file must have this attribute.
        +
        + android:layout_width + + This attribute defines how much of the available width on the screen this View should consume. +In this case, it's the only View so you want it to take up the entire screen, which is what a value of "fill_parent" means.
        +
        + android:layout_height + + This is just like android:layout_width, except that it refers to available screen height. +
        + android:text + + This sets the text that the TextView should display. In this example, you use a string + resource instead of a hard-coded string value. + The hello string is defined in the res/values/strings.xml file. This is the + recommended practice for inserting strings to your application, because it makes the localization + of your application to other languages graceful, without need to hard-code changes to the layout file. + For more information, see Resources + and Internationalization. +
        + + +

        These XML layout files belong in the res/layout/ directory of your project. The "res" is +short for "resources" and the directory contains all the non-code assets that +your application requires. In addition to layout files, resources also include assets +such as images, sounds, and localized strings.

        + + + +

        The Eclipse plugin automatically creates one of these layout files for you: main.xml. +In the "Hello World" application you just completed, this file was ignored and you created a +layout programmatically. This was meant to teach you more +about the Android framework, but you should almost always define your layout +in an XML file instead of in your code. +The following procedures will instruct you how to change your +existing application to use an XML layout.

        + +
          +
        1. In the Eclipse Package Explorer, expand the +/res/layout/ folder and open main.xml (once opened, you might need to click +the "main.xml" tab at the bottom of the window to see the XML source). Replace the contents with +the following XML: + +
          <?xml version="1.0" encoding="utf-8"?>
          +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          +  android:layout_width="fill_parent"
          +  android:layout_height="fill_parent"
          +  android:text="@string/hello"/>
          +

          Save the file.

          +
        2. + +
        3. Inside the res/values/ folder, open strings.xml. +This is where you should save all default text strings for your user interface. If you're using Eclipse, then +ADT will have started you with two strings, hello and app_name. +Revise hello to something else. Perhaps "Hello, Android! I am a string resource!" +The entire file should now look like this: +
          +<?xml version="1.0" encoding="utf-8"?>
          +<resources>
          +    <string name="hello">Hello, Android! I am a string resource!</string>
          +    <string name="app_name">Hello, Android</string>
          +</resources>
          +
          +
        4. + +
        5. Now open and modify your HelloAndroid class use the +XML layout. Edit the file to look like this: +
          +package com.example.helloandroid;
          +
          +import android.app.Activity;
          +import android.os.Bundle;
          +
          +public class HelloAndroid extends Activity {
          +    /** Called when the activity is first created. */
          +    @Override
          +    public void onCreate(Bundle savedInstanceState) {
          +        super.onCreate(savedInstanceState);
          +        setContentView(R.layout.main);
          +    }
          +}
          + +

          When you make this change, type it by hand to try the +code-completion feature. As you begin typing "R.layout.main" the plugin will offer you +suggestions. You'll find that it helps in a lot of situations.

          + +

          Instead of passing setContentView() a View object, you give it a reference +to the layout resource. +The resource is identified as R.layout.main, which is actually a compiled object representation of +the layout defined in /res/layout/main.xml. The Eclipse plugin automatically creates this reference for +you inside the project's R.java class. If you're not using Eclipse, then the R.java class will be generated for you +when you run Ant to build the application. (More about the R class in a moment.)

          +
        6. +
        + +

        Now re-run your application — because you've created a launch configuration, all +you need to do is click the green arrow icon to run, or select +Run > Run History > Android Activity. Other than the change to the TextView +string, the application looks the same. After all, the point was to show that the two different +layout approaches produce identical results.

        + +

        Tip: Use the shortcut Ctrl-F11 +(Cmd-Shift-F11, on Mac) to run your currently visible application.

        + +

        Continue reading for an introduction +to debugging and a little more information on using other IDEs. When you're ready to learn more, +read Application +Fundamentals for an introduction to all the elements that make Android applications work. +Also refer to the Developer's Guide +introduction page for an overview of the Dev Guide documentation.

        + + +
        +

        R class

        +

        In Eclipse, open the file named R.java (in the gen/ [Generated Java Files] folder). +It should look something like this:

        + +
        +package com.example.helloandroid;
        +
        +public final class R {
        +    public static final class attr {
        +    }
        +    public static final class drawable {
        +        public static final int icon=0x7f020000;
        +    }
        +    public static final class layout {
        +        public static final int main=0x7f030000;
        +    }
        +    public static final class string {
        +        public static final int app_name=0x7f040001;
        +        public static final int hello=0x7f040000;
        +    }
        +}
        +
        + +

        A project's R.java file is an index into all the resources defined in the +file. You use this class in your source code as a sort of short-hand +way to refer to resources you've included in your project. This is +particularly powerful with the code-completion features of IDEs like Eclipse +because it lets you quickly and interactively locate the specific reference +you're looking for.

        + +

        It's possible yours looks slighly different than this (perhaps the hexadecimal values are different). +For now, notice the inner class named "layout", and its +member field "main". The Eclipse plugin noticed the XML +layout file named main.xml and generated a class for it here. As you add other +resources to your project (such as strings in the res/values/string.xml file or drawables inside +the res/drawable/ direcory) you'll see R.java change to keep up.

        +

        When not using Eclipse, this class file will be generated for you at build time (with the Ant tool).

        +

        You should never edit this file by hand.

        +
        + +

        Debug Your Project

        + +

        The Android Plugin for Eclipse also has excellent integration with the Eclipse +debugger. To demonstrate this, introduce a bug into +your code. Change your HelloAndroid source code to look like this:

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        Object o = null;
        +        o.toString();
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        This change simply introduces a NullPointerException into your code. If +you run your application again, you'll eventually see this:

        + + + +

        Press "Force Quit" to terminate the application and close the emulator window.

        + +

        To find out more about the error, set a breakpoint in your source code +on the line Object o = null; (double-click on the marker bar next to the source code line). Then select Run > Debug History > Hello, +Android from the menu to enter debug mode. Your app will restart in the +emulator, but this time it will suspend when it reaches the breakpoint you +set. You can then step through the code in Eclipse's Debug Perspective, +just as you would for any other application.

        + + + + +

        Creating the Project without Eclipse

        + +

        If you don't use Eclipse (such as if you prefer another IDE, or simply use text + editors and command line tools) then the Eclipse plugin can't help you. + Don't worry though — you don't lose any functionality just because you don't + use Eclipse.

        + +

        The Android Plugin for Eclipse is really just a wrapper around a set of tools + included with the Android SDK. (These tools, like the emulator, aapt, adb, + ddms, and others are documented elsewhere.) + Thus, it's possible to + wrap those tools with another tool, such as an 'ant' build file.

        + +

        The Android SDK includes a tool named "android" that can be + used to create all the source code and directory stubs for your project, as well + as an ant-compatible build.xml file. This allows you to build your project + from the command line, or integrate it with the IDE of your choice.

        + +

        For example, to create a HelloAndroid project similar to the one created + in Eclipse, use this command:

        + +
        +android create project \
        +    --package com.android.helloandroid \
        +    --activity HelloAndroid \ 
        +    --target 2 \
        +    --path <path-to-your-project>/HelloAndroid 
        +
        + +

        This creates the required folders and files for the project at the location + defined by the path.

        + +

        For more information on how to use the SDK tools to create and build projects, please read +Developing in Other IDEs.

        diff --git a/docs/html/resources/tutorials/images/hello_world_0.png b/docs/html/resources/tutorials/images/hello_world_0.png new file mode 100644 index 0000000..330a07c Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_0.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_1.png b/docs/html/resources/tutorials/images/hello_world_1.png new file mode 100644 index 0000000..1e5f7b0 Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_1.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_2.png b/docs/html/resources/tutorials/images/hello_world_2.png new file mode 100644 index 0000000..3e9c58b Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_2.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_3.png b/docs/html/resources/tutorials/images/hello_world_3.png new file mode 100644 index 0000000..22901a9 Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_3.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_4.png b/docs/html/resources/tutorials/images/hello_world_4.png new file mode 100644 index 0000000..5c41e80 Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_4.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_5.png b/docs/html/resources/tutorials/images/hello_world_5.png new file mode 100644 index 0000000..96b830a Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_5.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_8.png b/docs/html/resources/tutorials/images/hello_world_8.png new file mode 100644 index 0000000..07db360 Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_8.png differ diff --git a/docs/html/resources/tutorials/images/hello_world_9.png b/docs/html/resources/tutorials/images/hello_world_9.png new file mode 100644 index 0000000..a66526a Binary files /dev/null and b/docs/html/resources/tutorials/images/hello_world_9.png differ diff --git a/docs/html/resources/tutorials/index.html b/docs/html/resources/tutorials/index.html new file mode 100644 index 0000000..4881acf --- /dev/null +++ b/docs/html/resources/tutorials/index.html @@ -0,0 +1,8 @@ + + + + + +click here if you are not redirected. + + \ No newline at end of file diff --git a/docs/html/resources/tutorials/localization/index.jd b/docs/html/resources/tutorials/localization/index.jd new file mode 100755 index 0000000..8a60814 --- /dev/null +++ b/docs/html/resources/tutorials/localization/index.jd @@ -0,0 +1,593 @@ +page.title=Hello, L10N +@jd:body + +
        +
        +

        In this document

        +
          +
        1. Create an Unlocalized App +
            +
          1. Create the Project and Layout
          2. +
          3. Create Default Resources
          4. +
          +
        2. +
        3. Run the Unlocalized App
        4. +
        5. Plan the Localization
        6. +
        7. Localize the App +
            +
          1. Localize the Strings
          2. +
          3. Localize the Images
          4. +
          +
        8. +
        9. Run and Test the Localized App
        10. +
        +

        See also

        +
          +
        1. {@link android.widget.Button}
        2. +
        3. {@link android.widget.TextView}
        4. +
        5. {@link android.app.AlertDialog}
        6. +
        +
        +
        + +

        In this tutorial, we will create a Hello, L10N application that uses the +Android framework to selectively load resources. Then we will localize the +application by adding resources to the res/ directory.

        + +

        This tutorial uses the practices described in the Localization +document.

        + + +

        Create an Unlocalized Application

        + +

        The first version of the Hello, L10N application will use only the default +resource directories (res/drawable, res/layout, and +res/values). These resources are not localized — they are the +graphics, layout, and strings that we expect the application to use most often. +When a user runs the application in the default locale, or in a locale that the +application does not specifically support, the application will load resources +from these default directories.

        + +

        The application consists of a simple user interface that displays two +{@link android.widget.TextView} objects and a {@link android.widget.Button} image with a + background image of a national flag. When clicked, the button displays an +{@link android.app.AlertDialog} object that shows additional text.

        + +

        Create the Project and Layout

        + +

        For this application, the default language will be British English and the +default location the United Kingdom.

        + +
          +
        1. Start a new project and Activity called "HelloL10N." If you are +using Eclipse, fill out these values in the New Android Project wizard: +
            +
          • Project name: HelloL10N
          • +
          • Application name: Hello, L10N
          • +
          • Package name: com.example.hellol10n (or your own private +namespace)
          • +
          • Create Activity: HelloL10N
          • +
          • Min SDK Version: 3
          • +
          +

          The basic project contains a res/ directory with +subdirectories for the three most common types of resources: graphics +(res/drawable/), layouts (res/layout/) and strings +(res/values/). Most of the localization work you do later in this +tutorial will involve adding more subdirectories to the res/ +directory.

          + plain project +
        2. +
        3. Open the res/layout/main.xml file and replace it with the +following code: +
          <?xml version="1.0" encoding="utf-8"?>
          +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          +    android:orientation="vertical"
          +    android:layout_width="fill_parent"
          +    android:layout_height="fill_parent"
          +    >
          +<TextView
          +    android:layout_width="fill_parent" 
          +    android:layout_height="wrap_content"
          +    android:gravity="center_horizontal"
          +    android:text="@string/text_a"
          +    />
          +<TextView
          +    android:layout_width="fill_parent"
          +    android:layout_height="wrap_content"
          +    android:gravity="center_horizontal"
          +    android:text="@string/text_b"
          +    />
          +<Button
          +    android:id="@+id/flag_button"
          +    android:layout_width="wrap_content"
          +    android:layout_height="wrap_content"
          +    android:layout_gravity="center"
          +    />
          +</LinearLayout>
          +    
          + +

          The LinearLayout has two {@link android.widget.TextView} objects that will +display localized text and one {@link android.widget.Button} that shows a flag. +

          +
        4. +
        + +

        Create Default Resources

        + +

        The layout refers to resources that need to be defined.

        + +
          +
        1. Create default text strings. To do this, open the res/values/strings.xml file and replace it with the following code:
          +
          <?xml version="1.0" encoding="utf-8"?>
          +<resources>
          +    <string name="app_name">Hello, L10N</string>
          +    <string name="text_a">Shall I compare thee to a summer"'"s day?</string>
          +    <string name="text_b">Thou art more lovely and more temperate.</string>
          +    <string name="dialog_title">No Localisation</string>
          +    <string name="dialog_text">This dialog box"'"s strings are not localised. For every locale, the text here will come from values/strings.xml.</string>
          +</resources>
          + +

          This code provides British English text for each string that the application +will use. When we localize this application, we will provide alternate text in +German, French, and Japanese for some of the strings.

          +
        2. +
        3. Add a default flag graphic to the res/drawable folder by +saving flag.png as +res/drawable/flag.png. When the application is not localized, it +will show a British flag.
          + +
        4. +
        5. Open HelloL10N.java (in the src/ directory) and add the +following code inside the onCreate() method (after +setContentView). + +
          // assign flag.png to the button, loading correct flag image for current locale
          +Button b;
          +(b = (Button)findViewById(R.id.flag_button)).setBackgroundDrawable(this.getResources().getDrawable(R.drawable.flag));
          +
          +// build dialog box to display when user clicks the flag
          +AlertDialog.Builder builder = new AlertDialog.Builder(this);
          +builder.setMessage(R.string.dialog_text)
          +    .setCancelable(false)
          +    .setTitle(R.string.dialog_title)
          +    .setPositiveButton("Done", new DialogInterface.OnClickListener() {
          +        public void onClick(DialogInterface dialog, int id) {
          +        dialog.dismiss();
          +        }
          +    });
          +final AlertDialog alert = builder.create();
          +
          +// set click listener on the flag to show the dialog box 
          +b.setOnClickListener(new View.OnClickListener() {
          +    public void onClick(View v) {
          +	alert.show();
          +    }
          +    });
          + +

          Tip: In Eclipse, use +Ctrl-Shift-O (Cmd-Shift-O, on Mac) to find and +add missing import packages to your project, then save the HelloL10N.java +file.

          + +

          The code that you added does the following:

          + +
            +
          • It assigns the correct flag icon to the button. + For now, no resources are defined other than the default, so this code +will always assign the contents of res/drawable/flag.png (the +British flag) as the flag icon, no matter what the locale. Once we add more +flags for different locales, this code will sometimes assign a different flag. +
          • +
          • It creates an {@link android.app.AlertDialog} object and sets a click listener so that when the +user clicks the button, the AlertDialog will display. + We will not localize the dialog text; +the AlertDialog will always display the dialog_text that is located +within res/values/strings.xml.
          • +
          + +
        6. +
        + +

        The project structure now looks like this:

        + + nonlocalized + +

        Tip: If you will want to run the application on +a device and not just on an emulator, open AndroidManifest.xml and +add android:debuggable="true" inside the +<application> element. For information about setting up the +device itself so it can run applications from your system, see Developing on a Device.

        + + +

        Run the Unlocalized Application

        + +

        Save the project and run the application to see how it works. No matter what +locale your device or emulator is set to, the application runs the same way. It +should look something like this:

        + + + + + + + + + + +
        The unlocalized application, running in any locale:After clicking the flag, in any locale:
        nonlocalized2
        +

        Plan the Localization

        +

        The first step in localizing an application is to plan how the application +will render differently in different locales. In this application, the default +locale will be the United Kingdom. We will add some locale-specific information +for Germany, France, Canada, Japan, and the United States. Table 1 shows the +plan for how the application will appear in different locales.

        + +

        Table 1

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Region /
        + Language
        United KingdomGermanyFranceCanadaJapanUnited StatesOther Location

        + English
        British English text; British flag (default)-- British English text; Canadian flag- British English text; U.S. flag British English text; British flag (default)
        German-German text for app_name, text_a and +text_b; German flag----German text for app_name, text_a and +text_b; British flag
        French--French text for app_name, text_a and +text_b; French flagFrench text for app_name, text_a and +text_b; Canadian flag--French text for app_name, text_a and +text_b; British flag
        Japanese----Japanese text for text_a and text_b; Japanese +flag-Japanese text for text_a and text_b; British +flag
        Other Language------ British English text; British flag (default)
        + +

        Note that other behaviors are possible; for example, the +application could support Canadian English or U.S. English text. But given the +small amount of text involved, adding more versions of English would not make +this application more useful.

        + +

        As shown in the table above, the plan calls for five flag icons in addition +to the British flag that is already in the res/drawable/ folder. It +also calls for three sets of text strings other than the text that is in +res/values/strings.xml.

        + +

        Table 2 shows where the needed text strings and flag icons will go, and +specifies which ones will be loaded for which locales. (For more about the +locale codes, see +Alternate Resources.)

        +

        Table 2

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Locale CodeLanguage / CountryLocation of strings.xmlLocation of flag.png
        DefaultEnglish / United Kingdomres/values/res/drawable/
        de-rDEGerman / Germanyres/values-de/res/drawable-de-rDE/
        fr-rFRFrench / Franceres/values-fr/res/drawable-fr-rFR/
        fr-rCAFrench / Canadares/values-fr/res/drawable-fr-rCA/
        en-rCAEnglish / Canada(res/values/)res/drawable-en-rCA/
        ja-rJPJapanese / Japanres/values-ja/res/drawable-ja-rJP/
        en-rUSEnglish / United States(res/values/)res/drawable-en-rUS/
        + +

        Tip: A folder qualifer cannot specify a region +without a language. Having a folder named res/drawable-rCA/, +for example, will prevent the application from compiling.

        + +

        At run time, the application will select a set of resources to load based on the locale +that is set in the user's device. In cases where no locale-specific resources +are available, the application will fall back on the defaults.

        + +

        For example, assume that the device's language is set to German and its +location to Switzerland. Because this application does not have a +res/drawable-de-rCH/ directory with a flag.png file in it, the system +will fall back on the default, which is the UK flag located in +res/drawable/flag.png. The language used will be German. Showing a +British flag to German speakers in Switzerland is not ideal, but for now we will +just leave the behavior as it is. There are several ways you could improve this +application's behavior if you wanted to:

        + +
          +
        • Use a generic default icon. In this application, it might be something +that represents Shakespeare.
        • +
        • Create a res/drawable-de/ folder that includes an icon that +the application will use whenever the language is set to German but the location +is not Germany.
        • +
        + + +

        Localize the Application

        + +

        Localize the Strings

        + +

        The application requires three more strings.xml files, one +each for German, French, and Japanese. To create these resource files within +Eclipse:

        + +
          +
        1. Select File > New > Android +XML File to open the New Android XML File wizard. You can also open +the wizard by clicking its icon in the toolbar:
          +
        2. +
        3. Select L10N for the Project field, and type strings.xml into +the File field. In the left-hand list, select Language, then click the right arrow.
          +res_file_copy
        4. +
        5. Type de in the Language box and click Finish.
          + res_file_copy +

          A new file, res/values-de/strings.xml, now appears among the project +files.

        6. +
        7. Repeat the steps twice more, for the language codes fr and + ja. +Now the project includes these new skeleton files:
          + res/values-de/strings.xml
          + res/values-fr/strings.xml
          + res/values-ja/strings.xml
          +
        8. +
        9. Add localized text to the new files. To do +this, open the res/values-<qualifier>/strings.xml files and +replace the code as follows:
        10. +
        + + + + + + + + + + + + + + + + + + +
        FileReplace the contents with the following code:
        res/values-de/strings.xml
        <?xml version="1.0" encoding="utf-8"?>
        +<resources>
        +    <string name="app_name">Hallo, Lokalisierung</string>
        +    <string name="text_a">Soll ich dich einem Sommertag vergleichen,</string>
        +    <string name="text_b">Der du viel lieblicher und sanfter bist?</string>
        +</resources>
        res/values-fr/strings.xml
        <?xml version="1.0" encoding="utf-8"?>
        +<resources>
        +    <string name="app_name">Bonjour, Localisation</string>
        +    <string name="text_a">Irai-je te comparer au jour d'été?</string>
        +    <string name="text_b">Tu es plus tendre et bien plus tempéré.</string>
        +</resources> 
        res/values-ja/strings.xml +
        <?xml version="1.0" encoding="utf-8"?>
        +<resources>
        +    <string name="text_a">あなたをなにかにたとえるとしたら夏の一日でしょうか?</string>
        +    <string name="text_b">だがあなたはもっと美しく、もっとおだやかです。</string>
        +</resources>
        + +

        Tip: In the +values-<qualifier>/strings.xml files, you only need to +include text for strings that are different from the default strings. For +example, when the application runs on a device that is configured for Japanese, +the plan is for text_a and text_b to be in Japanese +while all the other text is in English, so +res/values-ja/strings.xml only needs to include text_a +and text_b.

        + +

        Localize the Images

        + +

        As shown in Table 2, the application needs six more +drawable folders, each containing a flag.png icon. Add the needed +icons and folders to your project:

        + +
          +
        1. Save this German flag icon +as res/drawable-de-rDE/flag.png in the application's project +workspace. +

          For example:

          +
            +
          1. Click the link to open the flag image.
          2. +
          3. Save the image in +your-workspace/HelloL10N/res/drawable-de-rDE/ .
          4. +
          +
        2. +
        3. Save this French flag icon +as res/drawable-fr-rFR/flag.png in the application's project +workspace.
        4. +
        5. Save this Canadian flag icon +as res/drawable-fr-rCA/flag.png in the project workspace.
        6. +
        7. Save the Canadian flag icon +again, this time as res/drawable-en-rCA/flag.png in the project +workspace. (Why not have just one folder that contains the Canadian +flag? Because a folder qualifer cannot specify a region without a language. +You cannot have a folder named drawable-rCA/; instead you must +create two separate folders, one for each of the Canadian languages represented +in the application.)
        8. +
        9. Save this Japanese flag icon +as res/drawable-ja-rJP/flag.png in the project workspace.
        10. +
        11. Save this United States flag +icon as res/drawable-en-rUS/flag.png in the project workspace. +
        12. +
        + +

        If you are using Eclipse, refresh the project (F5). The new +res/drawable-<qualifier>/ folders should appear in the +project view.

        + + +

        Run and Test the Localized Application

        + +

        Once you've added the localized string and image resources, you are ready to + run the application and test its handling of them. To change the locale + on a device or in the emulator, use the Settings +application (Home > Menu > Settings > Locale & text > Select +locale). Depending on how a device was configured, it might not offer any +alternate locales via the Settings application, or might offer only a few. The +emulator, on the other hand, will offer a selection of all the locales that are +available in the Android system image.

        + +

        To set the emulator to a locale that is not available in the system image, +use the Custom Locale application, which is available in the Application +tab:

        + +

        custom locale app

        + +

        To switch to a new locale, long-press a locale name:

        + +

        using custom locale

        + +

        For a list of locales available on different versions of the Android platform, +refer to the platform notes documents, listed under "Downloadable SDK Components" +in the "SDK" tab. For example, Android 2.0 locales.

        + +

        Run the application for each of the expected locales, plus one unexpected +locale. Here are some of the results you should see:

        + + + + + + + + + + + + + + + + + + + + + + + + + + +
        LocaleOpening screen of application
        German / Germany +
        Specifically supported by the Hello, L10N application.
        custom locale app
        French / Canada +
        Specifically supported by the Hello, L10N application.
        custom locale app
        German / Switzerland +
        Only the language is specifically supported by +the Hello, L10N application.
        custom locale app`
        Japanese +
        Specifically supported by the Hello, L10N application. +
        custom locale app`
        Romansh / Switzerland (custom locale rm_CH) +
        Not specifically supported by the Hello, L10N +application, so the application uses the default resources.
        custom locale app
        diff --git a/docs/html/resources/tutorials/notepad/codelab/NotepadCodeLab.zip b/docs/html/resources/tutorials/notepad/codelab/NotepadCodeLab.zip new file mode 100644 index 0000000..24fefc1 Binary files /dev/null and b/docs/html/resources/tutorials/notepad/codelab/NotepadCodeLab.zip differ diff --git a/docs/html/resources/tutorials/notepad/index.jd b/docs/html/resources/tutorials/notepad/index.jd new file mode 100644 index 0000000..f569314 --- /dev/null +++ b/docs/html/resources/tutorials/notepad/index.jd @@ -0,0 +1,142 @@ +page.title=Notepad Tutorial +@jd:body + + +

        This tutorial on writing a notepad application gives you a "hands-on" introduction +to the Android framework and the tools you use to build applications on it. +Starting from a preconfigured project file, it guides you through the process of +developing a simple notepad application and provides concrete examples of how to +set up the project, develop the application logic and user interface, and then +compile and run the application.

        + +

        The tutorial presents the application development as a set of +exercises (see below), each consisting of several steps. You should follow +the steps in each exercise to gradually build and refine your +application. The exercises explain each step in detail and provide all the +sample code you need to complete the application.

        + +

        When you are finished with the tutorial, you will have created a functioning +Android application and will have learned many of the most important +concepts in Android development. If you want to add more complex features to +your application, you can examine the code in an alternative implementation +of a Note Pad application, in the +Sample Code section.

        + + + +

        Who Should Use this Tutorial

        + +

        This tutorial is designed for experienced developers, especially those with +knowledge of the Java programming language. If you haven't written Java +applications before, you can still use the tutorial, but you might need to work +at a slower pace.

        + +

        Also note that this tutorial uses +the Eclipse development environment, with the Android plugin installed. If you +are not using Eclipse, you can follow the exercises and build the application, +but you will need to determine how to accomplish the Eclipse-specific +steps in your environment.

        + + +

        Preparing for the Exercises

        + +

        The tutorial assumes that you have some familiarity with basic Android +application concepts and terminology. If you are not, you +should read Application +Fundamentals before continuing.

        + +

        This tutorial also builds on the introductory information provided in the +Hello World +tutorial, which explains how to set up your Eclipse environment +for building Android applications. We recommend you complete the Hello World +tutorial before starting this one.

        + +

        To prepare for this lesson:

        + +
          +
        1. Download the project + exercises archive (.zip).
        2. +
        3. Unpack the archive file to a suitable location on your machine.
        4. +
        5. Open the NotepadCodeLab folder.
        6. +
        + +

        Inside the NotepadCodeLab folder, you should see six project +files: Notepadv1, + Notepadv2, Notepadv3, + Notepadv1Solution, Notepadv2Solution + and Notepadv3Solution. The Notepadv# projects are +the starting points for each of the exercises, while the +Notepadv#Solution projects are the exercise + solutions. If you are having trouble with a particular exercise, you + can compare your current work against the exercise solution.

        + + +

        Exercises

        + +

        The table below lists the tutorial exercises and describes the development +areas that each covers. Each exercise assumes that you have completed any +previous exercises.

        + + + + + + + + + + + + + + + + + + +
        Exercise +1Start here. Construct a simple notes list that lets the user add new notes but not +edit them. Demonstrates the basics of ListActivity and creating +and handling + menu options. Uses a SQLite database to store the notes.
        Exercise 2Add a second Activity to the +application. Demonstrates constructing a +new Activity, adding it to the Android manifest, passing data between the +activities, and using more advanced screen layout. Also shows how to +invoke another Activity to return a result, using +startActivityForResult().
        Exercise 3Add handling of life-cycle events to +the application, to let it +maintain application state across the life cycle.
        Extra +CreditDemonstrates how to use the Eclipse +debugger and how you can use it to +view life-cycle events as they are generated. This section is optional but +highly recommended.
        + + + +

        Other Resources and Further Learning

        +
          +
        • For a lighter but broader introduction to concepts not covered in the +tutorial, +take a look at Common Android Tasks.
        • +
        • The Android SDK includes a variety of fully functioning sample applications +that make excellent opportunities for further learning. You can find the sample +applications in the samples/ directory of your downloaded SDK, or browser them +here, in the Sample Code section.
        • +
        • This tutorial draws from the full Notepad application included in the +samples/ directory of the SDK, though it does not match it exactly. +When you are done with the tutorial, +it is highly recommended that you take a closer look at this version of the Notepad +application, +as it demonstrates a variety of interesting additions for your application, +such as:
        • +
            +
          • Setting up a custom striped list for the list of notes.
          • +
          • Creating a custom text edit view that overrides the draw() + method to make it look like a lined notepad.
          • +
          • Implementing a full ContentProvider for notes.
          • +
          • Reverting and discarding edits instead of just automatically saving + them.
          • +
          +
        diff --git a/docs/html/resources/tutorials/notepad/notepad-ex1.jd b/docs/html/resources/tutorials/notepad/notepad-ex1.jd new file mode 100644 index 0000000..b26440b --- /dev/null +++ b/docs/html/resources/tutorials/notepad/notepad-ex1.jd @@ -0,0 +1,591 @@ +page.title=Notepad Exercise 1 +parent.title=Notepad Tutorial +parent.link=index.html +@jd:body + + +

        In this exercise, you will construct a simple notes list that lets the +user add new notes but not edit them. The exercise demonstrates:

        +
          +
        • The basics of ListActivities and creating and handling menu +options.
        • +
        • How to use a SQLite database to store the notes.
        • +
        • How to bind data from a database cursor into a ListView using a +SimpleCursorAdapter.
        • +
        • The basics of screen layouts, including how to lay out a list view, how +you can add items to the activity menu, and how the activity handles those menu +selections.
        • +
        + +
        + + [Exercise 1] + [Exercise 2] + [Exercise 3] + [Extra Credit] +
        + + + +

        Step 1

        + +

        Open up the Notepadv1 project in Eclipse.

        + +

        Notepadv1 is a project that is provided as a starting point. It + takes care of some of the boilerplate work that you have already seen if you + followed the Hello, + World tutorial.

        + +
          +
        1. + Start a new Android Project by clicking File > + New > Android Project.
        2. +
        3. + In the New Android Project dialog, select Create project from existing source.
        4. +
        5. + Click Browse and navigate to where you copied the NotepadCodeLab + (downloaded during setup) + and select Notepadv1.
        6. +
        7. + The Project Name and other properties should be automatically filled for you. + You must select the Build Target—we recommend selecting a target with the + lowest platform version available. Also add an integer to the Min SDK Version field + that matches the API Level of the selected Build Target.
        8. +
        9. + Click Finish. The Notepadv1 project should open and be + visible in your Eclipse package explorer.
        10. +
        + +

        If you see an error about AndroidManifest.xml, or some + problems related to an Android zip file, right click on the project and + select Android Tools > Fix Project Properties. + (The project is looking in the wrong location for the library file, + this will fix it for you.)

        + +

        Step 2

        + + + +

        Take a look at the NotesDbAdapter class — this class is provided to + encapsulate data access to a SQLite database that will hold our notes data + and allow us to update it.

        +

        At the top of the class are some constant definitions that will be used in the application + to look up data from the proper field names in the database. There is also a database creation + string defined, which is used to create a new database schema if one doesn't exist already.

        +

        Our database will have the name data, and have a single table called + notes, which in turn has three fields: _id, title and + body. The _id is named with an underscore convention used in a number of + places inside the Android SDK and helps keep a track of state. The _id + usually has to be specified when querying or updating the database (in the column projections + and so on). The other two fields are simple text fields that will store data. +

        +

        The constructor for NotesDbAdapter takes a Context, which allows it to communicate with aspects + of the Android operating system. This is quite common for classes that need to touch the + Android system in some way. The Activity class implements the Context class, so usually you will just pass + this from your Activity, when needing a Context.

        +

        The open() method calls up an instance of DatabaseHelper, which is our local + implementation of the SQLiteOpenHelper class. It calls getWritableDatabase(), + which handles creating/opening a database for us.

        +

        close() just closes the database, releasing resources related to the + connection.

        +

        createNote() takes strings for the title and body of a new note, + then creates that note in the database. Assuming the new note is created successfully, the + method also returns the row _id value for the newly created note.

        +

        deleteNote() takes a rowId for a particular note, and deletes that note from + the database.

        + +

        fetchAllNotes() issues a query to return a {@link android.database.Cursor} over all notes in the + database. The query() call is worth examination and understanding. The first field is the + name of the database table to query (in this case DATABASE_TABLE is "notes"). + The next is the list of columns we want returned, in this case we want the _id, + title and body columns so these are specified in the String array. + The remaining fields are, in order: selection, + selectionArgs, groupBy, having and orderBy. + Having these all null means we want all data, need no grouping, and will take the default + order. See {@link android.database.sqlite.SQLiteDatabase SQLiteDatabase} for more details.

        +

        Note: A Cursor is returned rather than a collection of rows. This allows + Android to use resources efficiently -- instead of putting lots of data straight into memory + the cursor will retrieve and release data as it is needed, which is much more efficient for + tables with lots of rows.

        + +

        fetchNote() is similar to fetchAllNotes() but just gets one note + with the rowId we specify. It uses a slightly different version of the + {@link android.database.sqlite.SQLiteDatabase} query() method. + The first parameter (set true) indicates that we are interested + in one distinct result. The selection parameter (the fourth parameter) has been specified to search + only for the row "where _id =" the rowId we passed in. So we are returned a Cursor on + the one row.

        +

        And finally, updateNote() takes a rowId, title and body, and uses a + {@link android.content.ContentValues ContentValues} instance to update the note of the given + rowId.

        + +

        Step 3

        + + + +

        Open the notepad_list.xml file in res/layout +and + take a look at it. (You may have to + hit the xml tab, at the bottom, in order to view the XML markup.)

        + +

        This is a mostly-empty layout definition file. Here are some + things you should know about a layout file:

        + + +
          +
        • + All Android layout files must start with the XML header line: + <?xml version="1.0" encoding="utf-8"?>.
        • +
        • + The next definition will often (but not always) be a layout + definition of some kind, in this case a LinearLayout.
        • +
        • + The XML namespace of Android should always be defined in + the top level component or layout in the XML so that android: tags can + be used through the rest of the file: +

          xmlns:android="http://schemas.android.com/apk/res/android"

          +
        • +
        + +

        Step 4

        +

        We need to create the layout to hold our list. Add code inside + of the LinearLayout element so the whole file looks like this:

        +
        +<?xml version="1.0" encoding="utf-8"?>
        +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        +    android:layout_width="wrap_content"
        +    android:layout_height="wrap_content">
        +
        +  <ListView android:id="@android:id/list"
        +        android:layout_width="wrap_content"
        +        android:layout_height="wrap_content"/>
        +  <TextView android:id="@android:id/empty"
        +        android:layout_width="wrap_content"
        +        android:layout_height="wrap_content"
        +        android:text="@string/no_notes"/>
        +
        +</LinearLayout>
        +
        +
          +
        • + The @ symbol in the id strings of the ListView and + TextView tags means + that the XML parser should parse and expand the rest of + the id string and use an ID resource.
        • +
        • + The ListView and TextView can be + thought as two alternative views, only one of which will be displayed at once. + ListView will be used when there are notes to be shown, while the TextView + (which has a default value of "No Notes Yet!" defined as a string + resource in res/values/strings.xml) will be displayed if there + aren't any notes to display.
        • +
        • The list and empty IDs are + provided for us by the Android platform, so, we must + prefix the id with android: (e.g., @android:id/list).
        • +
        • The View with the empty id is used + automatically when the {@link android.widget.ListAdapter} has no data for the ListView. The + ListAdapter knows to look for this name by default. Alternatively, you could change the + default empty view by using {@link android.widget.AdapterView#setEmptyView(View)} + on the ListView. +

          + More broadly, the android.R class is a set of predefined + resources provided for you by the platform, while your project's + R class is the set of resources your project has defined. + Resources found in the android.R resource class can be + used in the XML files by using the android: name space prefix + (as we see here).

          +
        • +
        + +

        Step 5

        + + +

        To make the list of notes in the ListView, we also need to define a View for each row:

        +
          +
        1. + Create a new file under res/layout called + notes_row.xml.
        2. +
        3. + Add the following contents (note: again the XML header is used, and the + first node defines the Android XML namespace)
          +
          +<?xml version="1.0" encoding="utf-8"?>
          +<TextView android:id="@+id/text1"
          +    xmlns:android="http://schemas.android.com/apk/res/android"
          +    android:layout_width="wrap_content"
          +    android:layout_height="wrap_content"/>
          +

          + This is the View that will be used for each notes title row — it has only + one text field in it.

          +

          In this case we create a new id called text1. The + + after the @ in the id string indicates that the id should + be automatically created as a resource if it does not already exist, so we are defining + text1 on the fly and then using it.

          +
        4. +
        5. Save the file.
        6. +
        +

        Open the R.java class in the + project and look at it, you should see new definitions for + notes_row and text1 (our new definitions) + meaning we can now gain access to these from the our code.

        + +

        Step 6

        +

        Next, open the Notepadv1 class in the source. In the following steps, we are going to + alter this class to become a list adapter and display our notes, and also + allow us to add new notes.

        + +

        Notepadv1 will inherit from a subclass + of Activity called a ListActivity, + which has extra functionality to accommodate the kinds of + things you might want to do with a list, for + example: displaying an arbitrary number of list items in rows on the screen, + moving through the list items, and allowing them to be selected.

        + +

        Take a look through the existing code in Notepadv1 class. + There is a currently an unused private field called mNoteNumber that + we will use to create numbered note titles.

        +

        There are also three override methods defined: + onCreate, onCreateOptionsMenu and + onOptionsItemSelected; we need to fill these + out:

        +
          +
        • onCreate() is called when the activity is + started — it is a little like the "main" method for an Activity. We use + this to set up resources and state for the activity when it is + running.
        • +
        • onCreateOptionsMenu() is used to populate the + menu for the Activity. This is shown when the user hits the menu button, +and + has a list of options they can select (like "Create + Note").
        • +
        • onOptionsItemSelected() is the other half of the + menu equation, it is used to handle events generated from the menu (e.g., + when the user selects the "Create Note" item). +
        • +
        + +

        Step 7

        +

        Change the inheritance of Notepadv1 from +Activity + to ListActivity:

        +
        public class Notepadv1 extends ListActivity
        +

        Note: you will have to import ListActivity into the +Notepadv1 + class using Eclipse, ctrl-shift-O on Windows or Linux, or + cmd-shift-O on the Mac (organize imports) will do this for you + after you've written the above change.

        + +

        Step 8

        +

        Fill out the body of the onCreate() method.

        +

        Here we will set the title for the Activity (shown at the top of the + screen), use the notepad_list layout we created in XML, + set up the NotesDbAdapter instance that will + access notes data, and populate the list with the available note + titles:

        +
          +
        1. + In the onCreate method, call super.onCreate() with the + savedInstanceState parameter that's passed in.
        2. +
        3. + Call setContentView() and pass R.layout.notepad_list.
        4. +
        5. + At the top of the class, create a new private class field called mDbHelper of class + NotesDbAdapter. +
        6. +
        7. + Back in the onCreate method, construct a new +NotesDbAdapter + instance and assign it to the mDbHelper field (pass + this into the constructor for DBHelper) +
        8. +
        9. + Call the open() method on mDbHelper to open (or create) the + database. +
        10. +
        11. + Finally, call a new method fillData(), which will get the data and + populate the ListView using the helper — we haven't defined this method yet.
        12. +
        +

        + onCreate() should now look like this:

        +
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        setContentView(R.layout.notepad_list);
        +        mDbHelper = new NotesDbAdapter(this);
        +        mDbHelper.open();
        +        fillData();
        +    }
        +

        And be sure you have the mDbHelper field definition (right + under the mNoteNumber definition):

        +
            private NotesDbAdapter mDbHelper;
        + +

        Step 9

        + + + +

        Fill out the body of the onCreateOptionsMenu() method.

        + +

        We will now create the "Add Item" button that can be accessed by pressing the menu +button on the device. We'll specify that it occupy the first position in the menu.

        + +
          +
        1. + In strings.xml resource (under res/values), add + a new string named "menu_insert" with its value set to Add Item: +
          <string name="menu_insert">Add Item</string>
          +

          Then save the file and return to Notepadv1.

          +
        2. +
        3. Create a menu position constant at the top of the class: +
          public static final int INSERT_ID = Menu.FIRST;
          +
        4. +
        5. In the onCreateOptionsMenu() method, change the + super call so we capture the boolean return as result. We'll return this value at the end.
        6. +
        7. Then add the menu item with menu.add().
        8. +
        +

        The whole method should now look like this: +

        +    @Override
        +    public boolean onCreateOptionsMenu(Menu menu) {
        +        boolean result = super.onCreateOptionsMenu(menu);
        +        menu.add(0, INSERT_ID, 0, R.string.menu_insert);
        +        return result;
        +    }
        +

        The arguments passed to add() indicate: a group identifier for this menu (none, + in this case), a unique ID (defined above), the order of the item (zero indicates no preference), + and the resource of the string to use for the item.

        + +

        Step 10

        +

        Fill out the body of the onOptionsItemSelected() method:

        +

        This is going + to handle our new "Add Note" menu item. When this is selected, the + onOptionsItemSelected() method will be called with the + item.getId() set to INSERT_ID (the constant we + used to identify the menu item). We can detect this, and take the + appropriate actions:

        +
          +
        1. + The super.onOptionsItemSelected(item) method call goes at the + end of this method — we want to catch our events first!
        2. +
        3. + Write a switch statement on item.getItemId(). +

          In the case of INSERT_ID, call a new method, createNote(), + and return true, because we have handled this event and do not want to + propagate it through the system.

          +
        4. +
        5. Return the result of the superclass' onOptionsItemSelected() + method at the end.
        6. +
        +

        + The whole onOptionsItemSelect() method should now look like + this:

        +
        +    @Override
        +    public boolean onOptionsItemSelected(MenuItem item) {
        +        switch (item.getItemId()) {
        +        case INSERT_ID:
        +            createNote();
        +            return true;
        +        }
        +       
        +        return super.onOptionsItemSelected(item);
        +    }
        + +

        Step 11

        +

        Add a new createNote() method:

        +

        In this first version of + our application, createNote() is not going to be very useful. +We will simply + create a new note with a title assigned to it based on a counter ("Note 1", + "Note 2"...) and with an empty body. At present we have no way of editing + the contents of a note, so for now we will have to be content making one + with some default values:

        +
          +
        1. Construct the name using "Note" and the counter we defined in the class: + String noteName = "Note " + mNoteNumber++
        2. +
        3. + Call mDbHelper.createNote() using noteName as the + title and "" for the body +
        4. +
        5. + Call fillData() to populate the list of notes (inefficient but + simple) — we'll create this method next.
        6. +
        +

        + The whole createNote() method should look like this:

        +
        +    private void createNote() {
        +        String noteName = "Note " + mNoteNumber++;
        +        mDbHelper.createNote(noteName, "");
        +        fillData();
        +    }
        + + +

        Step 12

        + + +

        Define the fillData() method:

        +

        This + method uses SimpleCursorAdapter, which takes a database Cursor + and binds it to fields provided in the layout. These fields define the row elements of our list + (in this case we use the text1 field in our + notes_row.xml layout), so this allows us to easily populate the list with + entries from our database.

        +

        To do this we have to provide a mapping from the title field in the returned Cursor, to + our text1 TextView, which is done by defining two arrays: the first a string array + with the list of columns to map from (just "title" in this case, from the constant + NotesDbAdapter.KEY_TITLE) and, the second, an int array + containing references to the views that we'll bind the data into + (the R.id.text1 TextView).

        +

        This is a bigger chunk of code, so let's first take a look at it:

        + +
        +    private void fillData() {
        +        // Get all of the notes from the database and create the item list
        +        Cursor c = mDbHelper.fetchAllNotes();
        +        startManagingCursor(c);
        +
        +        String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
        +        int[] to = new int[] { R.id.text1 };
        +        
        +        // Now create an array adapter and set it to display using our row
        +        SimpleCursorAdapter notes =
        +            new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
        +        setListAdapter(notes);
        +    }
        + +

        Here's what we've done:

        +
          +
        1. + After obtaining the Cursor from mDbHelper.fetchAllNotes(), we + use an Activity method called + startManagingCursor() that allows Android to take care of the + Cursor lifecycle instead of us needing to worry about it. (We will cover the implications + of the lifecycle in exercise 3, but for now just know that this allows Android to do some + of our resource management work for us.)
        2. +
        3. + Then we create a string array in which we declare the column(s) we want + (just the title, in this case), and an int array that defines the View(s) + to which we'd like to bind the columns (these should be in order, respective to + the string array, but here we only have one for each).
        4. +
        5. + Next is the SimpleCursorAdapter instantiation. + Like many classes in Android, the SimpleCursorAdapter needs a Context in order to do its + work, so we pass in this for the context (since subclasses of Activity + implement Context). We pass the notes_row View we created as the receptacle + for the data, the Cursor we just created, and then our arrays.
        6. +
        +

        + In the future, remember that the mapping between the from columns and to resources + is done using the respective ordering of the two arrays. If we had more columns we wanted + to bind, and more Views to bind them in to, we would specify them in order, for example we + might use { NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_BODY } and + { R.id.text1, R.id.text2 } to bind two fields into the row (and we would also need + to define text2 in the notes_row.xml, for the body text). This is how you can bind multiple fields + into a single row (and get a custom row layout as well).

        +

        + If you get compiler errors about classes not being found, ctrl-shift-O or + (cmd-shift-O on the mac) to organize imports. +

        + +

        Step 13

        +

        Run it! +

          +
        1. + Right click on the Notepadv1 project.
        2. +
        3. + From the popup menu, select Run As > + Android Application.
        4. +
        5. + If you see a dialog come up, select Android Launcher as the way of running + the application (you can also use the link near the top of the dialog to + set this as your default for the workspace; this is recommended as it will + stop the plugin from asking you this every time).
        6. +
        7. Add new notes by hitting the menu button and selecting Add + Item from the menu.
        8. +
        + +

        Solution and Next Steps

        +

        You can see the solution to this class in Notepadv1Solution +from +the zip file to compare with your own.

        + +

        Once you are ready, move on to Tutorial +Exercise 2 to add the ability to create, edit and delete notes.

        + diff --git a/docs/html/resources/tutorials/notepad/notepad-ex2.jd b/docs/html/resources/tutorials/notepad/notepad-ex2.jd new file mode 100644 index 0000000..bab9471 --- /dev/null +++ b/docs/html/resources/tutorials/notepad/notepad-ex2.jd @@ -0,0 +1,647 @@ +Rpage.title=Notepad Exercise 2 +parent.title=Notepad Tutorial +parent.link=index.html +@jd:body + + +

        In this exercise, you will add a second Activity to your notepad application, to let the user +create and edit notes. You will also allow the user to delete existing notes through a context menu. +The new Activity assumes responsibility for creating new notes by +collecting user input and packing it into a return Bundle provided by the intent. This exercise +demonstrates:

        +
          +
        • Constructing a new Activity and adding it to the Android manifest
        • +
        • Invoking another Activity asynchronously using startActivityForResult()
        • +
        • Passing data between Activity in Bundle objects
        • +
        • How to use a more advanced screen layout
        • +
        • How to create a context menu
        • +
        + +
        + [Exercise 1] + + [Exercise 2] + + [Exercise 3] + [Extra Credit] +
        + +

        Step 1

        + +

        Create a new Android project using the sources from Notepadv2 under the +NotepadCodeLab folder, just like you did for the first exercise. If you see an error about +AndroidManifest.xml, or some problems related to an +android.zip file, right click on the project and select Android +Tools > Fix Project Properties.

        + +

        Open the Notepadv2 project and take a look around:

        +
          +
        • + Open and look at the strings.xml file under + res/values — there are several new strings which we will use + for our new functionality +
        • +
        • + Also, open and take a look at the top of the Notepadv2 class, + you will notice several new constants have been defined along with a new mNotesCursor + field used to hold the cursor we are using. +
        • +
        • + Note also that the fillData() method has a few more comments and now uses + the new field to store the notes Cursor. The onCreate() method is + unchanged from the first exercise. Also notice that the member field used to store the + notes Cursor is now called mNotesCursor. The m denotes a member + field and is part of the Android coding style standards. +
        • +
        • + There are also a couple of new overridden methods + (onCreateContextMenu(), onContextItemSelected(), + onListItemClick() and onActivityResult()) + which we will be filling in below. +
        • +
        + + +

        Step 2

        + + + +

        First, let's create the context menu that will allow users to delete individual notes. +Open the Notepadv2 class.

        + +
          +
        1. In order for each list item in the ListView to register for the context menu, we call + registerForContextMenu() and pass it our ListView. So, at the very end of + the onCreate() method add this line: +
          registerForContextMenu(getListView());
          +

          Because our Activity extends the ListActivity class, getListView() will return us + the local ListView object for the Activity. Now, each list item in this ListView will activate the + context menu. +

        2. + Now fill in the onCreateContextMenu() method. This callback is similar to the other + menu callback used for the options menu. Here, we add just one line, which will add a menu item + to delete a note. Call menu.add() like so: +
          +public boolean onCreateContextMenu(Menu menu, View v
          +        ContextMenuInfo menuInfo) {
          +    super.onCreateContextMenu(menu, v, menuInfo);
          +    menu.add(0, DELETE_ID, 0, R.string.menu_delete);
          +}
          +

          The onCreateContextMenu() callback some passes other information in addition to the Menu object, + such as the View that has been triggered for the menu and + an extra object that may contain additional information about the object selected. However, we don't care about + these here, because we only have one kind of object in the Activity that uses context menus. In the next + step, we'll handle the menu item selection.

          +
        3. +
        + +

        Step 3

        +

        Now that the we've registered our ListView for a context menu and defined our context menu item, we need + to handle the callback when it is selected. For this, we need to identify the list ID of the + selected item, then delete it. So fill in the + onContextItemSelected() method like this:

        +
        +public boolean onContextItemSelected(MenuItem item) {
        +    switch(item.getItemId()) {
        +    case DELETE_ID:
        +        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        +        mDbHelper.deleteNote(info.id);
        +        fillData();
        +        return true;
        +    }
        +    return super.onContextItemSelected(item);
        +}
        +

        Here, we retrieve the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo} +with {@link android.view.MenuItem#getMenuInfo()}. The id field of this object tells us +the position of the item in the ListView. We then pass this to the deleteNote() +method of our NotesDbAdapter and the note is deleted. That's it for the context menu — notes +can now be deleted.

        + +

        Step 4

        + + +

        Fill in the body of the createNote() method: +

        Create a new Intent to create a note + (ACTIVITY_CREATE) using the NoteEdit class. + Then fire the Intent using the startActivityForResult() method + call:

        +
        +Intent i = new Intent(this, NoteEdit.class);
        +startActivityForResult(i, ACTIVITY_CREATE);
        +

        This form of the Intent call targets a specific class in our Activity, in this case + NoteEdit. Since the Intent class will need to communicate with the Android + operating system to route requests, we also have to provide a Context (this).

        +

        The startActivityForResult() method fires the Intent in a way that causes a method + in our Activity to be called when the new Activity is completed. The method in our Activity + that receives the callback is called + onActivityResult() and we will implement it in a later step. The other way + to call an Activity is using startActivity() but this is a "fire-and-forget" way + of calling it — in this manner, our Activity is not informed when the Activity is completed, and there is + no way to return result information from the called Activity with startActivity(). +

        Don't worry about the fact that NoteEdit doesn't exist yet, + we will fix that soon.

        + + + +

        Step 5

        + +

        Fill in the body of the onListItemClick() override.

        +

        onListItemClick() is a callback method that we'll override. It is called when + the user selects an item from the list. It is passed four parameters: the + ListView object it was invoked from, the View + inside the ListView that was clicked on, the + position in the list that was clicked, and the + mRowId of the item that was clicked. In this instance we can + ignore the first two parameters (we only have one ListView it + could be), and we ignore the mRowId as well. All we are + interested in is the position that the user selected. We use + this to get the data from the correct row, and bundle it up to send to + the NoteEdit Activity.

        +

        In our implementation of the callback, the method creates an + Intent to edit the note using + the NoteEdit class. It then adds data into the extras Bundle of + the Intent, which will be passed to the called Activity. We use it + to pass in the title and body text, and the mRowId for the note we are + editing. Finally, it will fire the Intent using the + startActivityForResult() method call. Here's the code that + belongs in onListItemClick():

        +
        +super.onListItemClick(l, v, position, id);
        +Cursor c = mNotesCursor;
        +c.moveToPosition(position);
        +Intent i = new Intent(this, NoteEdit.class);
        +i.putExtra(NotesDbAdapter.KEY_ROWID, id);
        +i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString(
        +        c.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
        +i.putExtra(NotesDbAdapter.KEY_BODY, c.getString(
        +        c.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
        +startActivityForResult(i, ACTIVITY_EDIT);
        +
          +
        • + putExtra() is the method to add items into the extras Bundle + to pass in to intent invocations. Here, we are + using the Bundle to pass in the title, body and mRowId of the note we want to edit. +
        • +
        • + The details of the note are pulled out from our query Cursor, which we move to the + proper position for the element that was selected in the list, with + the moveToPosition() method.
        • +
        • With the extras added to the Intent, we invoke the Intent on the + NoteEdit class by passing startActivityForResult() + the Intent and the request code. (The request code will be + returned to onActivityResult as the requestCode parameter.)
        • +
        +

        Note: We assign the mNotesCursor field to a local variable at the + start of the method. This is done as an optimization of the Android code. Accessing a local + variable is much more efficient than accessing a field in the Dalvik VM, so by doing this + we make only one access to the field, and five accesses to the local variable, making the + routine much more efficient. It is recommended that you use this optimization when possible.

        + + +

        Step 6

        + +

        The above createNote() and onListItemClick() + methods use an asynchronous Intent invocation. We need a handler for the callback, so here we fill + in the body of the onActivityResult().

        +

        onActivityResult() is the overridden method + which will be called when an Activity returns with a result. (Remember, an Activity + will only return a result if launched with startActivityForResult.) The parameters provided + to the callback are:

        +
          +
        • requestCode — the original request code + specified in the Intent invocation (either ACTIVITY_CREATE or + ACTIVITY_EDIT for us). +
        • +
        • resultCode — the result (or error code) of the call, this + should be zero if everything was OK, but may have a non-zero code indicating + that something failed. There are standard result codes available, and you + can also create your own constants to indicate specific problems. +
        • +
        • intent — this is an Intent created by the Activity returning + results. It can be used to return data in the Intent "extras." +
        • +
        +

        The combination of startActivityForResult() and + onActivityResult() can be thought of as an asynchronous RPC + (remote procedure call) and forms the recommended way for an Activity to invoke + another and share services.

        +

        Here's the code that belongs in your onActivityResult():

        +
        +super.onActivityResult(requestCode, resultCode, intent);
        +Bundle extras = intent.getExtras();
        +
        +switch(requestCode) {
        +case ACTIVITY_CREATE:
        +    String title = extras.getString(NotesDbAdapter.KEY_TITLE);
        +    String body = extras.getString(NotesDbAdapter.KEY_BODY);
        +    mDbHelper.createNote(title, body);
        +    fillData();
        +    break;
        +case ACTIVITY_EDIT:
        +    Long mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
        +    if (mRowId != null) {
        +        String editTitle = extras.getString(NotesDbAdapter.KEY_TITLE);
        +        String editBody = extras.getString(NotesDbAdapter.KEY_BODY);
        +        mDbHelper.updateNote(mRowId, editTitle, editBody);
        +    }
        +    fillData();
        +    break;
        +}
        + +
          +
        • + We are handling both the ACTIVITY_CREATE and + ACTIVITY_EDIT activity results in this method. +
        • +
        • + In the case of a create, we pull the title and body from the extras (retrieved from the + returned Intent) and use them to create a new note. +
        • +
        • + In the case of an edit, we pull the mRowId as well, and use that to update + the note in the database. +
        • +
        • + fillData() at the end ensures everything is up to date . +
        • +
        + + +

        Step 7

        + + + +

        Open the file note_edit.xml that has been provided and take a + look at it. This is the UI code for the Note Editor.

        +

        This is the most + sophisticated UI we have dealt with yet. The file is given to you to avoid + problems that may sneak in when typing the code. (The XML is very strict + about case sensitivity and structure, mistakes in these are the usual cause + of problems with layout.)

        +

        There is a new parameter used + here that we haven't seen before: android:layout_weight (in + this case set to use the value 1 in each case).

        +

        layout_weight is used in LinearLayouts + to assign "importance" to Views within the layout. All Views have a default + layout_weight of zero, meaning they take up only as much room + on the screen as they need to be displayed. Assigning a value higher than + zero will split up the rest of the available space in the parent View, according + to the value of each View's layout_weight and its ratio to the + overall layout_weight specified in the current layout for this + and other View elements.

        +

        To give an example: let's say we have a text label + and two text edit elements in a horizontal row. The label has no + layout_weight specified, so it takes up the minimum space + required to render. If the layout_weight of each of the two + text edit elements is set to 1, the remaining width in the parent layout will + be split equally between them (because we claim they are equally important). + If the first one has a layout_weight of 1 + and the second has a layout_weight of 2, then one third of the + remaining space will be given to the first, and two thirds to the + second (because we claim the second one is more important).

        +

        This layout also demonstrates how to nest multiple layouts + inside each other to achieve a more complex and pleasant layout. In this + example, a horizontal linear layout is nested inside the vertical one to + allow the title label and text field to be alongside each other, + horizontally.

        + + +

        Step 8

        + +

        Create a NoteEdit class that extends + android.app.Activity.

        +

        This is the first time we will have + created an Activity without the Android Eclipse plugin doing it for us. When + you do so, the onCreate() method is not automatically + overridden for you. It is hard to imagine an Activity that doesn't override + the onCreate() method, so this should be the first thing you do.

        +
          +
        1. Right click on the com.android.demo.notepad2 package + in the Package Explorer, and select New > Class from the popup + menu.
        2. +
        3. Fill in NoteEdit for the Name: field in the + dialog.
        4. +
        5. In the Superclass: field, enter + android.app.Activity (you can also just type Activity and hit + Ctrl-Space on Windows and Linux or Cmd-Space on the Mac, to invoke code + assist and find the right package and class).
        6. +
        7. Click Finish.
        8. +
        9. In the resulting NoteEdit class, right click in the editor + window and select Source > Override/Implement Methods...
        10. +
        11. Scroll down through the checklist in the dialog until you see + onCreate(Bundle) — and check the box next to it.
        12. +
        13. Click OK.

          The method should now appear in your class.

        14. +
        + +

        Step 9

        + +

        Fill in the body of the onCreate() method for NoteEdit.

        + +

        This will set the title of our new Activity to say "Edit Note" (one + of the strings defined in strings.xml). It will also set the + content view to use our note_edit.xml layout file. We can then + grab handles to the title and body text edit views, and the confirm button, + so that our class can use them to set and get the note title and body, + and attach an event to the confirm button for when it is pressed by the + user.

        +

        We can then unbundle the values that were passed in to the Activity + with the extras Bundle attached to the calling Intent. We'll use them to pre-populate + the title and body text edit views so that the user can edit them. + Then we will grab and store the mRowId so we can keep + track of what note the user is editing.

        + +
          +
        1. + Inside onCreate(), set up the layout:
          +
          setContentView(R.layout.note_edit);
          +
        2. +
        3. + Find the edit and button components we need: +

          These are found by the + IDs associated to them in the R class, and need to be cast to the right + type of View (EditText for the two text views, + and Button for the confirm button):

          +
          +mTitleText = (EditText) findViewById(R.id.title);
          +mBodyText = (EditText) findViewById(R.id.body);
          +Button confirmButton = (Button) findViewById(R.id.confirm);
          +

          Note that mTitleText and mBodyText are member + fields (you need to declare them at the top of the class definition).

          +
        4. +
        5. At the top of the class, declare a Long mRowId private field to store + the current mRowId being edited (if any). +
        6. +
        7. Continuing inside onCreate(), + add code to initialize the title, body and + mRowId from the extras Bundle in + the Intent (if it is present):
          +
          +mRowId = null;
          +Bundle extras = getIntent().getExtras();
          +if (extras != null) {
          +    String title = extras.getString(NotesDbAdapter.KEY_TITLE);
          +    String body = extras.getString(NotesDbAdapter.KEY_BODY);
          +    mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
          +           
          +    if (title != null) {
          +        mTitleText.setText(title);
          +    }
          +    if (body != null) {
          +        mBodyText.setText(body);
          +    }
          +}
          +
            +
          • + We are pulling the title and + body out of the + extras Bundle that was set from the + Intent invocation. +
          • + We also null-protect the text field setting (i.e., we don't want to set + the text fields to null accidentally).
          • +
          +
        8. +
        9. + Create an onClickListener() for the button: +

          Listeners can be one of the more confusing aspects of UI + implementation, but + what we are trying to achieve in this case is simple. We want an + onClick() method to be called when the user presses the + confirm button, and use that to do some work and return the values + of the edited note to the Intent caller. We do this using something called + an anonymous inner class. This is a bit confusing to look at unless you + have seen them before, but all you really need to take away from this is + that you can refer to this code in the future to see how to create a + listener and attach it to a button. (Listeners are a common idiom + in Java development, particularly for user interfaces.) Here's the empty listener:
          +

          +confirmButton.setOnClickListener(new View.OnClickListener() {
          +
          +    public void onClick(View view) {
          +               
          +    }
          +           
          +});
          +
        10. +
        +

        Step 10

        + +

        Fill in the body of the onClick() method of the OnClickListener created in the last step.

        + +

        This is the code that will be run when the user clicks on the + confirm button. We want this to grab the title and body text from the edit + text fields, and put them into the return Bundle so that they can be passed + back to the Activity that invoked this NoteEdit Activity. If the + operation is an edit rather than a create, we also want to put the + mRowId into the Bundle so that the + Notepadv2 class can save the changes back to the correct + note.

        +
          +
        1. + Create a Bundle and put the title and body text into it using the + constants defined in Notepadv2 as keys:
          +
          +Bundle bundle = new Bundle();
          +      
          +bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString());
          +bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString());
          +if (mRowId != null) {
          +    bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
          +}
          +
        2. +
        3. + Set the result information (the Bundle) in a new Intent and finish the Activity: +
          +Intent mIntent = new Intent();
          +mIntent.putExtras(bundle);
          +setResult(RESULT_OK, mIntent);
          +finish();
          +
            +
          • The Intent is simply our data carrier that carries our Bundle + (with the title, body and mRowId).
          • +
          • The setResult() method is used to set the result + code and return Intent to be passed back to the + Intent caller. In this case everything worked, so we return RESULT_OK for the + result code.
          • +
          • The finish() call is used to signal that the Activity + is done (like a return call). Anything set in the Result will then be + returned to the caller, along with execution control.
          • +
          +
        4. +
        +

        The full onCreate() method (plus supporting class fields) should + now look like this:

        +
        +private EditText mTitleText;
        +private EditText mBodyText;
        +private Long mRowId;
        +
        +@Override
        +protected void onCreate(Bundle savedInstanceState) {
        +    super.onCreate(savedInstanceState);
        +    setContentView(R.layout.note_edit);
        +   
        +    mTitleText = (EditText) findViewById(R.id.title);
        +    mBodyText = (EditText) findViewById(R.id.body);
        +  
        +    Button confirmButton = (Button) findViewById(R.id.confirm);
        +   
        +    mRowId = null;
        +    Bundle extras = getIntent().getExtras();
        +    if (extras != null) {
        +        String title = extras.getString(NotesDbAdapter.KEY_TITLE);
        +        String body = extras.getString(NotesDbAdapter.KEY_BODY);
        +        mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
        +      
        +        if (title != null) {
        +            mTitleText.setText(title);
        +        }
        +        if (body != null) {
        +            mBodyText.setText(body);
        +        }
        +    }
        +   
        +    confirmButton.setOnClickListener(new View.OnClickListener() {
        +
        +        public void onClick(View view) {
        +            Bundle bundle = new Bundle();
        +           
        +            bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString());
        +            bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString());
        +            if (mRowId != null) {
        +                bundle.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
        +            }
        +
        +            Intent mIntent = new Intent();
        +            mIntent.putExtras(bundle);
        +            setResult(RESULT_OK, mIntent);
        +            finish();
        +        }
        +    });
        +}
        + +
      + +

      Step 11

      + + + +

      Finally, the new Activity has to be defined in the manifest file:

      +

      Before the new Activity can be seen by Android, it needs its own + Activity entry in the AndroidManifest.xml file. This is to let + the system know that it is there and can be called. We could also specify + which IntentFilters the activity implements here, but we are going to skip + this for now and just let Android know that the Activity is + defined.

      +

      There is a Manifest editor included in the Eclipse plugin that makes it much easier + to edit the AndroidManifest file, and we will use this. If you prefer to edit the file directly + or are not using the Eclipse plugin, see the box at the end for information on how to do this + without using the new Manifest editor.

      +

        +
      1. Double click on the AndroidManifest.xml file in the package explorer to open it. +
      2. +
      3. Click the Application tab at the bottom of the Manifest editor.
      4. +
      5. Click Add... in the Application Nodes section. +

        If you see a dialog with radiobuttons at the top, select the top radio button: + "Create a new element at the top level, in Application".

      6. +
      7. Make sure "(A) Activity" is selected in the selection pane of the dialog, and click OK.
      8. +
      9. Click on the new "Activity" node, in the Application Nodes section, then + type .NoteEdit into the Name* + field to the right. Press Return/Enter.
      10. +
      +

      The Android Manifest editor helps you add more complex entries into the AndroidManifest.xml + file, have a look around at some of the other options available (but be careful not to select + them otherwise they will be added to your Manifest). This editor should help you understand + and alter the AndroidManifest.xml file as you move on to more advanced Android applications.

      + +

      If you prefer to edit this file directly, simply open the + AndroidManifest.xml file and look at the source (use the + AndroidManifest.xml tab in the eclipse editor to see the source code directly). + Then edit the file as follows:
      + <activity android:name=".NoteEdit"></activity>

      + This should be placed just below the line that reads:
      + </activity> for the .Notepadv2 activity.

      + +

      Step 12

      + +

      Now Run it!

      +

      You should now be able to add real notes from +the menu, as well as delete an existing one. Notice that in order to delete, you must +first use the directional controls on the device to highlight the note. +Furthermore, selecting a note title from the list should bring up the note +editor to let you edit it. Press confirm when finished to save the changes +back to the database. + +

      Solution and Next Steps

      + +

      You can see the solution to this exercise in Notepadv2Solution +from the zip file to compare with your own.

      +

      Now try editing a note, and then hitting the back button on the emulator +instead of the confirm button (the back button is below the menu button). You +will see an error come up. Clearly our application still has some problems. +Worse still, if you did make some changes and hit the back button, when you go +back into the notepad to look at the note you changed, you will find that all +your changes have been lost. In the next exercise we will fix these +problems.

      + +

      +Once you are ready, move on to Tutorial +Exercise 3 where you will fix the problems with the back button and lost +edits by introducing a proper life cycle into the NoteEdit Activity.

      + + diff --git a/docs/html/resources/tutorials/notepad/notepad-ex3.jd b/docs/html/resources/tutorials/notepad/notepad-ex3.jd new file mode 100644 index 0000000..8737280 --- /dev/null +++ b/docs/html/resources/tutorials/notepad/notepad-ex3.jd @@ -0,0 +1,358 @@ +page.title=Notepad Exercise 3 +parent.title=Notepad Tutorial +parent.link=index.html +@jd:body + + +

      In this exercise, you will use life-cycle event callbacks to store and +retrieve application state data. This exercise demonstrates:

      +
        +
      • Life-cycle events and how your application can use them
      • +
      • Techniques for maintaining application state
      • +
      + +
      + [Exercise 1] + [Exercise 2] + + [Exercise 3] + + [Extra Credit] +
      + +

      Step 1

      + +

      Import Notepadv3 into Eclipse. If you see an error about +AndroidManifest.xml, or some problems related to an Android zip +file, right click on the project and select Android Tools > +Fix Project Properties from the popup menu. The starting point for this exercise is +exactly where we left off at the end of the Notepadv2.

      +

      The current application has some problems — hitting the back button when editing +causes a crash, and anything else that happens during editing will cause the +edits to be lost.

      +

      To fix this, we will move most of the functionality for creating and editing +the note into the NoteEdit class, and introduce a full life cycle for editing +notes.

      + +
        +
      1. Remove the code in NoteEdit that parses the title and body + from the extras Bundle. +

        Instead, we are going to use the DBHelper class + to access the notes from the database directly. All we need passed into the + NoteEdit Activity is a mRowId (but only if we are editing, if creating we pass + nothing). Remove these lines:

        +
        +String title = extras.getString(NotesDbAdapter.KEY_TITLE);
        +String body = extras.getString(NotesDbAdapter.KEY_BODY);
        +
      2. +
      3. We will also get rid of the properties that were being passed in + the extras Bundle, which we were using to set the title + and body text edit values in the UI. So delete: +
        +if (title != null) {
        +    mTitleText.setText(title);
        +}
        +if (body != null) {
        +    mBodyText.setText(body);
        +}
        +
      4. +
      + +

      Step 2

      + +

      Create a class field for a NotesDbAdapter at the top of the NoteEdit class:

      +
          private NotesDbAdapter mDbHelper;
      +

      Also add an instance of NotesDbAdapter in the + onCreate() method (right below the super.onCreate() call):

      +
      +    mDbHelper = new NotesDbAdapter(this);
      +    mDbHelper.open();
      + +

      Step 3

      + +

      In NoteEdit, we need to check the savedInstanceState for the +mRowId, in case the note + editing contains a saved state in the Bundle, which we should recover (this would happen + if our Activity lost focus and then restarted).

      +
        +
      1. + Replace the code that currently initializes the mRowId:
        +
        +        mRowId = null;
        +
        +        Bundle extras = getIntent().getExtras();
        +        if (extras != null) {
        +            mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
        +        }
        +        
        + with this: +
        +        mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID) 
        +                                            : null;
        +        if (mRowId == null) {
        +            Bundle extras = getIntent().getExtras();            
        +            mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID) 
        +                                    : null;
        +        }
        +        
        +
      2. +
      3. + Note the null check for savedInstanceState, and we still need to load up + mRowId from the extras Bundle if it is not + provided by the savedInstanceState. This is a ternary operator shorthand + to safely either use the value or null if it is not present. +
      4. +
      + +

      Step 4

      + +

      Next, we need to populate the fields based on the mRowId if we + have it:

      +
      populateFields();
      +

      This goes before the confirmButton.setOnClickListener() line. + We'll define this method in a moment.

      + +

      Step 5

      + +

      Get rid of the Bundle creation and Bundle value settings from the + onClick() handler method. The Activity no longer needs to + return any extra information to the caller. And because we no longer have + an Intent to return, we'll use the shorter version + of setResult():

      +
      +public void onClick(View view) {
      +    setResult(RESULT_OK);
      +    finish();
      +}
      +

      We will take care of storing the updates or new notes in the database + ourselves, using the life-cycle methods.

      + +

      The whole onCreate() method should now look like this:

      +
      +super.onCreate(savedInstanceState);
      + 
      +mDbHelper = new NotesDbAdapter(this);
      +mDbHelper.open();
      + 
      +setContentView(R.layout.note_edit);
      + 
      +mTitleText = (EditText) findViewById(R.id.title);
      +mBodyText = (EditText) findViewById(R.id.body);
      + 
      +Button confirmButton = (Button) findViewById(R.id.confirm);
      + 
      +mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID) 
      +                                    : null;
      +if (mRowId == null) {
      +    Bundle extras = getIntent().getExtras();
      +    mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID) 
      +                            : null;
      +}
      + 
      +populateFields();
      + 
      +confirmButton.setOnClickListener(new View.OnClickListener() {
      +
      +    public void onClick(View view) {
      +        setResult(RESULT_OK);
      +        finish();
      +    }
      +     
      +});
      + +

      Step 6

      + +

      Define the populateFields() method.

      +
      +private void populateFields() {
      +    if (mRowId != null) {
      +        Cursor note = mDbHelper.fetchNote(mRowId);
      +        startManagingCursor(note);
      +        mTitleText.setText(note.getString(
      +	            note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
      +        mBodyText.setText(note.getString(
      +                note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
      +    }
      +}
      +

      This method uses the NotesDbAdapter.fetchNote() method to find the right note to +edit, then it calls startManagingCursor() from the Activity class, which +is an Android convenience method provided to take care of the Cursor life-cycle. This will release +and re-create resources as dictated by the Activity life-cycle, so we don't need to worry about +doing that ourselves. After that, we just look up the title and body values from the Cursor +and populate the View elements with them.

      + + +

      Step 7

      + + + +

      Still in the NoteEdit class, we now override the methods + onSaveInstanceState(), onPause() and + onResume(). These are our life-cycle methods + (along with onCreate() which we already have).

      + +

      onSaveInstanceState() is called by Android if the + Activity is being stopped and may be killed before it is + resumed! This means it should store any state necessary to + re-initialize to the same condition when the Activity is restarted. It is + the counterpart to the onCreate() method, and in fact the + savedInstanceState Bundle passed in to onCreate() is the same + Bundle that you construct as outState in the + onSaveInstanceState() method.

      + +

      onPause() and onResume() are also + complimentary methods. onPause() is always called when the + Activity ends, even if we instigated that (with a finish() call for example). + We will use this to save the current note back to the database. Good + practice is to release any resources that can be released during an + onPause() as well, to take up less resources when in the + passive state. onResume() will call our populateFields() method + to read the note out of the database again and populate the fields.

      + +

      So, add some space after the populateFields() method + and add the following life-cycle methods:

      +
        +
      1. + onSaveInstanceState(): +
        +    @Override
        +    protected void onSaveInstanceState(Bundle outState) {
        +        super.onSaveInstanceState(outState);
        +        outState.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
        +    }
        +
      2. +
      3. + onPause(): +
        +    @Override
        +    protected void onPause() {
        +        super.onPause();
        +        saveState();
        +    }
        +

        We'll define saveState() next.

        +
      4. +
      5. + onResume(): +
        +    @Override
        +    protected void onResume() {
        +        super.onResume();
        +        populateFields();
        +    }
        +
      6. +
      + + +

      Step 8

      + +

      Define the saveState() method to put the data out to the +database.

      +
      +     private void saveState() {
      +        String title = mTitleText.getText().toString();
      +        String body = mBodyText.getText().toString();
      +
      +        if (mRowId == null) {
      +            long id = mDbHelper.createNote(title, body);
      +            if (id > 0) {
      +                mRowId = id;
      +            }
      +        } else {
      +            mDbHelper.updateNote(mRowId, title, body);
      +        }
      +    }
      +

      Note that we capture the return value from createNote() and if a valid row ID is + returned, we store it in the mRowId field so that we can update the note in future + rather than create a new one (which otherwise might happen if the life-cycle events are + triggered).

      + + +

      Step 9

      + +

      Now pull out the previous handling code from the + onActivityResult() method in the Notepadv3 + class.

      +

      All of the note retrieval and updating now happens within the + NoteEdit life cycle, so all the onActivityResult() + method needs to do is update its view of the data, no other work is + necessary. The resulting method should look like this:

      +
      +@Override
      +protected void onActivityResult(int requestCode, int resultCode, 
      +                                Intent intent) {
      +    super.onActivityResult(requestCode, resultCode, intent);
      +    fillData();
      +}
      + +

      Because the other class now does the work, all this has to do is refresh + the data.

      + +

      Step 10

      + +

      Also remove the lines which set the title and body from the + onListItemClick() method (again they are no longer needed, + only the mRowId is):

      +
      +    Cursor c = mNotesCursor;
      +    c.moveToPosition(position);
      +
      +and also remove: +
      +
      +    i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString(
      +                    c.getColumnIndex(NotesDbAdapter.KEY_TITLE)));
      +    i.putExtra(NotesDbAdapter.KEY_BODY, c.getString(
      +                    c.getColumnIndex(NotesDbAdapter.KEY_BODY)));
      +
      +so that all that should be left in that method is: +
      +
      +    super.onListItemClick(l, v, position, id);
      +    Intent i = new Intent(this, NoteEdit.class);
      +    i.putExtra(NotesDbAdapter.KEY_ROWID, id);
      +    startActivityForResult(i, ACTIVITY_EDIT);
      + +

      You can also now remove the mNotesCursor field from the class, and set it back to using + a local variable in the fillData() method: +

      +    Cursor notesCursor = mDbHelper.fetchAllNotes();

      +

      Note that the m in mNotesCursor denotes a member field, so when we + make notesCursor a local variable, we drop the m. Remember to rename the + other occurrences of mNotesCursor in your fillData() method. +

    +

    +Run it! (use Run As -> Android Application on the project right +click menu again)

    + +

    Solution and Next Steps

    + +

    You can see the solution to this exercise in Notepadv3Solution +from +the zip file to compare with your own.

    +

    +When you are ready, move on to the Tutorial +Extra Credit exercise, where you can use the Eclipse debugger to +examine the life-cycle events as they happen.

    diff --git a/docs/html/resources/tutorials/notepad/notepad-extra-credit.jd b/docs/html/resources/tutorials/notepad/notepad-extra-credit.jd new file mode 100644 index 0000000..0d59b56 --- /dev/null +++ b/docs/html/resources/tutorials/notepad/notepad-extra-credit.jd @@ -0,0 +1,70 @@ +page.title=Notepad Extra Credit +parent.title=Notepad Tutorial +parent.link=index.html +@jd:body + + +

    In this exercise, you will use the debugger to look at the work you did +in Exercise 3. This exercise demonstrates:

    + + +
    + + [Exercise 1] + [Exercise 2] + [Exercise 3] + + [Extra Credit] + +
    + +

    Step 1

    + +

    Using the working Notepadv3, put breakpoints in the code at the + beginning of the onCreate(), onPause(), + onSaveInstanceState() and onResume() methods in the + NoteEdit class (if you are not familiar with Eclipse, just + right click in the narrow grey border on the left of the edit window at the + line you want a breakpoint, and select Toggle Breakpoint, you +should see a blue dot appear).

    + +

    Step 2

    + +

    Now start the notepad demo in debug mode:

    + +
      +
    1. + Right click on the Notepadv3 project and from the Debug menu + select Debug As -> Android Application.
    2. +
    3. + The Android emulator should say "waiting for debugger to connect" + briefly and then run the application.
    4. +
    5. + If it gets stuck on the waiting... screen, quit the emulator and Eclipse, + from the command line do an adb kill-server, and then restart +Eclipse and try again.
    + +

    Step 3

    + +

    When you edit or create a new note you should see the breakpoints getting + hit and the execution stopping.

    + +

    Step 4

    + +

    Hit the Resume button to let execution continue (yellow rectangle with a +green triangle to its right in the Eclipse toolbars near the top).

    + +

    Step 5

    + +

    Experiment a bit with the confirm and back buttons, and try pressing Home and + making other mode changes. Watch what life-cycle events are generated and +when.

    + +

    The Android Eclipse plugin not only offers excellent debugging support for +your application development, but also superb profiling support. You can also +try using Traceview to profile your application. If your application is running too slow, this can help you +find the bottlenecks and fix them.

    + diff --git a/docs/html/resources/tutorials/notepad/notepad-index.jd b/docs/html/resources/tutorials/notepad/notepad-index.jd new file mode 100644 index 0000000..151c50d --- /dev/null +++ b/docs/html/resources/tutorials/notepad/notepad-index.jd @@ -0,0 +1,143 @@ +page.title=Notepad Tutorial +@jd:body + + +

    The tutorial in this section gives you a "hands-on" introduction +to the Android framework and the tools you use to build applications on it. +Starting from a preconfigured project file, it guides you through the process of +developing a simple notepad application and provides concrete examples of how to +set up the project, develop the application logic and user interface, and then +compile and run the application.

    + +

    The tutorial presents the notepad application development as a set of +exercises (see below), each consisting of several steps. You can follow along +with the steps in each exercise and gradually build up and refine your +application. The exercises explain each step in detail and provide all the +sample code you need to complete the application.

    + +

    When you are finished with the tutorial, you will have created a functioning +Android application and learned in depth about many of the most important +concepts in Android development. If you want to add more complex features to +your application, you can examine the code in an alternative implementation +of a notepad application, in the +Sample Code documentation.

    + + + +

    Who Should Use this Tutorial

    + +

    This tutorial is designed for experienced developers, especially those with +knowledge of the Java programming language. If you haven't written Java +applications before, you can still use the tutorial, but you might need to work +at a slower pace.

    + +

    The tutorial assumes that you have some familiarity with the basic Android +application concepts and terminology. If you aren't yet familiar with those, you +should read Overview of an Android +Application before continuing.

    + +

    Also note that this tutorial uses +the Eclipse development environment, with the Android plugin installed. If you +are not using Eclipse, you can follow the exercises and build the application, +but you will need to determine how to accomplish the Eclipse-specific +steps in your environment.

    + + +

    Preparing for the Exercises

    + +

    This tutorial builds on the information provided in the Installing the SDK and Hello Android +documents, which explain in detail how to set up your development environment +for building Android applications. Before you start this tutorial, you should +read both these documents, have the SDK installed, and your work environment set up.

    + +

    To prepare for this lesson:

    + +
      +
    1. Download the project + exercises archive (.zip)
    2. +
    3. Unpack the archive file to a suitable location on your machine
    4. +
    5. Open the NotepadCodeLab folder
    6. +
    + +

    Inside the NotepadCodeLab folder, you should see six project +files: Notepadv1, + Notepadv2, Notepadv3, + Notepadv1Solution, Notepadv2Solution + and Notepadv3Solution. The Notepadv# projects are +the starting points for each of the exercises, while the +Notepadv#Solution projects are the exercise + solutions. If you are having trouble with a particular exercise, you + can compare your current work against the exercise solution.

    + + +

    Exercises

    + +

    The table below lists the tutorial exercises and describes the development +areas that each covers. Each exercise assumes that you have completed any +previous exercises.

    + + + + + + + + + + + + + + + + + + +
    Exercise +1Start here. Construct a simple notes list that lets the user add new notes but not +edit them. Demonstrates the basics of ListActivity and creating +and handling + menu options. Uses a SQLite database to store the notes.
    Exercise 2Add a second Activity to the +application. Demonstrates constructing a +new Activity, adding it to the Android manifest, passing data between the +activities, and using more advanced screen layout. Also shows how to +invoke another Activity to return a result, using +startActivityForResult().
    Exercise 3Add handling of life-cycle events to +the application, to let it +maintain application state across the life cycle.
    Extra +CreditDemonstrates how to use the Eclipse +debugger and how you can use it to +view life-cycle events as they are generated. This section is optional but +highly recommended.
    + + + +

    Other Resources and Further Learning

    + diff --git a/docs/html/resources/tutorials/views/hello-autocomplete.jd b/docs/html/resources/tutorials/views/hello-autocomplete.jd new file mode 100644 index 0000000..fba1ad8 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-autocomplete.jd @@ -0,0 +1,116 @@ +page.title=Hello, AutoCompleteTextView +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    {@link android.widget.AutoCompleteTextView} is an implementation of the EditText widget that will provide +auto-complete suggestions as the user types. The suggestions are extracted from a collection of strings.

    + + +
      +
    1. Start a new project/Activity called HelloAutoComplete.
    2. +
    3. Open the layout file. + Make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      +    android:orientation="horizontal"
      +    android:layout_width="fill_parent" 
      +    android:layout_height="wrap_content">
      +
      +    <TextView
      +        android:layout_width="wrap_content"
      +        android:layout_height="wrap_content"
      +        android:text="Country" />
      +
      +    <AutoCompleteTextView android:id="@+id/edit"
      +        android:layout_width="fill_parent"
      +        android:layout_height="wrap_content"/>
      +
      +</LinearLayout>
      +
      +
    4. + +
    5. Open HelloAutoComplete.java and insert the following as the onCreate method: +
      +@Override
      +protected void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +
      +    AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
      +    ArrayAdapter adapter = new ArrayAdapter(this,
      +            android.R.layout.simple_dropdown_item_1line, COUNTRIES);
      +    textView.setAdapter(adapter);
      +}
      +
      +

      Here, we create an AutoComplteteTextView from our layout. We then + create an {@link android.widget.ArrayAdapter} that binds a simple_dropdown_item_1line + layout item to each entry in the COUNTRIES array (which we'll add next). + The last part sets the ArrayAdapter to associate with our AutoCompleteTextView.

      +
    6. + +
    7. After the onCreate() method, add the String array: +
      +static final String[] COUNTRIES = new String[] {
      +  "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
      +  "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
      +  "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
      +  "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
      +  "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
      +  "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
      +  "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
      +  "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
      +  "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
      +  "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
      +  "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
      +  "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
      +  "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
      +  "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
      +  "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
      +  "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
      +  "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
      +  "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
      +  "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
      +  "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
      +  "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
      +  "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
      +  "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
      +  "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
      +  "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
      +  "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
      +  "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
      +  "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
      +  "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
      +  "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
      +  "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
      +  "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
      +  "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
      +  "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
      +  "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
      +  "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
      +  "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
      +  "Ukraine", "United Arab Emirates", "United Kingdom",
      +  "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
      +  "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
      +  "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
      +};
      +
      +

      This is the list of suggestions that will be offered as the user types into the + AutoCompleteTextView.

      +
    8. + +
    9. Now run it.
    10. +
    +

    As you type, you should see something like this:

    + + + +

    References

    + + + diff --git a/docs/html/resources/tutorials/views/hello-datepicker.jd b/docs/html/resources/tutorials/views/hello-datepicker.jd new file mode 100644 index 0000000..fcd43f3 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-datepicker.jd @@ -0,0 +1,151 @@ +page.title=Hello, DatePicker +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.DatePicker} is a widget that allows the user to select a month, day and year.

    + + +
      +
    1. Start a new project/Activity called HelloDatePicker.
    2. +
    3. Open the layout file and make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content"
      +    android:orientation="vertical">
      +
      +    <TextView android:id="@+id/dateDisplay"
      +            android:layout_width="wrap_content"
      +            android:layout_height="wrap_content"
      +            android:text=""/>
      +
      +    <Button android:id="@+id/pickDate"
      +            android:layout_width="wrap_content"
      +            android:layout_height="wrap_content"
      +            android:text="Change the date"/>
      +
      +</LinearLayout>
      +
      +

      For the layout, we're using a vertical LinearLayout, with a {@link android.widget.TextView} that + will display the date and a {@link android.widget.Button} that will initiate the DatePicker dialog. + With this layout, the TextView will sit above the Button. + The text value in the TextView is set empty, as it will be filled + with the current date when our Activity runs.

      +
    4. + +
    5. Open HelloDatePicker.java. Insert the following to the HelloDatePicker class: +
      +    private TextView mDateDisplay;
      +    private Button mPickDate;
      +
      +    private int mYear;
      +    private int mMonth;
      +    private int mDay;
      +
      +    static final int DATE_DIALOG_ID = 0;
      +
      +    @Override
      +    protected void onCreate(Bundle savedInstanceState) {
      +        super.onCreate(savedInstanceState);
      +        setContentView(R.layout.main);
      +
      +        // capture our View elements
      +        mDateDisplay = (TextView) findViewById(R.id.dateDisplay);
      +        mPickDate = (Button) findViewById(R.id.pickDate);
      +
      +        // add a click listener to the button
      +        mPickDate.setOnClickListener(new View.OnClickListener() {
      +            public void onClick(View v) {
      +                showDialog(DATE_DIALOG_ID);
      +            }
      +        });
      +
      +        // get the current date
      +        final Calendar c = Calendar.getInstance();
      +        mYear = c.get(Calendar.YEAR);
      +        mMonth = c.get(Calendar.MONTH);
      +        mDay = c.get(Calendar.DAY_OF_MONTH);
      +
      +        // display the current date
      +        updateDisplay();
      +    }
      +
      +

      Tip: Press Ctrl(or Cmd) + Shift + O to import all needed packages.

      +

      We start by instantiating variables for our Views and date fields. + The DATE_DIALOG_ID is a static integer that uniquely identifies the Dialog. In the + onCreate() method, we get prepared by setting the layout and capturing the View elements. + Then we create an on-click listener for the Button, so that when it is clicked it will + show our DatePicker dialog. The showDialog() method will pop-up the date picker dialog + by calling the onCreateDialog() callback method + (which we'll define in the next section). We then create an + instance of {@link java.util.Calendar} and get the current year, month and day. Finally, we call + updateDisplay()—our own method (defined later) that will fill the TextView.

      +
    6. + +
    7. After the onCreate() method, add the onCreateDialog() callback method +(which is called by showDialog()) +
      +@Override
      +protected Dialog onCreateDialog(int id) {
      +    switch (id) {
      +    case DATE_DIALOG_ID:
      +        return new DatePickerDialog(this,
      +                    mDateSetListener,
      +                    mYear, mMonth, mDay);
      +    }
      +    return null;
      +}
      +
      +

      This method is passed the identifier we gave showDialog() and initializes + the DatePicker to the date we retrieved from our Calendar instance.

      +
    8. + +
    9. Following that, add the updateDisplay() method: +
      +    // updates the date we display in the TextView
      +    private void updateDisplay() {
      +        mDateDisplay.setText(
      +            new StringBuilder()
      +                    // Month is 0 based so add 1
      +                    .append(mMonth + 1).append("-")
      +                    .append(mDay).append("-")
      +                    .append(mYear).append(" "));
      +    }
      +
      +

      This uses the member date values to write the date to our TextView.

      +
    10. +
    11. Finally, add a listener that will be called when the user sets a new date: +
      +    // the callback received when the user "sets" the date in the dialog
      +    private DatePickerDialog.OnDateSetListener mDateSetListener =
      +            new DatePickerDialog.OnDateSetListener() {
      +
      +                public void onDateSet(DatePicker view, int year, 
      +                                      int monthOfYear, int dayOfMonth) {
      +                    mYear = year;
      +                    mMonth = monthOfYear;
      +                    mDay = dayOfMonth;
      +                    updateDisplay();
      +                }
      +            };
      +
      +

      This OnDateSetListener method listens for when the user is done setting the date + (clicks the "Set" button). At that time, this fires and we update our member fields with + the new date defined by the user and update our TextView by calling updateDisplay().

      +
    12. + +
    13. Now run it.
    14. +
    +

    When you press the "Change the date" button, you should see the following:

    + + +

    References

    + + diff --git a/docs/html/resources/tutorials/views/hello-formstuff.jd b/docs/html/resources/tutorials/views/hello-formstuff.jd new file mode 100644 index 0000000..da4289c --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-formstuff.jd @@ -0,0 +1,262 @@ +page.title=Hello, Form Stuff +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    This page introduces a variety of widgets, like image buttons, +text fields, checkboxes and radio buttons.

    + + +
      +
    1. Start a new project/Activity called HelloFormStuff.
    2. +
    3. Your layout file should have a basic LinearLayout: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:orientation="vertical"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent" >
      +    	
      +</LinearLayout>
      +
      +

      For each widget you want to add, just put the respective View inside here.

      +
    4. +
    +

    Tip: As you add new Android code, press Ctrl(or Cmd) + Shift + O +to import all needed packages.

    + + +

    ImageButton

    +

    A button with a custom image on it. +We'll make it display a message when pressed.

    +
      +
    1. + Drag the Android image on the right (or your own image) into the + res/drawable/ directory of your project. + We'll use this for the button.
    2. +
    3. Open the layout file and, inside the LinearLayout, add the {@link android.widget.ImageButton} element: +
      +<ImageButton
      +    android:id="@+id/android_button"
      +    android:layout_width="100dip"
      +    android:layout_height="wrap_content"
      +    android:src="@drawable/android" />	
      +
      +

      The source of the button + is from the res/drawable/ directory, where we've placed the android.png.

      +

      Tip: You can also reference some of the many built-in + images from the Android {@link android.R.drawable} resources, + like ic_media_play, for a "play" button image. To do so, change the source + attribute to android:src="@android:drawable/ic_media_play".

      +
    4. +
    5. To make the button to actually do something, add the following +code at the end of the onCreate() method: +
      +final ImageButton button = (ImageButton) findViewById(R.id.android_button);
      +button.setOnClickListener(new OnClickListener() {
      +    public void onClick(View v) {
      +        // Perform action on clicks
      +        Toast.makeText(HelloFormStuff.this, "Beep Bop", Toast.LENGTH_SHORT).show();
      +    }
      +});
      +
      +

      This captures our ImageButton from the layout, then adds an on-click listener to it. +The {@link android.view.View.OnClickListener} must define the onClick() method, which +defines the action to be made when the button is clicked. Here, we show a +{@link android.widget.Toast} message when clicked.

      +
    6. +
    7. Run it.
    8. +
    + + +

    EditText

    +

    A text field for user input. We'll make it display the text entered so far when the "Enter" key is pressed.

    + +
      +
    1. Open the layout file and, inside the LinearLayout, add the {@link android.widget.EditText} element: +
      +<EditText
      +    android:id="@+id/edittext"
      +    android:layout_width="fill_parent"
      +    android:layout_height="wrap_content"/>
      +
      +
    2. +
    3. To do something with the text that the user enters, add the following code +to the end of the onCreate() method: +
      +final EditText edittext = (EditText) findViewById(R.id.edittext);
      +edittext.setOnKeyListener(new OnKeyListener() {
      +    public boolean onKey(View v, int keyCode, KeyEvent event) {
      +        if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
      +          // Perform action on key press
      +          Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show();
      +          return true;
      +        }
      +        return false;
      +    }
      +});
      +
      +

      This captures our EditText element from the layout, then adds an on-key listener to it. +The {@link android.view.View.OnKeyListener} must define the onKey() method, which +defines the action to be made when a key is pressed. In this case, we want to listen for the +Enter key (when pressed down), then pop up a {@link android.widget.Toast} message with the +text from the EditText field. Be sure to return true after the event is handled, +so that the event doesn't bubble-up and get handled by the View (which would result in a +carriage return in the text field).

      +
    4. Run it.
    5. +
    + + +

    CheckBox

    +

    A checkbox for selecting items. We'll make it display the the current state when pressed.

    + +
      +
    1. Open the layout file and, inside the LinearLayout, add the {@link android.widget.CheckBox} element: +
      +<CheckBox android:id="@+id/checkbox"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content"
      +    android:text="check it out" />
      +
      +
    2. +
    3. To do something when the state is changed, add the following code +to the end of the onCreate() method: +
      +final CheckBox checkbox = (CheckBox) findViewById(R.id.checkbox);
      +checkbox.setOnClickListener(new OnClickListener() {
      +    public void onClick(View v) {
      +        // Perform action on clicks
      +        if (checkbox.isChecked()) {
      +            Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show();
      +        } else {
      +            Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show();
      +        }
      +    }
      +});
      +
      +

      This captures our CheckBox element from the layout, then adds an on-click listener to it. +The {@link android.view.View.OnClickListener} must define the onClick() method, which +defines the action to be made when the checkbox is clicked. Here, we query the current state of the +checkbox, then pop up a {@link android.widget.Toast} message that displays the current state. +Notice that the CheckBox handles its own state change between checked and un-checked, so we just +ask which it currently is.

      +
    4. Run it.
    5. +
    +

    Tip: If you find that you need to change the state +in another way (such as when loading a saved {@link android.preference.CheckBoxPreference}), +use setChecked(true) or toggle().

    + + +

    RadioButton

    +

    Two mutually-exclusive radio buttons—enabling one disables the other. +When each is pressed, we'll pop up a message.

    + +
      +
    1. Open the layout file and, inside the LinearLayout, add two {@link android.widget.RadioButton}s, +inside a {@link android.widget.RadioGroup}: +
      +<RadioGroup
      +  android:layout_width="fill_parent"
      +  android:layout_height="wrap_content"
      +  android:orientation="vertical">
      +  
      +  <RadioButton android:id="@+id/radio_red"
      +      android:layout_width="wrap_content"
      +      android:layout_height="wrap_content"
      +      android:text="Red" />
      +  
      +  <RadioButton android:id="@+id/radio_blue"
      +      android:layout_width="wrap_content"
      +      android:layout_height="wrap_content"
      +      android:text="Blue" />
      +  
      +</RadioGroup>
      +
      +
    2. +
    3. To do something when each is selected, we'll need an OnClickListener. Unlike the other +listeners we've created, instead of creating this one as an anonymous inner class, +we'll create it as a new object. This way, we can re-use the OnClickLIstener for +both RadioButtons. So, add the following code in the HelloFormStuff Activity +(outside the onCreate() method): +
      +OnClickListener radio_listener = new OnClickListener() {
      +    public void onClick(View v) {
      +        // Perform action on clicks
      +        RadioButton rb = (RadioButton) v;
      +        Toast.makeText(HelloFormStuff.this, rb.getText(), Toast.LENGTH_SHORT).show();
      +    }
      +};
      +
      +

      Our onClick() method will be handed the View clicked, so the first thing to do +is cast it into a RadioButton. Then we pop up a +{@link android.widget.Toast} message that displays the selection.

      +
    4. Now, at the bottom of the onCreate() method, add the following: +
      +  final RadioButton radio_red = (RadioButton) findViewById(R.id.radio_red);
      +  final RadioButton radio_blue = (RadioButton) findViewById(R.id.radio_blue);
      +  radio_red.setOnClickListener(radio_listener);
      +  radio_blue.setOnClickListener(radio_listener);
      +
      +

      This captures each of the RadioButtons from our layout and adds the newly-created +OnClickListener to each.

      +
    5. Run it.
    6. +
    +

    Tip: If you find that you need to change the state of a +RadioButton in another way (such as when loading a saved {@link android.preference.CheckBoxPreference}), +use setChecked(true) or toggle().

    + + +

    ToggleButton

    +

    A button used specifically for toggling something on and off.

    + +
      +
    1. Open the layout file and, inside the LinearLayout, add the {@link android.widget.ToggleButton} element: +
      +<ToggleButton android:id="@+id/togglebutton"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content" />
      +
      +
    2. +
    3. To do something when the state is changed, add the following code +to the end of the onCreate() method: +
      +final ToggleButton togglebutton = (ToggleButton) findViewById(R.id.togglebutton);
      +togglebutton.setOnClickListener(new OnClickListener() {
      +    public void onClick(View v) {
      +        // Perform action on clicks
      +        if (togglebutton.isChecked()) {
      +            Toast.makeText(HelloFormStuff.this, "ON", Toast.LENGTH_SHORT).show();
      +        } else {
      +            Toast.makeText(HelloFormStuff.this, "OFF", Toast.LENGTH_SHORT).show();
      +        }
      +    }
      +});
      +
      +

      This captures our ToggleButton element from the layout, then adds an on-click listener to it. +The {@link android.view.View.OnClickListener} must define the onClick() method, which +defines the action to be made when the button is clicked. Here, we query the current state of the +ToggleButton, then pop up a {@link android.widget.Toast} message that displays the current state. +Notice that the ToggleButton handles its own state change between checked and un-checked, so we just +ask which it is.

      +
    4. Run it.
    5. +
    + +

    Tip: By default, the text on the button is "ON" and "OFF", but +you can change each of these with setTextOn(CharSequence) and +setTextOff(CharSequence). And, if you find that you need to change the state +in another way (such as when loading a saved {@link android.preference.CheckBoxPreference}), +use setChecked(true) or toggle().

    + + +

    If you've added all the form items above, your application should look something like this:

    + + +

    References

    + + diff --git a/docs/html/resources/tutorials/views/hello-gallery.jd b/docs/html/resources/tutorials/views/hello-gallery.jd new file mode 100644 index 0000000..084f912 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-gallery.jd @@ -0,0 +1,135 @@ +page.title=Hello, Gallery +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.Gallery} is a View commonly used to display items in a horizontally scrolling list +that locks the current selection at the center. When one is selected, we'll show a message.

    + + +
      +
    1. Start a new project/Activity called HelloGallery.
    2. +
    3. Add some images to your res/drawable/ directory.
    4. +
    5. Open the layout file and make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<Gallery xmlns:android="http://schemas.android.com/apk/res/android" 
      +    android:id="@+id/gallery"
      +    android:layout_width="fill_parent"
      +    android:layout_height="wrap_content"
      +/>
      +
      +
    6. + + +
    7. Open the HelloGallery.java file. Insert the following for the onCreate() method: +
      +@Override
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +
      +    Gallery g = (Gallery) findViewById(R.id.gallery);
      +    g.setAdapter(new ImageAdapter(this));
      +
      +    g.setOnItemClickListener(new OnItemClickListener() {
      +        public void onItemClick(AdapterView parent, View v, int position, long id) {
      +            Toast.makeText(HelloGallery.this, "" + position, Toast.LENGTH_SHORT).show();
      +        }
      +    });
      +}
      +
      +

      We start as usual: set the layout and capture the View we want (our Gallery). +We then set an Adapter, called ImageAdapter for the Gallery—this is a new class that +we'll create next. Then we create an item click listener for the Gallery. This is like a normal +on-click listener (which you might be familiar with for buttons), but it listens to each item +that we've added to the Gallery. The onItemClick() callback method +receives the AdapterView where the click occurred, the specific View that received the click, the +position of the View clicked (zero-based), and the row id of the item clicked (if applicable). All +that we care about is the position, so that we can pop up a {@link android.widget.Toast} message that +tells us the index position of the item clicked. We do this with Toast.makeText().show(). +

      +
    8. + +
    9. After the onCreate() method, add the ImageAdapter class: +
      +public class ImageAdapter extends BaseAdapter {
      +    int mGalleryItemBackground;
      +    private Context mContext;
      +
      +    private Integer[] mImageIds = {
      +            R.drawable.sample_1,
      +            R.drawable.sample_2,
      +            R.drawable.sample_3,
      +            R.drawable.sample_4,
      +            R.drawable.sample_5,
      +            R.drawable.sample_6,
      +            R.drawable.sample_7
      +    };
      +
      +    public ImageAdapter(Context c) {
      +        mContext = c;
      +        TypedArray a = obtainStyledAttributes(android.R.styleable.Theme);
      +        mGalleryItemBackground = a.getResourceId(
      +                android.R.styleable.Theme_galleryItemBackground, 0);
      +        a.recycle();
      +    }
      +
      +    public int getCount() {
      +        return mImageIds.length;
      +    }
      +
      +    public Object getItem(int position) {
      +        return position;
      +    }
      +
      +    public long getItemId(int position) {
      +        return position;
      +    }
      +
      +    public View getView(int position, View convertView, ViewGroup parent) {
      +        ImageView i = new ImageView(mContext);
      +
      +        i.setImageResource(mImageIds[position]);
      +        i.setLayoutParams(new Gallery.LayoutParams(150, 100));
      +        i.setScaleType(ImageView.ScaleType.FIT_XY);
      +        i.setBackgroundResource(mGalleryItemBackground);
      +
      +        return i;
      +    }
      +}
      +
      +

      First, there are a few member variables, including an array of IDs that reference +the images we placed in our drawable resources directory.

      +

      Next is the constructor, where we define the member Context. The rest of the constructor +sets up a reference for our Gallery them, which adds the nice framing for each Gallery item. +Once we have our mGalleryItemBackground, it's important to recycle the +StyledAttribute for later re-use.

      +

      The next three methods are required for basic member queries. +But then we have the getView() method, which is called +for each item read by our ImageAdapter, when the Gallery is being built. Here, we +use our member Context to create a new {@link android.widget.ImageView}. We then define +the image resource with the current position of the Gallery items (corresponding to our +array of drawables), set the dimensions for the ImageView, +set the image scaling to fit the ImageView dimensions, then finally set the +background theme for the ImageView.

      + +

      See {@link android.widget.ImageView.ScaleType} +for other image scaling options, in case you want to avoid stretching images that don't +exactly match the ImageView dimensions.

      + +
    10. Now run it.
    11. +
    +

    You should see something like this:

    + + + +

    References

    + + + diff --git a/docs/html/resources/tutorials/views/hello-gridview.jd b/docs/html/resources/tutorials/views/hello-gridview.jd new file mode 100644 index 0000000..ffb6c93 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-gridview.jd @@ -0,0 +1,129 @@ +page.title=Hello, GridView +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.GridView} displays items in a two-dimensional, scrolling grid. The items +are acquired from a {@link android.widget.ListAdapter}.

    + + +
      +
    1. Start a new project/Activity called HelloGridView.
    2. +
    3. Find some photos you'd like to use, or copy some from the SDK samples res/drawable/ + folder of your project.
    4. +
    5. Open the layout and make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
      +    android:id="@+id/gridview"
      +    android:layout_width="fill_parent" 
      +    android:layout_height="fill_parent"
      +    android:numColumns="auto_fit"
      +    android:verticalSpacing="10dp"
      +    android:horizontalSpacing="10dp"
      +    android:columnWidth="90dp"
      +    android:stretchMode="columnWidth"
      +    android:gravity="center"
      +/>
      +
      +
    6. +
    7. Open the HelloGridView Java file. Insert the following for the onCreate() method: +
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +
      +    GridView gridview = (GridView) findViewById(R.id.gridview);
      +    gridview.setAdapter(new ImageAdapter(this));
      +}
      +
      +

      Here, we get a handle on our GridView, from the layout, and give it an Adapter. + We're actually going to create our own Adapter called ImageAdapter.

      +
    8. +
    9. Create a new class (nested or otherwise), called ImageAdapter, which extends {@link android.widget.BaseAdapter}: +
      +public class ImageAdapter extends BaseAdapter {
      +    private Context mContext;
      +
      +    public ImageAdapter(Context c) {
      +        mContext = c;
      +    }
      +
      +    public int getCount() {
      +        return mThumbIds.length;
      +    }
      +
      +    public Object getItem(int position) {
      +        return null;
      +    }
      +
      +    public long getItemId(int position) {
      +        return 0;
      +    }
      +
      +    // create a new ImageView for each item referenced by the Adapter
      +    public View getView(int position, View convertView, ViewGroup parent) {
      +        ImageView imageView;
      +        if (convertView == null) {  // if it's not recycled, initialize some attributes
      +            imageView = new ImageView(mContext);
      +            imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
      +            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
      +            imageView.setPadding(8, 8, 8, 8);
      +        } else {
      +            imageView = (ImageView) convertView;
      +        }
      +
      +        imageView.setImageResource(mThumbIds[position]);
      +        return imageView;
      +    }
      +
      +    // references to our images
      +    private Integer[] mThumbIds = {
      +            R.drawable.sample_2, R.drawable.sample_3,
      +            R.drawable.sample_4, R.drawable.sample_5,
      +            R.drawable.sample_6, R.drawable.sample_7,
      +            R.drawable.sample_0, R.drawable.sample_1,
      +            R.drawable.sample_2, R.drawable.sample_3,
      +            R.drawable.sample_4, R.drawable.sample_5,
      +            R.drawable.sample_6, R.drawable.sample_7,
      +            R.drawable.sample_0, R.drawable.sample_1,
      +            R.drawable.sample_2, R.drawable.sample_3,
      +            R.drawable.sample_4, R.drawable.sample_5,
      +            R.drawable.sample_6, R.drawable.sample_7
      +    };
      +}
      +
      +

      First we take care of some required methods inherited from BaseAdapter. + The constructor and getCount() are self-explanitory. Normally, getItem() + should return the actual object at the specified position in our Adapter, but for this Hello World, + we're not going to bother. Likewise, getItemId() should return the row id of + the item, but right now we don't care.

      +

      However, getView() is the method we care about. This one creates a new View for each image that we + put in our ImageAdapter. So we're going to create an ImageView each time. When this is called, we're + going to receive a View, which is likely a recycled View object (at least after the first call), so we + check for this—if it's null, we initialize the ImageView and setup all the properties we want. + The LayoutParams() initialization sets the height and width of the View—this ensures + that no matter the drawable size, each image is resized and cropped to fit in the ImageView (if necessary). + With setScaleType(), we say that images should be cropped toward the center (if necessary). + And finally, we set the padding within the ImageView. (Note that, if the images have various aspect-ratios, + as they do in this demo, then less padding will cause for more cropping of the image, if it does not match + the dimensions given to the ImageView.) At the end of getView() we set the image resource and + return the ImageView.

      +

      All that's left is our array or drawable resources at the bottom.

      +
    10. +
    11. Run it.
    12. +
    +

    Your grid layout should look something like this:

    + + +

    Try experimenting with the behaviors of the GridView and ImageView by adjusting their properties. For example, + instead of setting the ImageView LayoutParams, you can try using + {@link android.widget.ImageView#setAdjustViewBounds(boolean)}.

    + +

    References

    + + diff --git a/docs/html/resources/tutorials/views/hello-linearlayout.jd b/docs/html/resources/tutorials/views/hello-linearlayout.jd new file mode 100644 index 0000000..0e8947c --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-linearlayout.jd @@ -0,0 +1,130 @@ +page.title=Hello, LinearLayout +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.LinearLayout} is a GroupView that will lay child View elements +vertically or horizontally.

    + + +
      +
    1. Start a new project/Activity called HelloLinearLayout.
    2. +
    3. Open the layout file. + Make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:orientation="vertical"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent">
      +
      +    <LinearLayout
      +	android:orientation="horizontal"
      +	android:layout_width="fill_parent"
      +	android:layout_height="fill_parent"
      +	android:layout_weight="1">
      +	
      +	<TextView
      +	    android:text="red"
      +	    android:gravity="center_horizontal"
      +	    android:background="#aa0000"
      +	    android:layout_width="wrap_content"
      +	    android:layout_height="fill_parent"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="green"
      +	    android:gravity="center_horizontal"
      +	    android:background="#00aa00"
      +	    android:layout_width="wrap_content"
      +	    android:layout_height="fill_parent"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="blue"
      +	    android:gravity="center_horizontal"
      +	    android:background="#0000aa"
      +	    android:layout_width="wrap_content"
      +	    android:layout_height="fill_parent"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="yellow"
      +	    android:gravity="center_horizontal"
      +	    android:background="#aaaa00"
      +	    android:layout_width="wrap_content"
      +	    android:layout_height="fill_parent"
      +	    android:layout_weight="1"/>
      +		
      +    </LinearLayout>
      +	
      +    <LinearLayout
      +	android:orientation="vertical"
      +	android:layout_width="fill_parent"
      +	android:layout_height="fill_parent"
      +	android:layout_weight="1">
      +	
      +	<TextView
      +	    android:text="row one"
      +	    android:textSize="15pt"
      +	    android:layout_width="fill_parent"
      +	    android:layout_height="wrap_content"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="row two"
      +	    android:textSize="15pt"
      +	    android:layout_width="fill_parent"
      +	    android:layout_height="wrap_content"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="row three"
      +	    android:textSize="15pt"
      +	    android:layout_width="fill_parent"
      +	    android:layout_height="wrap_content"
      +	    android:layout_weight="1"/>
      +	
      +	<TextView
      +	    android:text="row four"
      +	    android:textSize="15pt"
      +	    android:layout_width="fill_parent"
      +	    android:layout_height="wrap_content"
      +	    android:layout_weight="1"/>
      +        
      +    </LinearLayout>
      +        
      +</LinearLayout>
      +
      +

      Carefully inspect the XML. You'll notice how this layout works a lot like + an HTML layout. There is one parent LinearLayout that is defined to lay + its child elements vertically. The first child is another LinearLayout that uses a horizontal layout + and the second uses a vertical layout. Each LinearLayout contains several {@link android.widget.TextView} + elements.

      +
    4. +
    5. Now open the HelloLinearLayout Activity and be sure it loads this layout in the onCreate() method:

      +
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +}
      +
      +

      R.layout.main refers to the main.xml layout file.

      +
    6. +
    7. Run it.
    8. +
    +

    You should see the following:

    + + +

    Notice how the various XML attributes define the View's behavior. +Pay attention to the effect of the layout_weight. Try + experimenting with different values to see how the screen real estate is + distributed based on the weight of each element.

    + +

    References

    + + + diff --git a/docs/html/resources/tutorials/views/hello-listview.jd b/docs/html/resources/tutorials/views/hello-listview.jd new file mode 100644 index 0000000..d90005b --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-listview.jd @@ -0,0 +1,90 @@ +page.title=Hello, ListView +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.ListView} is a View that shows items in a vertically scrolling list. The items are + acquired from a {@link android.widget.ListAdapter}.

    + + +
      +
    1. Start a new project/ListActivity called HelloListView.
    2. +
    3. Open the HelloListView Java file. Make the class extend ListActivity (instead of Activity). +
      public class HelloListView extends ListActivity {
      +
    4. +
    5. Insert the following for the onCreate() method: +
      +@Override
      +public void onCreate(Bundle savedInstanceState) {
      +  super.onCreate(savedInstanceState);
      +  
      +  setListAdapter(new ArrayAdapter<String>(this,
      +          android.R.layout.simple_list_item_1, COUNTRIES));
      +  getListView().setTextFilterEnabled(true);
      +}
      +
      +

      Notice that we don't need to load a layout (at least, not in this case, because we're using + the whole screen for our list). Instead, we just call setListAdapter() (which automatically + adds a ListView to the ListActivity), and provide it with an ArrayAdapter that binds a + simple_list_item_1 layout item to each entry in the COUNTRIES + array (added next). The next line of code adds a text filter to the ListView, so that when the user + begins typing, the list will filter the entire view to display only the items that match the entry.

      +
    6. +
    7. Following the onCreate() method, add the String array: +
      +  static final String[] COUNTRIES = new String[] {
      +    "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
      +    "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
      +    "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
      +    "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
      +    "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
      +    "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
      +    "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
      +    "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
      +    "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
      +    "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
      +    "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
      +    "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
      +    "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
      +    "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
      +    "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
      +    "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
      +    "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
      +    "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
      +    "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
      +    "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
      +    "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
      +    "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
      +    "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
      +    "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
      +    "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
      +    "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
      +    "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
      +    "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
      +    "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
      +    "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
      +    "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
      +    "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
      +    "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
      +    "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
      +    "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
      +    "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
      +    "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
      +    "Ukraine", "United Arab Emirates", "United Kingdom",
      +    "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
      +    "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
      +    "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
      +  };
      +
      +
    8. +
    9. Run it.
    10. +
    +

    You can scroll the list, or type to filter it. You should see something like this:

    + + +

    References

    + + diff --git a/docs/html/resources/tutorials/views/hello-mapview.jd b/docs/html/resources/tutorials/views/hello-mapview.jd new file mode 100644 index 0000000..531300f --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-mapview.jd @@ -0,0 +1,273 @@ +page.title=Hello, MapView +parent.title=Hello, Views +parent.link=index.html +@jd:body + +
    +

    This tutorial requires that you have the Google Maps external library +installed in your SDK environment. By default the Android SDK includes the +Google APIs add-on, which in turn includes the Maps external library. If you +don't have the Google APIs SDK add-on, you can download it from this +location:

    + +

    http://code.google.com/android/add-ons/google-apis

    + +

    The Google APIs add-on requires Android 1.5 SDK or later release. After +installing the add-on in your SDK, set your project properties to use the build +target called "Google APIs Add-on". See the instructions for setting a build +target in Developing in +Eclipse with ADT or Developing in Other IDEs, +as appropriate for your environment.

    + +

    You will also need to use the android tool to set up an AVD that uses the +Google APIs deployment target. See Android Virtual Devices for +more information. Once you have set up your environment, you will be able to +build and run the project described in this tutorial

    + +
    + +

    A MapView allows you to create your own map-viewing Activity. +First, we'll create a simple Activity that can view and navigate a map. Then we will add some overlay items.

    + +
      +
    1. Start a new project/Activity called HelloMapView. + +
    2. Because we're using the Google Maps library, + which is not a part of the standard Android library, we need to + declare it in the Android Manifest. Open the AndroidManifest.xml + file and add the following as a child of the <application> element: + +
      <uses-library android:name="com.google.android.maps" />
      +
    3. +
    4. We also need access to the internet in order to retrieve the Google Maps tiles, + so the application must request the {@link android.Manifest.permission#INTERNET INTERNET} permissions. + In the manifest file, add the following as a child of the <manifest> element: +
      <uses-permission android:name="android.permission.INTERNET" />
      +
    5. +
    6. Now open the main layout file for your project. Define a layout with a com.google.android.maps.MapView + inside a android.widget.RelativeLayout: + +
      +<?xml version="1.0" encoding="utf-8"?>
      +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:id="@+id/mainlayout"
      +    android:orientation="vertical"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent" >
      +
      +    <com.google.android.maps.MapView
      +        android:id="@+id/mapview"
      +        android:layout_width="fill_parent"
      +        android:layout_height="fill_parent"
      +        android:clickable="true"
      +        android:apiKey="Your Maps API Key"
      +    />
      +
      +</RelativeLayout>
      +
      +

      The clickable attribute defines whether you want to allow user-interaction with the map. + In this case, we set it "true" so that the user can navigate.

      + +

      The apiKey attribute holds the Google Maps API Key that proves your application and signer + certificate has been registered with the Google Maps service. Because MapView uses Google Maps data, this key is required + in order to receive the map data, even while you are developing. Registration is free and it only takes a couple + minutes to register your certificate and receive a Maps API Key. For instructions on getting a key, read + Obtaining a Maps API Key. + (For the purpose of this tutorial, you should register with the fingerprint of the SDK debug certificate.) + Once you've acquired the Maps API Key, insert it for the apiKey value.

    7. + +
    8. Now open the HelloMapView.java file. For this Activity, we're going to extend the special sub-class of + Activity called MapActivity, so change the class declaration to extend + MapActicity, instead of Activity:

      + +
      public class HelloMapView extends MapActivity {
      + +
    9. The isRouteDisplayed() method is required, so add it inside the class: +
      +@Override
      +protected boolean isRouteDisplayed() {
      +    return false;
      +}
      +
      +

      You can actually run this now, but all it does is allow you to pan around the map.

      +

      Android provides a handy {@link android.widget.ZoomControls} widget for zooming in and out of a View. +MapView can automatically hook one for us by requesting it with the getZoomControls() +method. Let's do this.

      + +
    10. Go back to the layout file. We need a new ViewGroup element, in which we'll + place the ZoomControls. Just below the MapView element (but inside the RelativeLayout), add this element: +
      +<LinearLayout
      +    android:id="@+id/zoomview"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content"
      +    android:layout_alignBottom="@id/mapview"
      +    android:layout_centerHorizontal="true"
      +/>
      + +

      It doesn't really matter what kind of ViewGroup we use, because we just want a + container that we can position within our root RelativeLayout.

      + +

      The last two attributes are available only to an element that's a child of a + RelativeLayout. layout_alignBottom aligns the bottom of this element to the bottom of + the element identified with a resource tag (which must be a sibling to this element). + layout_centerHorizontal centers this on the horizontal plane.

    11. + +
    12. Now go back to the HelloMapView class. We'll now retrieve the ZoomControls object from + the MapView and add it to our new layout element. First, at the top of the HelloMapView, + instantiate handles for the MapView and LinearLayout, plus a ZoomControl object: +
      +LinearLayout linearLayout;
      +MapView mapView;
      +ZoomControls mZoom;
    13. + +
    14. Then initialize each of these in onCreate(). We'll capture the LinearLayout and + MapView through their layout resources. Then get the ZoomControls from the MapView:: +
      +linearLayout = (LinearLayout) findViewById(R.id.zoomview);
      +mapView = (MapView) findViewById(R.id.mapview);
      +mZoom = (ZoomControls) mapView.getZoomControls();
      + +

      By using the ZoomControls object provided by MapView, we don't have to do any of the work + required to actually perform the zoom operations. The ZoomControls widget that MapView + returns for us is already hooked into the MapView and works as soon as we add it to the + layout. The controls will appear whenever the user touches the map, then dissapear after + a few moments of inactivity.

    15. + +
    16. Now just plug our ZoomControls into the LinearLayout we added: + +
      linearLayout.addView(mZoom);
    17. + +
    18. Run it.
    19. +
    + +
    + +

    So, we now have full interaction controls. All well and good, but what we really want our map +for is custom markers and layovers. Let's add some Overlay +objects to our map. To do this, we're going to +implement the ItemizedOverlay +class, which can manage a whole set of Overlay items for us.

    + +
      +
    1. Create a new Java class named HelloItemizedOverlay that implements ItemizedOverlay. + +

      When using Eclipse, right-click the package name in the Eclipse Package Explorer, and select New > Class. Fill-in + the Name field as HelloItemizedOverlay. For the Superclass, enter + com.google.android.maps.ItemizedOverlay. Click the checkbox for Constructors from + superclass. Click Finish.

    2. + +
    3. First thing, we need an OverlayItem ArrayList, in which we'll put each of the OverlayItem + objects we want on our map. Add this at the top of the HelloItemizedOverlay class: + +
      private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
    4. + +
    5. All the constructor does is define the default marker to be used on each of the OverlayItems. + In order for the Drawable to actually get drawn, it must have its bounds defined. And we want the + center-point at the bottom of the image to be the point at which it's attached to the map + coordinates. We handle all this with the boundCenterBottom() method. Wrap this around our + defaultMarker, so the super constructor call looks like this: + +
      super(boundCenterBottom(defaultMarker));
    6. + +
    7. In order to add new OverlayItems to our ArrayList, we need a new public method. We'll handle + this with the following method: + +
      +public void addOverlay(OverlayItem overlay) {
      +    mOverlays.add(overlay);
      +    populate();
      +}
      + +

      Each time we add a new OverlayItem, we must call populate(), which will read each of out + OverlayItems and prepare them to be drawn.

    8. + +
    9. In order for the populate() method to read each OverlayItem, it will make a request to + createItem(int). We must define this method to properly read from our ArrayList. Replace the + existing contents of the createItem method with a get() call to our ArrayList: + +
      +@Override
      +protected OverlayItem createItem(int i) {
      +  return mOverlays.get(i);
      +}
      +
    10. + +
    11. We're also required to override the size() method. Replace the existing contents of the + method with a size request to our ArrayList: + +
      return mOverlays.size();
    12. +
    + + +

    That's it for the HelloItemizedOverlay class. We're now ready to use it.

    + +
    +

    Go back to the HelloMapView +class. We'll start by creating one OverlayItem, adding to an instance of our HelloItemizedOverlay, +and then adding this to the MapView.

    + + +

    First, we need the image that we'll use for our map overlay. Here, we'll use the Android on the +right as our marker. Drag this image (or your own) to the res/drawable/ directory of your project workspace.

    + +

    Now we're ready to work in the HelloMapView:

    + +
      +
    1. First we need some more types. Add the following at the top of the HelloMapView class: + +
      +List<Overlay> mapOverlays;
      +Drawable drawable;
      +HelloItemizedOverlay itemizedOverlay;
    2. + +
    3. Now pick up where we left off in the onCreate() method. Instantiate the + new fields: + +
      +mapOverlays = mapView.getOverlays();
      +drawable = this.getResources().getDrawable(R.drawable.androidmarker);
      +itemizedoverlay = new HelloItemizedOverlay(drawable);
      + +

      All overlay elements on a map are held by the MapView, so when we want to add some, we must + first retrieve the List with getOverlays() methods. We instantiate the Drawable, which will + be used as our map marker, by using our Context resources to get the Drawable we placed in + the res/drawable/ directory (androidmarker.png). Our HelloItemizedOverlay takes the Drawable in order to set the + default marker.

    4. + +
    5. Now let's make our first OverlayItem by creating a GeoPoint + that defines our map coordinates, then pass it to a new OverlayItem: + +
      +GeoPoint point = new GeoPoint(19240000,-99120000);
      +OverlayItem overlayitem = new OverlayItem(point, "", "");
      + +

      GeoPoint coordinates are based in microdegrees (degrees * 1e6). The OverlayItem takes this + GeoPoint and two strings. Here, we won't concern ourselves with the strings, which can display + text when we click our marker, because we haven't yet written the click handler for the OverlayItem.

    6. + +
    7. All that's left is for us to add this OverlayItem to our collection in the HelloItemizedOverlay, + and add this to the List of Overlay objects retrieved from the MapView: + +
      +itemizedoverlay.addOverlay(overlayitem);
      +mapOverlays.add(itemizedoverlay);
    8. + +
    9. Run it!
    10. +
    + +

    We've sent our droid to Mexico City. Hola, Mundo!

    +

    You should see the following:

    + + +

    Because we created our ItemizedOverlay class with an ArrayList, we can continue adding new +OverlayItems. Try adding another one. Before the addOverlay() method is called, add these lines:

    +
    +GeoPoint point2 = new GeoPoint(35410000, 139460000);
    +OverlayItem overlayitem2 = new OverlayItem(point2, "", "");
    +
    +

    Run it again... We've sent a new droid to Tokyo. Sekai, konichiwa!

    + diff --git a/docs/html/resources/tutorials/views/hello-relativelayout.jd b/docs/html/resources/tutorials/views/hello-relativelayout.jd new file mode 100644 index 0000000..1b91537 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-relativelayout.jd @@ -0,0 +1,75 @@ +page.title=Hello, RelativeLayout +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.RelativeLayout} is a ViewGroup that allows you to layout child elements +in positions relative to the parent or siblings elements.

    + +
      +
    1. Start a new project/Activity called HelloRelativeLayout.
    2. +
    3. Open the layout file. Make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent">
      +
      +    <TextView
      +        android:id="@+id/label"
      +        android:layout_width="fill_parent"
      +        android:layout_height="wrap_content"
      +        android:text="Type here:"/>
      +
      +    <EditText
      +        android:id="@+id/entry"
      +        android:layout_width="fill_parent"
      +        android:layout_height="wrap_content"
      +        android:background="@android:drawable/editbox_background"
      +        android:layout_below="@id/label"/>
      +
      +    <Button
      +        android:id="@+id/ok"
      +        android:layout_width="wrap_content"
      +        android:layout_height="wrap_content"
      +        android:layout_below="@id/entry"
      +        android:layout_alignParentRight="true"
      +        android:layout_marginLeft="10dip"
      +        android:text="OK" />
      +
      +    <Button
      +        android:layout_width="wrap_content"
      +        android:layout_height="wrap_content"
      +        android:layout_toLeftOf="@id/ok"
      +        android:layout_alignTop="@id/ok"
      +        android:text="Cancel" />
      +
      +</RelativeLayout>
      +
      +

      Pay attention to each of the additional layout_* attributes (besides the +usual width and height, which are required for all elements). When using relative layout, +we use attributes like layout_below and layout_toLeftOf to describe +how we'd like to position each View. Naturally, these are different relative positions, and the +value of the attribute is the id of the element we want the position relative to.

      +
    4. +
    5. Make sure your Activity loads this layout in the onCreate() method:

      +
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +}
      +
      +

      R.layout.main refers to the main.xml layout file.

      +
    6. +
    7. Run it.
    8. +
    +

    You should see the following:

    + + +

    Resources

    + diff --git a/docs/html/resources/tutorials/views/hello-spinner.jd b/docs/html/resources/tutorials/views/hello-spinner.jd new file mode 100644 index 0000000..3a04214 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-spinner.jd @@ -0,0 +1,106 @@ +page.title=Hello, Spinner +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.Spinner} is a widget that allows the user to select an item from a group. +It is similar to a dropdown list and will allow scrolling when the +list exceeds the available vertical space on the screen.

    + + +
      +
    1. Start a new project/Activity called HelloSpinner.
    2. +
    3. Open the layout file. + Make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:orientation="vertical"
      +    android:padding="10dip"
      +    android:layout_width="fill_parent"
      +    android:layout_height="wrap_content">
      +
      +    <TextView
      +        android:layout_width="fill_parent"
      +        android:layout_height="wrap_content"
      +        android:layout_marginTop="10dip"
      +        android:text="Please select a planet:"
      +    />
      +
      +    <Spinner 
      +        android:id="@+id/spinner"
      +        android:layout_width="fill_parent"
      +        android:layout_height="wrap_content"
      +        android:drawSelectorOnTop="true"
      +        android:prompt="@string/planet_prompt"
      +    />
      +
      +</LinearLayout>
      +
      +

      Notice that the Spinner's android:prompt is a string resource. In + this case, Android does not allow it to be a string, it must be a reference to a resource. + So...

      +
    4. + +
    5. Open the strings.xml file in res/values/ and add the following <string> +element inside the <resources> element: +
      +<string name="planet_prompt">Choose a planet</string>
      +
      +
    6. + +
    7. Create a new XML file in res/values/ called arrays.xml. Insert the following: +
      +<resources>
      +
      +    <string-array name="planets">
      +        <item>Mercury</item>
      +        <item>Venus</item>
      +        <item>Earth</item>
      +        <item>Mars</item>
      +        <item>Jupiter</item>
      +        <item>Saturn</item>
      +        <item>Uranus</item>
      +        <item>Neptune</item>
      +    </string-array>
      +    
      +</resources>
      +
      +

      This is the list of items (planets) that the user can select from in the Spinner widget.

      +
    8. + +
    9. Now open the HelloSpinner.java file. Insert the following code into the HelloSpinner class: +
      +@Override
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +
      +    Spinner s = (Spinner) findViewById(R.id.spinner);
      +    ArrayAdapter adapter = ArrayAdapter.createFromResource(
      +            this, R.array.planets, android.R.layout.simple_spinner_item);
      +    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      +    s.setAdapter(adapter);
      +}
      +
      +

      That's it. We start by creating a Spinner from our layout. We then create an {@link android.widget.ArrayAdapter} + that binds each element of our string array to a layout view—we pass createFromResource our Context, + the array of selectable items and the type of layout we'd like each one bound to. We then call + setDropDownViewResource() to define the type of layout in which to present the + entire collection. Finally, we set this Adapter to associate with our Spinner, + so the string items have a place to go.

      +
    10. + +
    11. Now run it.
    12. +
    +

    It should look like this:

    + + + +

    Resources

    + + diff --git a/docs/html/resources/tutorials/views/hello-tablelayout.jd b/docs/html/resources/tutorials/views/hello-tablelayout.jd new file mode 100644 index 0000000..83d6f5d --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-tablelayout.jd @@ -0,0 +1,118 @@ +page.title=Hello, TableLayout +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.TableLayout} is a ViewGroup that +will lay child View elements into rows and columns.

    + + +
      +
    1. Start a new project/Activity called HelloTableLayout.
    2. +
    3. Open the layout file. + Make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent"
      +    android:stretchColumns="1">
      +
      +    <TableRow>
      +        <TextView
      +            android:layout_column="1"
      +            android:text="Open..."
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Ctrl-O"
      +            android:gravity="right"
      +            android:padding="3dip" />
      +    </TableRow>
      +
      +    <TableRow>
      +        <TextView
      +            android:layout_column="1"
      +            android:text="Save..."
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Ctrl-S"
      +            android:gravity="right"
      +            android:padding="3dip" />
      +    </TableRow>
      +
      +    <TableRow>
      +        <TextView
      +            android:layout_column="1"
      +            android:text="Save As..."
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Ctrl-Shift-S"
      +            android:gravity="right"
      +            android:padding="3dip" />
      +    </TableRow>
      +
      +    <View
      +        android:layout_height="2dip"
      +        android:background="#FF909090" />
      +
      +    <TableRow>
      +        <TextView
      +            android:text="X"
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Import..."
      +            android:padding="3dip" />
      +    </TableRow>
      +
      +    <TableRow>
      +        <TextView
      +            android:text="X"
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Export..."
      +            android:padding="3dip" />
      +        <TextView
      +            android:text="Ctrl-E"
      +            android:gravity="right"
      +            android:padding="3dip" />
      +    </TableRow>
      +
      +    <View
      +        android:layout_height="2dip"
      +        android:background="#FF909090" />
      +
      +    <TableRow>
      +        <TextView
      +            android:layout_column="1"
      +            android:text="Quit"
      +            android:padding="3dip" />
      +    </TableRow>
      +</TableLayout>
      +
      +

      Notice how this resembles the structure of an HTML table. TableLayout is like the +table element; TableRow is like a tr element; but for our cells like +the html td element, we can use any kind of View. Here, we use TextView for the cells.

      + +
    4. +
    5. Make sure your Activity loads this layout in the onCreate() method: +
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +}
      +
      +

      R.layout.main refers to the main.xml layout file.

      +
    6. +
    7. Run it.
    8. +
    +

    You should see the following:

    + + +

    References

    + + + diff --git a/docs/html/resources/tutorials/views/hello-tabwidget.jd b/docs/html/resources/tutorials/views/hello-tabwidget.jd new file mode 100644 index 0000000..8424616 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-tabwidget.jd @@ -0,0 +1,124 @@ +page.title=Hello, TabWidget +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.TabWidget} offers the ability to easily draw an interface that uses +tabs to navigate between different views.

    + +
      +
    1. Start a new project/Activity called HelloTabWidget.
    2. +
    3. Open the layout file and make it like so:
    4. +
      +<?xml version="1.0" encoding="utf-8"?>
      +<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:id="@android:id/tabhost"
      +    android:layout_width="fill_parent"
      +    android:layout_height="fill_parent">
      +    <LinearLayout
      +        android:orientation="vertical"
      +        android:layout_width="fill_parent"
      +        android:layout_height="fill_parent">
      +        <TabWidget
      +            android:id="@android:id/tabs"
      +            android:layout_width="fill_parent"
      +            android:layout_height="wrap_content" />
      +        <FrameLayout
      +            android:id="@android:id/tabcontent"
      +            android:layout_width="fill_parent"
      +            android:layout_height="fill_parent">
      +            <TextView 
      +                android:id="@+id/textview1"
      +                android:layout_width="fill_parent"
      +                android:layout_height="fill_parent" 
      +                android:text="this is a tab" />
      +            <TextView 
      +                android:id="@+id/textview2"
      +                android:layout_width="fill_parent"
      +                android:layout_height="fill_parent" 
      +                android:text="this is another tab" />
      +            <TextView 
      +                android:id="@+id/textview3"
      +                android:layout_width="fill_parent"
      +                android:layout_height="fill_parent" 
      +                android:text="this is a third tab" />
      +    	</FrameLayout>
      +    </LinearLayout>
      +</TabHost>
      +
      +

      Here, we've created a {@link android.widget.TabHost} that contains the entire layout of the Activity. + A TabHost requires two descendant elements: a {@link android.widget.TabWidget} and a {@link android.widget.FrameLayout}. + In order to properly layout these elements, we've put them inside a vertical {@link android.widget.LinearLayout}. + The FrameLayout is where we keep the content that will change with each tab. Each child in the FrameLayout will + be associated with a different tab. + In this case, each tab simply shows a different {@link android.widget.TextView} with some text.

      +

      Notice that the TabWidget and the FrameLayout elements have specific android namespace IDs. These are necessary + so that the TabHost can automatically retireve references to them, populate the TabWidget with the tabs that we'll define + in our code, and swap the views in the FrameLayout. We've also defined our own IDs for each TextView, which we'll use to + associate each tab with the view that it should reveal.

      +

      Of course, you can + make these child views as large as complex as you'd like — instead of the TextView elements, + you could start with other layout views and build a unique layout hierarchy for each tab.

      + +
    5. Now we'll add our code. Open HelloTabWidget.java and make it a TabActivity. +

      By default, Eclipse creates a class that extends Activity. Change it to + extend TabActivity:

      +
      +public class HelloTabWidget extends TabActivity {
      +
      +
    6. +
    7. Now fill in the the onCreate method like this: +
      +public void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +
      +    mTabHost = getTabHost();
      +    
      +    mTabHost.addTab(mTabHost.newTabSpec("tab_test1").setIndicator("TAB 1").setContent(R.id.textview1));
      +    mTabHost.addTab(mTabHost.newTabSpec("tab_test2").setIndicator("TAB 2").setContent(R.id.textview2));
      +    mTabHost.addTab(mTabHost.newTabSpec("tab_test3").setIndicator("TAB 3").setContent(R.id.textview3));
      +    
      +    mTabHost.setCurrentTab(0);
      +}
      +
      +

      As usual, we start by setting our layout.

      +

      We then call the TabActivity method getTabHost(), + which returns us a reference to the TabHost we created in our layout. Upon our TabHost, we call addTab() + for each of the tabs that we want to add to the TabWidget. Each time we call this, we pass a + {@link android.widget.TabHost.TabSpec} that we build on the fly, and with it, chain together two necessary methods: + setIndicator() to set the text for the tab button, and setContent() to define + which View we want to associate with the tab and reveal when pressed. Our indicator is just a text string and + our content is an ID reference to the TextView elements we inserted in the FrameLayout.

      +

      At the end, we call setCurrentTab() to define which tab should be opened by default. The tabs + are saved like a zero-based array, so to open the first tab, we pass zero (0).

      +
    8. +
    9. To clean-up the presentation a bit more, let's remove the window title that appears at the top of the layout. + Android includes a theme that removes that title for us. To add it, open the Android Manifest file and add + the NoTitleBar theme to the <application> tag. It should end up like this: +
      +<application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
      +
      +
    10. +
    11. That's it. Run your application.
    12. + +
    + + +

    Your application should look like this:

    + + +

    You can include icons in your tabs by passing a +{@link android.graphics.drawable.Drawable} when you call setIndicator(). Here's an example +that uses a Drawable created from an image in the project resources:

    +
    setIndicator("TAB 1", getResources().getDrawable(R.drawable.tab_icon))
    +
    + +

    References

    + + diff --git a/docs/html/resources/tutorials/views/hello-timepicker.jd b/docs/html/resources/tutorials/views/hello-timepicker.jd new file mode 100644 index 0000000..1a6c8f9 --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-timepicker.jd @@ -0,0 +1,159 @@ +page.title=Hello, TimePicker +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.widget.TimePicker} is a widget that allows the +user to select the time by hour, minute and AM or PM.

    + + +
      +
    1. Start a new project/Activity called HelloTimePicker.
    2. +
    3. Open the layout file and make it like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content"
      +    android:orientation="vertical">
      +
      +    <TextView android:id="@+id/timeDisplay"
      +        android:layout_width="wrap_content"
      +        android:layout_height="wrap_content"
      +        android:text=""/>
      +
      +    <Button android:id="@+id/pickTime"
      +        android:layout_width="wrap_content"
      +        android:layout_height="wrap_content"
      +        android:text="Change the time"/>
      +
      +</LinearLayout>
      +
      +

      For the layout, we're using a vertical LinearLayout, with a {@link android.widget.TextView} that + will display the time and a {@link android.widget.Button} that will initiate the + {@link android.widget.TimePicker} dialog. + With this layout, the TextView will sit above the Button. + The text value in the TextView is set empty, as it will be filled by our Activity + with the current time.

      +
    4. + +
    5. Open HelloTimePicker.java. Insert the following to the HelloTimePicker class: +
      +private TextView mTimeDisplay;
      +private Button mPickTime;
      +
      +private int mHour;
      +private int mMinute;
      +
      +static final int TIME_DIALOG_ID = 0;
      +
      +@Override
      +protected void onCreate(Bundle savedInstanceState) {
      +    super.onCreate(savedInstanceState);
      +    setContentView(R.layout.main);
      +    
      +    // capture our View elements
      +    mTimeDisplay = (TextView) findViewById(R.id.timeDisplay);
      +    mPickTime = (Button) findViewById(R.id.pickTime);
      +
      +    // add a click listener to the button
      +    mPickTime.setOnClickListener(new View.OnClickListener() {
      +        public void onClick(View v) {
      +            showDialog(TIME_DIALOG_ID);
      +        }
      +    });
      +
      +    // get the current time
      +    final Calendar c = Calendar.getInstance();
      +    mHour = c.get(Calendar.HOUR_OF_DAY);
      +    mMinute = c.get(Calendar.MINUTE);
      +
      +    // display the current date
      +    updateDisplay();
      +}
      +
      +

      Tip: Press Ctrl(or Cmd) + Shift + O to import all needed packages.

      +

      We start by instantiating variables for our View elements and time fields. + The TIME_DIALOG_ID is a static integer that uniquely identifies the dialog. In the + onCreate() method, we get prepared by setting the layout and capturing the View elements. + We then set an on-click listener for the Button, so that when it is clicked, it will + show our TimePicker dialog. The showDialog() method will perform a callback + to our Activity. (We'll define this callback in the next section.) We then create an + instance of {@link java.util.Calendar} and get the current hour and minute. Finally, we call + updateDisplay()—our own method that will fill the TextView with the time.

      +
    6. + +
    7. After the onCreate() method, add the onCreateDialog() callback method: +
      +@Override
      +protected Dialog onCreateDialog(int id) {
      +    switch (id) {
      +    case TIME_DIALOG_ID:
      +        return new TimePickerDialog(this,
      +                mTimeSetListener, mHour, mMinute, false);
      +    }
      +    return null;
      +}
      +
      +

      This is passed the identifier we gave showDialog() and initializes + the TimePicker to the time we retrieved from our Calendar instance. It will be called by + showDialog().

      +
    8. + +
    9. Now add our updateDisplay() method: +
      +// updates the time we display in the TextView
      +private void updateDisplay() {
      +    mTimeDisplay.setText(
      +        new StringBuilder()
      +                .append(pad(mHour)).append(":")
      +                .append(pad(mMinute)));
      +}
      +
      +

      This simply takes our member fields for the time and inserts them in + the mTimeDisplay TextView. Note that we call a new method, pad(), + on the hour and minute. (We'll create this method in the last step.)

      +
    10. + +
    11. Next, add a listener to be called when the time is reset: +
      +// the callback received when the user "sets" the time in the dialog
      +private TimePickerDialog.OnTimeSetListener mTimeSetListener =
      +    new TimePickerDialog.OnTimeSetListener() {
      +        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
      +            mHour = hourOfDay;
      +            mMinute = minute;
      +            updateDisplay();
      +        }
      +    };
      +
      +

      Now when the user is done setting the time (clicks the "Set" button), we update our member fields with + the new time and update our TextView.

      +
    12. +
    13. Finally, add the pad() method that we called from the updateDisplay(): +
      +private static String pad(int c) {
      +    if (c >= 10)
      +        return String.valueOf(c);
      +    else
      +        return "0" + String.valueOf(c);
      +}
      +
      +

      This method returns the appropriate String representation of the hour or minute. + It will prefix a zero to the number if it's a single digit. +

      +
    14. + +
    15. Now run it.
    16. +
    +

    When you press the "Change the time" button, you should see the following:

    + + +

    References

    +
      +
    1. {@link android.widget.TimePicker}
    2. +
    3. {@link android.widget.Button}
    4. +
    5. {@link android.widget.TextView}
    6. +
    7. {@link java.util.Calendar}
    8. +
    + diff --git a/docs/html/resources/tutorials/views/hello-webview.jd b/docs/html/resources/tutorials/views/hello-webview.jd new file mode 100644 index 0000000..c4388ea --- /dev/null +++ b/docs/html/resources/tutorials/views/hello-webview.jd @@ -0,0 +1,118 @@ +page.title=Hello, WebView +parent.title=Hello, Views +parent.link=index.html +@jd:body + +

    A {@link android.webkit.WebView} allows you to create your own web browser Activity. In this tutorial, +we'll create a simple Activity that can view web pages.

    + +
      +
    1. Create a new project/Activity called HelloWebView.
    2. +
    3. Open the layout file. Insert a WebView so it looks like so: +
      +<?xml version="1.0" encoding="utf-8"?>
      +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      +    android:layout_width="wrap_content"
      +    android:layout_height="wrap_content"
      +    android:orientation="vertical">
      +
      +    <WebView 
      +        android:id="@+id/webview"
      +        android:layout_width="fill_parent"
      +        android:layout_height="fill_parent"
      +    />
      +
      +</LinearLayout>
      +
    4. + +
    5. Now open the HelloWebView.java file. + At the top of the class, instantiate a WebView object: +
      WebView webview;
      +

      Then add the following at the end of the onCreate() method:

      +
      +webview = (WebView) findViewById(R.id.webview);
      +webview.getSettings().setJavaScriptEnabled(true);
      +webview.loadUrl("http://www.google.com");
      +
      + +

      This captures the WebView we created in our layout, then requests a + {@link android.webkit.WebSettings} object and enables JavaScript. + Then we load a URL.

    6. + +
    7. Because we're accessing the internet, we need to add the appropriate + permissions to the Android manifest file. So open the AndroidManifest.xml file + and, add the following as a child of the <manifest> element: + +
      <uses-permission android:name="android.permission.INTERNET" />
    8. + +
    9. Now run it.
    10. +
    +

    You now have the world's simplest web page viewer. + It's not quite a browser yet. It only loads the page we've requested.

    + +
    + +

    We can load a page, but as soon as we click a link, the default Android web browser +handles the Intent, instead of our own WebView handling the action. So now we'll +override the {@link android.webkit.WebViewClient} to enable us to handle our own URL loading.

    + +
      +
    1. In the HelloAndroid Activity, add this nested private class: +
      +private class HelloWebViewClient extends WebViewClient {
      +    @Override
      +    public boolean shouldOverrideUrlLoading(WebView view, String url) {
      +        view.loadUrl(url);
      +        return true;
      +    }
      +}
    2. + +
    3. Now, in the onCreate() method, set an instance of the HelloWebViewClient + as our WebViewClient: +
      webview.setWebViewClient(new WebViewClientDemo());
      + +

      This line should immediately follow the initialization of our WebView object.

      +

      What we've done is create a WebViewClient that will load any URL selected in our +WebView in the same WebView. You can see this in the shouldOverrideUrlLoading() +method, above—it is passed the current WebView and the URL, so all we do +is load the URL in the given view. Returning true says that we've handled the URL +ourselves and the event should not bubble-up.

      +

      If you try it again, new pages will now load in the HelloWebView Activity. However, you'll notice that +we can't navigate back. We need to handle the back button +on the device, so that it will return to the previous page, rather than exit the application.

      +
    4. + +
    5. To handle the back button key press, add the following method inside the HelloWebView +Activity: +
       
      +@Override
      +public boolean onKeyDown(int keyCode, KeyEvent event) {
      +    if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {
      +        webview.goBack();
      +        return true;
      +    }
      +    return super.onKeyDown(keyCode, event);
      +}
      +

      The condition uses a {@link android.view.KeyEvent} to check + whether the key pressed is the BACK button and whether the + WebView is actually capable of navigating back (if it has a history). If both are + not true, then we send the event up the chain (and the Activity will close). + But if both are true, then we call goBack(), + which will navigate back one step in the history. We then return true to indicate + that we've handled the event.

      +
    6. +
    +

    When you open the application, it should look like this:

    + + +

    Resource

    + + + + + + diff --git a/docs/html/resources/tutorials/views/images/android.png b/docs/html/resources/tutorials/views/images/android.png new file mode 100755 index 0000000..39a1ac7 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/android.png differ diff --git a/docs/html/resources/tutorials/views/images/androidmarker.png b/docs/html/resources/tutorials/views/images/androidmarker.png new file mode 100755 index 0000000..8c43d46 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/androidmarker.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-autocomplete.png b/docs/html/resources/tutorials/views/images/hello-autocomplete.png new file mode 100755 index 0000000..e1fd80d Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-autocomplete.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-datepicker.png b/docs/html/resources/tutorials/views/images/hello-datepicker.png new file mode 100755 index 0000000..2075066 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-datepicker.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-formstuff.png b/docs/html/resources/tutorials/views/images/hello-formstuff.png new file mode 100755 index 0000000..3b4bf54 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-formstuff.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-gallery.png b/docs/html/resources/tutorials/views/images/hello-gallery.png new file mode 100755 index 0000000..22d1eaf Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-gallery.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-gridview.png b/docs/html/resources/tutorials/views/images/hello-gridview.png new file mode 100755 index 0000000..2def0df Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-gridview.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-linearlayout.png b/docs/html/resources/tutorials/views/images/hello-linearlayout.png new file mode 100755 index 0000000..dfef819 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-linearlayout.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-listview.png b/docs/html/resources/tutorials/views/images/hello-listview.png new file mode 100755 index 0000000..a1cf7aa Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-listview.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-mapview.png b/docs/html/resources/tutorials/views/images/hello-mapview.png new file mode 100755 index 0000000..0956760 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-mapview.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-relativelayout.png b/docs/html/resources/tutorials/views/images/hello-relativelayout.png new file mode 100755 index 0000000..ec4d9d4 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-relativelayout.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-spinner.png b/docs/html/resources/tutorials/views/images/hello-spinner.png new file mode 100755 index 0000000..42e2a91 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-spinner.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-tablelayout.png b/docs/html/resources/tutorials/views/images/hello-tablelayout.png new file mode 100755 index 0000000..3d80e7f Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-tablelayout.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-tabwidget.png b/docs/html/resources/tutorials/views/images/hello-tabwidget.png new file mode 100644 index 0000000..6a52356 Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-tabwidget.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-timepicker.png b/docs/html/resources/tutorials/views/images/hello-timepicker.png new file mode 100755 index 0000000..bd5a1ee Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-timepicker.png differ diff --git a/docs/html/resources/tutorials/views/images/hello-webview.png b/docs/html/resources/tutorials/views/images/hello-webview.png new file mode 100755 index 0000000..283ce7d Binary files /dev/null and b/docs/html/resources/tutorials/views/images/hello-webview.png differ diff --git a/docs/html/resources/tutorials/views/index.jd b/docs/html/resources/tutorials/views/index.jd new file mode 100644 index 0000000..2cb5d3a --- /dev/null +++ b/docs/html/resources/tutorials/views/index.jd @@ -0,0 +1,118 @@ +page.title=Hello, Views +@jd:body + + + +

    This collection of "Hello World"-style tutorials is designed +to get you quickly started with common Android Views and widgets. The aim is to let you copy and paste +these kinds of boring bits so you can focus on developing the code that makes your Android application rock. +Of course, we'll discuss some of the given code so that it all makes sense.

    + +

    Note that a certain amount of knowledge is assumed for these tutorials. If you haven't +completed the Hello, World tutorial, +please do so—it will teach you many things you should know about basic +Android development and Eclipse features. More specifically, you should know:

    + +

    Please, also notice that, in order to make these tutorials simple, some may +not convey the better Android coding practices. In particular, many of them +use hard-coded strings in the layout files—the better practice is to reference strings from +your strings.xml file.

    +

    With this knowledge, you're ready to begin, so take your pick.

    + +
    + + + + + + + + + +
    +Spinner
    + +
    + + +
    +ListView
    + +
    +
    +GridView
    + +
    + +
    +Gallery
    + +
    + +
    +TabWidget
    + +
    + +
    +MapView
    + +
    + +
    +WebView
    + +
    + + + +

    +There are plenty more Views and widgets available. See the {@link android.view.View} class +for more on View layouts, and the {@link android.widget widget package} +for more useful widgets. And for more raw code samples, visit the +Api Demos. +These can also be found offline, in /<sdk>/samples/ApiDemos.

    +
    + diff --git a/docs/html/sdk/1.1_r1/upgrading.jd b/docs/html/sdk/1.1_r1/upgrading.jd index 19095c0..5628d04 100644 --- a/docs/html/sdk/1.1_r1/upgrading.jd +++ b/docs/html/sdk/1.1_r1/upgrading.jd @@ -145,6 +145,6 @@ to seek help from other Android developers.

    to the new SDK, note that you will need to uninstall the version of ApiDemos that comes preinstalled in the emulator. For more information, or if you encounter an "reinstallation" error when running or installing ApiDemos, see the troubleshooting topic -I can't install ApiDemos +I can't install ApiDemos apps in my IDE because of a signing error for information about how to solve the problem.

    diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd index fdaba61..2c1d495 100644 --- a/docs/html/sdk/RELEASENOTES.jd +++ b/docs/html/sdk/RELEASENOTES.jd @@ -604,7 +604,7 @@ Device for Development.

    classes, you can do so. However, you need to set up a custom JUnit configuration before your tests will run properly. For detailed information about how to set up the JUnit configuration, see the troubleshooting topic Running a Junit test class +href="{@docRoot}resources/faq/troubleshooting.html#addjunit">Running a Junit test class in Eclipse. diff --git a/docs/html/sdk/android-2.0.1.jd b/docs/html/sdk/android-2.0.1.jd index fbce45e..43b1710 100644 --- a/docs/html/sdk/android-2.0.1.jd +++ b/docs/html/sdk/android-2.0.1.jd @@ -297,9 +297,8 @@ package name, rather than the process name.

    For a detailed view of API changes in Android {@sdkPlatformVersion} (API Level {@sdkPlatformApiLevel}), as compared to API Level 5, see the API -Differences Report. Note that this difference report compares only to -the most recent API Level, and there are few changes, so to see changes -introduces in Android 2.0 (API Level 5), see the . There are very few API changes in API Level 6, +so you might also be interested in reviewing the API -Differences between 4 and 5.

    +differences between 4 and 5.

    diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd index 7d9efdb..f861afd 100644 --- a/docs/html/sdk/eclipse-adt.jd +++ b/docs/html/sdk/eclipse-adt.jd @@ -53,6 +53,11 @@ Android — make sure that you have a suitable version of Eclipse installed on your computer (3.4 or newer is recommended). If you need to install Eclipse, you can download it from this location:

    +

    http://www.eclipse.org/downloads/ +

    + +

    A Java or RCP version of Eclipse is recommended.

    Installing the ADT Plugin

    @@ -196,7 +201,7 @@ Eclipse components (for example, WST). If you encounter an error when installing ADT, your Eclipse installion might not include these components. For information about how to quickly add the necessary components to your Eclipse installation, see the troubleshooting topic -ADT +ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

    For Linux users

    @@ -263,9 +268,10 @@ href="{@docRoot}sdk/adt-notes.html">ADT Plugin Notes document.

    If you encounter problems during the update of ADT, you can try removing the existing ADT plugin and then performing a fresh -installation. Fully remove your existing ADT Plugin as described in Uninstalling the ADT Plugin, below, and then follow the guide to Installing the ADT Plugin.

    +installation. To remove the plugin, follow the instructions in Uninstalling the ADT Plugin, below. To reinstall +the plugin, follow the instructions in Installing the ADT Plugin, above.

    Uninstalling the ADT plugin

    diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 6ca02b6..209a67b 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -84,6 +84,6 @@ Google Maps external library.

    project or move existing applications into the new SDK.

    If you are new to Android, you can use the Hello World tutorial to +href="{@docRoot}resources/tutorials/hello-world.html">Hello World tutorial to get started quickly. Next Steps offers other suggestions of how to begin. Welcome!

    diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd index 261b49f..698c347 100644 --- a/docs/html/sdk/installing.jd +++ b/docs/html/sdk/installing.jd @@ -186,7 +186,7 @@ multiversion documentation for the Android framework API.

    To develop any Android application, even if you are following the Hello World tutorial, you +href="{@docRoot}resources/tutorials/hello-world.html">Hello World tutorial, you must download at least one Android platform into your SDK. Typically, you will want to download multiple platforms, so that you can build your application on the lowest version you want to support, but test against @@ -342,9 +342,9 @@ begin developing applications. Here are a few ways you can get started:

    Explore some code