Resolve merge conflicts of a5060ee to nyc-dev
This undoes the automerger skip which occured in
commit e740c84dc32180214a7fd157105d6c18d30408ee and
replays it as a standard (NOT -s ours) merge.
Change-Id: If5a47be26f73d6a0735c425cd66310a3e2a89086
diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
new file mode 100644
index 0000000..cd4df43
--- /dev/null
+++ b/docs/html/training/_book.yaml
@@ -0,0 +1,1210 @@
+toc:
+- title: Getting Started
+ path: /training/index.html
+ section:
+ - title: Building Your First App
+ path: /training/basics/firstapp/index.html
+ custom_link_attributes:
+ - description="After you've installed the Android SDK, start with this class to learn the basics about Android app development."
+ section:
+ - title: Creating an Android Project
+ path: /training/basics/firstapp/creating-project.html
+ - title: Running Your Application
+ path: /training/basics/firstapp/running-app.html
+ - title: Building a Simple User Interface
+ path: /training/basics/firstapp/building-ui.html
+ - title: Starting Another Activity
+ path: /training/basics/firstapp/starting-activity.html
+ - title: Supporting Different Devices
+ path: /training/basics/supporting-devices/index.html
+ custom_link_attributes:
+ - description="How to build your app with alternative resources that provide an optimized user experience on multiple device form factors using a single APK."
+ section:
+ - title: Supporting Different Languages
+ path: /training/basics/supporting-devices/languages.html
+ - title: Supporting Different Screens
+ path: /training/basics/supporting-devices/screens.html
+ - title: Supporting Different Platform Versions
+ path: /training/basics/supporting-devices/platforms.html
+ - title: Managing the Activity Lifecycle
+ path: /training/basics/activity-lifecycle/index.html
+ custom_link_attributes:
+ - ja-lang="アクティビティのライフサイクル 管理"
+ - ko-lang="액티비티 수명 주기 관리하기"
+ - pt-br-lang="Como gerenciar o ciclo de vida da atividade"
+ - ru-lang="Управление жизненным циклом операций"
+ - zh-cn-lang="管理活动生命周期"
+ - zh-tw-lang="管理應用行為顯示生命週期"
+ - description="How Android activities live and die and how to create a seamless user experience by implementing lifecycle callback methods."
+ section:
+ - title: Starting an Activity
+ path: /training/basics/activity-lifecycle/starting.html
+ custom_link_attributes:
+ - ja-lang="アクティビティを開始する"
+ - ko-lang="액티비티 시작하기"
+ - pt-br-lang="Iniciando uma atividade"
+ - ru-lang="Запуск операции"
+ - zh-cn-lang="开始活动"
+ - zh-tw-lang="啟動應用行為顯示"
+ - title: Pausing and Resuming an Activity
+ path: /training/basics/activity-lifecycle/pausing.html
+ - title: Stopping and Restarting an Activity
+ path: /training/basics/activity-lifecycle/stopping.html
+ custom_link_attributes:
+ - ja-lang="アクティビティの一時停止と再開"
+ - ko-lang="액티비티 일시정지 및 재개하기"
+ - pt-br-lang="Pausando e reiniciando uma atividade"
+ - ru-lang="Приостановка и возобновление операции"
+ - zh-cn-lang="暂停和继续活动"
+ - zh-tw-lang="暫停並繼續應用行為顯示"
+ - title: Recreating an Activity
+ path: /training/basics/activity-lifecycle/recreating.html
+ custom_link_attributes:
+ - ja-lang="アクティビティを再作成する"
+ - ko-lang="액티비티 재생성하기"
+ - pt-br-lang="Recriando uma atividade"
+ - ru-lang="Воссоздание операции"
+ - zh-cn-lang="重新创建活动"
+ - zh-tw-lang="重新建立應用行為顯示"
+ - title: Building a Dynamic UI with Fragments
+ path: /training/basics/fragments/index.html
+ custom_link_attributes:
+ - description="How to build a user interface for your app that is flexible enough to present multiple UI components on large screens and a more constrained set of UI components on smaller screens—essential for building a single APK for both phones and tablets."
+ section:
+ - title: Creating a Fragment
+ path: /training/basics/fragments/creating.html
+ - title: Building a Flexible UI
+ path: /training/basics/fragments/fragment-ui.html
+ custom_link_attributes:
+ - zh-cn-lang="构建灵活的界面"
+ - title: Communicating with Other Fragments
+ path: /training/basics/fragments/communicating.html
+ - title: Saving Data
+ path: /training/basics/data-storage/index.html
+ custom_link_attributes:
+ - ja-lang="データの保存"
+ - ko-lang="데이터 저장하기"
+ - pt-br-lang="Salvando dados"
+ - ru-lang="Сохранение данных"
+ - zh-cn-lang="保存数据"
+ - zh-tw-lang="儲存資料"
+ - description="How to save data on the device, whether it's temporary files, downloaded app assets, user media, structured data, or something else."
+ section:
+ - title: Saving Key-Value Sets
+ path: /training/basics/data-storage/shared-preferences.html
+ custom_link_attributes:
+ - ja-lang="キー値セットを保存する"
+ - ko-lang="키-값 세트 저장하기"
+ - pt-br-lang="Salvando conjuntos de valor-chave"
+ - ru-lang="Сохранение наборов \"ключ-значение\""
+ - zh-cn-lang="保存键值集"
+ - zh-tw-lang="儲存索引鍵值組"
+ - title: Saving Files
+ path: /training/basics/data-storage/files.html
+ custom_link_attributes:
+ - ja-lang="ファイルを保存する"
+ - ko-lang="파일 저장하기"
+ - pt-br-lang="Salvando arquivos"
+ - ru-lang="Сохранение файлов"
+ - zh-cn-lang="保存文件"
+ - zh-tw-lang="儲存檔案"
+ - title: Saving Data in SQL Databases
+ path: /training/basics/data-storage/databases.html
+ custom_link_attributes:
+ - ja-lang="SQL データベースにデータを保存する"
+ - ko-lang="SQL 데이터베이스에 데이터 저장하기"
+ - pt-br-lang="Salvando dados em bancos de dados do SQL"
+ - ru-lang="Сохранение данных в базах данных SQL"
+ - zh-cn-lang="在 SQL 数据库中保存数据"
+ - zh-tw-lang="在 SQL 資料庫中儲存資料"
+ - title: Interacting with Other Apps
+ path: /training/basics/intents/index.html
+ custom_link_attributes:
+ - ja-lang="他のアプリとの相互操作"
+ - ko-lang="액티비티 수명 주기 관리하기"
+ - pt-br-lang="Interagindo com outros aplicativos"
+ - ru-lang="Взаимодействие с другими приложениями"
+ - zh-cn-lang="与其他应用交互"
+ - zh-tw-lang="與其他應用程式互動"
+ - description="How to build a user experience that leverages other apps available on the device to perform advanced user tasks, such as capture a photo or view an address on a map."
+ section:
+ - title: Sending the User to Another App
+ path: /training/basics/intents/sending.html
+ custom_link_attributes:
+ - ja-lang="別のアプリにユーザーを送る"
+ - ko-lang="다른 앱으로 사용자 보내기"
+ - pt-br-lang="Enviando o usuário para outro aplicativo"
+ - ru-lang="Направление пользователя в другое приложение"
+ - zh-cn-lang="向另一个应用发送用户"
+ - zh-tw-lang="將使用者傳送至其他應用程式"
+ - title: Getting a Result from the Activity
+ path: /training/basics/intents/result.html
+ custom_link_attributes:
+ - ja-lang="アクティビティから結果を取得する"
+ - ko-lang="액티비티로부터 결과 가져오기"
+ - pt-br-lang="Obtendo resultados de uma atividade"
+ - ru-lang="Получение результата операции"
+ - zh-cn-lang="获取活动的结果"
+ - zh-tw-lang="從應用行為顯示取得結果"
+ - title: Allowing Other Apps to Start Your Activity
+ path: /training/basics/intents/filters.html
+ custom_link_attributes:
+ - ja-lang="他のアプリからのアクティビティの開始を許可する"
+ - ko-lang="다른 앱이 자신의 액티비티를 시작하도록 허용하기"
+ - pt-br-lang="Permitindo que outros aplicativos iniciem sua atividade"
+ - ru-lang="Разрешение другим приложениям на запуск вашей операции"
+ - zh-cn-lang="允许其他应用开始您的活动"
+ - zh-tw-lang="允許其他應用程式啟動您的應用行為顯示"
+ - title: Working with System Permissions
+ path: /training/permissions/index.html
+ custom_link_attributes:
+ - description="How to declare that your app needs access to features and resources outside of its 'sandbox', and how to request those privileges at runtime."
+ section:
+ - title: Declaring Permissions
+ path: /training/permissions/declaring.html
+ - title: Requesting Permissions at Run Time
+ path: /training/permissions/requesting.html
+ - title: Best Practices for Runtime Permissions
+ path: /training/permissions/best-practices.html
+
+- title: Building Apps with Content Sharing
+ path: /training/building-content-sharing.html
+ section:
+ - title: Sharing Simple Data
+ path: /training/sharing/index.html
+ custom_link_attributes:
+ - description="How to take your app interaction to the next level by sharing information with other apps, receive information back, and provide a simple and scalable way to perform Share actions with user content."
+ section:
+ - title: Sending Simple Data to Other Apps
+ path: /training/sharing/send.html
+ - title: Receiving Simple Data from Other Apps
+ path: /training/sharing/receive.html
+ - title: Adding an Easy Share Action
+ path: /training/sharing/shareaction.html
+ - title: Sharing Files
+ path: /training/secure-file-sharing/index.html
+ custom_link_attributes:
+ - description="How to provide secure access to a file associated with your app using a content URI and temporary access permissions."
+ section:
+ - title: Setting Up File Sharing
+ path: /training/secure-file-sharing/setup-sharing.html
+ - title: Sharing a File
+ path: /training/secure-file-sharing/share-file.html
+ - title: Requesting a Shared File
+ path: /training/secure-file-sharing/request-file.html
+ - title: Retrieving File Information
+ path: /training/secure-file-sharing/retrieve-info.html
+ - title: Sharing Files with NFC
+ path: /training/beam-files/index.html
+ custom_link_attributes:
+ - description="How to transfer files between devices using the NFC Android Beam feature."
+ section:
+ - title: Sending Files to Another Device
+ path: /training/beam-files/send-files.html
+ - title: Receiving Files from Another Device
+ path: /training/beam-files/receive-files.html
+
+- title: Building Apps with Multimedia
+ path: /training/building-multimedia.html
+ section:
+ - title: Managing Audio Playback
+ path: /training/managing-audio/index.html
+ custom_link_attributes:
+ - description="How to respond to hardware audio key presses, request audio focus when playing audio, and respond appropriately to changes in audio focus."
+ section:
+ - title: Controlling Your App's Volume and Playback
+ path: /training/managing-audio/volume-playback.html
+ - title: Managing Audio Focus
+ path: /training/managing-audio/audio-focus.html
+ - title: Dealing with Audio Output Hardware
+ path: /training/managing-audio/audio-output.html
+ - title: Capturing Photos
+ path: /training/camera/index.html
+ custom_link_attributes:
+ - description="How to leverage existing camera apps on the user's device to capture photos or control the camera hardware directly and build your own camera app."
+ section:
+ - title: Taking Photos Simply
+ path: /training/camera/photobasics.html
+ - title: Recording Videos Simply
+ path: /training/camera/videobasics.html
+ - title: Controlling the Camera
+ path: /training/camera/cameradirect.html
+ - title: Printing Content
+ path: /training/printing/index.html
+ custom_link_attributes:
+ - description="How to print photos, HTML documents, and custom documents from your app."
+ section:
+ - title: Photos
+ path: /training/printing/photos.html
+ - title: HTML Documents
+ path: /training/printing/html-docs.html
+ - title: Custom Documents
+ path: /training/printing/custom-docs.html
+
+- title: Building Apps with Graphics & Animation
+ path: /training/building-graphics.html
+ section:
+ - title: Displaying Bitmaps Efficiently
+ path: /training/displaying-bitmaps/index.html
+ custom_link_attributes:
+ - description="How to load and process bitmaps while keeping your user interface responsive and avoid exceeding memory limits."
+ section:
+ - title: Loading Large Bitmaps Efficiently
+ path: /training/displaying-bitmaps/load-bitmap.html
+ - title: Processing Bitmaps Off the UI Thread
+ path: /training/displaying-bitmaps/process-bitmap.html
+ - title: Caching Bitmaps
+ path: /training/displaying-bitmaps/cache-bitmap.html
+ - title: Managing Bitmap Memory
+ path: /training/displaying-bitmaps/manage-memory.html
+ - title: Displaying Bitmaps in Your UI
+ path: /training/displaying-bitmaps/display-bitmap.html
+ - title: Displaying Graphics with OpenGL ES
+ path: /training/graphics/opengl/index.html
+ custom_link_attributes:
+ - description="How to create OpenGL graphics within the Android app framework and respond to touch input."
+ section:
+ - title: Building an OpenGL ES Environment
+ path: /training/graphics/opengl/environment.html
+ - title: Defining Shapes
+ path: /training/graphics/opengl/shapes.html
+ - title: Drawing Shapes
+ path: /training/graphics/opengl/draw.html
+ - title: Applying Projection and Camera Views
+ path: /training/graphics/opengl/projection.html
+ - title: Adding Motion
+ path: /training/graphics/opengl/motion.html
+ - title: Responding to Touch Events
+ path: /training/graphics/opengl/touch.html
+ - title: Animating Views Using Scenes and Transitions
+ path: /training/transitions/index.html
+ custom_link_attributes:
+ - description="How to animate state changes in a view hierarchy using transitions."
+ section:
+ - title: The Transitions Framework
+ path: /training/transitions/overview.html
+ - title: Creating a Scene
+ path: /training/transitions/scenes.html
+ - title: Applying a Transition
+ path: /training/transitions/transitions.html
+ - title: Creating Custom Transitions
+ path: /training/transitions/custom-transitions.html
+ - title: Adding Animations
+ path: /training/animation/index.html
+ custom_link_attributes:
+ - description="How to add transitional animations to your user interface."
+ section:
+ - title: Crossfading Two Views
+ path: /training/animation/crossfade.html
+ - title: Using ViewPager for Screen Slide
+ path: /training/animation/screen-slide.html
+ - title: Displaying Card Flip Animations
+ path: /training/animation/cardflip.html
+ - title: Zooming a View
+ path: /training/animation/zoom.html
+ - title: Animating Layout Changes
+ path: /training/animation/layout.html
+
+- title: Building Apps with Connectivity & the Cloud
+ path: /training/building-connectivity.html
+ section:
+ - title: Connecting Devices Wirelessly
+ path: /training/connect-devices-wirelessly/index.html
+ custom_link_attributes:
+ - description="How to find and connect to local devices using Network Service Discovery and how to create peer-to-peer connections with Wi-Fi."
+ section:
+ - title: Using Network Service Discovery
+ path: /training/connect-devices-wirelessly/nsd.html
+ - title: Creating P2P Connections with Wi-Fi
+ path: /training/connect-devices-wirelessly/wifi-direct.html
+ - title: Using Wi-Fi P2P for Service Discovery
+ path: /training/connect-devices-wirelessly/nsd-wifi-direct.html
+ - title: Performing Network Operations
+ path: /training/basics/network-ops/index.html
+ custom_link_attributes:
+ - description="How to create a network connection, monitor the connection for changes in connectivity, and perform transactions with XML data."
+ section:
+ - title: Connecting to the Network
+ path: /training/basics/network-ops/connecting.html
+ - title: Managing Network Usage
+ path: /training/basics/network-ops/managing.html
+ - title: Parsing XML Data
+ path: /training/basics/network-ops/xml.html
+ - title: Transferring Data Without Draining the Battery
+ path: /training/efficient-downloads/index.html
+ custom_link_attributes:
+ - description="How to minimize your app's impact on the battery when performing downloads and other network transactions."
+ section:
+ - title: Optimizing Downloads for Efficient Network Access
+ path: /training/efficient-downloads/efficient-network-access.html
+ - title: Minimizing the Effect of Regular Updates
+ path: /training/efficient-downloads/regular_updates.html
+ - title: Redundant Downloads are Redundant
+ path: /training/efficient-downloads/redundant_redundant.html
+ - title: Modifying Patterns Based on the Connectivity Type
+ path: /training/efficient-downloads/connectivity_patterns.html
+ - title: Syncing to the Cloud
+ path: /training/backup/index.html
+ custom_link_attributes:
+ - description="How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices."
+ section:
+ - title: Configuring Auto Backup
+ path: /training/backup/autosyncapi.html
+ - title: Using the Backup API
+ path: /training/backup/backupapi.html
+ - title: Resolving Cloud Save Conflicts
+ path: /training/cloudsave/conflict-res.html
+ custom_link_attributes:
+ - description="How to design a robust conflict resolution strategy for apps that save data to the cloud."
+ - title: Transferring Data Using Sync Adapters
+ path: /training/sync-adapters/index.html
+ custom_link_attributes:
+ - description="How to transfer data between the cloud and the device using the Android sync adapter framework"
+ section:
+ - title: Creating a Stub Authenticator
+ path: /training/sync-adapters/creating-authenticator.html
+ - title: Creating a Stub Content Provider
+ path: /training/sync-adapters/creating-stub-provider.html
+ - title: Creating a Sync Adapter
+ path: /training/sync-adapters/creating-sync-adapter.html
+ - title: Running a Sync Adapter
+ path: /training/sync-adapters/running-sync-adapter.html
+ - title: Transmitting Network Data Using Volley
+ path: /training/volley/index.html
+ custom_link_attributes:
+ - description="How to perform fast, scalable UI operations over the network using Volley"
+ section:
+ - title: Sending a Simple Request
+ path: /training/volley/simple.html
+ - title: Setting Up a RequestQueue
+ path: /training/volley/requestqueue.html
+ - title: Making a Standard Request
+ path: /training/volley/request.html
+ - title: Implementing a Custom Request
+ path: /training/volley/request-custom.html
+
+- title: Building Apps with Location & Maps
+ path: /training/building-location.html
+ section:
+ - title: Making Your App Location-Aware
+ path: /training/location/index.html
+ custom_link_attributes:
+ - description="How to add location-aware features to your app by getting the user's current location."
+ section:
+ - title: Getting the Last Known Location
+ path: /training/location/retrieve-current.html
+ - title: Changing Location Settings
+ path: /training/location/change-location-settings.html
+ - title: Receiving Location Updates
+ path: /training/location/receive-location-updates.html
+ - title: Displaying a Location Address
+ path: /training/location/display-address.html
+ - title: Creating and Monitoring Geofences
+ path: /training/location/geofencing.html
+ - title: Adding Maps
+ path: /training/maps/index.html
+ custom_link_attributes:
+ - description="How to add maps and mapping information to your app."
+
+- title: Building Apps with User Info & Sign-In
+ path: /training/building-userinfo.html
+ section:
+ - title: Accessing Contacts Data
+ path: /training/contacts-provider/index.html
+ custom_link_attributes:
+ - description="How to use Android's central address book, the Contacts Provider, to display contacts and their details and modify contact information."
+ section:
+ - title: Retrieving a List of Contacts
+ path: /training/contacts-provider/retrieve-names.html
+ - title: Retrieving Details for a Contact
+ path: /training/contacts-provider/retrieve-details.html
+ - title: Modifying Contacts Using Intents
+ path: /training/contacts-provider/modify-data.html
+ - title: Displaying the Quick Contact Badge
+ path: /training/contacts-provider/display-contact-badge.html
+ - title: Adding Sign-In
+ path: /training/sign-in/index.html
+ custom_link_attributes:
+ - description="How to add user sign-in functionality to your app."
+
+- title: Building Apps for Wearables
+ path: /training/building-wearables.html
+ section:
+ - title: Adding Wearable Features to Notifications
+ path: /training/wearables/notifications/index.html
+ custom_link_attributes:
+ - description="How to build handheld notifications that are synced to and look great on wearables."
+ section:
+ - title: Creating a Notification
+ path: /training/wearables/notifications/creating.html
+ - title: Receiving Voice Input in a Notification
+ path: /training/wearables/notifications/voice-input.html
+ - title: Adding Pages to a Notification
+ path: /training/wearables/notifications/pages.html
+ - title: Stacking Notifications
+ path: /training/wearables/notifications/stacks.html
+ - title: Creating Wearable Apps
+ path: /training/wearables/apps/index.html
+ custom_link_attributes:
+ - description="How to build apps that run directly on wearables."
+ section:
+ - title: Creating and Running a Wearable App
+ path: /training/wearables/apps/creating.html
+ - title: Creating Custom Layouts
+ path: /training/wearables/apps/layouts.html
+ - title: Keeping Your App Visible
+ path: /training/wearables/apps/always-on.html
+ - title: Adding Voice Capabilities
+ path: /training/wearables/apps/voice.html
+ - title: Packaging Wearable Apps
+ path: /training/wearables/apps/packaging.html
+ - title: Debugging over Bluetooth
+ path: /training/wearables/apps/bt-debugging.html
+ - title: Creating Custom UIs
+ path: /training/wearables/ui/index.html
+ custom_link_attributes:
+ - description="How to create custom user interfaces for wearable apps."
+ section:
+ - title: Defining Layouts
+ path: /training/wearables/ui/layouts.html
+ - title: Creating Cards
+ path: /training/wearables/ui/cards.html
+ - title: Creating Lists
+ path: /training/wearables/ui/lists.html
+ - title: Creating a 2D Picker
+ path: /training/wearables/ui/2d-picker.html
+ - title: Showing Confirmations
+ path: /training/wearables/ui/confirm.html
+ - title: Exiting Full-Screen Activities
+ path: /training/wearables/ui/exit.html
+ - title: Sending and Syncing Data
+ path: /training/wearables/data-layer/index.html
+ custom_link_attributes:
+ - description="How to sync data between handhelds and wearables."
+ section:
+ - title: Accessing the Wearable Data Layer
+ path: /training/wearables/data-layer/accessing.html
+ - title: Syncing Data Items
+ path: /training/wearables/data-layer/data-items.html
+ - title: Transferring Assets
+ path: /training/wearables/data-layer/assets.html
+ - title: Sending and Receiving Messages
+ path: /training/wearables/data-layer/messages.html
+ - title: Handling Data Layer Events
+ path: /training/wearables/data-layer/events.html
+ - title: Creating Watch Faces
+ path: /training/wearables/watch-faces/index.html
+ custom_link_attributes:
+ - description="How to create watch faces for wearables."
+ section:
+ - title: Designing Watch Faces
+ path: /training/wearables/watch-faces/designing.html
+ - title: Building a Watch Face Service
+ path: /training/wearables/watch-faces/service.html
+ - title: Drawing Watch Faces
+ path: /training/wearables/watch-faces/drawing.html
+ - title: Showing Information in Watch Faces
+ path: /training/wearables/watch-faces/information.html
+ - title: Creating Interactive Watch Faces
+ path: /training/wearables/watch-faces/interacting.html
+ - title: Providing Configuration Activities
+ path: /training/wearables/watch-faces/configuration.html
+ - title: Addressing Common Issues
+ path: /training/wearables/watch-faces/issues.html
+ - title: Optimizing Performance and Battery Life
+ path: /training/wearables/watch-faces/performance.html
+ - title: Detecting Location
+ path: /training/articles/wear-location-detection.html
+ custom_link_attributes:
+ - description="How to detect location data on Android Wear devices."
+ - title: Requesting Permissions
+ path: /training/articles/wear-permissions.html
+ custom_link_attributes:
+ - description="How to request permissions on Android Wear devices."
+ - title: Using the Speaker
+ path: /training/wearables/wearable-sounds.html
+ custom_link_attributes:
+ - description="How to use the speaker on Android Wear devices."
+
+- title: Building Apps for TV
+ path: /training/tv/index.html
+ section:
+ - title: Building TV Apps
+ path: /training/tv/start/index.html
+ custom_link_attributes:
+ - ja-lang="TV アプリのビルド"
+ - description="How to start building TV apps or extend your existing app to run on TV devices."
+ section:
+ - title: Getting Started with TV Apps
+ path: /training/tv/start/start.html
+ custom_link_attributes:
+ - ja-lang="TV アプリのビルドを開始する"
+ - title: Handling TV Hardware
+ path: /training/tv/start/hardware.html
+ custom_link_attributes:
+ - ja-lang="TV ハードウェアを処理する"
+ - title: Building TV Layouts
+ path: /training/tv/start/layouts.html
+ custom_link_attributes:
+ - ja-lang="TV 向けレイアウトをビルドする"
+ - title: Creating TV Navigation
+ path: /training/tv/start/navigation.html
+ custom_link_attributes:
+ - ja-lang="TV 用のナビゲーションを作成する"
+ - title: Building TV Playback Apps
+ path: /training/tv/playback/index.html
+ custom_link_attributes:
+ - ja-lang="TV 再生アプリのビルド"
+ - description="How to build apps that provide media catalogs and play content."
+ section:
+ - title: Creating a Catalog Browser
+ path: /training/tv/playback/browse.html
+ custom_link_attributes:
+ - ja-lang="カタログ ブラウザを作成する"
+ - title: Providing a Card View
+ path: /training/tv/playback/card.html
+ - title: Building a Details View
+ path: /training/tv/playback/details.html
+ custom_link_attributes:
+ - ja-lang="詳細ビューをビルドする"
+ - title: Displaying a Now Playing Card
+ path: /training/tv/playback/now-playing.html
+ custom_link_attributes:
+ - ja-lang="再生中カードを表示する"
+ - title: Adding a Guided Step
+ path: /training/tv/playback/guided-step.html
+ - title: Enabling Background Playback
+ path: /training/tv/playback/options.html
+ - title: Helping Users Find Content on TV
+ path: /training/tv/discovery/index.html
+ custom_link_attributes:
+ - description="How to help users discover content from your app."
+ section:
+ - title: Recommending TV Content
+ path: /training/tv/discovery/recommendations.html
+ - title: Making TV Apps Searchable
+ path: /training/tv/discovery/searchable.html
+ - title: Searching within TV Apps
+ path: /training/tv/discovery/in-app-search.html
+ - title: Building TV Games
+ path: /training/tv/games/index.html
+ custom_link_attributes:
+ - description="How to build games for TV."
+ - title: Building TV Channels
+ path: /training/tv/tif/index.html
+ custom_link_attributes:
+ - description="How to build channels for TV."
+ section:
+ - title: Developing a TV Input Service
+ path: /training/tv/tif/tvinput.html
+ - title: Working with Channel Data
+ path: /training/tv/tif/channel.html
+ - title: Managing User Interaction
+ path: /training/tv/tif/ui.html
+ - title: TV Apps Checklist
+ path: /training/tv/publishing/checklist.html
+ custom_link_attributes:
+ - description="An itemized list of requirements for TV apps."
+
+- title: Building Apps for Auto
+ path: /training/auto/index.html
+ section:
+ - title: Getting Started with Auto
+ path: /training/auto/start/index.html
+ custom_link_attributes:
+ - description="How to start building or extending apps that work with Auto devices."
+ - title: Playing Audio for Auto
+ path: /training/auto/audio/index.html
+ custom_link_attributes:
+ - description="How to extend audio apps to play content on Auto devices."
+ - title: Messaging for Auto
+ path: /training/auto/messaging/index.html
+ custom_link_attributes:
+ - description="How to extend text messaging apps to work with Auto devices."
+
+- title: Building Apps for Work
+ path: /training/enterprise/index.html
+ section:
+ - title: Ensuring Compatibility with Managed Profiles
+ path: /training/enterprise/app-compatibility.html
+ - title: Implementing App Restrictions
+ path: /training/enterprise/app-restrictions.html
+ - title: Building a Device Policy Controller
+ path: /training/enterprise/work-policy-ctrl.html
+ - title: Configuring Corporate-Owned, Single-Use Devices
+ path: /training/enterprise/cosu.html
+
+- title: Best Practices for Interaction & Engagement
+ path: /training/best-ux.html
+ section:
+ - title: Designing Effective Navigation
+ path: /training/design-navigation/index.html
+ custom_link_attributes:
+ - description="How to plan your app's screen hierarchy and forms of navigation so users can effectively and intuitively traverse your app content using various navigation patterns."
+ section:
+ - title: Planning Screens and Their Relationships
+ path: /training/design-navigation/screen-planning.html
+ - title: Planning for Multiple Touchscreen Sizes
+ path: /training/design-navigation/multiple-sizes.html
+ - title: Providing Descendant and Lateral Navigation
+ path: /training/design-navigation/descendant-lateral.html
+ - title: Providing Ancestral and Temporal Navigation
+ path: /training/design-navigation/ancestral-temporal.html
+ - title: "Putting it All Together: Wireframing the Example App"
+ path: /training/design-navigation/wireframing.html
+ - title: Implementing Effective Navigation
+ path: /training/implementing-navigation/index.html
+ custom_link_attributes:
+ - description="How to implement various navigation patterns such as swipe views, a navigation drawer, and up navigation."
+ section:
+ - title: Creating Swipe Views with Tabs
+ path: /training/implementing-navigation/lateral.html
+ - title: Creating a Navigation Drawer
+ path: /training/implementing-navigation/nav-drawer.html
+ - title: Providing Up Navigation
+ path: /training/implementing-navigation/ancestral.html
+ - title: Providing Proper Back Navigation
+ path: /training/implementing-navigation/temporal.html
+ - title: Implementing Descendant Navigation
+ path: /training/implementing-navigation/descendant.html
+ - title: Notifying the User
+ path: /training/notify-user/index.html
+ custom_link_attributes:
+ - description="How to display messages called notifications outside of your application's UI."
+ section:
+ - title: Building a Notification
+ path: /training/notify-user/build-notification.html
+ - title: Preserving Navigation when Starting an Activity
+ path: /training/notify-user/navigation.html
+ - title: Updating Notifications
+ path: /training/notify-user/managing.html
+ - title: Using Big View Styles
+ path: /training/notify-user/expanded.html
+ - title: Displaying Progress in a Notification
+ path: /training/notify-user/display-progress.html
+ - title: Supporting Swipe-to-Refresh
+ path: /training/swipe/index.html
+ custom_link_attributes:
+ - description="How to modify your app's layout to support manual content updates triggered by the swipe-to-refresh gesture."
+ section:
+ - title: Adding Swipe-to-Refresh To Your App
+ path: /training/swipe/add-swipe-interface.html
+ - title: Responding to a Refresh Gesture
+ path: /training/swipe/respond-refresh-request.html
+ - title: Adding Search Functionality
+ path: /training/search/index.html
+ custom_link_attributes:
+ - description="How to properly add a search interface to your app and create a searchable database."
+ section:
+ - title: Setting up the Search Interface
+ path: /training/search/setup.html
+ - title: Storing and Searching for Data
+ path: /training/search/search.html
+ - title: Remaining Backward Compatible
+ path: /training/search/backward-compat.html
+ - title: Making Your App Content Searchable by Google
+ path: /training/app-indexing/index.html
+ custom_link_attributes:
+ - description="How to enable deep linking and indexing of your application content so that users can open this content directly from their mobile search results."
+ section:
+ - title: Enabling Deep Links for App Content
+ path: /training/app-indexing/deep-linking.html
+ - title: Specifying App Content for Indexing
+ path: /training/app-indexing/enabling-app-indexing.html
+ - title: Optimizing Content for the Assistant
+ path: /training/articles/assistant.html
+ custom_link_attributes:
+ - description="Support contextually relevant actions through the Assist API."
+ - title: Handling App Links
+ path: /training/app-links/index.html
+ custom_link_attributes:
+ - description="How to enable the system to handle web requests by taking the user directly to your app instead of your website."
+
+- title: Best Practices for User Interface
+ path: /training/best-ui.html
+ section:
+ - title: Designing for Multiple Screens
+ path: /training/multiscreen/index.html
+ custom_link_attributes:
+ - es-lang="Cómo diseñar aplicaciones para varias pantallas"
+ - ja-lang="複数画面のデザイン"
+ - zh-cn-lang="针对多种屏幕进行设计"
+ - description="How to build a user interface that's flexible enough to fit perfectly on any screen and how to create different interaction patterns that are optimized for different screen sizes."
+ section:
+ - title: Supporting Different Screen Sizes
+ path: /training/multiscreen/screensizes.html
+ custom_link_attributes:
+ - es-lang="Cómo admitir varios tamaños de pantalla"
+ - ja-lang="さまざまな画面サイズのサポート"
+ - ko-lang="다양한 화면 크기 지원"
+ - zh-cn-lang="支持各种屏幕尺寸"
+ - title: Supporting Different Screen Densities
+ path: /training/multiscreen/screendensities.html
+ custom_link_attributes:
+ - es-lang="Cómo admitir varias densidades de pantalla"
+ - ja-lang="さまざまな画面密度のサポート"
+ - zh-cn-lang="支持各种屏幕密度"
+ - title: Implementing Adaptive UI Flows
+ path: /training/multiscreen/adaptui.html
+ custom_link_attributes:
+ - es-lang="Cómo implementar interfaces de usuario adaptables"
+ - ja-lang="順応性のある UI フローの実装"
+ - zh-cn-lang="实施自适应用户界面流程"
+ - title: Adding the App Bar
+ path: /training/appbar/index.html
+ custom_link_attributes:
+ - description="How to use the support library's toolbar widget to implement an app bar that displays properly on a wide range of devices."
+ section:
+ - title: Setting Up the App Bar
+ path: /training/appbar/setting-up.html
+ - title: Adding and Handling Actions
+ path: /training/appbar/actions.html
+ - title: Adding an Up Action
+ path: /training/appbar/up-action.html
+ - title: Action Views and Action Providers
+ path: /training/appbar/action-views.html
+ - title: Showing Pop-Up Messages
+ path: /training/snackbar/index.html
+ custom_link_attributes:
+ - description="How to use the support library's Snackbar widget to display a brief pop-up message."
+ section:
+ - title: Building and Displaying a Pop-Up Message
+ path: /training/snackbar/showing.html
+ - title: Adding an Action to a Message
+ path: /training/snackbar/action.html
+ - title: Creating Custom Views
+ path: /training/custom-views/index.html
+ custom_link_attributes:
+ - description="How to build custom UI widgets that are interactive and smooth."
+ section:
+ - title: Creating a Custom View Class
+ path: /training/custom-views/create-view.html
+ - title: Implementing Custom Drawing
+ path: /training/custom-views/custom-drawing.html
+ - title: Making the View Interactive
+ path: /training/custom-views/making-interactive.html
+ - title: Optimizing the View
+ path: /training/custom-views/optimizing-view.html
+ - title: Creating Backward-Compatible UIs
+ path: /training/backward-compatible-ui/index.html
+ custom_link_attributes:
+ - description="How to use UI components and other APIs from the more recent versions of Android while remaining compatible with older versions of the platform."
+ section:
+ - title: Abstracting the New APIs
+ path: /training/backward-compatible-ui/abstracting.html
+ - title: Proxying to the New APIs
+ path: /training/backward-compatible-ui/new-implementation.html
+ - title: Creating an Implementation with Older APIs
+ path: /training/backward-compatible-ui/older-implementation.html
+ - title: Using the Version-Aware Component
+ path: /training/backward-compatible-ui/using-component.html
+ - title: Implementing Accessibility
+ path: /training/accessibility/index.html
+ custom_link_attributes:
+ - description="How to make your app accessible to users with vision impairment or other physical disabilities."
+ section:
+ - title: Developing Accessible Applications
+ path: /training/accessibility/accessible-app.html
+ - title: Developing Accessibility Services
+ path: /training/accessibility/service.html
+ - title: Accessibility Testing Checklist
+ path: /training/accessibility/testing.html
+ - title: Managing the System UI
+ path: /training/system-ui/index.html
+ custom_link_attributes:
+ - description="How to hide and show status and navigation bars across different versions of Android, while managing the display of other screen components."
+ section:
+ - title: Dimming the System Bars
+ path: /training/system-ui/dim.html
+ - title: Hiding the Status Bar
+ path: /training/system-ui/status.html
+ - title: Hiding the Navigation Bar
+ path: /training/system-ui/navigation.html
+ - title: Using Immersive Full-Screen Mode
+ path: /training/system-ui/immersive.html
+ - title: Responding to UI Visibility Changes
+ path: /training/system-ui/visibility.html
+ - title: Creating Apps with Material Design
+ path: /training/material/index.html
+ custom_link_attributes:
+ - es-lang="Crear aplicaciones con Material Design"
+ - in-lang="Desain Bahan untuk Pengembang"
+ - ja-lang="マテリアル デザインでのアプリ作成"
+ - ko-lang="개발자를 위한 머티리얼 디자인"
+ - pt-br-lang="Material Design para desenvolvedores"
+ - ru-lang="Создание приложений с помощью Material Design"
+ - vi-lang="Material Design cho Nhà phát triển"
+ - zh-cn-lang="面向开发者的材料设计"
+ - zh-tw-lang="開發人員材料設計"
+ - description="How to implement material design on Android."
+ section:
+ - title: Getting Started
+ path: /training/material/get-started.html
+ custom_link_attributes:
+ - es-lang="Comencemos"
+ - in-lang="Memulai"
+ - ja-lang="スタート ガイド"
+ - ko-lang="시작하기"
+ - pt-br-lang="Como iniciar"
+ - ru-lang="Начало работы"
+ - vi-lang="Bắt đầu"
+ - zh-cn-lang="入门指南"
+ - zh-tw-lang="開始使用"
+ - title: Using the Material Theme
+ path: /training/material/theme.html
+ custom_link_attributes:
+ - es-lang="Usar el tema Material"
+ - in-lang="Menggunakan Tema Bahan"
+ - ja-lang="マテリアル テーマの使用"
+ - ko-lang="머티어리얼 테마 사용"
+ - pt-br-lang="Como usar o tema do Material"
+ - ru-lang="Использование темы Material Design"
+ - vi-lang="Sử dụng Chủ đề Material"
+ - zh-cn-lang="使用材料主题"
+ - zh-tw-lang="使用材料設計風格"
+ - title: Creating Lists and Cards
+ path: /training/material/lists-cards.html
+ custom_link_attributes:
+ - es-lang="Crear listas y tarjetas"
+ - in-lang="Membuat Daftar dan Kartu"
+ - ja-lang="リストとカードの作成"
+ - ko-lang="목록 및 카드 생성"
+ - pt-br-lang="Como criar listas e cartões"
+ - ru-lang="Создание списков и подсказок"
+ - vi-lang="Tạo Danh sách và Thẻ"
+ - zh-cn-lang="创建列表与卡片"
+ - zh-tw-lang="建立清單和卡片"
+ - title: Defining Shadows and Clipping Views
+ path: /training/material/shadows-clipping.html
+ custom_link_attributes:
+ - es-lang="Definir vistas de recorte y sombras"
+ - in-lang="Mendefinisikan Bayangan dan Memangkas Tampilan"
+ - ja-lang="シャドウとクリッピング ビューの定義"
+ - ko-lang="그림자 정의 및 뷰 클리핑"
+ - pt-br-lang="Como definir sombras e recortar visualizações"
+ - ru-lang="Определение теней и обрезка представлений"
+ - vi-lang="Định nghĩa Đổ bóng và Dạng xem Cắt hình"
+ - zh-cn-lang="定义阴影与裁剪视图"
+ - zh-tw-lang="定義陰影和裁剪檢視"
+ - title: Working with Drawables
+ path: /training/material/drawables.html
+ custom_link_attributes:
+ - es-lang="Trabajar con interfaces dibujables"
+ - in-lang="Bekerja dengan Drawable"
+ - ja-lang="ドローアブルの使用"
+ - ko-lang="Drawable 사용"
+ - pt-br-lang="Como trabalhar com desenháveis"
+ - ru-lang="Работа с элементами дизайна"
+ - vi-lang="Làm việc với Nội dung vẽ được"
+ - zh-cn-lang="使用 Drawables"
+ - zh-tw-lang="使用可繪項目"
+ - title: Defining Custom Animations
+ path: /training/material/animations.html
+ custom_link_attributes:
+ - es-lang="Definir animaciones personalizadas"
+ - in-lang="Mendefinisikan Animasi Custom"
+ - ja-lang="カスタム アニメーションの定義"
+ - ko-lang="사용자지정 애니메이션 정의"
+ - pt-br-lang="Como definir animações personalizadas"
+ - ru-lang="Определение настраиваемой анимации"
+ - vi-lang="Định nghĩa Hoạt hình Tùy chỉnh"
+ - zh-cn-lang="定义定制动画"
+ - zh-tw-lang="定義自訂動畫"
+ - title: Maintaining Compatibility
+ path: /training/material/compatibility.html
+ custom_link_attributes:
+ - es-lang="Mantener la compatibilidad"
+ - in-lang="Mempertahankan Kompatibilitas"
+ - ja-lang="互換性の維持"
+ - ko-lang="호환성 유지"
+ - pt-br-lang="Como manter a compatibilidade"
+ - ru-lang="Обеспечение совместимости"
+ - vi-lang="Duy trì Tính tương thích"
+ - zh-cn-lang="维护兼容性"
+ - zh-tw-lang="維持相容性"
+
+- title: Best Practices for User Input
+ path: /training/best-user-input.html
+ section:
+ - title: Using Touch Gestures
+ path: /training/gestures/index.html
+ custom_link_attributes:
+ - description="How to write apps that allow users to interact with the touch screen via touch gestures."
+ section:
+ - title: Detecting Common Gestures
+ path: /training/gestures/detector.html
+ - title: Tracking Movement
+ path: /training/gestures/movement.html
+ - title: Animating a Scroll Gesture
+ path: /training/gestures/scroll.html
+ - title: Handling Multi-Touch Gestures
+ path: /training/gestures/multi.html
+ - title: Dragging and Scaling
+ path: /training/gestures/scale.html
+ - title: Managing Touch Events in a ViewGroup
+ path: /training/gestures/viewgroup.html
+ - title: Handling Keyboard Input
+ path: /training/keyboard-input/index.html
+ custom_link_attributes:
+ - description="How to specify the appearance and behaviors of soft input methods (such as on-screen keyboards) and how to optimize the experience with hardware keyboards."
+ section:
+ - title: Specifying the Input Method Type
+ path: /training/keyboard-input/style.html
+ - title: Handling Input Method Visibility
+ path: /training/keyboard-input/visibility.html
+ - title: Supporting Keyboard Navigation
+ path: /training/keyboard-input/navigation.html
+ - title: Handling Keyboard Actions
+ path: /training/keyboard-input/commands.html
+ - title: Supporting Game Controllers
+ path: /training/game-controllers/index.html
+ custom_link_attributes:
+ - description="How to write apps that support game controllers."
+ section:
+ - title: Handling Controller Actions
+ path: /training/game-controllers/controller-input.html
+ - title: Supporting Controllers Across Android Versions
+ path: /training/game-controllers/compatibility.html
+ - title: Supporting Multiple Game Controllers
+ path: /training/game-controllers/multiple-controllers.html
+
+- title: Best Practices for Background Jobs
+ path: /training/best-background.html
+ section:
+ - title: Running in a Background Service
+ path: /training/run-background-service/index.html
+ custom_link_attributes:
+ - description="How to improve UI performance and responsiveness by sending work to a Service running in the background"
+ section:
+ - title: Creating a Background Service
+ path: /training/run-background-service/create-service.html
+ - title: Sending Work Requests to the Background Service
+ path: /training/run-background-service/send-request.html
+ - title: Reporting Work Status
+ path: /training/run-background-service/report-status.html
+ - title: Loading Data in the Background
+ path: /training/load-data-background/index.html
+ custom_link_attributes:
+ - description="How to use CursorLoader to query data without affecting UI responsiveness."
+ section:
+ - title: Running a Query with a CursorLoader
+ path: /training/load-data-background/setup-loader.html
+ - title: Handling the Results
+ path: /training/load-data-background/handle-results.html
+ - title: Managing Device Awake State
+ path: /training/scheduling/index.html
+ custom_link_attributes:
+ - description="How to use repeating alarms and wake locks to run background jobs."
+ section:
+ - title: Keeping the Device Awake
+ path: /training/scheduling/wakelock.html
+ - title: Scheduling Repeating Alarms
+ path: /training/scheduling/alarms.html
+
+- title: Best Practices for Performance
+ path: /training/best-performance.html
+ section:
+ - title: Managing Your App's Memory
+ path: /training/articles/memory.html
+ custom_link_attributes:
+ - description="How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices."
+ - title: Performance Tips
+ path: /training/articles/perf-tips.html
+ custom_link_attributes:
+ - description="How to optimize your app's performance in various ways to improve its responsiveness and battery efficiency."
+ - title: Improving Layout Performance
+ path: /training/improving-layouts/index.html
+ custom_link_attributes:
+ - description="How to identify problems in your app's layout performance and improve the UI responsiveness."
+ section:
+ - title: Optimizing Layout Hierarchies
+ path: /training/improving-layouts/optimizing-layout.html
+ - title: Re-using Layouts with <include/>
+ path: /training/improving-layouts/reusing-layouts.html
+ - title: Loading Views On Demand
+ path: /training/improving-layouts/loading-ondemand.html
+ - title: Making ListView Scrolling Smooth
+ path: /training/improving-layouts/smooth-scrolling.html
+ - title: Optimizing Battery Life
+ path: /training/monitoring-device-state/index.html
+ custom_link_attributes:
+ - es-lang="Cómo optimizar la duración de la batería"
+ - ja-lang="電池消費量の最適化"
+ - zh-cn-lang="优化电池使用时间"
+ - description="How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals."
+ section:
+ - title: Reducing Network Battery Drain
+ path: /training/performance/battery/network/index.html
+ section:
+ - title: Collecting Network Traffic Data
+ path: /training/performance/battery/network/gather-data.html
+ - title: Analyzing Network Traffic Data
+ path: /training/performance/battery/network/analyze-data.html
+ - title: Optimizing User-Initiated Network Use
+ path: /training/performance/battery/network/action-user-traffic.html
+ - title: Optimizing App-Initiated Network Use
+ path: /training/performance/battery/network/action-app-traffic.html
+ - title: Optimizing Server-Initiated Network Use
+ path: /training/performance/battery/network/action-server-traffic.html
+ - title: Optimizing General Network Use
+ path: /training/performance/battery/network/action-any-traffic.html
+ - title: Optimizing for Doze and App Standby
+ path: /training/monitoring-device-state/doze-standby.html
+ - title: Monitoring the Battery Level and Charging State
+ path: /training/monitoring-device-state/battery-monitoring.html
+ custom_link_attributes:
+ - es-lang="Cómo controlar el nivel de batería y el estado de carga"
+ - ja-lang="電池残量と充電状態の監視"
+ - zh-cn-lang="监控电池电量和充电状态"
+ - title: Determining and Monitoring the Docking State and Type
+ path: /training/monitoring-device-state/docking-monitoring.html
+ custom_link_attributes:
+ - es-lang="Cómo determinar y controlar el tipo de conector y el estado de la conexión"
+ - ja-lang="ホルダーの装着状態とタイプの特定と監視"
+ - zh-cn-lang="确定和监控基座对接状态和类型"
+ - title: Determining and Monitoring the Connectivity Status
+ path: /training/monitoring-device-state/connectivity-monitoring.html
+ custom_link_attributes:
+ - es-lang="Cómo determinar y controlar el estado de la conectividad"
+ - ja-lang="接続状態の特定と監視"
+ - zh-cn-lang="确定和监控网络连接状态"
+ - title: Manipulating Broadcast Receivers On Demand
+ path: /training/monitoring-device-state/manifest-receivers.html
+ custom_link_attributes:
+ - es-lang="Cómo manipular los receptores de emisión bajo demanda"
+ - ja-lang="オンデマンドでのブロードキャスト レシーバ操作"
+ - zh-cn-lang="根据需要操作广播接收器"
+ - title: Sending Operations to Multiple Threads
+ path: /training/multiple-threads/index.html
+ custom_link_attributes:
+ - description="How to improve the performance and scalability of long-running operations by dispatching work to multiple threads."
+ section:
+ - title: Specifying the Code to Run on a Thread
+ path: /training/multiple-threads/define-runnable.html
+ - title: Creating a Manager for Multiple Threads
+ path: /training/multiple-threads/create-threadpool.html
+ - title: Running Code on a Thread Pool Thread
+ path: /training/multiple-threads/run-code.html
+ - title: Communicating with the UI Thread
+ path: /training/multiple-threads/communicate-ui.html
+ - title: Keeping Your App Responsive
+ path: /training/articles/perf-anr.html
+ custom_link_attributes:
+ - description="How to keep your app responsive to user interaction so the UI does not lock-up and display an \"Application Not Responding\" dialog."
+ - title: JNI Tips
+ path: /training/articles/perf-jni.html
+ custom_link_attributes:
+ - description="How to efficiently use the Java Native Interface with the Android NDK."
+ - title: SMP Primer for Android
+ path: /training/articles/smp.html
+ custom_link_attributes:
+ - description="Tips for coding Android apps on symmetric multiprocessor systems."
+
+- title: Best Practices for Security & Privacy
+ path: /training/best-security.html
+ section:
+ - title: Security Tips
+ path: /training/articles/security-tips.html
+ custom_link_attributes:
+ - description="How to perform various tasks and keep your app's data and your user's data secure."
+ - title: Security with HTTPS and SSL
+ path: /training/articles/security-ssl.html
+ custom_link_attributes:
+ - description="How to ensure that your app is secure when performing network transactions."
+ - title: Updating Your Security Provider to Protect Against SSL Exploits
+ path: /training/articles/security-gms-provider.html
+ custom_link_attributes:
+ - description="How to use and update Google Play services security provider, to protect against SSL exploits."
+ - title: Checking Device Compatibility with SafetyNet
+ path: /training/safetynet/index.html
+ custom_link_attributes:
+ - description="How to use the SafetyNet service to analyze a device where your app is running and get information about its compatibility with your app."
+ - title: Enhancing Security with Device Management Policies
+ path: /training/enterprise/device-management-policy.html
+ custom_link_attributes:
+ - description="How to create an application that enforces security policies on devices."
+
+- title: Best Practices for Permissions & Identifiers
+ path: /training/best-permissions-ids.html
+ section:
+ - title: Permissions and User Data
+ path: /training/articles/user-data-overview.html
+ custom_link_attributes:
+ - description="Overview of app permissions on Android and how they affect your users."
+ - title: Best Practices for App Permissions
+ path: /training/articles/user-data-permissions.html
+ custom_link_attributes:
+ - description="How to manage permissions the right way for users."
+ - title: Best Practices for Unique Identifiers
+ path: /training/articles/user-data-ids.html
+ custom_link_attributes:
+ - description="Unique identifiers available and how to choose the right one for your use case."
+
+- title: Best Practices for Testing
+ path: /training/testing/index.html
+ section:
+ - title: Getting Started with Testing
+ path: /training/testing/start/index.html
+ custom_link_attributes:
+ - description="How to get started with testing your Android applications."
+ - title: Building Effective Unit Tests
+ path: /training/testing/unit-testing/index.html
+ custom_link_attributes:
+ - description="How to build effective unit tests for Android apps."
+ section:
+ - title: Building Local Unit Tests
+ path: /training/testing/unit-testing/local-unit-tests.html
+ - title: Building Instrumented Unit Tests
+ path: /training/testing/unit-testing/instrumented-unit-tests.html
+ - title: Automating UI Tests
+ path: /training/testing/ui-testing/index.html
+ custom_link_attributes:
+ - description="How to automate your user interface tests for Android apps."
+ section:
+ - title: Testing UI for a Single App
+ path: /training/testing/ui-testing/espresso-testing.html
+ - title: Testing UI for Multiple Apps
+ path: /training/testing/ui-testing/uiautomator-testing.html
+ - title: Testing App Component Integrations
+ path: /training/testing/integration-testing/index.html
+ custom_link_attributes:
+ - description="How to build effective integration tests for Android apps."
+ section:
+ - title: Testing Your Service
+ path: /training/testing/integration-testing/service-testing.html
+ - title: Testing Your Content Provider
+ path: /training/testing/integration-testing/content-provider-testing.html
+ - title: Testing Display Performance
+ path: /training/testing/performance.html
+ custom_link_attributes:
+ - description="How to automate UI performance testing."
+
+- title: Using Google Play to Distribute & Monetize
+ path: /training/distribute.html
+ section:
+ - title: Selling In-app Products
+ path: /training/in-app-billing/index.html
+ custom_link_attributes:
+ - description="How to sell in-app products from your application using In-app Billing."
+ section:
+ - title: Preparing Your App
+ path: /training/in-app-billing/preparing-iab-app.html
+ - title: Establishing Products for Sale
+ path: /training/in-app-billing/list-iab-products.html
+ - title: Purchasing Products
+ path: /training/in-app-billing/purchase-iab-products.html
+ - title: Testing Your App
+ path: /training/in-app-billing/test-iab-app.html
+ - title: Maintaining Multiple APKs
+ path: /training/multiple-apks/index.html
+ custom_link_attributes:
+ - description="How to publish your app on Google Play with separate APKs that target different devices, while using a single app listing."
+ section:
+ - title: Creating Multiple APKs for Different API Levels
+ path: /training/multiple-apks/api.html
+ - title: Creating Multiple APKs for Different Screen Sizes
+ path: /training/multiple-apks/screensize.html
+ - title: Creating Multiple APKs for Different GL Textures
+ path: /training/multiple-apks/texture.html
+ - title: Creating Multiple APKs with 2+ Dimensions
+ path: /training/multiple-apks/multiple.html
diff --git a/docs/html/training/accessibility/index.jd b/docs/html/training/accessibility/index.jd
index ea54dc4..7a5d6d7 100644
--- a/docs/html/training/accessibility/index.jd
+++ b/docs/html/training/accessibility/index.jd
@@ -50,5 +50,7 @@
and uses that information to communicate with the user. The example will
use a text-to-speech engine to speak to the user.</dd>
+ <dt><b><a href="testing.html">Accessibility Checklist</a></b></dt>
+ <dd>Learn how to test your app for accessibility.</dd>
</dl>
diff --git a/docs/html/training/accessibility/service.jd b/docs/html/training/accessibility/service.jd
old mode 100644
new mode 100755
index 953c558..5b99c46
--- a/docs/html/training/accessibility/service.jd
+++ b/docs/html/training/accessibility/service.jd
@@ -132,7 +132,7 @@
}
</pre>
-<p>Starting with Android 4.0, there is a second option available: configure the
+<p>The second option is to configure the
service using an XML file. Certain configuration options like
{@link android.R.attr#canRetrieveWindowContent} are only available if you
configure your service using XML. The same configuration options above, defined
@@ -201,8 +201,7 @@
</pre>
<h2 id="query">Query the View Heirarchy for More Context</h2>
-<p>This step is optional, but highly useful. One of the new features in Android
-4.0 (API Level 14) is the ability for an
+<p>This step is optional, but highly useful. The Android platform provides the ability for an
{@link android.accessibilityservice.AccessibilityService} to query the view
hierarchy, collecting information about the UI component that generated an event, and
its parent and children. In order to do this, make sure that you set the
diff --git a/docs/html/training/accessibility/testing.jd b/docs/html/training/accessibility/testing.jd
new file mode 100644
index 0000000..6563f4e
--- /dev/null
+++ b/docs/html/training/accessibility/testing.jd
@@ -0,0 +1,257 @@
+page.title=Accessibility Testing Checklist
+page.tags=testing,accessibility
+
+trainingnavtop=true
+startpage=true
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>Checklist sections</h2>
+ <ol>
+ <li><a href="#goals">Testing Goals</a></li>
+ <li><a href="#requirements">Testing Requirements</a></li>
+ <li><a href="#recommendations">Testing Recommendations</a></li>
+ <li><a href="#special-cases">Special Cases and Considerations</a></li>
+ <li><a href="#how-to">Testing Accessibility Features</a>
+ <ol>
+ <li><a href="#test-audibles">Testing audible feedback</a></li>
+ <li><a href="#test-navigation">Testing focus navigation</a></li>
+ <li><a href="#test-gestures">Testing gesture navigation</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ol>
+ <li>
+ <a href="{@docRoot}guide/topics/ui/accessibility/checklist.html">
+ Accessibility Developer Checklist</a>
+ </li>
+ <li>
+ <a href="{@docRoot}design/patterns/accessibility.html">
+ Android Design: Accessibility</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/ui/accessibility/apps.html">
+ Making Applications Accessible</a>
+ </li>
+ </ol>
+ </div>
+</div>
+<p>
+ Testing is an important part of making your application accessible to users with varying
+ abilities. Following <a href="{@docRoot}design/patterns/accessibility.html">design</a> and
+ <a href="{@docRoot}guide/topics/ui/accessibility/checklist.html">development</a> guidelines for
+ accessibility are important steps toward that goal, but testing for accessibility can uncover
+ problems with user interaction that are not obvious during design and development.</p>
+
+<p>This accessibility testing checklist guides you through the important aspects of
+ accessibility testing, including overall goals, required testing steps, recommended testing and
+ special considerations. This document also discusses how to enable accessibility features on
+ Android devices for testing purposes.</p>
+
+
+<h2 id="goals">Testing Goals</h2>
+
+<p>Your accessibility testing should have the following, high level goals:</p>
+
+<ul>
+ <li>Set up and use the application without sighted assistance</li>
+ <li>All task workflows in the application can be easily navigated using directional controls and
+ provide clear and appropriate feedback</li>
+</ul>
+
+
+<h2 id="requirements">Testing Requirements</h2>
+
+<p>The following tests must be completed in order to ensure a minimum level of application
+ accessibility.</p>
+
+<ol>
+ <li><strong>Directional controls:</strong> Verify that the application can be operated
+ without the use of a touch screen. Attempt to use only directional controls to accomplish the
+ primary tasks in the application. Use the keyboard and directional-pad (D-Pad) controls in the
+ Android <a href="{@docRoot}tools/devices/emulator.html">Emulator</a> or use
+ <a href="http://support.google.com/nexus/bin/answer.py?hl=en&answer=2700718">gesture
+ navigation</a> on devices with Android 4.1 (API Level 16) or higher.
+ <p class="note"><strong>Note:</strong> Keyboards and D-pads provide different navigation paths
+ than accessibility gestures. While gestures allow users to focus on nearly any on-screen
+ content, keyboard and D-pad navigation only allow focus on input fields and buttons.</p>
+ </li>
+ <li><strong>TalkBack audio prompts:</strong> Verify that user interface controls that provide
+ information (graphics or text) or allow user action have clear and accurate audio descriptions
+ when <a href="#testing-talkback">TalkBack is enabled</a> and controls are focused. Use
+ directional controls to move focus between application layout elements.</li>
+ <li><strong>Explore by Touch prompts:</strong> Verify that user interface controls that
+ provide information (graphics or text) or allow user action have appropriate audio descriptions
+ when <a href="#testing-ebt">Explore by Touch is enabled</a>. There should be no
+ regions where contents or controls do not provide an audio description.</li>
+ <li><strong>Touchable control sizes:</strong> All controls where a user can select or take an
+ action must be a minimum of 48 dp (approximately 9mm) in length and width, as recommended by
+ <a href="{@docRoot}design/patterns/accessibility.html">Android Design</a>.</li>
+ <li><strong>Gestures work with TalkBack enabled:</strong> Verify that app-specific gestures,
+ such as zooming images, scrolling lists, swiping between pages or navigating carousel controls
+ continue to work when <a href="#testing-talkback">TalkBack is enabled</a>. If these gestures do
+ not function, then an alternative interface for these actions must be provided.</li>
+ <li><strong>No audio-only feedback:</strong> Audio feedback must always have a secondary
+ feedback mechanism to support users who are deaf or hard of hearing, for example: A sound alert
+ for the arrival of a message should also be accompanied by a system
+ {@link android.app.Notification}, haptic feedback (if available) or another visual alert.</li>
+</ol>
+
+
+<h2 id="recommendations">Testing Recommendations</h2>
+
+<p>The following tests are recommended for ensuring the accessibility of your application. If you
+ do not test these items, it may impact the overall accessibility and quality of your
+ application.</p>
+
+<ol>
+ <li><strong>Repetitive audio prompting:</strong> Check that closely related controls (such as
+ items with multiple components in a list) do not simply repeat the same audio prompt. For
+ example, in a contacts list that contains a contact picture, written name and title, the prompts
+ should not simply repeat “Bob Smith” for each item.</li>
+ <li><strong>Audio prompt overloading or underloading:</strong> Check that closely related
+ controls provide an appropriate level of audio information that enables users to understand and
+ act on a screen element. Too little or too much prompting can make it difficult to understand
+ and use a control.</li>
+</ol>
+
+
+<h2 id="special-cases">Special Cases and Considerations</h2>
+
+<p>The following list describes specific situations that should be tested to ensure an
+ accessible app. Some, none or all of the cases described here may apply to your application. Be
+ sure to review this list to find out if these special cases apply and take appropriate action.</p>
+
+<ol>
+ <li><strong>Review developer special cases and considerations:</strong> Review the list of
+ <a href="{@docRoot}guide/topics/ui/accessibility/checklist.html#special-cases">special cases</a>
+ for accessibility development and test your application for the cases that apply.</li>
+ <li><strong>Prompts for controls that change function:</strong> Buttons or other controls
+ that change function due to application context or workflow must provide audio prompts
+ appropriate to their current function. For example, a button that changes function from play
+ video to pause video should provide an audio prompt which is appropriate to its current state.</li>
+ <li><strong>Video playback and captioning:</strong> If the application provides video
+ playback, verify that it supports captioning and subtitles to assist users who are deaf or hard
+ of hearing. The video playback controls must clearly indicate if captioning is available for a
+ video and provide a clear way of enabling captions.</li>
+</ol>
+
+
+<h2 id="how-to">Testing Accessibility Features</h2>
+
+<p>Testing of accessibility features such as TalkBack, Explore by Touch and accessibility Gestures
+requires setup of your testing device. This section describes how to enable these features for
+accessibility testing.</p>
+
+
+<h3 id="test-audibles">Testing audible feedback</h3>
+
+<p>Audible accessibility feedback features on Android devices provide audio prompts that speaks
+ the screen content as you move around an application. By enabling these features on an Android
+ device, you can test the experience of users with blindness or low-vision using your application.
+</p>
+
+<p>Audible feedback for users on Android is typically provided by TalkBack accessibility service and
+the Explore by Touch system feature. The TalkBack accessibility service comes preinstalled on most
+Android devices and can also be downloaded for free from
+<a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">Google
+Play</a>. The Explore by Touch system feature is available on devices running Android 4.0 and later.
+</p>
+
+<h4 id="testing-talkback">Testing with TalkBack</h4>
+
+<p>The <em>TalkBack</em> accessibility service works by speaking the contents of user interface
+controls as the user moves focus onto controls. This service should be enabled as part of testing
+focus navigation and audible prompts.</p>
+
+<p>To enable the TalkBack accessibility service:</p>
+<ol>
+ <li>Launch the <strong>Settings</strong> application.</li>
+ <li>Navigate to the <strong>Accessibility</strong> category and select it.</li>
+ <li>Select <strong>Accessibility</strong> to enable it.</li>
+ <li>Select <strong>TalkBack</strong> to enable it.</li>
+</ol>
+
+<p class="note">
+ <strong>Note:</strong> While TalkBack is the most available Android accessibility service for
+ users with disabilities, other accessibility services are available and may be installed by users.
+</p>
+
+<p>For more information about using TalkBack, see
+<a href="https://support.google.com/accessibility/android/topic/3529932">TalkBack</a>.</p>
+
+<h4 id="testing-ebt">Testing with Explore by Touch</h4>
+
+<p>The <em>Explore by Touch</em> system feature is available on devices running Android 4.0 and
+ later, and works by enabling a special accessibility mode that allows users to drag a finger
+ around the interface of an application and hear the contents of the screen spoken. This feature
+ does not require screen elements to be focused using an directional controller, but listens for
+ hover events over user interface controls.
+</p>
+
+<p>To enable Explore by Touch on Android 4.0 and later:</p>
+<ol>
+ <li>Launch the <strong>Settings</strong> application.</li>
+ <li>Navigate to the <strong>Accessibility</strong> category and select it.</li>
+ <li>Select the <strong>TalkBack</strong> to enable it.
+ <p class="note"><strong>Note:</strong> On Android 4.1 (API Level 16) and higher, the system
+ provides a popup message to enable Explore by Touch. On older versions, you must follow the
+ step below.</p>
+ </li>
+ <li>Return to the <strong>Accessibility</strong> category and select <strong>Explore by
+Touch</strong> to enable it.
+ <p class="note"><strong>Note:</strong> You must turn on TalkBack <em>first</em>, otherwise this
+option is not available.</p>
+ </li>
+</ol>
+
+<p>For more information about using the Explore by Touch features, see
+<a href="https://support.google.com/accessibility/android/answer/6006598">Touch Exploration</a>.</p>
+
+<h3 id="test-navigation">Testing focus navigation</h3>
+
+<p>Focus navigation is the use of directional controls to navigate between the individual user
+ interface elements of an application in order to operate it. Users with limited vision or limited
+ manual dexterity often use this mode of navigation instead of touch navigation. As part of
+ accessibility testing, you should verify that your application can be operated using only
+ directional controls.</p>
+
+<p>You can test navigation of your application using only focus controls, even if your test devices
+ does not have a directional controller. The <a href="{@docRoot}tools/help/emulator.html">Android
+ Emulator</a> provides a simulated directional controller that you can use to test navigation. You
+ can also use a software-based directional controller, such as the one provided by the
+ <a href="https://play.google.com/store/apps/details?id=com.googlecode.eyesfree.inputmethod.latin"
+ >Eyes-Free Keyboard</a> to simulate use of a D-pad on a test device that does not have a physical
+ D-pad.</p>
+
+
+<h3 id="test-gestures">Testing gesture navigation</h3>
+
+<p>Gesture navigation is an accessibility navigation mode that allows users to navigate Android
+ devices and applications using specific
+ <a href="https://support.google.com/accessibility/android/answer/6006598">gestures</a>. This
+ navigation mode is available on Android 4.1 (API Level 16) and higher.</p>
+
+<p class="note"><strong>Note:</strong> Accessibility gestures provide a different navigation path
+than keyboards and D-pads. While gestures allow users to focus on nearly any on-screen
+content, keyboard and D-pad navigation only allow focus on input fields and buttons.</p>
+
+<p>To enable gesture navigation on Android 4.1 and later:</p>
+<ul>
+ <li>Enable both TalkBack and the Explore by Touch feature as described in the
+ <a href="#testing-ebt">Testing with Explore by Touch</a>. When <em>both</em> of these
+ features are enabled, accessibility gestures are automatically enabled.</li>
+ <li>You can change gesture settings using <strong>Settings > Accessibility > TalkBack >
+ Settings > Manage shortcut gestures</strong>.
+</ul>
+
+<p>For more information about using Explore by Touch accessibility gestures, see
+<a href="https://support.google.com/accessibility/android/answer/6006598">Touch Exploration</a>.</p>
+
+<p class="note">
+ <strong>Note:</strong> Accessibility services other than TalkBack may map accessibility gestures
+ to different user actions. If gestures are not producing the expected actions during testing, try
+ disabling other accessibility services before proceeding.</p>
\ No newline at end of file
diff --git a/docs/html/training/activity-testing/activity-basic-testing.jd b/docs/html/training/activity-testing/activity-basic-testing.jd
deleted file mode 100644
index 6f39bcd..0000000
--- a/docs/html/training/activity-testing/activity-basic-testing.jd
+++ /dev/null
@@ -1,227 +0,0 @@
-page.title=Creating and Running a Test Case
-trainingnavtop=true
-
-@jd:body
-
-<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#testcase">Create a Test Case for Activity Testing</a>
- <ol>
- <li><a href="#fixture">Set Up Your Test Fixture</a></li>
- <li><a href="#preconditions">Add Test Preconditions</a></li>
- <li><a href="#test_method">Add Test Methods to Verify Your Activity</a></li>
- </ol>
- </li>
- <li><a href="#build_run">Build and Run Your Test</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
-<li><a href="{@docRoot}tools/testing/testing_android.html">Testing
-Fundamentals</a></li>
-</ul>
-
-</div>
-</div>
-<p>In order to verify that there are no regressions in the layout design and
-functional behavior in your application, it's important to
-create a test for each {@link android.app.Activity} in your application. For
-each test, you need to create the individual parts of a test case, including
-the test fixture, preconditions test method, and {@link android.app.Activity}
-test methods. You can then run your test to get a test report. If any test
-method fails, this might indicate a potential defect in your code.</p>
-<p class="note"><strong>Note:</strong> In the Test-Driven Development (TDD)
-approach, instead of writing most or all of your app code up-front and then
-running tests later in the development cycle, you would progressively write
-just enough production code to satisfy your test dependencies, update your
-test cases to reflect new functional requirements, and iterate repeatedly this
-way.</p>
-
-<h2 id="testcase">Create a Test Case</h2>
-<p>{@link android.app.Activity} tests are written in a structured way.
-Make sure to put your tests in a separate package, distinct from the code under
-test.</p>
-<p>By convention, your test package name should follow the same name as the
-application package, suffixed with <strong>".tests"</strong>. In the test package
-you created, add the Java class for your test case. By convention, your test case
-name should also follow the same name as the Java or Android class that you
-want to test, but suffixed with <strong>“Test”</strong>.</p>
-<p>To create a new test case in Eclipse:</p>
-<ol type="a">
- <li>In the Package Explorer, right-click on the {@code /src} directory for
-your test project and select <strong>New > Package</strong>.</li>
- <li>Set the <strong>Name</strong> field to
-{@code <your_app_package_name>.tests} (for example,
-{@code com.example.android.testingfun.tests}) and click
-<strong>Finish</strong>.</li>
- <li>Right-click on the test package you created, and select
-<strong>New > Class</strong>.</li>
- <li>Set the <strong>Name</strong> field to
-{@code <your_app_activity_name>Test} (for example,
-{@code MyFirstTestActivityTest}) and click <strong>Finish</strong>.</li>
-</ol>
-
-<h3 id="fixture">Set Up Your Test Fixture</h3>
-<p>A <em>test fixture</em> consists of objects that must be initialized for
-running one or more tests. To set up the test fixture, you can override the
-{@link junit.framework.TestCase#setUp()} and
-{@link junit.framework.TestCase#tearDown()} methods in your test. The
-test runner automatically runs {@link junit.framework.TestCase#setUp()} before
-running any other test methods, and {@link junit.framework.TestCase#tearDown()}
-at the end of each test method execution. You can use these methods to keep
-the code for test initialization and clean up separate from the tests methods.
-</p>
-<p>To set up your test fixture in Eclipse:</p>
-<ol>
-<li>In the Package Explorer, double-click on the test case that you created
-earlier to bring up the Eclipse Java editor, then modify your test case class
-to extend one of the sub-classes of {@link android.test.ActivityTestCase}.
-<p>For example:</p>
-<pre>
-public class MyFirstTestActivityTest
- extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
-</pre>
-</li>
-<li>Next, add the constructor and {@link junit.framework.TestCase#setUp()}
-methods to your test case, and add variable declarations for the
-{@link android.app.Activity} that you want to test.</p>
-<p>For example:</p>
-<pre>
-public class MyFirstTestActivityTest
- extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
-
- private MyFirstTestActivity mFirstTestActivity;
- private TextView mFirstTestText;
-
- public MyFirstTestActivityTest() {
- super(MyFirstTestActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mFirstTestActivity = getActivity();
- mFirstTestText =
- (TextView) mFirstTestActivity
- .findViewById(R.id.my_first_test_text_view);
- }
-}
-</pre>
-<p>The constructor is invoked by the test runner to instantiate the test
-class, while the {@link junit.framework.TestCase#setUp()} method is invoked by
-the test runner before it runs any tests in the test class.</p>
-</li>
-</ol>
-
-<p>Typically, in the {@link junit.framework.TestCase#setUp()} method, you
-should:</p>
-<ul>
-<li>Invoke the superclass constructor for
-{@link junit.framework.TestCase#setUp()}, which is required by JUnit.</li>
-<li>Initialize your test fixture state by:
- <ul>
- <li>Defining the instance variables that store the state of the fixture.</li>
- <li>Creating and storing a reference to an instance of the
-{@link android.app.Activity} under test.</li>
- <li>Obtaining a reference to any UI components in the
-{@link android.app.Activity} that you want to test.</li>
- </ul>
-</ul>
-
-<p>You can use the
-{@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to
-get a reference to the {@link android.app.Activity} under test.</p>
-
-<h3 id="preconditions">Add Test Preconditions</h3>
-<p>As a sanity check, it is good practice to verify that the test fixture has
-been set up correctly, and the objects that you want to test have been correctly
-instantiated or initialized. That way, you won’t have to see
-tests failing because something was wrong with the setup of your test fixture.
-By convention, the method for verifying your test fixture is called
-{@code testPreconditions()}.</p>
-
-<p>For example, you might want to add a {@code testPreconditons()} method like
-this to your test case:</p>
-
-<pre>
-public void testPreconditions() {
- assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity);
- assertNotNull(“mFirstTestText is null”, mFirstTestText);
-}
-</pre>
-
-<p>The assertion methods are from the JUnit {@link junit.framework.Assert}
-class. Generally, you can use assertions to
-verify if a specific condition that you want to test is true.
-<ul>
-<li>If the condition is false, the assertion method throws an
-{@link android.test.AssertionFailedError} exception, which is then typically
-reported by the test runner. You can provide a string in the first argument of
-your assertion method to give some contextual details if the assertion fails.</li>
-<li>If the condition is true, the test passes.</li>
-</ul>
-<p>In both cases, the test runner proceeds to run the other test methods in the
-test case.</p>
-
-<h3 id="test_method">Add Test Methods to Verify Your Activity</h3>
-<p>Next, add one or more test methods to verify the layout and functional
-behavior of your {@link android.app.Activity}.</p>
-<p>For example, if your {@link android.app.Activity} includes a
-{@link android.widget.TextView}, you can add a test method like this to check
-that it has the correct label text:</p>
-<pre>
-public void testMyFirstTestTextView_labelText() {
- final String expected =
- mFirstTestActivity.getString(R.string.my_first_test);
- final String actual = mFirstTestText.getText().toString();
- assertEquals(expected, actual);
-}
-</pre>
-
-<p>The {@code testMyFirstTestTextView_labelText()} method simply checks that the
-default text of the {@link android.widget.TextView} that is set by the layout
-is the same as the expected text defined in the {@code strings.xml} resource.</p>
-<p class="note"><strong>Note:</strong> When naming test methods, you can use
-an underscore to separate what is being tested from the specific case being
-tested. This style makes it easier to see exactly what cases are being tested.</p>
-<p>When doing this type of string value comparison, it’s good practice to read
-the expected string from your resources, instead of hardcoding the string in
-your comparison code. This prevents your test from easily breaking whenever the
-string definitions are modified in the resource file.</p>
-<p>To perform the comparison, pass both the expected and actual strings as
-arguments to the
-{@link junit.framework.Assert#assertEquals(java.lang.String, java.lang.String) assertEquals()}
-method. If the values are not the same, the assertion will throw an
-{@link junit.framework.AssertionFailedError} exception.</p>
-<p>If you added a {@code testPreconditions()} method, put your test methods
-after the {@code testPreconditions()} definition in your Java class.</p>
-<p>For a complete test case example, take a look at
-{@code MyFirstTestActivityTest.java} in the sample app.</p>
-
-<h2 id="build_run">Build and Run Your Test</h2>
-<p>You can build and run your test easily from the Package Explorer in
-Eclipse.</p>
-<p>To build and run your test:</p>
-<ol>
-<li>Connect an Android device to your machine. On the device or emulator, open
-the <strong>Settings</strong> menu, select <strong>Developer options</strong>
-and make sure that USB debugging is enabled.</li>
-<li>In the Project Explorer, right-click on the test class that you created
-earlier and select <strong>Run As > Android Junit Test</strong>.</li>
-<li>In the Android Device Chooser dialog, select the device that you just
-connected, then click <strong>OK</strong>.</li>
-<li>In the JUnit view, verify that the test passes with no errors or failures.</li>
-</ol>
-<p>For example, if the test case passes with no errors, the result should look
-like this:</p>
-<img src="{@docRoot}images/training/activity-testing_lesson2_MyFirstTestActivityTest_result.png" alt="" />
-<p class="img-caption">
- <strong>Figure 1.</strong> Result of a test with no errors.
-</p>
-
-
-
diff --git a/docs/html/training/activity-testing/activity-functional-testing.jd b/docs/html/training/activity-testing/activity-functional-testing.jd
deleted file mode 100644
index 7c8ff1d..0000000
--- a/docs/html/training/activity-testing/activity-functional-testing.jd
+++ /dev/null
@@ -1,166 +0,0 @@
-page.title=Creating Functional Tests
-trainingnavtop=true
-@jd:body
-
-<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#test_methods">Add Test Method to Validate Functional Behavior</a>
- <ol>
- <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li>
- <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li>
- </ol>
- </li>
-</ol>
-
-<h2>Try it out</h2>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
-class="button">Download the demo</a>
- <p class="filename">AndroidTestingFun.zip</p>
-</div>
-
-</div>
-</div>
-<p>Functional testing involves verifying that individual application
-components work together as expected by the user. For example, you can create a
-functional test to verify that an {@link android.app.Activity} correctly
-launches a target {@link android.app.Activity} when the user performs a UI
-interaction.</p>
-
-<p>To create a functional test for your {@link android.app.Activity}, your test
-class should extend {@link android.test.ActivityInstrumentationTestCase2}.
-Unlike {@link android.test.ActivityUnitTestCase},
-tests in {@link android.test.ActivityInstrumentationTestCase2} can
-communicate with the Android system and send keyboard input and click events to
-the UI.</p>
-
-<p>For a complete test case example, take a look at
-{@code SenderActivityTest.java} in the sample app.</p>
-
-<h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2>
-<p id="test_goals">Your functional testing goals might include:</p>
-<ul>
-<li>Verifying that a target {@link android.app.Activity} is started when a
-UI control is pushed in the sender {@link android.app.Activity}.</li>
-<li>Verifying that the target {@link android.app.Activity} displays the
-correct data based on the user's input in the sender
-{@link android.app.Activity}.</li>
-</ul>
-<p>You might implement your test method like this:</p>
-
-<pre>
-@MediumTest
-public void testSendMessageToReceiverActivity() {
- final Button sendToReceiverButton = (Button)
- mSenderActivity.findViewById(R.id.send_message_button);
-
- final EditText senderMessageEditText = (EditText)
- mSenderActivity.findViewById(R.id.message_input_edit_text);
-
- // Set up an ActivityMonitor
- ...
-
- // Send string input value
- ...
-
- // Validate that ReceiverActivity is started
- ...
-
- // Validate that ReceiverActivity has the correct data
- ...
-
- // Remove the ActivityMonitor
- ...
-}
-</pre>
-<p>The test waits for an {@link android.app.Activity} that matches this monitor,
-otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was
-started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}
-that you set
-up earlier receives a hit. You can use the assertion methods to verify that
-the {@code ReceiverActivity} is indeed started, and that the hit count on the
-{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented
-as expected.</p>
-
-<h2 id="activitymonitor">Set up an ActivityMonitor</h2>
-<p>To monitor a single {@link android.app.Activity} in your application, you
-can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}.
-The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is
-notified by the system whenever an {@link android.app.Activity} that matches your criteria is started.
-If a match is found, the monitor’s hit count is updated.</p>
-<p>Generally, to use an
-{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p>
-<ol>
-<li>Retrieve the {@link android.app.Instrumentation} instance for your test
-case by using the
-{@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li>
-<li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to
-the current instrumentation using one of the {@link android.app.Instrumentation}
-{@code addMonitor()} methods. The match criteria can be specified as an
-{@link android.content.IntentFilter} or a class name string.</li>
-<li>Wait for the {@link android.app.Activity} to start.</li>
-<li>Verify that the monitor hits were incremented.</li>
-<li>Remove the monitor.</li>
-</ol>
-<p>For example:</p>
-<pre>
-// Set up an ActivityMonitor
-ActivityMonitor receiverActivityMonitor =
- getInstrumentation().addMonitor(ReceiverActivity.class.getName(),
- null, false);
-
-// Validate that ReceiverActivity is started
-TouchUtils.clickView(this, sendToReceiverButton);
-ReceiverActivity receiverActivity = (ReceiverActivity)
- receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS);
-assertNotNull("ReceiverActivity is null", receiverActivity);
-assertEquals("Monitor for ReceiverActivity has not been called",
- 1, receiverActivityMonitor.getHits());
-assertEquals("Activity is of wrong type",
- ReceiverActivity.class, receiverActivity.getClass());
-
-// Remove the ActivityMonitor
-getInstrumentation().removeMonitor(receiverActivityMonitor);
-</pre>
-
-<h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2>
-<p>If your {@link android.app.Activity} has an {@link android.widget.EditText}
-field, you might want to test that users can enter values into the
-{@link android.widget.EditText} object.</p>
-<p>Generally, to send a string input value to an {@link android.widget.EditText}
-object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p>
-<ol>
-<li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()}
-method to run the {@link android.view.View#requestFocus()} call synchronously
-in a loop. This way, the UI thread is blocked until focus is received.</li>
-<li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait
-for the main thread to become idle (that is, have no more events to process).</li>
-<li>Send a text string to the {@link android.widget.EditText} by calling
-{@link android.app.Instrumentation#sendStringSync(java.lang.String)
-sendStringSync()} and pass your input string as the parameter.</p>
-</ol>
-<p>For example:</p>
-<pre>
-// Send string input value
-getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- senderMessageEditText.requestFocus();
- }
-});
-getInstrumentation().waitForIdleSync();
-getInstrumentation().sendStringSync("Hello Android!");
-getInstrumentation().waitForIdleSync();
-</pre>
-
-
-
-
-
-
-
-
diff --git a/docs/html/training/activity-testing/activity-ui-testing.jd b/docs/html/training/activity-testing/activity-ui-testing.jd
deleted file mode 100644
index a47ccf3..0000000
--- a/docs/html/training/activity-testing/activity-ui-testing.jd
+++ /dev/null
@@ -1,216 +0,0 @@
-page.title=Testing UI Components
-trainingnavtop=true
-
-@jd:body
-
-<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#testcase">Create a Test Case for UI Testing with Instrumentation</a>
- <li><a href="#test_method">Add Test Methods to Verify UI Behavior</a>
- <ol>
- <li><a href="#verify_button_display">Verify Button Layout Parameters</a></li>
- <li><a href="#verify_TextView">Verify TextView Layout Parameters</a></li>
- <li><a href="#verify_button_behavior">Verify Button Behavior</a></li>
- </ol>
- </li>
- <li><a href="#annotations">Apply Test Annotations</a></li>
-</ol>
-
-<h2>Try it out</h2>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
-class="button">Download the demo</a>
- <p class="filename">AndroidTestingFun.zip</p>
-</div>
-
-</div>
-</div>
-
-<p>Typically, your {@link android.app.Activity} includes user interface
-components (such as buttons, editable text fields, checkboxes, and pickers) to
-allow users to interact with your Android application. This lesson shows how
-you can test an {@link android.app.Activity} with a simple push-button UI. You
-can use the same general steps to test other, more sophisticated types of UI
-components.</p>
-
-<p class="note"><strong>Note:</strong> The type of UI testing in this lesson is
-called <em>white-box testing</em> because you have the
-source code for the application that you want to test. The Android
-<a href="{@docRoot}tools/testing/testing_android.html#Instrumentation">Instrumentation</a>
-framework is suitable for creating white-box tests for UI components within an
-application. An alternative type of UI testing is <em>black-box testing</em>,
-where you may not have access to the application source. This type of testing
-is useful when you want to test how your app interacts with other apps or with
-the system. Black-box testing is not covered in this training. To learn more
-about how to perform black-box testing on your Android apps, see the
-<a href="{@docRoot}tools/testing/testing_ui.html">UI Testing guide</a>.
-<p>For a complete test case example, take a look at
-{@code ClickFunActivityTest.java} in the sample app.</p>
-
-<h2 id="testcase">Create a Test Case for UI Testing with Instrumentation</h2>
-<p>When testing an {@link android.app.Activity} that has a user interface (UI),
-the {@link android.app.Activity} under test runs in the UI thread. However, the
-test application itself runs in a separate thread in the same process as the
-application under test. This means that your test app can reference objects
-from the UI thread, but if it attempts to change properties on those objects or
-send events to the UI thread, you will usually get a {@code WrongThreadException}
-error.</p>
-<p>To safely inject {@link android.content.Intent} objects into your
-{@link android.app.Activity} or run test methods on the UI thread, you can
-extend your test class to use {@link android.test.ActivityInstrumentationTestCase2}.
-To learn more about how to run test methods on the UI thread, see
-<a href="{@docRoot}tools/testing/activity_testing.html#RunOnUIThread">Testing
-on the UI thread</a>.</p>
-
-<h3 id="fixture">Set Up Your Test Fixture</h3>
-<p>When setting up the test fixture for UI testing, you should specify the
-<a href="{@docRoot}guide/topics/ui/ui-events.html#TouchMode">touch mode</a>
-in your {@link junit.framework.TestCase#setUp()} method. Setting the touch mode
-to {@code true} prevents the UI control from taking focus when you click it
-programmatically in the test method later (for example, a button UI will just
-fire its on-click listener). Make sure that you call
-{@link android.test.ActivityInstrumentationTestCase2#setActivityInitialTouchMode(boolean) setActivityInitialTouchMode()}
-before calling {@link android.test.ActivityInstrumentationTestCase2#getActivity()}.
-</p>
-<p>For example:</ap>
-<pre>
-public class ClickFunActivityTest
- extends ActivityInstrumentationTestCase2<ClickFunActivity> {
- ...
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- setActivityInitialTouchMode(true);
-
- mClickFunActivity = getActivity();
- mClickMeButton = (Button)
- mClickFunActivity
- .findViewById(R.id.launch_next_activity_button);
- mInfoTextView = (TextView)
- mClickFunActivity.findViewById(R.id.info_text_view);
- }
-}
-</pre>
-
-<h2 id="test_methods">Add Test Methods to Validate UI Behavior</h2>
-<p id="test_goals">Your UI testing goals might include:</p>
-<ul>
-<li>Verifying that a button is displayed with the correct layout when the
-{@link android.app.Activity} is launched.</li>
-<li>Verifying that a {@link android.widget.TextView} is initially hidden.</li>
-<li>Verifying that a {@link android.widget.TextView} displays the expected string
-when a button is pushed.</li>
-</ul>
-<p>The following section demonstrates how you can implement test methods
-to perform these verifications.</p>
-
-<h3 id="verify_button_display">Verify Button Layout Parameters</h3>
-<p>You might add a test method like this to verify that a button is displayed
-correctly in your {@link android.app.Activity}:</p>
-<pre>
-@MediumTest
-public void testClickMeButton_layout() {
- final View decorView = mClickFunActivity.getWindow().getDecorView();
-
- ViewAsserts.assertOnScreen(decorView, mClickMeButton);
-
- final ViewGroup.LayoutParams layoutParams =
- mClickMeButton.getLayoutParams();
- assertNotNull(layoutParams);
- assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT);
- assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT);
-}
-</pre>
-
-<p>In the {@link android.test.ViewAsserts#assertOnScreen(android.view.View,android.view.View) assertOnScreen()}
-method call, you should pass in the root view and the view that you are
-expecting to be present on the screen. If the expected view is not found in the
-root view, the assertion method throws an {@link junit.framework.AssertionFailedError}
-exception, otherwise the test passes.</p>
-<p>You can also verify that the layout of a {@link android.widget.Button} is
-correct by getting a reference to its {@link android.view.ViewGroup.LayoutParams}
-object, then call assertion methods to verify that the
-{@link android.widget.Button} object's width and height attributes match the
-expected values.</p>
-<p>The {@code @MediumTest} annotation specifies how the test is categorized,
-relative to its absolute execution time. To learn more about using test size
-annotations, see <a href="#annotations">Apply Test Annotations</a>.</p>
-
-<h3 id="verify_TextView">Verify TextView Layout Parameters</h3>
-<p>You might add a test method like this to verify that a
-{@link android.widget.TextView} initially appears hidden in
-your {@link android.app.Activity}:</p>
-<pre>
-@MediumTest
-public void testInfoTextView_layout() {
- final View decorView = mClickFunActivity.getWindow().getDecorView();
- ViewAsserts.assertOnScreen(decorView, mInfoTextView);
- assertTrue(View.GONE == mInfoTextView.getVisibility());
-}
-</pre>
-<p>You can call {@link android.view.Window#getDecorView()} to get a reference
-to the decor view for the {@link android.app.Activity}. The decor view is the
-top-level ViewGroup ({@link android.widget.FrameLayout}) view in the layout
-hierarchy.</p>
-
-<h3 id="verify_button_behavior">Verify Button Behavior</h3>
-<p>You can use a test method like this to verify that a
-{@link android.widget.TextView} becomes visible when a
-{@link android.widget.Button} is pushed:</p>
-
-<pre>
-@MediumTest
-public void testClickMeButton_clickButtonAndExpectInfoText() {
- String expectedInfoText = mClickFunActivity.getString(R.string.info_text);
- TouchUtils.clickView(this, mClickMeButton);
- assertTrue(View.VISIBLE == mInfoTextView.getVisibility());
- assertEquals(expectedInfoText, mInfoTextView.getText());
-}
-</pre>
-
-<p>To programmatically click a {@link android.widget.Button} in your
-test, call {@link android.test.TouchUtils#clickView(android.test.InstrumentationTestCase,android.view.View) clickView()}.
-You must pass in a reference to the test case that is being run and a reference
-to the {@link android.widget.Button} to manipulate.</p>
-
-<p class="note"><strong>Note: </strong>The {@link android.test.TouchUtils}
-helper class provides convenience methods for simulating touch interactions
-with your application. You can use these methods to simulate clicking, tapping,
-and dragging of Views or the application screen.</p>
-<p class="caution"><strong>Caution: </strong>The {@link android.test.TouchUtils}
-methods are designed to send events to the UI thread safely from the test thread.
-You should not run {@link android.test.TouchUtils} directly in the UI thread or
-any test method annotated with {@code @UIThread}. Doing so might
-raise the {@code WrongThreadException}.</p>
-
-<h2 id="annotations">Apply Test Annotations</h2>
-<p>The following annotations can be applied to indicate the size of a test
-method:</p>
-<dl>
-<dt>{@link
-android.test.suitebuilder.annotation.SmallTest @SmallTest}</dt>
-<dd>Marks a test that should run as part of the small tests.</dd>
-<dt>{@link
-android.test.suitebuilder.annotation.MediumTest @MediumTest}</dt>
-<dd>Marks a test that should run as part of the medium tests.</dd>
-<dt>{@link android.test.suitebuilder.annotation.LargeTest @LargeTest}</dt>
-<dd>Marks a test that should run as part of the large tests.</dd>
-</dl>
-<p>Typically, a short running test that take only a few milliseconds should be
-marked as a {@code @SmallTest}. Longer running tests (100 milliseconds or
-more) are usually marked as {@code @MediumTest}s or {@code @LargeTest}s,
-depending on whether the test accesses resources on the local system only or
-remote resources over a network. For guidance on using test size annotations,
-see this <a href="https://plus.sandbox.google.com/+AndroidDevelopers/posts/TPy1EeSaSg8">Android Tools Protip</a>.</p>
-<p>You can mark up your test methods with other test annotations to control
-how the tests are organized and run. For more information on other annotations,
-see the {@link java.lang.annotation.Annotation} class reference.</p>
-
-
-
-
diff --git a/docs/html/training/activity-testing/activity-unit-testing.jd b/docs/html/training/activity-testing/activity-unit-testing.jd
deleted file mode 100644
index 74dcda9..0000000
--- a/docs/html/training/activity-testing/activity-unit-testing.jd
+++ /dev/null
@@ -1,134 +0,0 @@
-page.title=Creating Unit Tests
-trainingnavtop=true
-@jd:body
-
-<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#testcase">Create a Test Case for Activity Unit Testing</a>
- <li><a href="#test_method">Validate Launch of Another Activity</a>
-</ol>
-
-<h2>Try it out</h2>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
-class="button">Download the demo</a>
- <p class="filename">AndroidTestingFun.zip</p>
-</div>
-
-</div>
-</div>
-
-<p>An {@link android.app.Activity} unit test is an excellent way to quickly
-verify the state of an {@link android.app.Activity} and its interactions with
-other components in isolation (that is, disconnected from the rest of the
-system). A unit test generally tests the smallest possible unit of code
-(which could be a method, class, or component), without dependencies on system
-or network resources. For example, you can write a unit test to check
-that an {@link android.app.Activity} has the correct layout or that it
-triggers an {@link android.content.Intent} object correctly.</p>
-<p>Unit tests are generally not suitable for testing complex UI interaction
-events with the system. Instead, you should use
-the {@link android.test.ActivityInstrumentationTestCase2} class, as described
-in <a href="activity-ui-testing.html">Testing UI Components</a>.</p>
-<p>This lesson shows how you can write a unit test to verify that an
-{@link android.content.Intent} is triggered to launch another
-{@link android.app.Activity}.
-Since the test runs in an isolated environment, the
-{@link android.content.Intent}
-is not actually sent to the Android system, but you can inspect that the
-{@link android.content.Intent} object's payload data is accurate.</p>
-<p>For a complete test case example, take a look at
-{@code LaunchActivityTest.java} in the sample app.</p>
-
-<p class="note"><strong>Note: </strong>To test against system or external
-dependencies, you can use mock objects from a mocking
-framework and inject them into your unit tests. To learn more about the mocking
-framework provided by Android, see
-<a href="{@docRoot}tools/testing/testing_android.html#MockObjectClasses}">Mock
-Object Classes</a>.</p>
-
-<h2 id="testcase">Create a Test Case for Activity Unit Testing</h2>
-<p>The {@link android.test.ActivityUnitTestCase} class provides support for
-isolated testing of a single {@link android.app.Activity}. To create a unit
-test for your {@link android.app.Activity}, your test class should extend
-{@link android.test.ActivityUnitTestCase}.</p>
-
-<p>The {@link android.app.Activity} in an {@link android.test.ActivityUnitTestCase}
-is not automatically started by Android Instrumentation. To start the
-{@link android.app.Activity} in isolation, you need to explicitly call the
-{@link android.test.ActivityUnitTestCase#startActivity(android.content.Intent, android.os.Bundle, java.lang.Object) startActivity()}
-method, and pass in the {@link android.content.Intent} to
-launch your target {@link android.app.Activity}.</p>
-
-<p>For example:</p>
-<pre>
-public class LaunchActivityTest
- extends ActivityUnitTestCase<LaunchActivity> {
- ...
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mLaunchIntent = new Intent(getInstrumentation()
- .getTargetContext(), LaunchActivity.class);
- startActivity(mLaunchIntent, null, null);
- final Button launchNextButton =
- (Button) getActivity()
- .findViewById(R.id.launch_next_activity_button);
- }
-}
-</pre>
-
-<h2 id="test_method">Validate Launch of Another Activity</h2>
-<p id="test_goals">Your unit testing goals might include:</p>
-<ul>
-<li>Verifying that {@code LaunchActivity} fires an
-{@link android.content.Intent} when a button is pushed clicked.</li>
-<li>Verifying that the launched {@link android.content.Intent} contains the
-correct payload data.</li>
-</ul>
-
-<p>To verify if an {@link android.content.Intent} was triggered
-following the {@link android.widget.Button} click, you can use the
-{@link android.test.ActivityUnitTestCase#getStartedActivityIntent()} method.
-By using assertion methods, you can verify that the returned
-{@link android.content.Intent} is not null, and that it contains the expected
-string value to launch the next {@link android.app.Activity}. If both assertions
-evaluate to {@code true}, you've successfully verified that the
-{@link android.content.Intent} was correctly sent by your
-{@link android.app.Activity}.</p>
-
-<p>You might implement your test method like this:</p>
-<pre>
-@MediumTest
-public void testNextActivityWasLaunchedWithIntent() {
- startActivity(mLaunchIntent, null, null);
- final Button launchNextButton =
- (Button) getActivity()
- .findViewById(R.id.launch_next_activity_button);
- launchNextButton.performClick();
-
- final Intent launchIntent = getStartedActivityIntent();
- assertNotNull("Intent was null", launchIntent);
- assertTrue(isFinishCalled());
-
- final String payload =
- launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY);
- assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD, payload);
-}
-</pre>
-<p>Because {@code LaunchActivity} runs in isolation, you cannot use the
-{@link android.test.TouchUtils} library to manipulate UI controls. To directly
-click a {@link android.widget.Button}, you can call the
-{@link android.view.View#performClick()} method instead.</p>
-
-
-
-
-
-
-
diff --git a/docs/html/training/activity-testing/index.jd b/docs/html/training/activity-testing/index.jd
deleted file mode 100644
index b9542b6..0000000
--- a/docs/html/training/activity-testing/index.jd
+++ /dev/null
@@ -1,68 +0,0 @@
-page.title=Testing Your Android Activity
-page.tags=testing
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.2 (API Level 8) or higher.</li>
-</ul>
-
-<h2>You Should Also Read</h2>
-<ul>
-<li><a href="{@docRoot}tools/testing/index.html">Testing
-(Developer's Guide)</a></li>
-</ul>
-
-</div>
-</div>
-
-<p>You should be writing and running tests as part of your Android application
-development cycle. Well-written tests can help you to catch bugs early in
-development and give you confidence in your code.</p>
-
-<p>A <em>test case</em> defines a set of objects and methods to run multiple
-tests independently from each other. Test cases can be organized into
-<em>test suites</em> and run programmatically, in a repeatable manner, with
-a <em>test runner</em> provided by a testing framework.</p>
-
-<p>The lessons in this class teaches you how to use the Android's custom
-testing framework that is based on the popular JUnit framework. You can
-write test cases to verify specific behavior in your application, and check for
-consistency across different Android devices. Your test cases also serve as a
-form of internal code documentation by describing the expected behavior of
-app components.</p>
-
-<h2>Lessons</h2>
-
-<!-- Create a list of the lessons in this class along with a short description
-of each lesson. These should be short and to the point. It should be clear from
-reading the summary whether someone will want to jump to a lesson or not.-->
-
-<dl>
- <dt><b><a href="preparing-activity-testing.html">Setting Up Your Test
-Environment</a></b></dt>
- <dd>Learn how to create your test project.</dd>
- <dt><b><a href="activity-basic-testing.html">Creating and Running a Test
-Case</a></b></dt>
- <dd>Learn how to write test cases to verify the
-expected properties of your {@link android.app.Activity}, and run the test
-cases with the {@code Instrumentation} test runner provided by the Android
-framework.</dd>
- <dt><b><a href="activity-ui-testing.html">Testing UI Components</a></b></dt>
- <dd>Learn how to test the behavior of specific UI
-components in your {@link android.app.Activity}.</dd>
- <dt><b><a href="activity-unit-testing.html">Creating Unit Tests</a></b></dt>
- <dd>Learn how to how to perform unit testing to
-verify the behavior of an Activity in isolation.</dd>
- <dt><b><a href="activity-functional-testing.html">Creating Functional Tests</a></b></dt>
- <dd>Learn how to perform functional testing to
-verify the interaction of multiple Activities.</dd>
-
diff --git a/docs/html/training/activity-testing/preparing-activity-testing.jd b/docs/html/training/activity-testing/preparing-activity-testing.jd
deleted file mode 100644
index c43c9ed..0000000
--- a/docs/html/training/activity-testing/preparing-activity-testing.jd
+++ /dev/null
@@ -1,95 +0,0 @@
-page.title=Setting Up Your Test Environment
-trainingnavtop=true
-
-@jd:body
-
-<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#eclipse">Set Up Eclipse for Testing</a></li>
- <li><a href="#cmdline">Set Up the Command Line Interface for Testing</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
-<li><a href="{@docRoot}sdk/index.html">Getting the SDK Bundle</a></li>
-<li><a href="{@docRoot}tools/testing/testing_eclipse.html">Testing from Eclipse
-with ADT</a></li>
-<li><a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other
-IDEs</a></li>
-</ul>
-
-<h2>Try it out</h2>
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
-class="button">Download the demo</a>
- <p class="filename">AndroidTestingFun.zip</p>
-</div>
-
-</div>
-</div>
-
-<p>Before you start writing and running your tests, you should set up your test
-development environment. This lesson teaches you how to set up the Eclipse
-IDE to build and run tests, and how to
-build and run tests with the Gradle framework by using the command line
-interface.</p>
-
-<p class="note"><strong>Note:</strong> To help you get started, the lessons are
-based on Eclipse with the ADT plugin. However, for your own test development, you
-are free to use the IDE of your choice or the command-line.</p>
-
-<h2 id="eclipse">Set Up Eclipse for Testing</h2>
-<p>Eclipse with the Android Developer Tools (ADT) plugin provides an integrated
-development environment for you to create, build, and run Android application
-test cases from a graphical user interface (GUI). A convenient feature that
-Eclipse provides is the ability to auto-generate a new test project that
-corresponds with your Android application project</a>.
-
-<p>To set up your test environment in Eclipse:</p>
-
-<ol>
-<li><a href="{@docRoot}sdk/installing/bundle.html">Download and install the
-Eclipse ADT plugin</a>, if you haven’t installed it yet.</li>
-<li>Import or create the Android application project that you want to test
-against.</li>
-<li>Generate a test project that corresponds to the application project under
-test. To generate a test project for the app project that you imported:</p>
- <ol type="a">
- <li>In the Package Explorer, right-click on your app project, then
-select <strong>Android Tools</strong> > <strong>New Test Project</strong>.</li>
- <li>In the New Android Test Project wizard, set the property
-values for your test project then click <strong>Finish</strong>.</li>
- </ol>
-</li>
-</ol>
-<p>You should now be able to create, build, and run test
-cases from your Eclipse environment. To learn how to perform these tasks in
-Eclipse, proceed to <a href="activity-basic-testing.html">Creating and Running
-a Test Case</a>.</p>
-
-<h2 id="cmdline">Set Up the Command Line Interface for Testing</h2>
-<p>If you are using Gradle version 1.6 or higher as your build environment, you
-can build and run your Android application tests from the command line by using
-the Gradle Wrapper. Make sure that in your {@code gradle.build} file, the
-<a href={@docRoot}guide/topics/manifest/uses-sdk-element.html#min>minSdkVersion</a>
-attribute in the {@code defaultConfig} section is set to 8 or higher. You can
-refer to the sample {@code gradle.build} file that is
-included in the download bundle for this training class.</p>
-<p>To run your tests with the Gradle Wrapper:</p>
-<ol>
- <li>Connect a physical Android device to your machine or launch the Android
-Emulator.</li>
- <li>Run the following command from your project directory:
- <pre>./gradlew build connectedCheck</pre>
- </li>
-</ol>
-<p>To learn more about using Gradle for Android testing, see the
-<a href="//tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing">Gradle Plugin User Guide</a>.</p>
-<p>To learn more about using command line tools other than Gradle for test
-development, see
-<a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other IDEs</a>.</p>
-
diff --git a/docs/html/training/animation/cardflip.jd b/docs/html/training/animation/cardflip.jd
index 48fbbd8..721a9a3 100644
--- a/docs/html/training/animation/cardflip.jd
+++ b/docs/html/training/animation/cardflip.jd
@@ -2,98 +2,105 @@
trainingnavtop=true
@jd:body
- <div id="tb-wrapper">
- <div id="tb">
- <h2>
- This lesson teaches you to
- </h2>
- <ol>
- <li>
- <a href="#animators">Create the Animators</a>
- </li>
- <li>
- <a href="#views">Create the Views</a>
- </li>
- <li>
- <a href="#fragment">Create the Fragment</a>
- </li>
- <li>
- <a href="#animate">Animate the Card Flip</a>
- </li>
- </ol>
- <h2>
- Try it out
- </h2>
- <div class="download-box">
- <a href="{@docRoot}shareables/training/Animations.zip" class=
- "button">Download the sample app</a>
- <p class="filename">
- Animations.zip
- </p>
- </div>
- </div>
- </div>
- <p> This lesson shows you how to do a card flip
- animation with custom fragment animations.
- Card flips animate between views of content by showing an animation that emulates
- a card flipping over.
- </p>
- <p>Here's what a card flip looks like:
- </p>
-
- <div class="framed-galaxynexus-land-span-8">
- <video class="play-on-hover" autoplay>
- <source src="anim_card_flip.mp4" type="video/mp4">
- <source src="anim_card_flip.webm" type="video/webm">
- <source src="anim_card_flip.ogv" type="video/ogg">
- </video>
- </div>
- <div class="figure-caption">
- Card flip animation
- <div class="video-instructions"> </div>
- </div>
-
- <p>
- If you want to jump ahead and see a full working example,
- <a href="{@docRoot}shareables/training/Animations.zip">download</a> and
- run the sample app and select the Card Flip example. See the following
- files for the code implementation:
- </p>
- <ul>
- <li>
- <code>src/CardFlipActivity.java</code>
- </li>
- <li>
- <code>animator/card_flip_right_in.xml</code>
- </li>
- <li>
- <code>animator/card_flip_right_out.xml</code>
- </li>
- <li>
- <code>animator/card_flip_left_in.xml</code>
- </li>
- <li>
- <code>animator/card_flip_left_out.xml</code>
- </li>
- <li>
- <code>layout/fragment_card_back.xml</code>
- </li>
- <li>
- <code>layout/fragment_card_front.xml</code>
- </li>
- </ul>
-
- <h2 id="animate">
- Create the Animators
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>
+ This lesson teaches you to
</h2>
- <p>
- Create the animations for the card flips. You'll need two animators for when the front
- of the card animates out and to the left and in and from the left. You'll also need two animators
- for when the back of the card animates in and from the right and out and to the right.
- </p>
- <h4>
- card_flip_left_in.xml
- </h4>
+ <ol>
+ <li>
+ <a href="#animators">Create the Animators</a>
+ </li>
+ <li>
+ <a href="#views">Create the Views</a>
+ </li>
+ <li>
+ <a href="#fragment">Create the Fragment</a>
+ </li>
+ <li>
+ <a href="#animate">Animate the Card Flip</a>
+ </li>
+ </ol>
+ <h2>
+ Try it out
+ </h2>
+ <div class="download-box">
+ <a href="{@docRoot}shareables/training/Animations.zip" class=
+ "button">Download the sample app</a>
+ <p class="filename">
+ Animations.zip
+ </p>
+ </div>
+ </div>
+</div>
+
+<p> This lesson shows you how to do a card flip
+ animation with custom fragment animations.
+ Card flips animate between views of content by showing an animation that emulates
+ a card flipping over.
+</p>
+
+<p>Here's what a card flip looks like:
+</p>
+
+<div class="framed-galaxynexus-land-span-8">
+ <video class="play-on-hover" autoplay>
+ <source src="anim_card_flip.mp4" type="video/mp4">
+ <source src="anim_card_flip.webm" type="video/webm">
+ <source src="anim_card_flip.ogv" type="video/ogg">
+ </video>
+</div>
+<div class="figure-caption">
+ Card flip animation
+ <div class="video-instructions"> </div>
+</div>
+
+<p>
+ If you want to jump ahead and see a full working example,
+ <a href="{@docRoot}shareables/training/Animations.zip">download</a> and
+ run the sample app and select the Card Flip example. See the following
+ files for the code implementation:
+</p>
+
+<ul>
+ <li>
+ <code>src/CardFlipActivity.java</code>
+ </li>
+ <li>
+ <code>animator/card_flip_right_in.xml</code>
+ </li>
+ <li>
+ <code>animator/card_flip_right_out.xml</code>
+ </li>
+ <li>
+ <code>animator/card_flip_left_in.xml</code>
+ </li>
+ <li>
+ <code>animator/card_flip_left_out.xml</code>
+ </li>
+ <li>
+ <code>layout/fragment_card_back.xml</code>
+ </li>
+ <li>
+ <code>layout/fragment_card_front.xml</code>
+ </li>
+</ul>
+
+<h2 id="animate">
+ Create the Animators
+</h2>
+
+<p>
+ Create the animations for the card flips. You'll need two animators for when the front
+ of the card animates out and to the left and in and from the left. You'll also need two
+ animators for when the back of the card animates in and from the right and out and to the
+ right.
+</p>
+
+<h4 id="left-in">
+ card_flip_left_in.xml
+</h4>
+
<pre>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
@@ -120,10 +127,12 @@
android:duration="1" />
</set>
</pre>
- <h4>
- card_flip_left_out.xml
- </h4>
- <pre>
+
+<h4 id="left-out">
+ card_flip_left_out.xml
+</h4>
+
+<pre>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
@@ -141,11 +150,13 @@
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
- </pre>
- <h4>
- card_flip_right_in.xml
- </h4>
- <pre>
+</pre>
+
+<h4 id="right-in">
+ card_flip_right_in.xml
+</h4>
+
+<pre>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
@@ -169,13 +180,14 @@
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
-</set>
-
+</set>
</pre>
- <h4>
- card_flip_right_out.xml
- </h4>
- <pre>
+
+<h4 id="right-out">
+ card_flip_right_out.xml
+</h4>
+
+<pre>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
@@ -194,17 +206,18 @@
android:duration="1" />
</set>
</pre>
- <h2 id="views">
- Create the Views
- </h2>
- <p>
- Each side of the "card" is a separate layout that can contain any content you want,
- such as two screens of text, two images, or any combination of views to flip between. You'll then
- use the two layouts in the fragments that you'll later animate. The following layouts
- create one side of a card that shows text:
- </p>
- <pre>
+<h2 id="views">
+ Create the Views
+</h2>
+<p>
+ Each side of the "card" is a separate layout that can contain any content you want,
+ such as two screens of text, two images, or any combination of views to flip between. You'll then
+ use the two layouts in the fragments that you'll later animate. The following layouts
+ create one side of a card that shows text:
+</p>
+
+<pre>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -232,9 +245,11 @@
</LinearLayout>
</pre>
+
<p>
and the other side of the card that displays an {@link android.widget.ImageView}:
</p>
+
<pre>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
@@ -243,17 +258,20 @@
android:scaleType="centerCrop"
android:contentDescription="@string/description_image_1" />
</pre>
- <h2 id="fragment">
- Create the Fragment
- </h2>
- <p>
- Create fragment classes for the front and back of the card. These classes return the layouts
- that you created previously in the {@link android.app.Fragment#onCreateView onCreateView()} method
- of each fragment. You can then create instances of this fragment in the parent activity
- where you want to show the card. The following example shows nested fragment classes inside
- of the parent activity that uses them:
- </p>
- <pre>
+
+<h2 id="fragment">
+ Create the Fragment
+</h2>
+
+<p>
+ Create fragment classes for the front and back of the card. These classes return the layouts
+ that you created previously in the {@link android.app.Fragment#onCreateView onCreateView()} method
+ of each fragment. You can then create instances of this fragment in the parent activity
+ where you want to show the card. The following example shows nested fragment classes inside
+ of the parent activity that uses them:
+</p>
+
+<pre>
public class CardFlipActivity extends Activity {
...
/**
@@ -279,28 +297,27 @@
}
}
</pre>
- <h2 id="animate">
- Animate the Card Flip
- </h2>
- <p> Now, you'll need to display the fragments inside of a parent activity.
- To do this, first create the layout for your activity. The following example creates a
- {@link android.widget.FrameLayout} that you
- can add fragments to at runtime:</p>
+<h2 id="animate">
+ Animate the Card Flip
+</h2>
- <pre>
+<p> Now, you'll need to display the fragments inside of a parent activity.
+To do this, first create the layout for your activity. The following example creates a
+{@link android.widget.FrameLayout} that you
+can add fragments to at runtime:</p>
+
+<pre>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</pre>
- <p>In the activity code, set the content view to be the layout that you just created. It's also
- good idea to show a default fragment when the activity is created, so the following example
- activity shows you how to display the front of the card by default:
- </p>
-
-
+<p>In the activity code, set the content view to be the layout that you just created. It's also
+ good idea to show a default fragment when the activity is created, so the following example
+ activity shows you how to display the front of the card by default:
+</p>
<pre>
public class CardFlipActivity extends Activity {
@@ -320,22 +337,25 @@
...
}
</pre>
- <p>
- Now that you have the front of the card showing, you can show the back of the card
- with the flip animation at an appropriate time. Create a method to show the other
- side of the card that does the following things:
- </p>
- <ul>
- <li>Sets the custom animations that you created earlier for the fragment transitions.
- </li>
- <li>Replaces the currently displayed fragment with a new fragment and animates this event
- with the custom animations that you created.
- </li>
- <li>Adds the previously displayed fragment to the fragment back stack
- so when the user presses the <em>Back</em> button, the card flips back over.
- </li>
- </ul>
- <pre>
+
+<p>
+ Now that you have the front of the card showing, you can show the back of the card
+ with the flip animation at an appropriate time. Create a method to show the other
+ side of the card that does the following things:
+</p>
+
+<ul>
+ <li>Sets the custom animations that you created earlier for the fragment transitions.
+ </li>
+ <li>Replaces the currently displayed fragment with a new fragment and animates this event
+ with the custom animations that you created.
+ </li>
+ <li>Adds the previously displayed fragment to the fragment back stack
+ so when the user presses the <em>Back</em> button, the card flips back over.
+ </li>
+</ul>
+
+<pre>
private void flipCard() {
if (mShowingBack) {
getFragmentManager().popBackStack();
@@ -346,27 +366,30 @@
mShowingBack = true;
- // Create and commit a new fragment transaction that adds the fragment for the back of
- // the card, uses custom animations, and is part of the fragment manager's back stack.
+ // Create and commit a new fragment transaction that adds the fragment for
+ // the back of the card, uses custom animations, and is part of the fragment
+ // manager's back stack.
getFragmentManager()
.beginTransaction()
- // Replace the default fragment animations with animator resources representing
- // rotations when switching to the back of the card, as well as animator
- // resources representing rotations when flipping back to the front (e.g. when
- // the system Back button is pressed).
+ // Replace the default fragment animations with animator resources
+ // representing rotations when switching to the back of the card, as
+ // well as animator resources representing rotations when flipping
+ // back to the front (e.g. when the system Back button is pressed).
.setCustomAnimations(
- R.animator.card_flip_right_in, R.animator.card_flip_right_out,
- R.animator.card_flip_left_in, R.animator.card_flip_left_out)
+ R.animator.card_flip_right_in,
+ R.animator.card_flip_right_out,
+ R.animator.card_flip_left_in,
+ R.animator.card_flip_left_out)
- // Replace any fragments currently in the container view with a fragment
- // representing the next page (indicated by the just-incremented currentPage
- // variable).
+ // Replace any fragments currently in the container view with a
+ // fragment representing the next page (indicated by the
+ // just-incremented currentPage variable).
.replace(R.id.container, new CardBackFragment())
- // Add this transaction to the back stack, allowing users to press Back
- // to get to the front of the card.
+ // Add this transaction to the back stack, allowing users to press
+ // Back to get to the front of the card.
.addToBackStack(null)
// Commit the transaction.
diff --git a/docs/html/training/app-indexing/deep-linking.jd b/docs/html/training/app-indexing/deep-linking.jd
index fc67b26..2c4a131 100644
--- a/docs/html/training/app-indexing/deep-linking.jd
+++ b/docs/html/training/app-indexing/deep-linking.jd
@@ -66,10 +66,10 @@
android:host="www.example.com"
android:pathPrefix="/gizmos" />
<!-- note that the leading "/" is required for pathPrefix-->
- <!-- Accepts URIs that begin with "example://gizmos”
+ <!-- Accepts URIs that begin with "example://gizmos” -->
<data android:scheme="example"
android:host="gizmos" />
- -->
+
</intent-filter>
</activity>
</pre>
diff --git a/docs/html/training/app-indexing/index.jd b/docs/html/training/app-indexing/index.jd
index 15a6367..a1a47e9 100644
--- a/docs/html/training/app-indexing/index.jd
+++ b/docs/html/training/app-indexing/index.jd
@@ -22,6 +22,7 @@
target="_blank">App Indexing for Google Search</a></li>
<li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent
Filters</a></li>
+<li><a href="{@docRoot}tools/help/app-link-indexing.html">Deep Link and App Indexing API Support in Android Studio</a></li>
</ul>
</div>
</div>
diff --git a/docs/html/training/app-links/index.jd b/docs/html/training/app-links/index.jd
new file mode 100644
index 0000000..27b6480
--- /dev/null
+++ b/docs/html/training/app-links/index.jd
@@ -0,0 +1,585 @@
+page.title=Handling App Links
+page.image=images/cards/card-app-linking_2x.png
+page.keywords=applinking, deeplinks, intents
+page.tags=androidm,marshmallow
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#url-handling">Understand URI Request Handling</a> </li>
+ <li><a href="#intent-handler">Create an Intent Handler for URIs</a></li>
+ <li><a href="#request-verify">Request App Links Verification</a></li>
+ <li><a href="#web-assoc">Declare Website Associations</a></li>
+ <li><a href="#testing">Test App Links</a></li>
+ </ol>
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}tools/help/app-link-indexing.html">Deep Link and App Indexing API Support in Android Studio</a></li>
+ </ol>
+ </div>
+</div>
+
+
+
+<p>
+ Users following web links on devices are frequently presented with confusing choices. Tapping a
+ link often results in the system asking the user which app should handle that link. For example,
+ clicking a URI in an email from a bank might result in a dialog asking the user whether to use
+ the browser, or the bank's own app, to open the link. Android 6.0 (API level 23) and higher allow
+ an app to designate itself as the default handler of a given type of link. If the user doesn't
+ want the app to be the default handler, they can override this behavior from
+ <strong>Settings</strong>.
+</p>
+
+<p>
+ Automatic handling of links requires the cooperation of app developers and website owners.
+ A developer must configure their app to declare associations with one or more websites, and to
+ request that the system verify those associations. A website owner must, in turn, provide
+ that verification by publishing a <a href="http://developers.google.com/digital-asset-links/"><i>Digital
+ Asset Links</i></a> file. The general steps for creating verified app links are as follows:
+</p>
+
+<ol>
+ <li>In your app manifest, create intent filters for your website URIs.</li>
+ <li>Configure your app to request verification of app links.</li>
+ <li>Publish a Digital Asset Links JSON file on your websites to provide verification.</li>
+</ol>
+
+<h2 id="url-handling">Understand URI Request Handling</h2>
+
+<p>
+ The app links feature allows your app to become the default handler for the website URIs you
+ specify, as long as the user has not already chosen a default app to handle that URI pattern.
+ When a clicked link or programmatic request invokes a web URI intent, the Android system
+ uses the following criteria, in descending order, to determine how to handle the request:
+</p>
+
+<ol>
+ <li>
+ <strong>The user has set app link associations</strong>: If the user has designated an app to
+ handle app links, the system passes the web URI request to that app. A user can set this
+ association in one of two ways: clicking <strong>Always</strong> when selecting an app
+ from an app-selection dialog; or, opening <em>Settings > Apps > (gear icon)
+ > App links</em>, selecting an app to use, and setting the app's
+ <strong>App links</strong> property to the <strong>Open in this app</strong> option.
+ </li>
+
+ <li>
+ <strong>The user has set no association, and there is one supporting app</strong>: If the user
+ has not set a preference that matches the web URI request, and there is only one app declaring
+ support for the intent’s URI pattern, the system automatically passes the request to that app.
+ </li>
+
+ <li>
+ <strong>The user has set no association, and there are multiple supporting apps</strong>: If
+ there are multiple apps declaring support for the web URI pattern, the system displays an
+ app-selection dialog, prompting the user to select the most appropriate app.
+ </li>
+</ol>
+
+<p>
+ In case 2, if the user has newly installed the app, and the system has
+ verified it as a handler for this type of link, the system sets the app as the default handler. In
+ the other two cases, the presence of a verified app link handler has no effect on system behavior.
+</p>
+
+
+<h2 id="intent-handler">Create an Intent Handler for URIs</h2>
+
+<p>
+ App links are based on the <a href="{@docRoot}guide/components/intents-filters.html">Intent</a>
+ framework, which enables apps to handle requests from the system or other apps. Multiple apps may
+ declare the same web link URI patterns in their intent filters. When a user clicks on a web link
+ that does not have a default launch handler, the platform selects an app to handle the request,
+ using the criteria described in <a href="#url-handling">Understanding URI Request Handling</a>.
+</p>
+
+<p>
+ To enable your app to handle links, use intent filters in your app manifest to declare the URI
+ patterns that your app handles. The following example shows an intent filter that can
+ handle links to {@code http://www.android.com} and {@code https://www.android.com}:
+</p>
+
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:host="www.android.com" />
+ </intent-filter>
+</activity>
+</pre>
+
+<p>
+ As this example shows, intent filters for app links must declare an {@code android:scheme}
+ value of {@code http}, {@code https}, or both. The filter must not declare
+ any other schemes. The filter must also include the {@code android.intent.action.VIEW} and
+ {@code android.intent.category.BROWSABLE} category names.
+</p>
+
+<p>
+ This manifest declaration defines the connection between your app and a website. However, in
+ order to have the system treat your app as the default handler for a set of URIs, you must
+ also request that the system verify this connection.
+ The next section explains how to implement this verification.
+</p>
+
+
+<h2 id="request-verify">Request App Links Verification</h2>
+
+<p>
+ In addition to using intent filters to declare an association between your app and a website,
+ your manifest must also include an additional declaration for requesting automatic verification.
+ When this declaration is present, the Android system attempts to verify your app after
+ installation. If the verification succeeds, and the user has not set an alternate
+ preference for handling your website URIs, the system automatically routes those URI requests to
+ your app.
+</p>
+
+<p>
+ The system performs app-link verifications by comparing the host names in the data elements of
+ the app’s intent filters against the Digital Asset Links files ({@code assetlinks.json}) hosted
+ on the respective web domains. To enable the system to verify a host, make sure that your intent
+ filter declarations include the {@code android.intent.action.VIEW} intent action and {@code
+ android.intent.category.BROWSABLE} intent category.
+</p>
+
+
+<h3 id="config-verify">Enabling automatic verification</h3>
+
+<p>
+ To enable link handling verification for your app, set the {@code android:autoVerify} attribute to
+ {@code true} on at least one of the web URI intent filters in your app manifest, as shown in the
+ following manifest code snippet:
+</p>
+
+<pre>
+<activity ...>
+
+ <intent-filter <strong>android:autoVerify="true"</strong>>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.android.com" />
+ <data android:scheme="https" android:host="www.android.com" />
+ </intent-filter>
+
+</activity>
+</pre>
+
+<p>
+ When the {@code android:autoVerify} attribute is present, installing your app causes the system
+ to attempt to verify all hosts associated with the web URIs in all of your app's intent filters.
+ The system treats your app as the default handler for the specified URI pattern only if it
+ successfully verifies <em>all</em> app link patterns declared in your manifest.
+</p>
+
+
+<h3 id="multi-host">Supporting app linking for multiple hosts</h3>
+
+<p>
+ The system must be able to verify every host specified in the app’s web URI intent filters’ data
+ elements against the Digital Asset Links files hosted on the respective web domains. If any
+ verification fails, the app is not verified to be a default handler for any of the web URI
+ patterns defined in the app's intent filters. For example, an app with the following intent
+ filters would fail verification if an {@code assetlinks.json} file were not found at both
+ {@code https://www.domain1.com/.well-known/assetlinks.json} and
+ {@code https://www.domain2.com/.well-known/assetlinks.json}:
+</p>
+
+<pre>
+<application>
+
+ <activity android:name=”MainActivity”>
+ <intent-filter <strong>android:autoVerify="true"</strong>>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.domain1.com" />
+ <data android:scheme="https" android:host="www.domain1.com" />
+ </intent-filter>
+ </activity>
+ <activity android:name=”SecondActivity”>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="https" android:host="www.domain2.com" />
+ </intent-filter>
+ </activity>
+
+</application
+</pre>
+
+
+<h3 id="multi-subdomain">Supporting app linking for multiple subdomains</h3>
+
+<p>
+ The Digital Asset Links protocol treats subdomains as unique, separate hosts. If your intent
+ filter lists both the {@code www.example.com} and {@code mobile.example.com} subdomains as
+ hosts, you must host a separate {@code assetlink.json} file on each subdomain. For example, an
+ app with the following intent filter declaration would pass verification only if the website
+ owner published valid {@code assetlinks.json} files at both
+ {@code https://www.example.com/.well-known/assetlinks.json} and
+ {@code https://mobile.example.com/.well-known/assetlinks.json}:
+</p>
+
+<pre>
+<application>
+ <activity android:name=”MainActivity”>
+ <intent-filter <strong>android:autoVerify="true"</strong>>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.example.com" />
+ <data android:scheme="https" android:host="mobile.example.com" />
+ </intent-filter>
+ </activity>
+</application>
+</pre>
+
+
+<h2 id="web-assoc">Declare Website Associations</h2>
+
+<p>
+ For app link verification to be successful, website owners must declare associations
+ with apps. A site owner declares the relationship to an app by hosting a Digital Asset Links JSON
+ file, with the name {@code assetlinks.json}, at the following well-known location on the domain:
+</p>
+
+<pre>
+https://<em>domain</em>[:<em>optional_port</em>]/.well-known/assetlinks.json
+</pre>
+
+<p class="note">
+ <strong>Important:</strong> The system verifies the JSON file via the encrypted HTTPS protocol.
+ Make sure that your hosted file is accessible over an HTTPS connection, regardless of whether
+ your app's intent filter includes {@code https}.
+</p>
+
+<p>
+ A Digital Asset Links JSON file indicates the Android apps that are associated with the website.
+ The JSON file uses the following fields to identify associated apps:
+</p>
+
+<ul>
+ <li>{@code package_name}: The package name declared in the app's manifest.</li>
+
+ <li>{@code sha256_cert_fingerprints}: The SHA256 fingerprints of your app’s signing certificate.
+ You can use the following command to generate the fingerprint via the Java keytool:
+
+ <pre class="no-pretty-print">
+$ keytool -list -v -keystore my-release-key.keystore
+ </pre>
+
+ This field supports multiple fingerprints, which can be used to support different versions
+ of your app, such as debug and production builds.
+ </li>
+</ul>
+
+<p>
+ The following example {@code assetlinks.json} file grants link-opening rights to a
+ {@code com.example} Android app:
+</p>
+
+<pre>
+[{
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target": {
+ "namespace": "android_app",
+ "package_name": "com.example",
+ "sha256_cert_fingerprints":
+ ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
+ }
+}]
+</pre>
+
+
+<h3 id="multiple-apps">Associating a website with multiple apps</h3>
+
+<p>
+ A website can declare associations with multiple apps within the same {@code assetlinks.json}
+ file. The following file listing shows an example of a statement file that declares association
+ with two apps, separately, and resides at
+ <code>https://www.example.com/.well-known/assetlinks.json</code>:
+</p>
+
+<pre>
+[{
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target": {
+ "namespace": "android_app",
+ "package_name": <strong>"example.com.puppies.app"</strong>,
+ "sha256_cert_fingerprints":
+ ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
+ }
+ },
+ {
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target": {
+ "namespace": "android_app",
+ "package_name": "<strong>example.com.monkeys.app</strong>",
+ "sha256_cert_fingerprints":
+ ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
+ }
+}]
+</pre>
+
+<p>
+ Different apps may handle links for different resources under the same web host. For example,
+ app1 may declare an intent filter for {@code https://example.com/articles}, and app2 may declare
+ an intent filter for {@code https://example.com/videos}.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> Multiple apps associated with a domain may be signed with the same or
+ different certificates.
+</p>
+
+
+<h3 id="multi-site">Associating multiple websites with a single app</h3>
+
+<p>
+ Multiple websites can declare associations with the same app in their respective {@code
+ assetlinks.json} files. The following file listings show an example of how to declare the
+ association of domain1 and domain2 with app1. The first listing shows the association of
+ domain1 with app1:
+</p>
+
+<pre>
+https://www.domain1.com/.well-known/assetlinks.json
+
+[{
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target": {
+ "namespace": "android_app",
+ "package_name": "<strong>com.mycompany.app1</strong>",
+ "sha256_cert_fingerprints":
+ ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
+ }
+}]
+</pre>
+
+<p>The next listing shows the association of domain2 with app1. Only the very last line, which
+specifies the URL, is different:</p>
+
+<pre>
+https://www.domain2.com/.well-known/assetlinks.json
+
+[{
+ "relation": ["delegate_permission/common.handle_all_urls"],
+ "target": {
+ "namespace": "android_app",
+ "package_name": "<strong>com.mycompany.app1</strong>",
+ "sha256_cert_fingerprints":
+ ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
+ }
+}]
+</pre>
+
+<h2 id="testing">Test App Links</h2>
+
+<p>
+ When implementing the app linking feature, you should test the linking functionality to
+ make sure the system can associate your app with your websites, and handle URI requests,
+ as you expect.
+</p>
+
+
+<h3 id="test-hosts">Confirm the list of hosts to verify</h3>
+
+<p>
+ When testing, you should confirm the list of associated hosts that the system should verify
+ for your app. Make a list of all web URIs whose corresponding intent filters include the following
+ attributes and elements:
+</p>
+
+<ul>
+ <li>{@code android:scheme} attribute with a value of {@code http} or {@code https}
+ </li>
+ <li>{@code android:host} attribute with a domain URI pattern
+ </li>
+ <li>{@code android.intent.action.VIEW} category element
+ </li>
+ <li>{@code android.intent.category.BROWSABLE} category element
+ </li>
+</ul>
+
+<p>
+ Use this list to check that a Digital Asset Links JSON file is provided on each named host
+ and subdomain.
+</p>
+
+
+<h3 id="test-dal-files">Confirm the Digital Asset Links files</h3>
+
+<p>
+ For each website, use the Digital Asset Links API to confirm that the Digital Asset Links JSON
+ file is properly hosted and defined:
+</p>
+
+<pre>
+https://digitalassetlinks.googleapis.com/v1/statements:list?
+ source.web.site=https://<strong><domain1>:<port></strong>&
+ relation=delegate_permission/common.handle_all_urls
+</pre>
+
+
+<h3 id="test-intent">Testing a web URI intent</h3>
+
+<p>
+ Once you have confirmed the list of websites to associate with your app, and you have confirmed
+ that the hosted JSON file is valid, install the app on your device. Wait at least 20 seconds for
+ the asynchronous verification process to complete. Use the following command to check
+ whether the system verified your app and set the correct link handling policies:
+</p>
+
+<pre>
+adb shell am start -a android.intent.action.VIEW \
+ -c android.intent.category.BROWSABLE \
+ -d "http://<domain1>:<port>"
+</pre>
+
+
+<h3 id="check-link-policies">Check link policies</h3>
+
+<p>
+ As part of your testing process, you can check the current system settings for link handling.
+ Use the following command to get a listing of existing link-handling policies for all
+ applications:
+</p>
+
+<pre>
+adb shell dumpsys package domain-preferred-apps
+ --or--
+adb shell dumpsys package d
+</pre>
+
+<p class="note">
+ <strong>Note:</strong> Make sure you wait at least 20 seconds after installation of your app to
+ allow for the system to complete the verification process.
+</p>
+
+<p>
+ The command returns a listing of each user or profile defined on the device,
+ preceded by a header in the following format:
+</p>
+
+<pre>
+App linkages for user 0:
+</pre>
+
+<p>
+ Following this header, the output uses the following format to list the link-handling settings
+ for that user:
+</p>
+
+<pre>
+Package: com.android.vending
+Domains: play.google.com market.android.com
+Status: always : 200000002
+</pre>
+
+<p>This listing indicates which apps are associated with which domains for that user:</p>
+
+<ul>
+ <li>{@code Package} - Identifies an app by its package name, as declared in its manifest.
+ </li>
+ <li>{@code Domains} - Shows the full list of hosts whose web links this app handles, using
+ blank spaces as delimiters.
+ </li>
+ <li>{@code Status} - Shows the current link-handling setting for this app. An app that has
+ passed verification, and whose manifest contains {@code android:autoVerify="true"}, shows a status
+ of {@code always}. The hexadecimal number after this status is related to the Android system's
+ record of the user’s app linkage preferences. This value does not indicate whether verification
+ succeeded.
+ </li>
+</ul>
+
+<p class="note">
+ <strong>Note:</strong> If a user changes the app link settings for an app before verification
+ is complete, you may see a false positive for a successful verification, even though
+ verification has failed. This verification failure, however, does not matter if the user
+ explicitly enabled the app to open supported links without asking. This is because
+ user preferences take precedence over programmatic verification (or lack of it). As a result,
+ the link goes directly to your app, without showing a dialog, just as if verification had
+ succeeded.
+</p>
+
+
+
+<h3 id="test-example">Test example</h3>
+
+<p>
+ For app link verification to succeed, the system must be able to verify your app with all of
+ the websites that you specify in your app’s intent filters, and that meet the criteria for app
+ links. The following example shows a manifest configuration with several app links defined:
+</p>
+
+<pre>
+<application>
+
+ <activity android:name=”MainActivity”>
+ <intent-filter <strong>android:autoVerify="true"</strong>>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.example.com" />
+ <data android:scheme="https" android:host="mobile.example.com" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.example2.com" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=”SecondActivity”>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="account.example.com" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=”ThirdActivity”>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" android:host="map.example.com" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="market" android:host="example.com" />
+ </intent-filter>
+ </activity>
+
+</application>
+</pre>
+
+<p>
+ The list of hosts that the platform would attempt to verify from the above manifest is:
+</p>
+
+<pre>
+www.example.com
+mobile.example.com
+www.example2.com
+account.example.com
+</pre>
+
+<p>
+ The list of hosts that the platform would not attempt to verify from the above manifest is:
+</p>
+
+<pre>
+map.example.com (it does not have android.intent.category.BROWSABLE)
+market://example.com (it does not have either an “http” or “https” scheme)
+</pre>
diff --git a/docs/html/training/appbar/action-views.jd b/docs/html/training/appbar/action-views.jd
new file mode 100644
index 0000000..37d8a51
--- /dev/null
+++ b/docs/html/training/appbar/action-views.jd
@@ -0,0 +1,248 @@
+page.title=Action Views and Action Providers
+page.tags="action view", "action provider"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#action-view">Add an Action View</a></li>
+ <li><a href="#action-provider">Add an Action Provider</a></li>
+ </ol>
+
+<!--
+ <h2>Useful Resources</h2>
+ <ul>
+ <li></li>
+ </ul>
+-->
+
+ </div>
+</div>
+
+<p>
+ The <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+ appcompat</a> support library {@link android.support.v7.widget.Toolbar} provides several
+ different ways for users to interact with your app. Previous lessons
+ described how to define an <em>action</em>, which can be either a button or a
+ menu item. This lesson describes how to add two versatile components:
+</p>
+
+<ul>
+ <li>An <em>action view</em> is an action that provides rich functionality
+ within the app bar. For example, a search action view allows the user to type
+ their search text in the app bar, without having to change activities or
+ fragments.
+ </li>
+
+ <li>An <em>action provider</em> is an action with its own customized layout.
+ The action initially appears as a button or menu item, but when the user clicks the
+ action, the action provider controls the action's behavior in any way you
+ want to define. For example, the action provider might respond to a click by
+ displaying a menu.
+ </li>
+</ul>
+
+<p>
+ The Android support libraries provide several specialized action view and
+ action provider widgets. For example, the {@link
+ android.support.v7.widget.SearchView} widget implements an action view for
+ entering search queries, and the {@link
+ android.support.v7.widget.ShareActionProvider} widget implements an action
+ provider for
+ sharing information with other apps. You can also define your own action
+ views and action providers.
+</p>
+
+<h2 id="action-view">
+ Add an Action View
+</h2>
+
+<p>
+ To add an action view, create an <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element in the toolbar's menu resource, as <a href="actions.html">Add Action
+ Buttons</a> describes. Add one of the following two
+ attributes to the <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element:
+</p>
+
+<ul>
+ <li>
+ <code>actionViewClass</code>: The class of a widget that implements the
+ action.
+ </li>
+
+ <li>
+ <code>actionLayout</code>: A layout resource describing the action's
+ components.
+ </li>
+</ul>
+
+<p>
+ Set the <code>showAsAction</code> attribute to either
+ <code>"ifRoom|collapseActionView"</code> or
+ <code>"never|collapseActionView"</code>. The <code>collapseActionView</code>
+ flag indicates how to display the widget when the user is not interacting with
+ it: If the widget is on the app bar, the app should display the widget as an
+ icon. If the widget is in the overflow menu, the app should display the widget
+ as a menu item. When the user interacts with the action view, it
+ expands to fill the app bar.
+</p>
+
+<p>
+ For example, the following code adds a {@link
+ android.support.v7.widget.SearchView} widget to the app bar:
+</p>
+
+<pre>
+<item android:id="@+id/action_search"
+ android:title="@string/action_search"
+ android:icon="@drawable/ic_search"
+ <strong>app:showAsAction="ifRoom|collapseActionView"</strong>
+ <strong>app:actionViewClass="android.support.v7.widget.SearchView" /></strong>
+</pre>
+
+<p>
+ If the user is not interacting with the widget, the app displays the widget
+ as the icon specified by <code>android:icon</code>. (If there is not enough
+ room in the app bar, the app adds the action to the overflow menu.) When the
+ user taps the icon or menu item, the widget expands to fill the toolbar,
+ allowing the user to interact with it.
+</p>
+
+<img src="{@docRoot}images/training/appbar/action_view_2x.png"
+ srcset="{@docRoot}images/training/appbar/action_view.png 1x,
+ {@docRoot}images/training/appbar/action_view_2x.png 2x"
+ alt="" width="400" id="figure-action-view">
+<p class="img-caption">
+ <strong>Figure 1.</strong> When the user clicks an action view's icon, the
+ view's UI fills the toolbar.
+</p>
+
+<p>
+ If you need to configure the action, do so in your activity's {@link
+ android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback. You
+ can get the action view's object reference by calling the static {@link
+ android.support.v4.view.MenuItemCompat#getActionView getActionView()} method.
+ For example, the following code gets the object reference for the {@link
+ android.support.v7.widget.SearchView} widget defined in the previous code
+ example:
+</p>
+
+<pre>
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main_activity_actions, menu);
+
+ <strong>MenuItem searchItem = menu.findItem(R.id.action_search);</strong>
+ <strong>SearchView searchView =
+ (SearchView) MenuItemCompat.getActionView(searchItem);</strong>
+
+ // Configure the search info and add any event listeners...
+
+ return super.onCreateOptionsMenu(menu);
+}
+</pre>
+<h3 id="view-expansion">Responding to action view expansion</h3>
+
+<p>
+ If the action's <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element has a <code>collapseActionView</code> flag, the app displays the action
+ view as an icon until the user interacts with the action view.
+ When the user clicks on the icon, the built-in handler for {@link
+ android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} expands
+ the action view. If your activity subclass overrides the {@link
+ android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method,
+ your override method must call {@link android.app.Activity#onOptionsItemSelected
+ super.onOptionsItemSelected()} so the superclass can expand the action view.
+</p>
+
+<p>
+ If you want to do something when the action is expanded or collapsed, you can
+ define a class that implements
+ {@link android.view.MenuItem.OnActionExpandListener}, and pass a member of
+ that class to
+ {@link android.view.MenuItem#setOnActionExpandListener
+ setOnActionExpandListener()}. For example, you might want to update the
+ activity based on whether an action view is expanded or collapsed. The
+ following snippet shows how to define and pass a listener:
+</p>
+<pre>
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.options, menu);
+ // ...
+
+ // Define the listener
+ OnActionExpandListener expandListener = new OnActionExpandListener() {
+ @Override
+ public boolean onMenuItemActionCollapse(MenuItem item) {
+ // Do something when action item collapses
+ return true; // Return true to collapse action view
+ }
+
+ @Override
+ public boolean onMenuItemActionExpand(MenuItem item) {
+ // Do something when expanded
+ return true; // Return true to expand action view
+ }
+ };
+
+ // Get the MenuItem for the action item
+ MenuItem actionMenuItem = menu.findItem(R.id.myActionItem);
+
+ // Assign the listener to that action item
+ MenuItemCompat.setOnActionExpandListener(actionMenuItem, expandListener);
+
+ // Any other things you have to do when creating the options menu…
+
+ return true;
+}
+</pre>
+
+<h2 id="action-provider">
+ Add an Action Provider
+</h2>
+
+<p>
+ To declare an action provider, create an <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element in the toolbar's menu resource, as described in <a href=
+ "actions.html">Add Action Buttons</a>. Add an
+ <code>actionProviderClass</code> attribute, and set it to the fully qualified
+ class name for the action provider class.
+</p>
+
+<p>
+ For example, the following code declares a {@link
+ android.support.v7.widget.ShareActionProvider}, which is a widget defined in
+ the support library that allows your app to share data with other apps:
+</p>
+
+<pre>
+<item android:id="@+id/action_share"
+ android:title="@string/share"
+ app:showAsAction="ifRoom"
+ app:actionProviderClass="android.support.v7.widget.ShareActionProvider"/>
+</pre>
+
+<p>
+ In this case, it is not necessary to declare an icon for the widget, since {@link
+ android.support.v7.widget.ShareActionProvider} provides its own graphics. If
+ you are using a custom action, declare an icon.
+</p>
+
+<p>
+ For information about creating a custom action provider, see the {@link
+ android.support.v4.view.ActionProvider} reference. For information about
+ configuring a {@link android.support.v7.widget.ShareActionProvider}, see the
+ reference for that class.
+</p>
diff --git a/docs/html/training/appbar/actions.jd b/docs/html/training/appbar/actions.jd
new file mode 100644
index 0000000..68483ca
--- /dev/null
+++ b/docs/html/training/appbar/actions.jd
@@ -0,0 +1,154 @@
+page.title=Adding and Handling Actions
+page.tags="appbar","actionbar"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#add-actions">Add Action Buttons</a></li>
+ <li><a href="#handle-actions">Respond to Actions</a></li>
+ </ol>
+
+ <h2>Useful Resources</h2>
+ <ul>
+ <li><a href="https://www.google.com/design/icons/">Material Icons</a></li>
+ </ul>
+
+
+ </div>
+</div>
+
+
+<a class="notice-designers wide" href="{@docRoot}design/patterns/actionbar.html#ActionButtons">
+ <div>
+ <h3>Design Guide</h3>
+ <p>Action Buttons</p>
+ </div>
+</a>
+
+
+<p>
+ The app bar allows you to add buttons for user actions. This feature lets you
+ put the most important <em>actions</em> for the current context right at the
+ top of the app. For example, a photo browsing app might show <em>share</em>
+ and <em>create album</em> buttons at the top when the user is looking at
+ their photo roll; when the user looks at an individual photo, the app might
+ show <em>crop</em> and <em>filter</em> buttons.
+</p>
+
+<p>
+ Space in the app bar is limited. If an app declares more actions than can
+ fit in the app bar, the app bar send the excess actions to an
+ <em>overflow</em> menu. The app can also specify that an action should always
+ be shown in the overflow menu, instead of being displayed on the app bar.
+</p>
+
+<img src="{@docRoot}images/training/appbar/appbar_with_button_2x.png"
+ srcset="{@docRoot}images/training/appbar/appbar_with_button.png 1x,
+ {@docRoot}images/training/appbar/appbar_with_button_2x.png 2x"
+ width="400" alt="">
+
+<p class="img-caption">
+ <strong>Figure 1.</strong> An app bar with a single action button and an
+ overflow menu.
+</p>
+
+<h2 id="add-actions">Add Action Buttons</h2>
+
+<p>
+ All action buttons and other items available in the action overflow are
+ defined in an XML <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. To
+ add actions to the action bar, create a new XML file in your project's
+ <code>res/menu/</code> directory.
+</p>
+
+<p>
+ Add an <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element for each item you want to include in the action bar, as shown in this
+ code example of a menu XML file:
+</p>
+
+<pre>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <!-- "Mark Favorite", should appear as action button if possible -->
+ <item
+ android:id="@+id/action_favorite"
+ android:icon="@drawable/ic_favorite_black_48dp"
+ android:title="@string/action_favorite"
+ app:showAsAction="ifRoom"/>
+
+ <!-- Settings, should always be in the overflow -->
+ <item android:id="@+id/action_settings"
+ android:title="@string/action_settings"
+ app:showAsAction="never"/>
+
+</menu>
+</pre>
+
+<p>
+ The <code>app:showAsAction</code> attribute specifies whether the action
+ should be shown as a button on the app bar. If you set
+ <code>app:showAsAction="ifRoom"</code> (as in the example code's <em>favorite</em> action), the action is displayed as a button
+ if there is room in the app bar for it; if there is not enough room, excess
+ actions are sent to the overflow menu. If you set
+ <code>app:showAsAction="never"</code> (as in the example code's <em>settings</em> action), the action is always listed in the
+ overflow menu, not displayed in the app bar.
+</p>
+
+<p>
+ The system uses the action's icon as the action button if the action is
+ displayed in the app bar. You can find many useful icons on the <a href=
+ "https://www.google.com/design/icons/">Material Icons</a> page.
+</p>
+
+<h2 id="handle-actions">Respond to Actions</h2>
+
+<p>
+ When the user selects one of the app bar items, the system calls your
+ activity's {@link android.app.Activity#onOptionsItemSelected
+ onOptionsItemSelected()} callback method, and passes a {@link
+ android.view.MenuItem} object to indicate which item was clicked. In your
+ implementation of {@link android.app.Activity#onOptionsItemSelected
+ onOptionsItemSelected()}, call the {@link android.view.MenuItem#getItemId
+ MenuItem.getItemId()} method to determine which item was pressed. The ID returned
+ matches the value you declared in the corresponding <a href=
+ "{@docRoot}guide/topics/resources/menu-resource.html#item-element"><code><item></code></a>
+ element's <code>android:id</code> attribute.
+</p>
+
+<p>
+ For example, the following code checks to see which action the user selected.
+ If the method does not recognize the user's action, it invokes the superclass
+ method:
+</p>
+
+<pre>
+@Override
+public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_settings:
+ // User chose the "Settings" item, show the app settings UI...
+ return true;
+
+ case R.id.action_favorite:
+ // User chose the "Favorite" action, mark the current item
+ // as a favorite...
+ return true;
+
+ default:
+ // If we got here, the user's action was not recognized.
+ // Invoke the superclass to handle it.
+ return super.onOptionsItemSelected(item);
+
+ }
+}
+</pre>
diff --git a/docs/html/training/appbar/index.jd b/docs/html/training/appbar/index.jd
new file mode 100755
index 0000000..64ce94d
--- /dev/null
+++ b/docs/html/training/appbar/index.jd
@@ -0,0 +1,101 @@
+page.title=Adding the App Bar
+page.tags="appbar","actionbar"
+helpoutsWidget=true
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}training/implementing-navigation/index.html">
+ Implementing Effective Navigation</a></li>
+ <li><a href="http://www.google.com/design/spec/layout/structure.html#structure-app-bar">
+ Material Design: App Bar</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>
+ The <em>app bar</em>, also known as the <em>action bar</em>, is one of the most
+ important design elements in your app's activities, because
+ it provides a visual structure and interactive elements that are familiar to
+ users. Using the app bar makes your app consistent with other Android apps,
+ allowing users to quickly understand how to operate your app and have a great
+ experience.
+ The key functions of the app bar
+ are as follows:
+</p>
+
+<ul>
+ <li>A dedicated space for giving your app an identity and indicating the
+ user's location in the app.
+ </li>
+
+ <li>Access to important actions in a predictable way, such as search.
+ </li>
+
+ <li>Support for navigation and view switching (with tabs or drop-down lists).
+ </li>
+</ul>
+
+<img src="{@docRoot}images/training/appbar/appbar_sheets_2x.png"
+ srcset="{@docRoot}images/training/appbar/appbar_sheets.png 1x,
+ {@docRoot}images/training/appbar/appbar_sheets_2x.png 2x"
+ width="400" alt="" />
+
+<p>
+ This class describes how to use the
+ <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+ appcompat</a> support library's {@link
+ android.support.v7.widget.Toolbar} widget as an app bar. There are other ways
+ to implement an app bar—for example, some themes set up an {@link
+ android.app.ActionBar} as an app bar by default—but using the appcompat
+ {@link android.support.v7.widget.Toolbar} makes it easy to set up an app bar
+ that works on the widest range of devices, and also gives you room to
+ customize your app bar later on as your app develops.
+</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <b><a href="setting-up.html">Setting Up the App Bar</a></b>
+ </dt>
+
+ <dd>
+ Learn how to add a {@link android.support.v7.widget.Toolbar} widget to your
+ activity, and set it as the activity's app bar.
+ </dd>
+
+ <dt>
+ <b><a href="actions.html">Adding and Handling Actions</a></b>
+ </dt>
+
+ <dd>
+ Learn how to add actions to the app bar and its overflow menu, and how to
+ respond when users choose those actions.
+ </dd>
+
+ <dt>
+ <b><a href="up-action.html">Adding an Up Action</a></b>
+ </dt>
+
+ <dd>
+ Learn how to add an <em>Up</em> button to your app bar, so users
+ can navigate back to the app's home screen.
+ </dd>
+
+ <dt>
+ <b><a href="action-views.html">Action Views and Action Providers</a></b>
+ </dt>
+
+ <dd>
+ Learn how to use these widgets to provide advanced functionality in your
+ app bar.
+ </dd>
+</dl>
diff --git a/docs/html/training/appbar/setting-up.jd b/docs/html/training/appbar/setting-up.jd
new file mode 100644
index 0000000..cc963c6
--- /dev/null
+++ b/docs/html/training/appbar/setting-up.jd
@@ -0,0 +1,181 @@
+page.title=Setting Up the App Bar
+page.tags="appbar","actionbar", "toolbar"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#add-toolbar">Add a Toolbar to an Activity</a></li>
+ <li><a href="#utility">Use App Bar Utility Methods</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}tools/support-library/setup.html"
+ >Setting Up the Support Library</a></li>
+ </ul>
+ </div>
+</div>
+
+
+<p>
+ In its most basic form, the action bar displays the title for the activity on
+ one side and an <em>overflow menu</em> on the other. Even in this simple
+ form, the app bar provides useful information to the users, and helps to give
+ Android apps a consistent look and feel.
+</p>
+
+<img src="{@docRoot}images/training/appbar/appbar_basic_2x.png"
+ srcset="{@docRoot}images/training/appbar/appbar_basic.png 1x,
+ {@docRoot}images/training/appbar/appbar_basic_2x.png 2x"
+ width="400" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> An app bar with the app
+title and overflow menu.</a>
+
+<p>
+ Beginning with Android 3.0 (API level 11), all
+ activities that use the default theme have an {@link android.app.ActionBar}
+ as an app bar. However, app bar features have gradually been added to the
+ native {@link android.app.ActionBar} over various Android releases. As a
+ result, the native {@link android.app.ActionBar} behaves differently
+ depending on what version of the Android system a device may be using. By
+ contrast, the most recent features are added to the support library's version
+ of {@link android.support.v7.widget.Toolbar}, and they are available on any
+ device that can use the support library.
+</p>
+
+<p>
+ For this reason, you should use the support library's {@link
+ android.support.v7.widget.Toolbar} class to implement your activities' app
+ bars. Using the support library's toolbar helps ensure that your app will
+ have consistent behavior across the widest range of devices. For example, the
+ {@link android.support.v7.widget.Toolbar} widget provides a <a href=
+ "{@docRoot}design/material/index.html">material design</a> experience on
+ devices running Android 2.1 (API level 7) or later, but the native action
+ bar doesn't support material design unless the device is running Android 5.0
+ (API level 21) or later.
+</p>
+
+<h2 id="add-toolbar">Add a Toolbar to an Activity</h2>
+
+These steps describe how to set up a {@link android.support.v7.widget.Toolbar}
+as your activity's app bar:
+
+<ol>
+ <li>Add the the
+ <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+ appcompat</a> support library to your project, as described in <a href=
+ "{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
+ </li>
+
+ <li>Make sure the activity extends {@link
+ android.support.v7.app.AppCompatActivity}:
+
+ <pre>
+public class MyActivity extends AppCompatActivity {
+ // ...
+}
+</pre>
+ <p class="note">
+ <strong>Note:</strong> Make this change for every activity in your app
+ that uses a {@link android.support.v7.widget.Toolbar} as an app bar.
+ </p>
+ </li>
+
+ <li>In the app manifest, set the <a href=
+ "{@docRoot}guide/topics/manifest/application-element.html"><code><application></code></a>
+ element to use one of appcompat's {@link
+ android.support.v7.appcompat.R.style#Theme_AppCompat_NoActionBar NoActionBar}
+ themes. Using one of these themes prevents the app from using the native
+ {@link android.app.ActionBar} class to provide the app bar. For example:
+
+ <pre>
+<application
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar"
+ />
+</pre>
+ </li>
+
+ <li>Add a {@link android.support.v7.widget.Toolbar} to the activity's layout.
+ For example, the following layout code adds a {@link
+ android.support.v7.widget.Toolbar} and gives it the appearance of floating
+ above the activity:
+
+ <pre>
+<android.support.v7.widget.Toolbar
+ android:id="@+id/my_toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ android:elevation="4dp"
+ android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
+ app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
+</pre>
+ <p>
+ The <a href=
+ "https://www.google.com/design/spec/what-is-material/elevation-shadows.html#elevation-shadows-shadows">
+ Material Design specification</a> recommends that app bars have an
+ elevation of 4 dp.
+ </p>
+
+ <p>
+ Position the toolbar at the top of the activity's
+ <a href="{@docRoot}guide/topics/ui/declaring-layout.html">layout</a>,
+ since you are using it as an app bar.
+ </p>
+ </li>
+
+ <li>In the activity's {@link android.app.Activity#onCreate onCreate()}
+ method, call the activity's {@link
+ android.support.v7.app.AppCompatActivity#setSupportActionBar
+ setSupportActionBar()} method, and pass the activity's toolbar. This method
+ sets the toolbar as the app bar for the activity. For example:
+
+ <pre>
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_my);
+ <strong>Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
+ setSupportActionBar(myToolbar);</strong>
+ }
+</pre>
+ </li>
+</ol>
+
+<p>
+ Your app now has a basic action bar. By default, the action bar contains just
+ the name of the app and an overflow menu. The options menu initially contains
+ just the <strong>Settings</strong> item. You can add more actions to the
+ action bar and the overflow menu, as described in <a href=
+ "actions.html">Adding and Handling Actions</a>.
+</p>
+
+<h2 id="utility">Use App Bar Utility Methods</h2>
+
+<p>
+ Once you set the toolbar as an activity's app bar, you have access to the
+ various utility methods provided by the
+ <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+ appcompat</a> support library's {@link
+ android.support.v7.app.ActionBar} class. This approach lets you do a number of useful
+ things, like hide and show the app bar.
+</p>
+
+<p>
+ To use the {@link android.support.v7.app.ActionBar} utility methods, call the
+ activity's {@link
+ android.support.v7.app.AppCompatActivity#getSupportActionBar
+ getSupportActionBar()} method. This method returns a reference to an
+ appcompat {@link android.support.v7.app.ActionBar} object.
+ Once you have that reference, you can call any of the {@link
+ android.support.v7.app.ActionBar} methods to adjust the app bar. For example,
+ to hide the app bar, call {@link android.support.v7.app.ActionBar#hide
+ ActionBar.hide()}.
+</p>
diff --git a/docs/html/training/appbar/up-action.jd b/docs/html/training/appbar/up-action.jd
new file mode 100644
index 0000000..1336d20
--- /dev/null
+++ b/docs/html/training/appbar/up-action.jd
@@ -0,0 +1,134 @@
+page.title=Adding an Up Action
+page.tags="appbar","actionbar", "up"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li>
+ <a href="#declare-parent">Declare a Parent Activity</a>
+ </li>
+
+ <li>
+ <a href="#enable-up">Enable the Up Button</a>
+ </li>
+ </ol>
+
+ <h2>See Also</h2>
+ <ul>
+ <li><a href="{@docRoot}training/implementing-navigation/ancestral.html">
+ Providing Up Navigation</a></li>
+ </ul>
+
+
+ </div>
+</div>
+
+<p>
+ Your app should make it easy for users to find their way back to the app's
+ main screen. One simple way to do this is to provide an <em>Up</em>
+ button on the app bar for all activities except the main one. When the user
+ selects the <em>Up</em> button, the app navigates to the parent
+ activity.
+</p>
+
+<p>
+ This lesson shows you how to add an <em>Up</em> button to an activity by
+ declaring the activity's parent in the manifest, and enabling the app bar's
+ <em>Up</em> button.
+</p>
+
+<h2 id="declare-parent">Declare a Parent Activity</h2>
+
+<p>
+ To support the up functionality in an activity, you need to declare the
+ activity's parent. You can do this in the app manifest, by setting an
+ <code>android:parentActivityName</code> attribute.
+</p>
+
+<p>
+ The <code>android:parentActivityName</code> attribute
+ was introduced in Android 4.1 (API level 16). To support devices with older
+ versions of Android, define a <a href=
+ "{@docRoot}guide/topics/manifest/meta-data-element.html"><code><meta-data></code></a>
+ name-value pair, where the name is
+ <code>"android.support.PARENT_ACTIVITY"</code> and the value is the name of
+ the parent activity.
+</p>
+
+<p>
+ For example, suppose your app has a main activity named
+ <code>MainActivity</code> and a single child activity. The following manifest
+ code declares both activities, and specifies the parent/child relationship:
+</p>
+<pre>
+<application ... >
+ ...
+
+ <!-- The main/home activity (it has no parent activity) -->
+
+ <activity
+ android:name="com.example.myfirstapp.MainActivity" ...>
+ ...
+ </activity>
+
+ <!-- A child of the main activity -->
+ <activity
+ android:name="com.example.myfirstapp.MyChildActivity"
+ android:label="@string/title_activity_child"
+ <strong>android:parentActivityName="com.example.myfirstapp.MainActivity"</strong> >
+
+ <!-- Parent activity meta-data to support 4.0 and lower -->
+ <meta-data
+ <strong>android:name="android.support.PARENT_ACTIVITY"
+ android:value="com.example.myfirstapp.MainActivity" /></strong>
+ </activity>
+</application>
+</pre>
+
+<h2 id="enable-up">Enable the Up Button</h2>
+
+<p>
+ To enable the <em>Up</em> button for an activity that has a parent
+ activity, call the app bar's {@link
+ android.support.v7.app.ActionBar#setDisplayHomeAsUpEnabled
+ setDisplayHomeAsUpEnabled()} method. Typically, you would do this when the
+ activity is created. For example, the following {@link
+ android.app.Activity#onCreate onCreate()} method sets a {@link
+ android.support.v7.widget.Toolbar} as the app bar for
+ <code>MyChildActivity</code>, then enables that app bar's <em>Up</em> button:
+</p>
+
+<pre>
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_my_child);
+
+ // my_child_toolbar is defined in the layout file
+ Toolbar myChildToolbar =
+ (Toolbar) findViewById(R.id.my_child_toolbar);
+ setSupportActionBar(myChildToolbar);
+
+ // Get a support ActionBar corresponding to this toolbar
+ ActionBar ab = getSupportActionBar();
+
+ // Enable the Up button
+ <strong>ab.setDisplayHomeAsUpEnabled(true);</strong>
+}
+</pre>
+
+<p>
+ You do <em>not</em> need to catch the up action in the activity's {@link
+ android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method.
+ Instead, that method should call its superclass, as shown in <a href=
+ "actions.html#handle-actions">Respond to Actions</a>. The superclass method
+ responds to the <em>Up</em> selection by navigating to the parent
+ activity, as specified in the app manifest.
+</p>
diff --git a/docs/html/training/articles/assistant.jd b/docs/html/training/articles/assistant.jd
new file mode 100644
index 0000000..a1fbd6b
--- /dev/null
+++ b/docs/html/training/articles/assistant.jd
@@ -0,0 +1,317 @@
+page.title=Optimizing Content for the Assistant
+page.metaDescription=Support contextually relevant actions through the Assist API.
+page.tags=assist, accessibility, now, now on tap
+meta.tags="assistant", "marshmallow", "now"
+page.image=images/cards/card-assist_16-9_2x.png
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#assist_api">Using the Assist API</a>
+ <ol>
+ <li><a href="#assist_api_lifecycle">Assist API Lifecycle</a></li>
+ <li><a href="#source_app">Source App</a></li>
+ <li><a href="#destination_app">Destination App</a></li>
+ </ol>
+ </li>
+ <li><a href="#implementing_your_own_assistant">Implementing your
+ own assistant</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Android 6.0 Marshmallow introduces a new way for users to engage with apps
+ through the assistant.
+</p>
+
+<p>
+ Users summon the assistant with a long-press on the Home button or by saying
+ the {@link android.service.voice.AlwaysOnHotwordDetector keyphrase}. In
+ response to the long-press, the system opens a top-level window that displays
+ contextually relevant actions for the current activity. These potential
+ actions might include deep links to other apps on the device.
+</p>
+
+<p>
+ This guide explains how Android apps use Android's Assist API to improve the
+ assistant user experience.
+</p>
+
+
+<h2 id="assist_api">Using the Assist API</h2>
+
+<p>
+ The example below shows how Google Now integrates with the Android assistant
+ using a feature called Now on Tap.
+</p>
+
+<p>
+ The assistant overlay window in our example (2, 3) is implemented by Google
+ Now through a feature called Now on Tap, which works in concert with the
+ Android platform-level functionality. The system allows the user to select
+ the assistant app (Figure 2) that obtains contextual information from the
+ <em>source</em> app using the Assist API which is a part of the platform.
+</p>
+
+
+<div>
+ <img src="{@docRoot}images/training/assistant/image01.png">
+ <p class="img-caption" style="text-align:center;">
+ Figure 1. Assistant interaction example with the Now on Tap feature of
+ Google Now
+ </p>
+</div>
+
+<p>
+ An Android user first configures the assistant and can change system options
+ such as using text and view hierarchy as well as the screenshot of the
+ current screen (Figure 2).
+</p>
+
+<p>
+ From there, the assistant receives the information only when the user
+ activates assistance, such as when they tap and hold the Home button ( shown
+ in Figure 1, step 1).
+</p>
+
+<div style="float:right;margin:1em;max-width:300px">
+ <img src="{@docRoot}images/training/assistant/image02.png">
+ <p class="img-caption" style="text-align:center;">
+ Figure 2. Assist & voice input settings (<em>Settings/Apps/Default
+ Apps/Assist & voice input</em>)
+ </p>
+</div>
+
+<h3 id="assist_api_lifecycle">Assist API Lifecycle</h3>
+
+<p>
+ Going back to our example from Figure 1, the Assist API callbacks are invoked
+ in the <em>source</em> app after step 1 (user long-presses the Home button)
+ and before step 2 (the assistant renders the overlay window). Once the user
+ selects the action to perform (step 3), the assistant executes it, for
+ example by firing an intent with a deep link to the (<em>destination</em>)
+ restaurant app (step 4).
+</p>
+
+<h3 id="source_app">Source App</h3>
+
+<p>
+ In most cases, your app does not need to do anything extra to integrate with
+ the assistant if you already follow <a href=
+ "{@docRoot}guide/topics/ui/accessibility/apps.html">accessibility best
+ practices</a>. This section describes how to provide additional information
+ to help improve the assistant user experience, as well as scenarios, such as
+ custom Views, that need special handling.
+</p>
+
+<h4 id="share_additional_information_with_the_assistant">Share Additional Information with the Assistant</h4>
+
+<p>
+ In addition to the text and the screenshot, your app can share
+ <em>additional</em> information with the assistant. For example, your music
+ app can choose to pass current album information, so that the assistant can
+ suggest smarter actions tailored to the current activity.
+</p>
+
+<p>
+ To provide additional information to the assistant, your app provides
+ <em>global application context</em> by registering an app listener and
+ supplies activity-specific information with activity callbacks as shown in
+ Figure 3.
+</p>
+
+<div>
+ <img src="{@docRoot}images/training/assistant/image03.png">
+ <p class="img-caption" style="text-align:center;">
+ Figure 3. Assist API lifecycle sequence diagram.
+ </p>
+</div>
+
+<p>
+ To provide global application context, the app creates an implementation of
+ {@link android.app.Application.OnProvideAssistDataListener} and registers it
+ using {@link
+ android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener)}.
+ In order to provide activity-specific contextual information, activity
+ overrides {@link android.app.Activity#onProvideAssistData(android.os.Bundle)}
+ and {@link
+ android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent)}.
+ The two activity methods are called <em>after</em> the optional global
+ callback (registered with {@link
+ android.app.Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener)})
+ is invoked. Since the callbacks execute on the main thread, they should
+ complete <a href="{@docRoot}training/articles/perf-anr.html">promptly</a>.
+ The callbacks are invoked only when the activity is <a href=
+ "{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">running</a>.
+</p>
+
+<h5 id="providing_context">Providing Context</h5>
+
+<p>
+ {@link android.app.Activity#onProvideAssistData(android.os.Bundle)} is called
+ when the user is requesting the assistant to build a full {@link
+ android.content.Intent#ACTION_ASSIST} Intent with all of the context of the
+ current application represented as an instance of the {@link
+ android.app.assist.AssistStructure}. You can override this method to place
+ into the bundle anything you would like to appear in the
+ <code>EXTRA_ASSIST_CONTEXT</code> part of the assist Intent.
+</p>
+
+<h5 id="describing_content">Describing Content</h5>
+
+<p>
+ Your app can implement {@link
+ android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent)}
+ to improve assistant user experience by providing references to content
+ related to the current activity. You can describe the app content using the
+ common vocabulary defined by <a href="https://schema.org">Schema.org</a>
+ through a JSON-LD object. In the example below, a music app provides
+ structured data to describe the music album the user is currently
+ looking at.
+</p>
+
+<pre class="prettyprint">
+@Override
+public void onProvideAssistContent(AssistContent <strong>assistContent</strong>) {
+ super.onProvideAssistContent(<strong>assistContent</strong>);
+
+ String structuredJson = <strong>new </strong>JSONObject()
+ .put(<strong>"@type"</strong>, <strong>"MusicRecording"</strong>)
+ .put(<strong>"@id"</strong>, <strong>"https://example.com/music/recording"</strong>)
+ .put(<strong>"name"</strong>, <strong>"Album Title"</strong>)
+ .toString();
+
+ <strong>assistContent</strong>.setStructuredData(structuredJson);
+}
+</pre>
+
+<p>
+ Custom implementations of {@link
+ android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent)}
+ may also adjust the provided {@link
+ android.app.assist.AssistContent#setIntent(android.content.Intent) content
+ intent} to better reflect the top-level context of the activity, supply
+ {@link android.app.assist.AssistContent#setWebUri(android.net.Uri) the URI}
+ of the displayed content, and fill in its {@link
+ android.app.assist.AssistContent#setClipData(android.content.ClipData)} with
+ additional content of interest that the user is currently viewing.
+</p>
+
+<h4 id="default_implementation">Default Implementation</h4>
+
+<p>
+ If neither {@link
+ android.app.Activity#onProvideAssistData(android.os.Bundle)} nor {@link
+ android.app.Activity#onProvideAssistContent(android.app.assist.AssistContent)}
+ callbacks are implemented, the system will still proceed and pass the
+ information collected automatically to the assistant unless the current
+ window is flagged as <a href="#excluding_views">secure</a>.
+ As shown in Figure 3, the system uses the default implementations of {@link
+ android.view.View#onProvideStructure(android.view.ViewStructure)} and {@link
+ android.view.View#onProvideVirtualStructure(android.view.ViewStructure)} to
+ collect text and view hierarchy information. If your view implements custom
+ text drawing, you should override {@link
+ android.view.View#onProvideStructure(android.view.ViewStructure)} to provide
+ the assistant with the text shown to the user by calling {@link
+ android.view.ViewStructure#setText(java.lang.CharSequence)}.
+</p>
+
+<p>
+ <strong>In most cases, implementing accessibility support will enable the
+ assistant to obtain the information it needs.</strong> This includes
+ providing {@link android.R.attr#contentDescription
+ android:contentDescription} attributes, populating {@link
+ android.view.accessibility.AccessibilityNodeInfo} for custom views, making
+ sure custom {@link android.view.ViewGroup ViewGroups} correctly {@link
+ android.view.ViewGroup#getChildAt(int) expose} their children, and following
+ the best practices described in <a href=
+ "{@docRoot}guide/topics/ui/accessibility/apps.html">“Making Applications
+ Accessible”</a>.
+</p>
+
+<h4 id="excluding_views">Excluding views from the assistant</h4>
+
+<p>
+ An activity can exclude the current view from the assistant. This is accomplished
+ by setting the {@link android.view.WindowManager.LayoutParams#FLAG_SECURE
+ FLAG_SECURE} layout parameter of the WindowManager and must be done
+ explicitly for every window created by the activity, including Dialogs. Your
+ app can also use {@link android.view.SurfaceView#setSecure(boolean)
+ SurfaceView.setSecure} to exclude a surface from the assistant. There is no
+ global (app-level) mechanism to exclude all views from the assistant. Note
+ that <code>FLAG_SECURE</code> does not cause the Assist API callbacks to stop
+ firing. The activity which uses <code>FLAG_SECURE</code> can still explicitly
+ provide information to the assistant using the callbacks described earlier
+ this guide.
+</p>
+
+<h4 id="voice_interactions">Voice Interactions</h4>
+
+<p>
+ Assist API callbacks are also invoked upon {@link
+ android.service.voice.AlwaysOnHotwordDetector keyphrase detection}. For more
+ information see the <a href="https://developers.google.com/voice-actions/">voice
+ actions</a> documentation.
+</p>
+
+<h4 id="z-order_considerations">Z-order considerations</h4>
+
+<p>
+ The assistant uses a lightweight overlay window displayed on top of the
+ current activity. The assistant can be summoned by the user at any time.
+ Therefore, apps should not create permanent {@link
+ android.Manifest.permission#SYSTEM_ALERT_WINDOW system alert}
+ windows interfering with the overlay window shown in Figure 4.
+</p>
+
+<div style="">
+ <img src="{@docRoot}images/training/assistant/image04.png">
+ <p class="img-caption" style="text-align:center;">
+ Figure 4. Assist layer Z-order.
+ </p>
+</div>
+
+<p>
+ If your app uses {@link
+ android.Manifest.permission#SYSTEM_ALERT_WINDOW system alert} windows, it
+ must promptly remove them as leaving them on the screen will degrade user
+ experience and annoy the users.
+</p>
+
+<h3 id="destination_app">Destination App</h3>
+
+<p>
+ The matching between the current user context and potential actions displayed
+ in the overlay window (shown in step 3 in Figure 1) is specific to the
+ assistant’s implementation. However, consider adding <a href=
+ "{@docRoot}training/app-indexing/deep-linking.html">deep linking</a> support
+ to your app. The assistant will typically take advantage of deep linking. For
+ example, Google Now uses deep linking and <a href=
+ "https://developers.google.com/app-indexing/">App Indexing</a> in order to
+ drive traffic to destination apps.
+</p>
+
+<h2 id="implementing_your_own_assistant">Implementing your own assistant </h2>
+
+<p>
+ Some developers may wish to implement their own assistant. As shown in Figure
+ 2, the active assistant app can be selected by the Android user. The
+ assistant app must provide an implementation of {@link
+ android.service.voice.VoiceInteractionSessionService} and {@link
+ android.service.voice.VoiceInteractionSession} as shown in <a href=
+ "https://android.googlesource.com/platform/frameworks/base/+/android-5.0.1_r1/tests/VoiceInteraction?autodive=0%2F%2F%2F%2F%2F%2F">
+ this</a> example and it requires the {@link
+ android.Manifest.permission#BIND_VOICE_INTERACTION} permission. It can then
+ receive the text and view hierarchy represented as an instance of the {@link
+ android.app.assist.AssistStructure} in {@link
+ android.service.voice.VoiceInteractionSession#onHandleAssist(android.os.Bundle,
+ android.app.assist.AssistStructure,android.app.assist.AssistContent) onHandleAssist()}.
+ The assistant receives the screenshot through {@link
+ android.service.voice.VoiceInteractionSession#onHandleScreenshot(android.graphics.Bitmap)
+ onHandleScreenshot()}.
+</p>
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index aa1ed0a..a1563a7 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -1,8 +1,8 @@
page.title=Android Keystore System
@jd:body
-<div id="qv-wrapper">
- <div id="qv">
+<div id="tb-wrapper">
+<div id="tb">
<h2>In this document</h2>
<ol>
<li><a href="#SecurityFeatures">Security Features</a></li>
@@ -442,7 +442,7 @@
<td>
<ul>
<li>Supported sizes: 224, 256, 384, 521</li>
- <li>Supported named curves: P-224 (secp256r1), P-256 (aka secp256r1 and prime256v1), P-384
+ <li>Supported named curves: P-224 (secp224r1), P-256 (aka secp256r1 and prime256v1), P-384
(aka secp384r1), P-521 (aka secp521r1)</li>
</ul>
diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
index b32cc4f..bbebec5 100644
--- a/docs/html/training/articles/perf-anr.jd
+++ b/docs/html/training/articles/perf-anr.jd
@@ -91,7 +91,7 @@
resizing bitmaps should be done in a worker thread (or in the case of databases
operations, via an asynchronous request).</p>
-<p>The most effecive way to create a worker thread for longer
+<p>The most effective way to create a worker thread for longer
operations is with the {@link android.os.AsyncTask}
class. Simply extend {@link android.os.AsyncTask} and implement the
{@link android.os.AsyncTask#doInBackground doInBackground()} method to perform the work.
@@ -168,7 +168,7 @@
<p class="note"><strong>Tip:</strong>
You can use {@link android.os.StrictMode} to help find potentially
long running operations such as network or database operations that
-you might accidentally be doing your main thread.</p>
+you might accidentally be doing on your main thread.</p>
diff --git a/docs/html/training/articles/security-ssl.jd b/docs/html/training/articles/security-ssl.jd
index 7f43d9c..c3a2d9e 100644
--- a/docs/html/training/articles/security-ssl.jd
+++ b/docs/html/training/articles/security-ssl.jd
@@ -376,9 +376,8 @@
hostname to the server so the proper certificate can be returned.</p>
<p>Fortunately, {@link javax.net.ssl.HttpsURLConnection} supports
-SNI since Android 2.3. Unfortunately, Apache
-HTTP Client does not, which is one of the many reasons we discourage its use. One workaround
-if you need to support Android 2.2 (and older) or Apache HTTP Client is to set up an alternative
+SNI since Android 2.3. One workaround
+if you need to support Android 2.2 (and older) is to set up an alternative
virtual host on a unique port so that it's unambiguous which server certificate to return.</p>
<p>The more drastic alternative is to replace {@link javax.net.ssl.HostnameVerifier}
diff --git a/docs/html/training/articles/user-data-ids.jd b/docs/html/training/articles/user-data-ids.jd
new file mode 100644
index 0000000..5a4648b
--- /dev/null
+++ b/docs/html/training/articles/user-data-ids.jd
@@ -0,0 +1,741 @@
+page.title=Best Practices for Unique Identifiers
+page.metaDescription=How to manage unique identifiers the right way for users.
+page.tags=ids, user data
+meta.tags="ids", "user data"
+page.image=images/cards/card-user-ids_2x.png
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#tenets_of_working_with_android_identifiers">Tenets of Working with
+ Android Identifiers</a></li>
+ <li><a href="#version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</a></li>
+ <li><a href="#working_with_advertising_ids">Working with Advertising IDs</a></li>
+ <li><a href="#working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</a></li>
+ <li><a href="#understand_identifier_characteristics">Understanding Identifier
+ Characteristics</a>
+ <ol>
+ <li><a href="#scope">Scope</a></li>
+ <li><a href="#resettability_&_persistence">Resettability & persistence</a></li>
+ <li><a href="#uniqueness">Uniqueness</h3>
+ <li><a href="#integrity_protection_and_non-repudiability">Integrity protection and
+ non-repudiability</a></li>
+ </ol>
+ </li>
+ <li><a href="#use_appropriate_identifiers">Common Use Cases and the Identifier to Use</a>
+ <ol>
+ <li><a href="#a_track_signed-out_user_preferences">Tracking signed-out user
+ preferences</a></li>
+ <li><a href="#b_track_signed-out_user_behavior">Tracking signed-out user behavior</a></li>
+ <li><a href="#c_generate_signed-out_anonymous_user_analytics">Generating
+ signed-out/anonymous user analytics</a></li>
+ <li><a href="#d_track_signed-out_user_conversion">Tracking signed-out user
+ conversion</a></li>
+ <li><a href="#e_handle_multiple_installations">Handling multiple installations</a></li>
+ <li><a href="#f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud:
+ Enforcing free content limits / detecting Sybil attacks</a></li>
+ <li><a href="#g_manage_telephony_&_carrier_functionality">Managing telephony and carrier
+ functionality</a></li>
+ <li><a href="#h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
+ Identifying bots and DDoS attacks</a></li>
+ <li><a href="#i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
+ Detecting high value stolen credentials</a></li>
+ </ol>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ While there are valid reasons why your application may need to identify a
+ device rather than an instance of the application or an authenticated user on
+ the device, for the vast majority of applications, the ultimate goal is to
+ identify a particular <em>installation</em> of your app (not the actual
+ physical device).
+</p>
+
+<p>
+ Fortunately, identifying an installation on Android is straightforward using
+ an Instance ID or by creating your own GUID at install time. This document
+ provides guidance for selecting appropriate identifiers for your application,
+ based on your use-case.
+</p>
+
+<p>
+ For a general look at Android permissions, please see <a href=
+ "{@docRoot}training/articles/user-data-overview.html">Permissions
+ and User Data</a>. For specific best practices for
+ working with Android permissions, please see <a href=
+ "{@docRoot}training/articles/user-data-permissions.html">Best Practices for
+ App Permissions</a>.
+</p>
+
+
+<h2 id="tenets_of_working_with_android_identifiers">Tenets of Working with Android Identifiers</h2>
+
+<p>
+ We recommend that you follow these tenets when working with Android
+ identifiers:
+</p>
+
+<p>
+ <em><strong>#1: Avoid using hardware identifiers.</strong></em> Hardware
+ identifiers such as SSAID (Android ID) and IMEI can be avoided in most
+ use-cases without limiting required functionality.
+</p>
+
+<p>
+ <em><strong>#2: Only use Advertising ID for user profiling or ads
+ use-cases.</strong></em> When using an <a href=
+ "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
+ Advertising ID</a>, always respect the <a href=
+ "https://play.google.com/about/developer-content-policy.html#ADID">Limit Ad
+ Tracking</a> flag, ensure the identifier cannot be connected to personally
+ identifiable information (PII) and avoid bridging Advertising ID resets.
+</p>
+
+<p>
+ <em><strong>#3: Use an Instance ID or a privately stored GUID whenever
+ possible for all other use-cases except payment fraud prevention and
+ telephony.</strong></em> For the vast majority of non-ads use-cases, an
+ instance ID or GUID should be sufficient.
+</p>
+
+<p>
+ <em><strong>#4: Use APIs that are appropriate to your use-case to minimize
+ privacy risk.</strong></em> Use the
+ <a href="http://source.android.com/devices/drm.html">DRM
+ API</a> API for high value content
+ protection and the <a href="{@docRoot}training/safetynet/index.html">SafetyNet
+ API</a> for abuse prevention. The Safetynet API is
+ the easiest way to determine whether a device is genuine without incurring
+ privacy risk.
+</p>
+
+<p>
+ The remaining sections of this guide elaborate on these rules in the context
+ of developing Android applications.
+</p>
+
+<h2 id="version_specific_details_identifiers_in_m">Identifiers in Android 6.0+</h2>
+
+<p>
+ MAC addresses are globally unique, not user-resettable and survive factory
+ reset. It is generally not recommended to use MAC address for any form of
+ user identification. As a result, as of Android M, local device MAC addresses
+ (for example, Wifi and Bluetooth) <em><strong>are not available via third party
+ APIs</strong></em>. The {@link android.net.wifi.WifiInfo#getMacAddress WifiInfo.getMacAddress()}
+ method and the {@link android.bluetooth.BluetoothAdapter#getAddress
+ BluetoothAdapter.getDefaultAdapter().getAddress()} method will
+ both return <code>02:00:00:00:00:00</code>..
+</p>
+
+<p>
+ Additionally, you must hold the following permissions to access MAC addresses
+ of nearby external devices available via Bluetooth and Wifi scans:
+</p>
+
+<table>
+ <tr>
+ <th><strong>Method/Property</strong></td>
+ <th><strong>Permissions Required</strong></td>
+ </tr>
+ <tr>
+ <td>
+ <code><a href="{@docRoot}reference/android/net/wifi/WifiManager.html#getScanResults()">WifiManager.getScanResults()</a></code>
+ </td>
+ <td>
+ <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <code><a href="{@docRoot}reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND">BluetoothDevice.ACTION_FOUND</a></code>
+ </td>
+ <td>
+ <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <code><a href="{@docRoot}reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(android.bluetooth.le.ScanCallback)">BluetoothLeScanner.startScan(ScanCallback)</a></code>
+ </td>
+ <td>
+ <code>ACCESS_FINE_LOCATION</code> or <code>ACCESS_COARSE_LOCATION</code>
+ </td>
+ </tr>
+</table>
+
+
+<h2 id="working_with_advertising_ids">Working with Advertising IDs</h2>
+
+<p>
+ Advertising ID is a user-resettable identifier and is appropriate for Ads
+ use-cases, but there are some key points to bear in mind when using it:
+</p>
+
+<p>
+ <em><strong>Always respect the user’s intention in resetting the advertising
+ ID</strong></em>. Do not bridge user resets by using a more persistent device
+ identifier or fingerprint to link subsequent Advertising IDs together without
+ the user’s consent. The <a href=
+ "https://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Content Policy</a> states:
+</p>
+
+<div style="padding:.5em 2em;">
+<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
+<p>...upon reset, a new advertising
+ identifier must not be connected to a previous advertising identifier or data
+ derived from a previous advertising identifier without the explicit consent
+ of the user</span></p>
+</div>
+</div>
+
+<p>
+ <em><strong>Always respect the associated Interest Based Advertising
+ flag</strong></em>. Advertising IDs are configurable in that users can limit
+ the amount of tracking associated with the ID. Always use the <code><a href=
+ "https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html#isLimitAdTrackingEnabled()">
+ AdvertisingIdClient.Info.isLimitAdTrackingEnabled()</a></code> method to
+ ensure you are not circumventing your users' wishes. The <a href=
+ "https://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Content Policy</a> states:
+</p>
+
+
+<div style="padding:.5em 2em;">
+<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
+<p>...you must abide by a user’s ‘opt out of
+ interest-based advertising’ setting. If a user has enabled this setting, you
+ may not use the advertising identifier for creating user profiles for
+ advertising purposes or for targeting users with interest-based advertising.
+ Allowed activities include contextual advertising, frequency capping,
+ conversion tracking, reporting and security and fraud detection.</span></p>
+</div>
+</div>
+
+<p>
+ <em><strong>Be aware of any privacy or security policies associated with SDKs
+ you use that are related to Advertising ID use.</strong></em> For example, if
+ you are using the Google Analytics SDK
+ <code><a href=
+ "https://developers.google.com/android/reference/com/google/android/gms/analytics/Tracker.html#enableAdvertisingIdCollection(boolean)">mTracker.enableAdvertisingIdCollection(true)</a></code>
+ method, make sure to review and adhere to all applicable <a href=
+ "https://developers.google.com/analytics/devguides/collection/android/v4/policy">
+ Analytics SDK policies</a>.
+</p>
+
+<p>
+ Also, be aware that the <a href=
+ "https://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Content Policy</a> requires that the Advertising ID “must not be
+ connected to personally-identifiable information or associated with any
+ persistent device identifier (for example: SSAID, MAC address, IMEI, etc.,)
+ without the explicit consent of the user.”
+</p>
+
+<p>
+ As an example, suppose you want to collect information to populate database
+ tables with the following columns:
+</p>
+
+<table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td class="tab2">
+ <code>timestamp</code></td>
+ <td class="tab2">
+ <code>ad_id</code></td>
+ <td>
+ <code><strong>account_id</strong></code></td>
+ <td class="tab2">
+ <code>clickid</code></td>
+ </tr>
+ </table>
+
+ <p>TABLE-01</p>
+ </td>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <code><strong>account_id</strong></code></td>
+ <td class="tab2">
+ <code>name</code></td>
+ <td class="tab2">
+ <code>dob</code></td>
+ <td class="tab2">
+ <code>country</code></td>
+ </tr>
+ </table>
+ <p>TABLE-02</p>
+ </td>
+ </tr>
+</table>
+
+
+<p>
+ In this example, the <code>ad_id</code> column could be joined to PII via the
+ <code>account_id</code> column in both tables, which would be a violation of
+ the <a href=
+ "https://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Content Policy</a>.
+</p>
+
+<p>
+ Keep in mind that links between Advertiser ID and PII aren't always this
+ explicit. It's possible to have “quasi-identifiers” that appear in both PII
+ and Ad ID keyed tables, which also cause problems. For example, assume we
+ change TABLE-01 and TABLE-02 as follows:
+</p>
+
+<table>
+ <tr>
+ <td><table>
+ <tr>
+ <td>
+ <code><strong>timestamp</strong></code></td>
+ <td class="tab2">
+ <code>ad_id</code></td>
+ <td>
+ <code>clickid</code></td>
+ <td>
+ <code><strong>dev_model</strong></code></td>
+ </tr>
+ </table>
+
+ </pre>
+ <p>TABLE-01</p>
+ </td>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <code><strong>timestamp</strong></code></td>
+ <td class="tab2">
+ <code>demo</code></td>
+ <td class="tab2">
+ <code>account_id</code></td>
+ <td>
+ <code><strong>dev_model</strong></code></td>
+ <td class="tab2">
+ <code>name</code></td>
+ </tr>
+ </table>
+ <p>TABLE-02</p>
+ </td>
+ </tr>
+</table>
+
+
+<p>
+ In this case, with sufficiently rare click events, it's still possible to
+ join between the Advertiser ID TABLE-01 and the PII contained in TABLE-2
+ using the timestamp of the event and the device model.
+</p>
+
+<p>
+ While it is often difficult to guarantee that no such quasi-identifiers exist
+ in a dataset, the most obvious join risks can be prevented by generalizing
+ unique data where possible. In the example, this would mean reducing the
+ accuracy of the timestamp so that multiple devices with the same model appear
+ for every timestamp.
+</p>
+
+<p>
+ Other solutions include:
+</p>
+
+<ul>
+<li><em><strong>Not designing tables that explicitly link PII with Advertising
+IDs</strong></em>. In the first example above this would mean not including the
+account_id column in TABLE-01.</li>
+
+<li><em><strong>Segregating and monitoring access control lists for users or roles
+that have access to both the Advertising ID keyed data and PII</strong></em>. If the
+ability to access both sources simultaneously (for example, to perform
+a join between two tables) is tightly controlled and audited, it reduces the
+risk of association between the Advertising ID and PII. Generally speaking,
+controlling access means:
+
+<ol>
+ <li> Keeping access control lists (ACLs) for Advertiser ID keyed data and PII disjoint to
+ minimize the number of individuals or roles that are in both ACLs, and</li>
+ <li> Implementing access logging and auditing to detect and manage any exceptions to
+ this rule.</li>
+</ol>
+</li>
+</ul>
+
+<p>
+ For more information on working responsibly with Advertising IDs, please see
+ the <a href=
+ "https://support.google.com/googleplay/android-developer/answer/6048248?hl=en">
+ Advertising ID</a> help center article.
+</p>
+
+<h2 id="working_with_instance_ids_&_guids">Working with Instance IDs and GUIDs</h2>
+
+<p>
+ The most straightforward solution to identifying an application instance
+ running on a device is to use an Instance ID, and this is the recommended
+ solution in the majority of non-ads use-cases. Only the app instance for
+ which it was provisioned can access this identifier, and it's (relatively)
+ easily resettable because it only persists as long as the app is installed.
+</p>
+
+<p>
+ As a result, Instance IDs provide better privacy properties compared to
+ non-resettable, device-scoped hardware IDs. They also come with a key-pair
+ for message signing (and similar actions) and are available on Android, iOS
+ and Chrome. Please see the <a href=
+ "https://developers.google.com/instance-id/">What is Instance ID?</a> help
+ center document for more information.
+</p>
+
+<p>
+ In cases where an Instance ID isn't practical, custom globally unique IDs
+ (GUIDs) can also be used to uniquely identify an app instance. The simplest
+ way to do so is by generating your own GUID using the following code.
+</p>
+
+<pre>String uniqueID = UUID.randomUUID().toString();</pre>
+
+<p>
+ Because the identifier is globally unique, it can be used to identify a
+ specific app instance. To avoid concerns related to linking the identifier
+ across applications, GUIDs should be stored in internal storage rather than
+ external (shared) storage. Please see <a href=
+ "{@docRoot}guide/topics/data/data-storage.html">Storage Options</a> guide for
+ more information.
+</p>
+
+
+<h2 id="understand_identifier_characteristics">Understanding Identifier Characteristics</h2>
+
+<p>
+ The Android Operating system offers a number of IDs with different behavior
+ characteristics and which ID you should use depends on how those following
+ characteristics work with your use-case. But these characteristics also come
+ with privacy implications so it's important to understand how these
+ characteristics play together.
+</p>
+
+<h3 id="scope">Scope</h3>
+
+<p>
+ Identifier scope explains which systems can access the identifier. Android
+ identifier scope generally comes in three flavors:
+</p>
+
+<ul>
+ <li> <em>Single app</em>. the ID is internal to the app and not accessible to other apps.
+ <li> <em>Group of apps</em> - the ID is accessible to a pre-defined group of related apps.
+ <li> <em>Device</em> - the ID is accessible to all apps installed on the device.
+</ul>
+
+<p>
+ The wider the scope granted to an identifier, the greater the risk of it
+ being used for tracking purposes. Conversely, if an identifier can only be
+ accessed by a single app instance, it can’t be used to track a device across
+ transactions in different apps.
+</p>
+<h3 id="resettability_&_persistence">Resettability and persistence</h3>
+
+<p>
+ Resettability and persistence define the lifespan of the identifier and
+ explain how it can be reset. Common reset triggers are: in-app resets, resets
+ via System Settings, resets on launch, and resets on installation. Android
+ Identifiers can have varying lifespans, but the lifespan is usually related
+ to how the ID is reset:
+</p>
+<ul>
+ <li> <em>Session-only</em> - a new ID is used every time the user restarts the app.
+ <li> <em>Install-reset</em> - a new ID is used every time user uninstalls and reinstalls the app.
+ <li> <em>FDR-reset</em> - a new ID is used every time the user factory-resets the device.
+ <li> <em>FDR-persistent</em> - the ID survives factory reset.
+</ul>
+
+<p>
+ Resettability gives users the ability to create a new ID that is
+ disassociated from any existing profile information. This is important
+ because the longer, and more reliably, an identifier persists (e.g. across
+ factory resets etc.), the greater the risk that the user may be subjected to
+ long-term tracking. If the identifier is reset upon app reinstall, this
+ reduces the persistence and provides a means for the ID to be reset, even if
+ there is no explicit user control to reset it from within the app or the
+ System Settings.
+</p>
+<h3 id="uniqueness">Uniqueness</h3>
+
+<p>
+ Uniqueness establishes the likelihood that identical identifiers exist within
+ the associated scope. At the highest level, a globally unique identifier will
+ never have a collision - even on other devices/apps. Otherwise, the level of
+ uniqueness depends on the size of the identifier and the source of randomness
+ used to create it. For example, the chance of a collision is much higher for
+ random identifiers seeded with the calendar date of installation (e.g.,
+ 2015-01-05) than for identifiers seeded with the Unix timestamp of
+ installation (e.g., 1445530977).
+</p>
+
+<p>
+ In general, user account identifiers can be considered unique (i.e., each
+ device/account combo has a unique ID). On the other hand, the less unique
+ an identifier is within a population (e.g. of devices), the greater the
+ privacy protection because it's less useful for tracking an individual user.
+</p>
+
+<h3 id="integrity_protection_and_non-repudiability">Integrity protection and
+non-repudiability</h3>
+
+<p>
+ An identifier that is difficult to spoof or replay can be used to prove that
+ the associated device or account has certain properties (e.g. it’s not a
+ virtual device used by a spammer). Difficult to spoof identifiers also
+ provide <em>non-repudiability</em>. If the device signs a message with a
+ secret key, it is difficult to claim someone else’s device sent the message.
+ Non-repudiability could be something a user wants (e.g. authenticating a
+ payment) or it could be an undesirable property (e.g. sending a message they
+ regret).
+</p>
+
+
+<h2 id="use_appropriate_identifiers">Common Use Cases and the Identifier to Use</h2>
+
+<p>
+ This section provides alternatives to using hardware IDs such as IMEI or
+ SSAID for the majority of use-cases. Relying on hardware IDs is discouraged
+ because the user cannot reset them and generally has limited control over
+ their collection.
+</p>
+
+<h3 id="a_track_signed-out_user_preferences">Tracking signed-out user preferences</h3>
+
+<p>
+ <em>In this case, you are saving per-device state on the server side.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Instance ID or a GUID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ Persisting information through reinstalls is not recommended because users
+ may want to reset their preferences by reinstalling the app.
+</p>
+
+<h3 id="b_track_signed-out_user_behavior">Tracking signed-out user behavior</h3>
+
+<p>
+ <em>In this case, you have created a profile of a user based on their
+ behavior across different apps/sessions on the same device.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Advertising ID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ Use of the Advertising ID is mandatory for Advertising use-cases per the
+ <a href="https://play.google.com/about/developer-content-policy.html">Google
+ Play Developer Content Policy</a> because the user can reset it.
+</p>
+
+<h3 id="c_generate_signed-out_anonymous_user_analytics">Generating signed-out/anonymous user analytics</h3>
+
+<p>
+ <em>In this case, you are measuring usage statistics and analytics for
+ signed-out or anonymous users.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Instance ID; if an Instance ID is
+ insufficient, you can also use a GUID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ An Instance ID or a GUID is scoped to the app that creates it, which prevents
+ it from being used to track users across apps. It is also easily reset by
+ clearing app data or reinstalling the app. Creating Instance IDs and GUIDs is
+ straightforward:
+</p>
+
+<ul>
+ <li> Creating an Instance ID: <code>String iid = InstanceID.getInstance(context).getId()</code>
+ <li> Creating a GUID: <code>String uniqueID = UUID.randomUUID().toString</code>
+</ul>
+
+<p>
+ Be aware that if you have told the user that the data you are collecting is
+ anonymous, you should <em><strong>ensure you are not connecting the
+ identifier to PII</strong></em> or other identifiers that may be linked to
+ PII.
+</p>
+
+<p>
+ You can also use Google Analytics for Mobile Apps, which offers a solution
+ for per-app analytics.
+</p>
+
+<h3 id="d_track_signed-out_user_conversion">Tracking signed-out user conversion</h3>
+
+<p>
+ <em>In this case, you are tracking conversions to detect if your marketing
+ strategy was successful.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Advertising ID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ This is an ads-related use-case which may require an ID that is available
+ across different apps so using an Advertising ID is the most appropriate
+ solution.
+</p>
+
+<h3 id="e_handle_multiple_installations">Handling multiple installations</h3>
+
+<p>
+ <em>In this case, you need to identify the correct instance of the app when
+ it's installed on multiple devices for the same user.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Instance ID or GUID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ Instance ID is designed explicitly for this purpose; its scope is limited to
+ the app so that it cannot be used to track users across different apps and it
+ is reset upon app reinstall. In the rare cases where an Instance ID is
+ insufficient, you can also use a GUID.
+</p>
+
+<h3 id="f_anti-fraud_enforcing_free_content_limits_detecting_sybil_attacks">Anti-fraud: Enforcing free content limits / detecting Sybil attacks</h3>
+
+<p>
+ <em>In this case, you want to limit the number of free content (e.g.
+ articles) a user can see on a device.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: Instance ID or GUID.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ Using a GUID or Instance ID forces the user to reinstall the app in order to
+ overcome the content limits, which is a sufficient burden to deter most
+ people. If this is not sufficient protection, Android provides a
+ <a href="http://source.android.com/devices/drm.html">DRM API</a>
+ which can be used to limit access to content.
+</p>
+
+<h3 id="g_manage_telephony_&_carrier_functionality">Managing telephony and carrier functionality</h3>
+
+<p>
+ <em>In this case, your app is interacting with the device's phone and texting
+ functionality.</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: IMEI, IMSI, and Line1 (requires <code>PHONE</code>
+ permission group in Android 6.0 (API level 23) and higher).
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ Leveraging hardware identifiers is acceptable if it is required for
+ telephony/carrier related functionality; for example, switching between
+ cellular carriers/SIM slots or delivering SMS messages over IP (for Line1) -
+ SIM-based user accounts. But it's important to note that in Android 6.0+
+ these identifiers can only be used via a runtime permission and that users
+ may toggle off this permission so your app should handle these exceptions
+ gracefully.
+</p>
+
+<h3 id="h_abuse_detection_identifying_bots_and_ddos_attacks">Abuse detection:
+Identifying bots and DDoS attacks</h3>
+
+<p>
+ <em>In this case, you are trying to detect multiple fake devices attacking
+ your backend services.</em>
+</p>
+
+<p>
+ <strong>We Recommend:</strong> The Safetynet API.
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ An identifier in isolation does little to indicate that a device is genuine.
+ You can verify that a request comes from a genuine Android device (as opposed
+ to an emulator or other code spoofing another device) using the Safetynet
+ API's <code>SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)</code>
+ method to verify the integrity of a device making a request. For more
+ detailed information, please see <a href=
+ "{@docRoot}training/safetynet/index.html">Safetynet's API documentation</a>.
+</p>
+
+<h3 id="i_abuse_detection_detecting_high_value_stolen_credentials">Abuse detection:
+Detecting high value stolen credentials</h3>
+
+<p>
+ <em>In this case, you are trying to detect if a single device is being used
+ multiple times with high-value, stolen credentials (e.g. to make fraudulent
+ payments).</em>
+</p>
+
+<p>
+ <strong>We Recommend</strong>: IMEI/IMSI (requires <code>PHONE</code>
+ permission group in Android 6.0 (API level 23) and higher.)
+</p>
+
+<p>
+ <strong>Why this Recommendation?</strong>
+</p>
+
+<p>
+ With stolen credentials, devices can be used to monetize multiple high value
+ stolen credentials (such as tokenized credit cards). In these scenarios,
+ software IDs can be reset to avoid detection, so hardware identifiers may be
+ used.
+</p>
\ No newline at end of file
diff --git a/docs/html/training/articles/user-data-overview.jd b/docs/html/training/articles/user-data-overview.jd
new file mode 100644
index 0000000..8715d36
--- /dev/null
+++ b/docs/html/training/articles/user-data-overview.jd
@@ -0,0 +1,269 @@
+page.title=Permissions and User Data
+page.metaDescription=An overview of permissions on Android and how to manage them.
+page.tags="user data","permissions","identifiers"
+page.image=images/cards/card-user_2x.png
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#introduction">Introduction</a></li>
+ <li><a href="#permission_groups">Permission Groups</a></li>
+ <li><a href="#permission_requests_and_app_downloads">Permission
+ Requests and App Downloads</a></li>
+ <li><a href="#permission_requests_trend_downward">Permission Requests
+ Trend Downward</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ol>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></li>
+ <li><a href="{@docRoot}training/permissions/index.html">Working with System
+ Permissions</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Permissions protect sensitive information available from a device and should
+ only be used when access to information is necessary for the functioning of
+ your app.
+</p>
+
+<p>
+ This document provides a high-level overview on how permissions work in
+ Android so you can make better, more informed decisions about the permissions
+ you're requesting. The information in this document is not use-case specific
+ and avoids complex, low-level discussions of the underlying code.
+</p>
+
+<p>
+ For specific recommendations on how to manage permissions, please see
+ <a href="{@docRoot}training/articles/user-data-permissions.html">Best
+ Practices for App Permissions</a>. For best practices on using unique
+ identifiers on Android, please see <a href=
+ "{@docRoot}training/articles/user-data-ids.html">Best Practices for Unique
+ Identifiers</a>. For details on how to work with permissions in your code,
+ see <a href="{@docRoot}training/permissions/index.html">Working with System
+ Permissions</a>.
+</p>
+
+
+<h2 id="introduction">Introduction</h2>
+
+<p>
+ Every Android application must have a <em>manifest file</em> that presents
+ essential information about the app to the Android system. The Android system
+ also requires apps to request permission when they want to access sensitive
+ device or user information, and these requests must be documented in advance
+ as a part of your app's manifest. Moreover, accessing sensitive information
+ can affect user behavior, so it's important to make sure you are only making
+ permission requests when that information is necessary for the functioning of
+ your app.
+</p>
+
+
+<h2 id="permission_groups">Permission Groups</h2>
+
+<p>
+ Permissions in Android are organized into <code><a href=
+ "{@docRoot}guide/topics/security/permissions.html#perm-groups">permission
+ groups</a></code> that organize, and group, permissions related to a device's
+ capabilities or features. Under this system, permission requests are handled
+ at the group level and a <em><strong>single permission group</strong></em>
+ corresponds to <em><strong>several permission declarations</strong></em> in
+ the app manifest; for example, the SMS group includes both the
+ <code>READ_SMS</code> and the <code>RECEIVE_SMS</code> declarations.
+</p>
+
+
+<div class="wrap">
+ <img src="{@docRoot}images/training/articles/user-data-overview-permissions-flow01.jpg">
+</div>
+
+<p>
+ This arrangement is simpler and more informative for users; once an app is
+ granted permission to access the group, it can use API calls within that
+ group and users with auto-update enabled will not be asked for additional
+ permissions because they have already granted access to the group. Grouping
+ permissions in this way enables the user to make more meaningful and informed
+ choices, without being overwhelmed by complex and technical permission
+ requests.
+</p>
+
+<p>
+ This also means that when you request access to a particular API call or
+ query a content provider behind a permission, the user will be presented with
+ a request to grant permission for the whole group rather than the specific
+ API call. For example, if you request the <code>WRITE_CALL_LOG</code>
+ permission, the user will be asked to grant access to the <em>PHONE</em>
+ group (in API level 23 and higher), which is composed of the
+ <code>READ_PHONE_STATE</code>, <code>CALL_PHONE</code>,
+ <code>READ_CALL_LOG</code>, <code>WRITE_CALL_LOG</code>,
+ <code>ADD_VOICEMAIL</code>, <code>USE_SIP</code>, and
+ <code>PROCESS_OUTGOING_CALLS</code> permissions, and
+ all their associated methods.
+</p>
+
+<div class="wrap">
+ <img src="{@docRoot}images/training/articles/user-data-overview-permissions-flow02.png">
+</div>
+
+<p>
+ One consequence of grouping permissions is that a single API call within your
+ app can have a multiplying effect in terms of the number of permissions
+ requested by your app.
+</p>
+
+<ol>
+<li>API Call →</li>
+<li stydle="margin-left:.5em;">Triggers a specific <em>Permission Group</em> access
+request →</li>
+<li stydle="margin-left:1em;">Successful request grants access to all permissions in
+group (if auto-update
+enabled) →</li>
+<li stydle="margin-left:1.5em;">Each permission grants access to all APIs under that
+permission</li>
+</ol>
+
+<p>
+ As another example, let's assume your application uses one or more <a href=
+ "{@docRoot}reference/android/telephony/TelephonyManager.html"><code>TelephonyManager</code></a>
+ methods, such as:
+</p>
+
+<pre class="prettyprint">
+TelephonyManager.getDeviceId()
+TelephonyManager.getSubscriberId()
+TelephonyManager.getSimSerialNumber()
+TelephonyManager.getLine1Number()
+TelephonyManager.getVoiceMailNumber()
+</pre>
+
+<p>
+ To use these methods, the <code>READ_PHONE_STATE</code> permission must be
+ declared in the app's manifest, and the associated permission group,
+ <em>PHONE</em>, will be surfaced to the user. This
+ is important, because it means the user will be asked to grant permission for
+ the relevant group and all its associated permissions and API calls, rather
+ than for the specific API call you're requesting.
+</p>
+
+<p>For a full mapping between permissions and their associated permission groups,
+please refer to the appropriate version-specific documentation below:</p>
+
+<ul>
+ <!--<li> <a href="">pre-M Android OS versions</a>.</li> -->
+ <li> <a href="{@docRoot}guide/topics/security/permissions.html#perm-groups">Permission
+ groups, Android 6.0 Marshmallow (API level 23) and later</a>.</li>
+</ul>
+
+
+<h2 id="permission_requests_and_app_downloads">Permission Requests and App Downloads</h2>
+
+<div style="padding:.5em 2em;">
+<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
+<p><em>I'm currently using the READ_PHONE_STATE permission in Android to pause my
+media player when there's a call, and to resume playback when the call is over.
+The permission seems to scare a lot of people</em>...<span
+style="font-size:.8em;color:#777"><sup><em><a
+href="#references" style="color:#777;padding-left:.1em;">1</a></em></sup></span></p>
+</div>
+</div>
+
+<p>
+ Research shows that among apps that are otherwise identical (e.g.,
+ functionality, brand recognition), requesting fewer permissions leads to more
+ downloads. Publicly available sources exist that assign grades to apps based
+ on their permissions usage and allow users to compare related apps by score;
+ such grades exist for many of the current Android apps and users pay close
+ attention to the related rankings.
+</p>
+
+<p>
+ One study<span style="font-size:.8em;color:#777"><sup><em><a href=
+ "#references" style=
+ "color:#777;padding-left:.1em;">2</a></em></sup></span>, in which users
+ were shown two unbranded apps with similar ratings that had the same
+ functionality but different sets of permission requests, showed that users
+ were, on average, 3 times more likely to install the app with fewer
+ permissions requests. And a similar study <span style=
+ "font-size:.8em;color:#777"><sup><em><a href="#references" style=
+ "color:#777;padding-left:.1em;">3</a></em></sup></span> showed that users are 1.7
+ times more likely, on average, to select the application with fewer
+ permission requests.
+</p>
+
+<p>
+ Finally, permissions usage is not evenly distributed across apps within
+ a similar category of Play apps. For example, 39.3% of arcade game apps in
+ the Play store request no permissions that are surfaced to the user while
+ only 1.5% of arcade games request the Phone permission group (see Figure
+ 1).
+</p>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-16of16">
+ <img src="{@docRoot}images/training/articles/user-data-overview-permissions-groups.png">
+ <p class="figure-caption"><strong>Figure 1.</strong> Distribution of
+ permission groups use across Arcade Games category.</p>
+ </div>
+ </div>
+</div>
+
+<p>
+ Users comparing your app to other similar apps may determine that it is
+ making unusual permission requests for that category - in this case, Arcade
+ Games apps accessing the <em>Phone</em> permission group. As a result, they
+ may install a similar app in that category that avoids those
+ requests.<span style="font-size:.8em;color:#777"><sup><em><a href=
+ "#references" style="color:#777;padding-left:.1em;">4</a></em></sup></span>
+</p>
+
+
+<h2 id="permission_requests_trend_downward">Permission Requests Trend Downward</h2>
+
+<p>
+ A recent analysis of Play store apps over time indicated that many developers
+ trim permissions after first publishing their apps, suggesting that they may
+ be employing more caution around which permission groups they declare.
+</p>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-16of16">
+ <img src="{@docRoot}images/training/articles/user-data-overview-permissions-usage.jpg">
+ <p class="figure-caption"><strong>Figure 2.</strong> Developer usage of popular
+ permissions has decreased over time.</p>
+ </div>
+ </div>
+</div>
+
+<p>
+ The graph in <em>Figure 2</em> illustrates this trend. There has been a
+ steady decrease in the average percentage of developers' apps requesting at
+ least one of the three most popular permissions in the Play store
+ (<code>READ_PHONE_STATE</code>, <code>ACCESS_FINE_LOCATION</code>, and
+ <code>ACCESS_COARSE_LOCATION</code>). These results indicate that developers
+ are reducing the permissions their apps request in response to user behavior.
+</p>
+
+<p>
+ The bottom line is that providing the same functionality to the user with
+ minimal access to sensitive information means more downloads for your app.
+ For specific recommendations on how to achieve this, please see <a href=
+ "{@docRoot}training/articles/user-data-permissions.html">Best Practices for
+ Application Permissions</a>.
+</p>
+
+
+<h2 id="references">References</h2>
+
+<p>[1] Developer quote on StackOverflow. <em>(<a
+ href="http://stackoverflow.com/questions/24374701/alternative-to-read-phone-state-permission-for-getting-notified-of-call">source</a>)</em></p>
+<p>[2] <em>Using Personal Examples to Improve Risk Communication for Security and Privacy Decisions</em>, by M. Harbach, M. Hettig, S. Weber, and M. Smith. In Proceedings of ACM CHI 2014.</p>
+<p>[3] <em>Modeling Users’ Mobile App Privacy Preferences: Restoring Usability in a Sea of Permission Settings</em>, by J. Lin B. Liu, N. Sadeh and J. Hong. In Proceedings of SOUPS 2014.</p>
+<p>[4] <em>Teens and Mobile Apps Privacy. (<a href="http://www.pewinternet.org/files/old-media/Files/Reports/2013/PIP_Teens%20and%20Mobile%20Apps%20Privacy.pdf">source</a>)</em></p>
diff --git a/docs/html/training/articles/user-data-permissions.jd b/docs/html/training/articles/user-data-permissions.jd
new file mode 100644
index 0000000..edc7558
--- /dev/null
+++ b/docs/html/training/articles/user-data-permissions.jd
@@ -0,0 +1,381 @@
+page.title=Best Practices for App Permissions
+page.metaDescription=How to manage permissions to give users context and control.
+page.tags=permissions, user data
+meta.tags="permissions", "user data"
+page.image=images/cards/card-user-permissions_2x.png
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#tenets_of_working_with_android_permissions">Tenets</a></li>
+ <li><a href="#version_specific_details_permissions_in_m">Permissions in Android
+ 6.0+</h2></a></li>
+ <li><a href="#avoid_requesting_unnecessary_permissions">Avoid Requesting
+Unnecessary Permissions</h2></a>
+ <ol>
+ <li><a href="#a_camera_contact_access_with_real-time_user_requests">Camera/Contact
+ access with realtime user requests</a></li>
+ <li><a href="#b_running_in_the_background_after_losing_audio_focus">Running in
+the background after losing audio focus</a></li>
+ <li><a href="#c_determine_the_device_your_instance_is_running_on">Determine the
+device your instance is running on</a></li>
+ <li><a href="#d_create_a_unique_identifier_for_advertising_or_user_analytics">
+Create a unique identifier for advertising or user analytics</a></li>
+ </ol>
+ </li>
+ <li><a href="#know_the_libraries_you're_working_with">Know the Libraries You're
+Working With</a></li>
+ <li><a href="#be_transparent">Be Transparent</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ol>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></li>
+ <li><a href="{@docRoot}training/permissions/index.html">Working with System
+ Permissions</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Permission requests protect sensitive information available from a device and
+ should only be used when access to information is necessary for the
+ functioning of your app. This document provides tips on ways you might be
+ able to achieve the same (or better) functionality without requiring access
+ to such information; it is not an exhaustive discussion of how permissions
+ work in the Android operating system.
+</p>
+
+<p>
+ For a more general look at Android permissions, please see <a href=
+ "{@docRoot}training/articles/user-data-overview.html">Permissions
+ and User Data</a>. For details on how to work with permissions in your code,
+ see <a href="{@docRoot}training/permissions/index.html">Working with System Permissions</a>.
+ For best practices for working with unique identifiers, please see <a href=
+ "{@docRoot}training/articles/user-data-ids.html">Best Practices for
+ Unique Identifiers</a>.
+</p>
+
+<h2 id="tenets_of_working_with_android_permissions">Tenets of Working
+with Android Permissions</h2>
+
+<p>
+ We recommend following these tenets when working with Android permissions:
+</p>
+
+<p>
+ <em><strong>#1: Only use the permissions necessary for your app to
+ work</strong></em>. Depending on how you are using the permissions, there may
+ be another way to do what you need (system intents, identifiers,
+ backgrounding for phone calls) without relying on access to sensitive
+ information.
+</p>
+
+<p>
+ <em><strong>#2: Pay attention to permissions required by
+ libraries.</strong></em> When you include a library, you also inherit its
+ permission requirements. You should be aware of what you're including, the
+ permissions they require, and what those permissions are used for.
+</p>
+
+<p>
+ <em><strong>#3: Be transparent.</strong></em> When you make a permissions
+ request, be clear about what you’re accessing, and why, so users can make
+ informed decisions. Make this information available alongside the permission
+ request including install, runtime, or update permission dialogues.
+</p>
+
+<p>
+ <em><strong>#4: Make system accesses explicit.</strong></em> Providing
+ continuous indications when you access sensitive capabilities (for example, the
+ camera or microphone) makes it clear to users when you’re collecting data and
+ avoids the perception that you're collecting data surreptitiously.
+</p>
+
+<p>
+ The remaining sections of this guide elaborate on these rules in the context
+ of developing Android applications.
+</p>
+
+<h2 id="version_specific_details_permissions_in_m">Permissions in Android 6.0+</h2>
+
+<p>
+ Android 6.0 Marshmallow introduced a <a href=
+ "{@docRoot}training/permissions/requesting.html">new permissions model</a> that
+ lets apps request permissions from the user at runtime, rather than prior to
+ installation. Apps that support the new model request permissions when the app
+ actually requires the services or data protected by the services. While this
+ doesn't (necessarily) change overall app behavior, it does create a few
+ changes relevant to the way sensitive user data is handled:
+</p>
+
+<p>
+ <em><strong>Increased situational context</strong></em>: Users are
+ prompted at runtime, in the context of your app, for permission to access the
+ functionality covered by those permission groups. Users are more sensitive to
+ the context in which the permission is requested, and if there’s a mismatch
+ between what you are requesting and the purpose of your app, it's even
+ more important to provide detailed explanation to the user as to why you’re
+ requesting the permission; whenever possible, you should provide an
+ explanation of your request both at the time of the request and in a
+ follow-up dialog if the user denies the request.
+</p>
+
+<p>
+ <em><strong>Greater flexibility in granting permissions</strong></em>: Users
+ can deny access to individual permissions at the time they’re requested
+ <em>and</em> in settings, but they may still be surprised when functionality is
+ broken as a result. It’s a good idea to monitor how many users are denying
+ permissions (e.g. using Google Analytics) so that you can either refactor
+ your app to avoid depending on that permission or provide a better
+ explanation of why you need the permission for your app to work properly. You
+ should also make sure that your app handles exceptions created when users
+ deny permission requests or toggle off permissions in settings.
+</p>
+
+<p>
+ <em><strong>Increased transactional burden</strong></em>: Users will be asked
+ to grant access for permission groups individually and not as a set. This
+ makes it extremely important to minimize the number of permissions you’re
+ requesting because it increases the user burden for granting permissions and
+ increases the probability that at least one of the requests will be denied.
+</p>
+
+<h2 id="avoid_requesting_unnecessary_permissions">Avoid Requesting
+Unnecessary Permissions</h2>
+
+<p>
+ This section provides alternatives to common use-cases that will help you
+ limit the number of permission requests you make. Since the number and type
+ of user-surfaced permissions requested affects downloads compared to other
+ similar apps requesting fewer permissions, it’s best to avoid requesting
+ permissions for unnecessary functionality.
+</p>
+
+<h3 id="a_camera_contact_access_with_real-time_user_requests">Camera/contact
+access with realtime user requests</h3>
+
+<p>
+ <em>In this case, you need occasional access to the device's camera or
+ contact information and don’t mind the user being asked every time you need
+ access.</em>
+</p>
+
+<p>
+ If your requirement for access to user data is infrequent — in other
+ words, it's not unacceptably disruptive for the user to be presented with a
+ runtime dialogue each time you need to access data — you can use an
+ <em>intent based request</em>. Android provides some system intents that
+ applications can use without requiring permissions because the user chooses
+ what, if anything, to share with the app at the time the intent based request
+ is issued.
+</p>
+
+<p>
+ For example, an intent action type of <code><a href=
+ "{@docRoot}reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE">MediaStore.ACTION_IMAGE_CAPTURE</a></code>
+ or <code><a href=
+ "{@docRoot}reference/android/provider/MediaStore.html#ACTION_VIDEO_CAPTURE">MediaStore.ACTION_VIDEO_CAPTURE</a></code>
+ can be used to capture images or videos without directly using the <a href=
+ "{@docRoot}reference/android/hardware/Camera.html">Camera</a> object (or
+ requiring the permission). In this case, the system intent will ask for the
+ user’s permission on your behalf every time an image is captured.
+</p>
+
+<h3 id="b_running_in_the_background_after_losing_audio_focus">Running in
+the background after losing audio focus</h3>
+
+<p>
+ <em>In this case, your application needs to go into the background when the
+ user gets a phone call and refocus only once the call stops.</em>
+</p>
+
+<p>
+ The common approach in these cases - for example, a media player muting or
+ pausing during a phone call - is to listen for changes in the call state
+ using <code>PhoneStateListener</code> or listening for the broadcast of
+ <code>android.intent.action.PHONE_STATE</code>. The problem with this
+ solution is that it requires the <code>READ_PHONE_STATE</code> permission,
+ which forces the user to grant access to a wide cross section of sensitive
+ data such as their device and SIM hardware IDs and the phone number of the
+ incoming call.
+</p>
+
+<p>
+ You can avoid this by requesting <code>AudioFocus</code> for your app, which
+ doesn't require explicit permissions (because it does not access sensitive
+ information). Simply put the code required to background your audio in the
+ <code><a href=
+ "{@docRoot}reference/android/media/AudioManager.OnAudioFocusChangeListener.html#onAudioFocusChange(int)">
+ onAudioFocusChange()</a></code> event handler and it will run automatically
+ when the OS shifts its audio focus. More detailed documentation on how to do
+ this can be found <a href=
+ "{@docRoot}training/managing-audio/audio-focus.html">here</a>.
+</p>
+
+<h3 id="c_determine_the_device_your_instance_is_running_on">Determine the
+device your instance is running on</h3>
+
+<p>
+ <em>In this case, you need a unique identifier to determine which device the
+ instance of your app is running on.</em>
+</p>
+
+<p>
+ Applications may have device-specific preferences or messaging (e.g., saving
+ a device-specific playlist for a user in the cloud so that they can have a
+ different playlist for their car and at home). A common solution is to
+ leverage device identifiers such as <code>Device IMEI</code>, but this
+ requires the <code>Device ID and call information</code>
+ permission group (<code>PHONE</code> in M+). It also uses an identifier which
+ cannot be reset and is shared across all apps.
+</p>
+
+<p>
+ There are two alternatives to using these types of identifiers:
+</p>
+
+<ol>
+ <li> Use the <code>com.google.android.gms.iid</code> InstanceID API.
+ <code>getInstance(Context context).getID()<strong></code> </strong>will return a
+ unique device identifier for your application instance. The
+result is an app instance scoped identifier that can be used as a key when
+storing information about the app and is reset if the user re-installs the app.
+ <li> Create your own identifier that’s scoped to your app’s storage using basic
+ system functions like <a
+ href="{@docRoot}reference/java/util/UUID.html#randomUUID()"><code>randomUUID()</code></a>.</li>
+</ol>
+
+<h3 id="d_create_a_unique_identifier_for_advertising_or_user_analytics">Create a unique
+identifier for advertising or user analytics</h3>
+
+<p>
+ <em>In this case, you need a unique identifier for building a profile for
+ users who are not signed in to your app (e.g., for ads targeting or measuring
+ conversions).</em>
+</p>
+
+<p>
+ Building a profile for advertising and user analytics sometimes requires an
+ identifier that is shared across other applications. Common solutions for
+ this involve leveraging device identifiers such as <code>Device IMEI</code>,
+ which requires the <code>Device ID</code> <code>and call information</code>
+ permission group (<code>PHONE</code> in API level 23+) and cannot be reset by
+ the user. In any of these cases, in addition to using a non-resettable
+ identifier and requesting a permission that might seem unusual to users, you
+ will also be in violation of the <a href=
+ "https://play.google.com/about/developer-content-policy.html">Play Developer
+ Program Policies</a>.
+</p>
+
+<p>
+ Unfortunately, in these cases using the
+ <code>com.google.android.gms.iid</code> InstanceID API or system functions to
+ create an app-scoped ID are not appropriate solutions because the ID may need
+ to be shared across apps. An alternative solution is to use the
+ <code>Advertising Identifier</code> available from the <code><a href=
+ "{@docRoot}reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info.html">
+ AdvertisingIdClient.Info</a></code> class via the <code>getId()</code>
+ method. You can create an <code>AdvertisingIdClient.Info</code> object using
+ the <code>getAdvertisingIdInfo(Context)</code> method and call the
+ <code>getId()</code> method to use the identifier. <em><strong>Note that this
+ method is blocking</strong></em>, so you should not call it from the main
+ thread; a detailed explanation of this method is available <a href=
+ "{@docRoot}google/play-services/id.html">here</a>.
+</p>
+
+<h2 id="know_the_libraries_you're_working_with">Know the Libraries You're
+Working With</h2>
+
+<p>
+ Sometimes permissions are required by the libraries you use in your app. For
+ example, ads and analytics libraries may require access to the
+ <code>Location</code> or <code>Identity</code> permissions groups to
+ implement the required functionality. But from the user’s point of view, the
+ permission request comes from your app, not the library.
+</p>
+
+<p>
+ Just as users select apps that use fewer permissions for the same
+ functionality, developers should review their libraries and select
+ third-party SDKs that are not using unnecessary permissions. For example, try
+ to avoid libraries that require the <code>Identity</code> permission group
+ unless there is a clear user-facing reason why the app needs those permissions.
+ In particular, for libraries that provide location functionality, make sure you
+ are not required to request the <code>FINE_LOCATION</code> permission unless
+ you are using location-based targeting functionality.
+</p>
+
+<h2 id="be_transparent">Be Transparent</h2>
+
+<p>You should inform your users about what you’re accessing and why. Research shows
+that users are much less uncomfortable with permissions requests if they know
+why the app needs them. A user study showed that:</p>
+
+<div style="padding:.5em 2em;">
+<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
+<p>...a user’s willingness to grant a given permission to a given mobile app is
+strongly influenced by the purpose associated with such a permission. For
+instance a user’s willingness to grant access to his or her location will vary
+based on whether the request is required to support the app’s core
+functionality or whether it is to share this information with an advertising
+network or an analytics company.<span
+style="font-size:.8em;color:#777"><sup><em><a
+ href="#references" style="color:#777;padding-left:.1em;">1</a></em></sup></span></p>
+</div>
+</div>
+
+<p>
+ Based on his group’s research, Professor Jason Hong from CMU concluded that,
+ in general:
+</p>
+
+<div style="padding:.5em 2em;">
+<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
+<p>...when people know why an app is using something as sensitive as their location —
+for example, for targeted advertising — it makes them more comfortable than
+when simply told an app is using their location.<span
+style="font-size:.8em;color:#777"><sup><em><a
+ href="#references" style="color:#777;padding-left:.1em;">1</a></em></sup></span></p>
+</div>
+</div>
+
+<p>
+ As a result, if you’re only using a fraction of the API calls that fall under
+ a permission group, it helps to explicitly list which of those permissions
+ you're using, and why. For example:
+</p>
+
+<ul>
+ <li> If you’re only using coarse location, let the user know this in your app
+ description or in help articles about your app. </li>
+ <li> If you need access to SMS messages to receive authentication codes that
+ protect the user from fraud, let the user know this in your app description
+ and/or the first time you access the data.</li>
+</ul>
+
+<p>
+ Under certain conditions, it's also advantageous to let users know about
+ sensitive data accesses in real-time. For example, if you’re accessing the
+ camera or microphone, it’s usually a good idea to let the user know with a
+ notification icon somewhere in your app, or in the notification tray (if the
+ application is running in the background), so it doesn't seem like you're
+ collecting data surreptitiously.
+</p>
+
+<p>
+ Ultimately, if you need to request a permission to make something in your app
+ work, but the reason is not clear to the user, find a way to let the user
+ know why you need the most sensitive permissions.
+</p>
+
+<h2 id="references">References</h2>
+
+<p>
+ [1] <em>Modeling Users’ Mobile App Privacy Preferences: Restoring Usability
+ in a Sea of Permission Settings</em>, by J. Lin B. Liu, N. Sadeh and J. Hong.
+ In Proceedings of SOUPS 2014.
+</p>
diff --git a/docs/html/training/articles/wear-permissions.jd b/docs/html/training/articles/wear-permissions.jd
new file mode 100644
index 0000000..5f226e4
--- /dev/null
+++ b/docs/html/training/articles/wear-permissions.jd
@@ -0,0 +1,323 @@
+page.title=Requesting Permissions on Android Wear
+page.tags="Permissions"
+
+page.article=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>In this document</h2>
+<ol class="nolist">
+ <li><a href="#scenarios">Permission Scenarios</a></li>
+ <li><a href="#requesting">Requesting Permissions</a></li>
+ <li><a href="#services">Permissions for Services</a></li>
+ <li><a href="#settings">Settings</a></li>
+</ol>
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li><a href="{@docRoot}about/versions/marshmallow/index.html">Android 6.0</a>
+ (API Level 23) or higher on the wearable and accompanying device</li>
+ <li><a href="{@docRoot}google/play-services/index.html">Google Play
+services</a> 8.3 or higher</li>
+ <li>An <a href="{@docRoot}wear/index.html">Android Wear</a> device</li>
+</ul>
+<h2>See also</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html">System Permissions</a></li>
+ <li><a href="{@docRoot}training/permissions/index.html">Working with System Permissions</a></li>
+</ul>
+</div></div>
+
+<p><a href="{@docRoot}about/versions/marshmallow/index.html">Android 6.0</a> (API level 23)
+introduces a new <a href="{@docRoot}training/permissions/requesting.html">permissions model</a>,
+bringing some changes that are specific to Wear, and other changes that apply to all Android-powered
+devices.</p>
+
+<p>The user must now grant permissions to Wear apps separately from the handset versions of the
+apps. Previously, when a user installed a Wear app, it automatically inherited the set of
+permissions that the user had granted to the handset version of the app. However, from Android 6.0
+(API level 23), the Wear app no longer inherits these permissions. Thus, for example,
+a user might grant a handset app permission to use location data, and subsequently
+have to grant the same permission to the Wear version of the app.</p>
+
+<p>For both Wear and handset apps, the Android 6.0 (API level 23) permissions model also
+streamlines app installation and upgrade by eliminating the requirement that the user grant upfront
+every permission an app may ever need. Instead, the app does not request permissions until it
+actually needs them.</p>
+
+<p class="note"><strong>Note: </strong> For an app to use the new permissions model, it must
+specify a value of {@code 23} for both
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code uses-sdk-element}</a>
+and <a href="{@docRoot}tools/building/configuring-gradle.html">{@code compileSdkVersion}</a>.</p>
+
+<p>The rest of this document discusses how to use the Android 6.0 (API level 23) permissions model
+when developing Android Wear apps.</p>
+
+<h2 id="scenarios">Permission Scenarios</h2>
+
+<p>Broadly speaking, there are four scenarios you may encounter when requesting
+<a href="{@docRoot}guide/topics/security/permissions.html#normal-dangerous">dangerous permissions</a>
+on Android Wear:</p>
+
+<ul>
+ <li>The <em>Wear app</em> requests permissions for an app running on the <em>wearable</em>
+ device.</li>
+
+ <li>The <em>Wear app</em> requests permissions for an app running on the <em>handset</em>.</li>
+
+ <li>The <em>handset app</em> requests permissions for an app running on the
+ <em>wearable</em> device.</li>
+
+ <li>The wearable app uses a <em>different permission model</em> from its handset counterpart.
+ </li>
+</ul>
+
+<p>The rest of this section explains each of these scenarios. For more detailed information
+about requesting permissions, see <a href="#requesting">Requesting Permissions</a>.</p>
+
+<h3 id="wear-app-wear-perm">Wear app requests permission for an app running on the wearable
+device</h3>
+
+<p>When the Wear app requests a permission for an app running on the wearable device, the system
+displays a dialog to prompt the user for that permission. An app or service can only call the
+{@link android.support.v4.app.ActivityCompat#requestPermissions requestPermissions()}
+method from an activity. If the user interacts with your app
+<a href="#services">via a service</a>, such as
+a watch face, the service must open an activity before requesting the permission.</p>
+
+<p>Your app requests permissions in context when it’s clear why the
+permissions are needed to perform a given operation. If it's obvious that your app requires
+certain permissions, your app can prompt for them on launch. If it may not be so obvious,
+you may choose to provide additional education before prompting for a permission.</p>
+
+<p>If an app or watch face requires more than one permission at a time,
+permission requests appear one after the other.</p>
+
+<img src="{@docRoot}images/training/wear/multiple_permissions.png"
+srcset="{@docRoot}images/training/wear/multiple_permissions.png 1x,
+{@docRoot}images/training/wear/multiple_permissions_2x.png 2x"
+alt="Multiple permission screens, one after another." width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Permission screens appearing in succession.
+</p>
+
+<p class="note"><strong>Note:</strong> From Android 6.0 (API level 23), Android Wear
+automatically syncs Calendar, Contact, and Location data to the Wear device. As a result, this
+scenario is the applicable one when Wear requests this data.</p>
+
+<h3>Wear app requests handset permission</h3>
+
+<p>When the Wear app requests a handset permission, the
+Wear app must send the user to the handset to accept the permission. There, the handset app can
+provide additional education to the user via an activity. The activity should include two buttons:
+one for granting, and one for denying, the permission.</p>
+
+<img src="{@docRoot}images/training/wear/open_on_phone.png"
+srcset="{@docRoot}images/training/wear/open_on_phone.png 1x,
+{@docRoot}images/training/wear/open_on_phone_2x.png 2x"
+alt="The Wear app sends the user to the handset to grant permission." width="700"
+height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> Sending the user to the handset to grant permission.
+</p>
+<h3>Handset app requests wearable permission</h3>
+
+<p>When the user is in a handset app and the app requires a wearable permission, the
+handset app must send the user to the wearable to accept the permission.
+The handset app uses the
+{@link android.support.v4.app.ActivityCompat#requestPermissions requestPermissions()}
+method on the wearable to trigger the system permissions dialog.</p>
+
+<img src="{@docRoot}images/training/wear/phone_requests_wear.png"
+srcset="{@docRoot}images/training/wear/phone_requests_wear.png 1x,
+{@docRoot}images/training/wear/phone_requests_wear_2x.png 2x"
+alt="The handset app sends the user to the wearable to grant permission."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> Sending the user to the wearable to grant permission.
+</p>
+
+<h3>Mismatching permission models between wearable and handset app</h3>
+
+<p>If your handset app begins using the Android 6.0 (API level 23) model but your
+wearable app does not, the system downloads the Wear app, but does not install it.
+The first time the user launches the app, the system prompts them to grant all pending permissions.
+Once they do so, it installs the app.
+If your app, for example a watch face, does not have a launcher, the system displays a
+stream notification asking the user to grant the permissions the app needs.
+</p>
+
+<h2 id="requesting">Permission-Request Patterns</h2>
+
+<p>There are different patterns for requesting permission from users. In order of
+priority, they are:</p>
+
+<ul>
+ <li><a href="#aic">Ask in context</a> when the permission is obviously necessary for a specific
+ functionality, but is not necessary for the app to run at all.</li>
+
+ <li><a href="#eic">Educate in context</a> when the reason for requesting the permission is
+ not obvious, and the permission is not necessary for the app to run at all.</li>
+
+ <li><a href="#auf">Ask up front</a> when the need for the permission is obvious, and the
+ permission is required in order for the app to run at all.</li>
+
+ <li><a href="#euf">Educate up front</a> when the need for the permission is not obvious, but
+ the permission is required in order for the app to run at all.</li>
+</ul>
+
+<h3 id="aic">Ask in context</h3>
+
+<p>Your app should request permissions when it’s clear why they are needed in order to perform a
+given operation. Users are more likely to grant a permission when they understand its connection to
+the feature they want to use.</p>
+
+<p>For example, an app may require a user’s location in order to show nearby
+places of interest. When the user taps to search for nearby places, the app can
+immediately request the location permission, because there is a clear
+relationship between searching for nearby places and the need for the location
+permission. The obviousness of this relationship makes it unnecessary for the app to display
+additional education screens.</p>
+
+<img src="{@docRoot}images/training/wear/ask_in_context.png"
+srcset="{@docRoot}images/training/wear/ask_in_context.png 1x,
+{@docRoot}images/training/wear/ask_in_context_2x.png 2x"
+alt="The app requests permission when it's obviously necessary."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> Asking in context.
+
+<h3 id="eic">Educate in context</h3>
+
+<p>If necessary, you may choose to provide additional education before prompting
+for a permission. Again, your app should do this in context of a specific
+action, if it’s unclear why your app needs access to the requested permission
+in order to complete that action.</p>
+
+<p>Figure 5 shows an example of in-context education. The app does not require permissions
+in order to start the timer, but an inline educational cue shows that part of the
+activity (location detection) is locked. When the user taps the cue, a permission-request screen
+appears, allowing the user to unlock location-detection.</p>
+
+<p>You can use the {@link
+ android.support.v4.app.ActivityCompat#shouldShowRequestPermissionRationale
+ shouldShowRequestPermissionRationale()} method to help your app decide whether to provide more
+ information. For additional details, see <a
+ href="{@docRoot}training/permissions/requesting.html#explain">Requesting Permissions
+ at Run Time</a>.</p>
+
+
+<img src="{@docRoot}images/training/wear/educate_in_context.png"
+srcset="{@docRoot}images/training/wear/educate_in_context.png 1x,
+{@docRoot}images/training/wear/educate_in_context_2x.png 2x"
+alt="When the need for the permission arises, the app explains why the permission is necessary."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 5.</strong> Educating in context.
+
+<h3 id="auf">Ask up front</h3>
+
+<p>If your app clearly requires a permission in order to work at all, you can prompt for that
+permission when the user launches the app. For example, a maps app clearly requires access
+to the device’s location to run its expected activities. No further education
+is necessary for this permission.</p>
+
+<img src="{@docRoot}images/training/wear/ask_up_front.png"
+srcset="{@docRoot}images/training/wear/ask_up_front.png 1x,
+{@docRoot}images/training/wear/ask_up_front_2x.png 2x"
+alt="If the app obviously needs a permission to run at all, it can ask for it immediately on
+launch."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 6.</strong> Asking up front.
+
+
+<h3 id="euf">Educate up front</h3>
+
+<p>In some cases, the app requires a permission for basic functionality, but the need for that
+permission is not obvious. In these cases, when the user first
+starts the app or sets a watch face, the app or watch face may choose to educate the user and
+ask for the permission.</p>
+
+<img src="{@docRoot}images/training/wear/educate_up_front.png"
+srcset="{@docRoot}images/training/wear/educate_up_front.png 1x,
+{@docRoot}images/training/wear/educate_up_front_2x.png 2x"
+alt="When requesting a permission on launch, the app can explain why it needs the permission."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 7.</strong> Educating up front.
+
+<h3 id="nope">Handling Rejection</h3>
+
+<p>If a user denies a requested permission that is not critical to an intended
+activity, do not block them from continuing the activity. If certain parts of
+the activity are disabled by the denied permission, provide visual, actionable
+feedback. Figure 8 shows the use of a lock icon to indicate that a feature is
+locked because the user did not grant permission to use it.</p>
+
+<img src="{@docRoot}images/training/wear/deny.png"
+srcset="{@docRoot}images/training/wear/deny.png 1x,
+{@docRoot}images/training/wear/deny_2x.png 2x"
+alt="When the user denies permission, a lock icon is shown alongside the associated feature."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 8.</strong> Lock icon, showing a feature is locked because of denied permission.
+</p>
+<p>When a previously denied wearable permission dialog appears a second
+time, it includes a <strong>Deny, don't show again</strong> option. If the user
+chooses this option, then the only way for them to allow this permission in the
+future is to go into the wearable's Settings app.</p>
+
+<img src="{@docRoot}images/training/wear/ask_again.png"
+srcset="{@docRoot}images/training/wear/ask_again.png 1x,
+{@docRoot}images/training/wear/ask_again_2x.png 2x"
+alt="The system offers to stop requesting permission."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 9.</strong> Offering not to show the permission-request screen anymore.
+
+<h2 id="services">Permissions for Services</h2>
+
+<p>As mentioned above, only an activity can call the
+{@link android.support.v4.app.ActivityCompat#requestPermissions requestPermissions()}
+method, so if the user interacts with your app via a service,
+for example a watch face, the service must open a background activity before requesting
+the permission. This activity could provide additional education, or it could simply
+be an invisible activity that brings up the system dialog.</p>
+
+<p>If your wearable app runs a service that is not a watch face, and the user does not launch
+an app in which it might make sense to request a permission,
+you can post an educational notification on the wearable. The notification can
+provide an action to open an activity that then triggers the system permissions
+dialog.</p>
+
+<p class="note"><strong>Note:</strong> This is the only acceptable use of a stream notification
+for permissions requests.</p>
+
+<img src="{@docRoot}images/training/wear/for_services.png"
+srcset="{@docRoot}images/training/wear/for_services.png 1x,
+{@docRoot}images/training/wear/for_services_2x.png 2x"
+alt="The user may need to grant a permission when indirectly interacting with an app, via a
+service."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 10.</strong> A service requesting permission.
+
+<h2 id="settings">Settings</h2>
+
+<p>As with the handset, the user can change a Wear app’s permissions in Settings at any time.
+Therefore, when the user tries to do something that requires a
+permission, the app should always first call the
+{@link android.support.v4.content.ContextCompat#checkSelfPermission(android.content.Context,java.lang.String) checkSelfPermission()}
+method to see if the app currently has permission to perform this operation. The app should perform
+this check even if it knows the user has previously granted that permission, since the
+user might have subsequently revoked that permission.</p>
+
+<img src="{@docRoot}images/training/wear/for_settings.png"
+srcset="{@docRoot}images/training/wear/for_settings.png 1x,
+{@docRoot}images/training/wear/for_settings_2x.png 2x"
+alt="The user can change permissions through the Settings app."
+width="700" height="" id="permission-flow" />
+<p class="img-caption">
+ <strong>Figure 11.</strong> Changing settings via the Settings app.
diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
index f5a797c..9144900 100644
--- a/docs/html/training/auto/audio/index.jd
+++ b/docs/html/training/auto/audio/index.jd
@@ -19,6 +19,7 @@
<ol>
<li><a href="#overview">Provide Audio Services</a></li>
<li><a href="#config_manifest">Configure Your Manifest</a></li>
+ <li><a href="#isconnected">Determine if Your App is Connected</a></li>
<li><a href="#implement_browser">Build a Browser Service</a></li>
<li><a href="#implement_callback">Implement Play Controls</a></li>
<li><a href="#support_voice">Support Voice Actions</a></li>
@@ -29,8 +30,8 @@
<ul>
<li><a href="{@docRoot}samples/MediaBrowserService/index.html">
MediaBrowserService</a></li>
- <li><a href="//github.com/googlesamples/android-UniversalMusicPlayer">Universal Media
- Player</a></li>
+ <li><a href="//github.com/googlesamples/android-UniversalMusicPlayer"
+ class="external-link">Universal Media Player</a></li>
</ul>
<h2>See Also</h2>
@@ -210,6 +211,34 @@
<p class="note"><strong>Note:</strong> The icon you provide should have transparency enabled, so the
icon's background gets filled in with the app's primary color.</p>
+<h2 id="isconnected">Determine if Your App is Connected</h2>
+<p>
+It is possible to determine if your app is selected as the current media app.</p>
+<p>
+Android Auto broadcasts an intent with <code>com.google.android.gms.car.media.STATUS</code>
+action when a user connects or disconnects from a media app. The broadcast intent is
+scoped to the package name of the media app selected. You can register a broadcast receiver in your
+app, preferably in your <a href="{@docRoot}reference/android/service/media/MediaBrowserService.html">
+MediaBrowserService</a> implementation and listen for this intent
+and adjust advertisements, metadata, and UI buttons in your app to operate safely in a vehicle.</p>
+
+<p>The broadcasted intent has a String extra <code>media_connection_status</code>, that
+contains either <code>media_connected</code> or <code>media_disconnected</code> string that represents
+ the current connection status. </p>
+
+<pre>
+IntentFilter filter = new IntentFilter("com.google.android.gms.car.media.STATUS");
+BroadcastReceiver receiver = new BroadcastReceiver() {
+ ...
+ public void onReceive(Context context, Intent intent) {
+ String status = intent.getStringExtra("media_connection_status");
+ boolean isConnectedToCar = "media_connected".equals(status);
+ // adjust settings based on the connection status
+ }
+};
+registerReceiver(receiver, filter);
+</pre>
+
<h2 id="implement_browser">Build a Browser Service</h2>
@@ -290,13 +319,20 @@
<p>Your implementation of {@link android.service.media.MediaBrowserService#onGetRoot
onGetRoot()} returns information about the root node of the menu
-hierarchy. This root node is the parent of the top items your browse hierarchy.
+hierarchy. This root node is the parent of the top items of your browse hierarchy.
The method is passed information about the calling client. You can use this
information to decide if the client should have access to your content at all.
For example, if you want to limit your app's content to a list of approved
-clients, you can compare the passed {@code clientPackageName} to your whitelist.
-If the caller isn't an approved package, you can return null to deny access to
-your content.</p>
+clients, you can compare the passed {@code clientPackageName} to your whitelist
+and verify the certificate used to sign the caller's APK.
+If the caller can't be verified to be an approved package, return null to deny access to
+your content. For an example of an app that validates that the caller is an
+approved app, see the
+<a href="https://github.com/googlesamples/android-UniversalMusicPlayer/blob/master/mobile/src/main/java/com/example/android/uamp/PackageValidator.java"
+class="external-link"><code>PackageValidator</code></a> class in the
+<a href="https://github.com/googlesamples/android-UniversalMusicPlayer"
+class="external-link">Universal Android Music Player</a> sample app.
+</p>
<p>A typical implementation of {@link
android.service.media.MediaBrowserService#onGetRoot onGetRoot()} might
@@ -307,28 +343,23 @@
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
Bundle rootHints) {
- // To ensure you are not allowing any arbitrary app to browse your app's
- // contents, you need to check the origin:
- if (!PackageValidator.isCallerAllowed(this, clientPackageName, clientUid)) {
+ // Verify that the specified package is allowed to access your
+ // content! You'll need to write your own logic to do this.
+ if (!isValid(clientPackageName, clientUid)) {
// If the request comes from an untrusted package, return null.
// No further calls will be made to other media browsing methods.
- LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package "
- + clientPackageName);
+
return null;
}
- if (ANDROID_AUTO_PACKAGE_NAME.equals(clientPackageName)) {
- // Optional: if your app needs to adapt ads, music library or anything
- // else that needs to run differently when connected to the car, this
- // is where you should handle it.
- }
- return new BrowserRoot(MEDIA_ID_ROOT, null);
+
+ return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
}
</pre>
<p>
The Auto device client builds the top-level menu by calling {@link
android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()}
- with the root node object and getting it's children. The client builds
+ with the root node object and getting its children. The client builds
submenus by calling the same method with other child nodes. The following
example code shows a simple implementation of {@link
android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} method:
@@ -341,21 +372,30 @@
// Assume for example that the music catalog is already loaded/cached.
- List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();
+ List<MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
- if (MEDIA_BROWSER_ROOT.equals(parentMediaId)) {
+ if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
// build the MediaItem objects for the top level,
- // and put them in the <result> list
+ // and put them in the mediaItems list
} else {
// examine the passed parentMediaId to see which submenu we're at,
- // and put the children of that menu in the <result> list
+ // and put the children of that menu in the mediaItems list
}
+ result.sendResult(mediaItems);
}
</pre>
+<p>
+ For examples of how to implement {@link
+ android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()},
+ see the <a href="{@docRoot}samples/MediaBrowserService/index.html">
+ MediaBrowserService</a> and
+ <a href="https://github.com/googlesamples/android-UniversalMusicPlayer"
+ class="external-link">Universal Android Music Player</a> sample apps.
+</p>
<h2 id="implement_callback">Enable Playback Control</h2>
@@ -480,7 +520,13 @@
<a href="{@docRoot}training/managing-audio/index.html">Managing Audio Playback</a>, and
<a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p>
-
+<a class="notice-developers-video wide"
+href="https://www.youtube.com/watch?v=xc2HZSwPcwM">
+<div>
+ <h3>Video</h3>
+ <p>Devbytes: Android Auto Voice Actions</p>
+</div>
+</a>
<h2 id="support_voice">Support Voice Actions</h2>
<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
@@ -671,4 +717,4 @@
the
<a href="//github.com/googlesamples/android-UniversalMusicPlayer/">Universal Media Player</a>
sample.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/training/auto/index.jd b/docs/html/training/auto/index.jd
index c34911c..0a7ceb3 100644
--- a/docs/html/training/auto/index.jd
+++ b/docs/html/training/auto/index.jd
@@ -27,8 +27,7 @@
For more information, follow the links below to learn how to extend your Android app to support
use in vehicles.
</p>
-
-
+
<h2 id="overview">Get Started</h2>
<p>
@@ -82,3 +81,20 @@
data-cardSizes="9x3"
data-maxResults="6">
</div>
+
+<h2 id="training">Video Training</h2>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-1of2">
+ <p>If you prefer to learn through interactive video training,
+ check out this online course about extending your apps to work with Android Auto.</p>
+ <p><a href="https://www.udacity.com/course/ud875C" class="button">
+ Start the video course</a>
+ </p>
+ </div>
+ <div class="col-1of2">
+ <iframe width="300" height="169" src="https://www.youtube.com/embed/pK2HQMTdq6Y?utohide=1&showinfo=0" frameborder="0" allowfullscreen="" style="float: right; margin: 0 0 20px 20px;"></iframe>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/training/auto/messaging/index.jd b/docs/html/training/auto/messaging/index.jd
index 0177c84..fa8a8c4 100644
--- a/docs/html/training/auto/messaging/index.jd
+++ b/docs/html/training/auto/messaging/index.jd
@@ -143,17 +143,23 @@
messages belong to. It is important to use the same tag and ID for all messages in
a conversation, and to not use that tag for other conversations.</p>
-<h3 id="#workflow">Workflow</h3>
+<h3 id="workflow">Workflow</h3>
<p>This section describes how the mobile device interacts with Auto to present
messages to the user.</p>
<ol>
-<li>The app receives a message that it wants to pass on to the user. It attaches
-the message to an {@link
+<li>The app receives a message that it wants to pass on to the user. The app
+attaches the message to an {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+UnreadConversation.Builder} object, then uses the {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation.Builder
+UnreadConversation.Builder} to generate an {@link
android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
-UnreadConversation} object and attaches it to a notification. That notification
+UnreadConversation}. The app attaches that {@link
+android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation
+UnreadConversation} to a notification. That notification
is associated with a {@link
android.support.v4.app.NotificationCompat.CarExtender CarExtender} object, which
indicates that the notification can be handled by Android Auto.</li>
@@ -176,7 +182,7 @@
</ol>
-<h2 id="#manifest">Configure Your Manifest</h2>
+<h2 id="manifest">Configure Your Manifest</h2>
<p>
You configure your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>
diff --git a/docs/html/training/auto/start/index.jd b/docs/html/training/auto/start/index.jd
index 0fdcb2a..ee01fe7 100644
--- a/docs/html/training/auto/start/index.jd
+++ b/docs/html/training/auto/start/index.jd
@@ -22,6 +22,7 @@
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/auto/index.html">Designing for Auto</a></li>
+ <li><a href="{@docRoot}distribute/googleplay/auto.html">Distribute to Android Auto</a></li>
<li><a href="{@docRoot}training/auto/audio/index.html">Providing Audio Playback with Auto</a></li>
<li><a href="{@docRoot}training/auto/messaging/index.html">Providing Messaging for Auto</a></li>
</ul>
@@ -192,18 +193,24 @@
</li>
</ol>
-<div class="figure" style="width:330px">
- <img src="{@docRoot}images/training/auto-desktop-head-unit-server-running.png"
- alt="" >
- <p class="img-caption">
- <strong>Figure 2.</strong> Notification that the head unit server is running.
- </p>
-</div>
-<img src="{@docRoot}images/training/auto-desktop-head-unit-context-menu-enabled.png"
- alt="" >
-<p class="img-caption">
- <strong>Figure 1.</strong> Context menu with developer options.
-</p>
+<div class="cols">
+ <div class="col-6">
+ <img src="{@docRoot}images/training/auto-desktop-head-unit-context-menu-enabled.png"
+ alt="" >
+ <p class="img-caption">
+ <strong>Figure 1.</strong> Context menu with developer options.
+ </p>
+ </div>
+
+ <div class="col-6">
+ <img src="{@docRoot}images/training/auto-desktop-head-unit-server-running.png"
+ alt="" >
+ <p class="img-caption">
+ <strong>Figure 2.</strong> Notification that the head unit server is running.
+ </p>
+ </div>
+</div> <!-- end cols-->
+
<h3 id="connecting-dhu">Connecting the DHU to your mobile device</h3>
@@ -213,7 +220,7 @@
<ol>
<li>On the mobile device, enable Android Auto developer mode by starting the Android Auto
- companion app, and then tapping the header image 10 times.
+ companion app, and then tapping the <i>Android Auto</i> toolbar title 10 times.
This step is only required the first time you run the companion app.
</li>
<li>If the server is not already running, select <strong>Start head unit server</strong>
@@ -221,9 +228,13 @@
<p>On the device, a foreground service appears in the notification area. </p>
</li>
- <li>Connect the mobile device to the development machine via USB. Your device must be unlocked to
- launch the DHU.
- </li>
+ <li>In the Android Auto app, make sure the <strong>Only connect to known cars</strong> option
+ is disabled.</li>
+
+ <li>Connect the mobile device to the development machine via USB.</li>
+
+ <li>Make sure the mobile device has its screen unlocked, otherwise it cannot launch the DHU.</li>
+
<li>On the development machine, run the following {@code adb} command to
forward socket connections from the
development machine's port 5277 to the same port number on the Android device.
@@ -241,9 +252,13 @@
<p>
By default, the head unit server connects over port 5277. To override the host or port
- (for example, to forward over SSH), use the <code>--adb</code> flag.
+ (for example, to forward over SSH), use the
+ <code>desktop-head-unit --adb <[localhost:]port></code> flag, as in
+ the following example:
</p>
+ <pre class="no-pretty-print">$ ./desktop-head-unit --adb 5999</pre>
+
</li>
</ol>
diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd
new file mode 100644
index 0000000..0e2a9a9
--- /dev/null
+++ b/docs/html/training/backup/autosyncapi.jd
@@ -0,0 +1,370 @@
+page.title=Configuring Auto Backup for Apps
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, autobackup
+page.image=images/cards/card-auto-backup_2x.png
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#configuring">Configure Data Backup</a></li>
+ <li><a href="#previous-androids">Support Lower Versions of Android</a></li>
+ <li><a href="#testing">Test Backup Configuration</a></li>
+ <li><a href="#issues">Handle Google Cloud Messaging</a></li>
+</ol>
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
+ <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a>
+ </li>
+ </ul>
+
+</div>
+</div>
+
+<p>
+ Users frequently invest time and effort to configure apps just the way they like them. Switching
+ to a new device can cancel out all that careful configuration. For apps whose <a href=
+ "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a>
+ is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically
+ back up app data to the cloud. The system performs this automatic backup
+ for nearly all app data by default, and does so without your having to write any additional app
+ code.
+</p>
+
+<p class="note">
+<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google
+services for Auto Backup to work. The Google services opt-in dialog appears when the user goes
+through the Setup Wizard or configures the first Google account on the device.
+</p>
+
+<p>
+ When a user installs your app on
+ a new device, or reinstalls your app on one (for example, after a factory reset), the system
+ automatically restores the app data from the cloud. This lesson provides information about how to
+ configure the Auto Backup for Apps feature, explaining its default behavior and how to
+ exclude data that you don't want the system to back up.
+</p>
+
+<p>
+ The automatic backup feature preserves the data your app creates on a user device by uploading it
+ to the user’s Google Drive account and encrypting it. There is no charge to you or the user for
+ data storage, and the saved data does not count towards the user's personal Google Drive quota.
+ Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends
+ data to the cloud. If the system performs a data restore, it uses the last data snapshot that
+ the app had sent to the cloud.
+</p>
+
+<p>Automatic backups occur when the following conditions are met:</p>
+ <ul>
+ <li>The device is idle.</li>
+ <li>The device is charging.</li>
+ <li>The device is connected to a Wi-Fi network.</li>
+ <li>At least 24 hours have elapsed since the last backup.</li>
+ </ul>
+</p>
+
+<h2 id="configuring">Configure Data Backup</h2>
+
+<p>
+ On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up
+ almost all data that an app creates. The exception is <a href="#auto-exclude">
+ automatically excluded data files</a>. This section explains how you can use settings in
+ your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further
+ limit and configure what data the system backs up.
+</p>
+
+<h3 id="include-exclude">Including or excluding data</h3>
+
+<p>
+ Depending on what data your app needs and how you save it, you may need to set specific
+ rules for including or excluding certain files or directories. Auto Backup for Apps
+ lets you set these backup rules through the app manifest, in which you specify a backup scheme
+ configuration XML file. For example:
+</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.my.appexample">
+ <uses-sdk android:minSdkVersion="23"/>
+ <uses-sdk android:targetSdkVersion="23"/>
+ <application ...
+<strong> android:fullBackupContent="@xml/mybackupscheme"></strong>
+ </app>
+ ...
+</manifest>
+</pre>
+
+<p>
+ In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file
+ called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your
+ app development project. This configuration file contains rules controlling which files are backed
+ up. The following example code shows a configuration file that excludes a specific file,
+ {@code device_info.db}:
+</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<full-backup-content>
+ <exclude domain="database" path="device_info.db"/>
+</full-backup-content>
+</pre>
+
+<h3 id="auto-exclude">Automatically excluded data files</h3>
+
+<p>
+ Most apps do not need to, and in fact should not, back up all data. For example, the system
+ should not back up temporary files and caches. For this reason, the automatic backup
+ service excludes certain data files by default:
+</p>
+
+<ul>
+ <li>Files in the directories to which the
+ {@link android.content.Context#getCacheDir getCacheDir()} and
+ {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer.
+ </li>
+
+ <li>Files located on external storage, unless they reside in the directory to which the
+ {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers.
+ </li>
+
+ <li>Files located in the directory to which the
+ {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers.
+ </li>
+</ul>
+<h3>Backup Configuration Syntax</h3>
+
+<p>
+ The backup service configuration allows you to specify what files to include or exclude from
+ backup. The syntax for the data backup configuration XML file is as follows:
+</p>
+
+<pre>
+<full-backup-content>
+ <include domain=["file" | "database" | "sharedpref" | "external" | "root"]
+ path="string" />
+ <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
+ path="string" />
+</full-backup-content>
+</pre>
+
+<p>
+ The following elements and attributes allow you to specify the files to include in, and exclude
+ from, backup:
+</p>
+
+<ul>
+ <li>
+ <code><include></code>: Specifies a set of resources to
+ back up, instead of having the system back up all data in your app by default. If you specify
+ an <code><include></code> element, the system backs up <em>only the resources specified</em>
+ with this element. You can specify multiple sets of resources to back up by using multiple
+ <code><include></code> elements
+ </li>
+
+ <li>
+ <code><exclude></code>: Specifies any data you want the system to exclude
+ when it does a full backup. If you target the same set of resources with both the
+ <code><include></code> and <code><exclude></code> elements,
+ <code><exclude></code> takes precedence.
+ </li>
+
+ <li>
+ <code>domain</code>: Specifies the type of resource you want to include in,
+ or exclude from, backup. Valid values for this attribute include:
+
+
+
+ <ul>
+ <li>
+ <code>root</code>: Specifies that the resource is in the app’s root directory.
+ </li>
+
+ <li>
+ <code>file</code>: Specifies a resource in the directory returned by the
+ {@link android.content.Context#getFilesDir getFilesDir()} method.
+ </li>
+
+ <li>
+ <code>database</code>: Specifies a database that the
+ {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that
+ the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class.
+ </li>
+
+ <li>
+ <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object
+ that the {@link android.content.Context#getSharedPreferences getSharedPreferences()}
+ method returns.
+ </li>
+
+ <li>
+ <code>external</code>: Specifies that the resource is in external storage, and corresponds
+ to a file in the directory that the
+ {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns.
+ </li>
+ </ul>
+ </li>
+ <li>
+ <code>path</code>: Specifies the file path to a resource that you want to include in, or
+ exclude from, backup.
+ </li>
+
+ </li>
+</ul>
+
+
+<h3 id="disabling">Disabling data backups</h3>
+
+<p>
+ You can choose to prevent automatic backups of any of your app data by setting the
+ <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of
+ your manifest. This setting is illustrated in the following example:
+</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.my.appexample">
+ <uses-sdk android:minSdkVersion="23"/>
+ <uses-sdk android:targetSdkVersion="23"/>
+ <application ...
+<strong> android:allowBackup="false"></strong>
+ </application>
+ ...
+</manifest>
+</pre>
+
+<h2 id="previous-androids">Support Lower Versions of Android</h2>
+
+<p>There are two scenarios in which you may also need to support versions of Android lower
+than 6.0 (API level 23): You may be updating your existing app to take advantage of the
+new auto backup functionality in Android 6.0, while wanting
+to continue supporting earlier versions of Android. Or you may be releasing a new app, but
+want to make sure devices running on versions of Android predating 6.0 also have backup
+functionality.</p>
+
+<h3 id="updating">Updating an existing app to support auto backup</h3>
+
+<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app
+defines a subclass of {@link android.app.backup.BackupAgent} and sets
+<a href="{@docRoot}guide/topics/manifest/application-element.html#agent">
+{@code android:backupAgent}</a> in its
+<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app
+used this legacy approach, you can transition to full-data backups by adding the
+{@code android:fullBackupOnly="true"} attribute to the
+<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a>
+element in the manifest. When running on a device with Android 5.1
+(API level 22) or lower, your app ignores this value in the manifest, and continues performing
+backups in the previous manner.</p>
+
+<p>Even if you’re not using key/value backups, you can still use the approach described above to do
+any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
+or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that
+approach to receive a notification when a restore operation happens in
+{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain
+the system's default implementation of
+<a href="#include-exclude">XML include/exclude rules handling</a>, call
+{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p>
+
+<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3>
+
+<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup
+for devices running on Android 5.1 (API level 22) and lower, you must also
+<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p>
+
+<h2 id="testing">Test Backup Configuration</h2>
+
+<p>
+ Once you have created a backup configuration, you should test it to make sure your app saves data
+ and can restore it properly.
+</p>
+
+
+<h3>Enabling Backup Logging</h3>
+
+<p>
+ To help determine how the backup feature is parsing your XML file, enable logging before
+ performing a test backup:
+</p>
+
+<pre class="no-pretty-print">
+$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE
+</pre>
+
+<h3>Testing Backup</h3>
+
+<p>To manually run a backup, first initialize the Backup Manager by executing the following
+ command:
+</p>
+
+<pre class="no-pretty-print">
+$ adb shell bmgr run
+</pre>
+
+<p>
+ Next, manually back up your application using the following command. Use the
+ <code><PACKAGE></code> parameter to specify the package name for your app:
+</p>
+
+<pre class="no-pretty-print">
+$ adb shell bmgr fullbackup <PACKAGE></pre>
+
+
+<h3>Testing restore</h3>
+
+<p>
+ To manually initiate a restore after the system has backed up your app data, execute the following
+ command, using the <code><PACKAGE></code> parameter to specify the package name for your
+ app:
+</p>
+
+<pre class="noprettyprint">
+$ adb shell bmgr restore <PACKAGE>
+</pre>
+
+<p class="warning">
+ <b>Warning:</b> This action stops your app and wipes its data before performing the restore
+ operation.
+</p>
+
+<p>
+ You can test automatic restore for your app by uninstalling and reinstalling your app. The app
+ data is automatically restored from the cloud once the app installation is complete.
+</p>
+
+
+<h3>Troubleshooting backups</h3>
+
+<p>
+ If backup fails, you can clear the backup data and associated metadata either by turning backup
+ off and on in <strong>Settings > Backup</strong>, factory-resetting the device, or
+ executing this command:
+</p>
+
+<pre>$ adb shell bmgr wipe <TRANSPORT> <PACKAGE></pre>
+
+<p>
+ You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value.
+ To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the
+ following command:
+</p>
+
+<pre>$ adb shell bmgr list transports</pre>
+
+<h2 id="gcm">Handle Google Cloud Messaging</h2>
+
+ <p>
+ For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud
+ Messaging</a> (GCM) for push notifications, backing up the registration
+ token that Google Cloud Messaging registration returned can cause unexpected behavior in
+ notifications for the restored app. This is because when a user installs your app on a new device,
+ the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register">
+ query the GCM API for a new registration token</a>. If the old registration is present, because the
+ system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue
+ from arising, exclude the registration token from the set of backed-up files.
+ </p>
diff --git a/docs/html/training/cloudsync/backupapi.jd b/docs/html/training/backup/backupapi.jd
similarity index 72%
rename from docs/html/training/cloudsync/backupapi.jd
rename to docs/html/training/backup/backupapi.jd
index fd35ada..b115b8b 100644
--- a/docs/html/training/cloudsync/backupapi.jd
+++ b/docs/html/training/backup/backupapi.jd
@@ -21,23 +21,29 @@
</ol>
<h2>You should also read</h2>
<ul>
- <li><a
- href="http://developer.android.com/guide/topics/data/backup.html">Data
- Backup</a></li>
+ <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
+ <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a>
+ (Android 6.0 (API level 23) and higher)</li>
</ul>
</div>
</div>
<p>When a user purchases a new device or resets their existing one, they might
expect that when Google Play restores your app back to their device during the
-initial setup, the previous data associated with the app restores as well. By
-default, that doesn't happen and all the user's accomplishments or settings in
-your app are lost.</p>
+initial setup, the previous data associated with the app restores as well. On versions of Android
+prior to 6.0 (API level 23), app data is not restored by default, and all the user's accomplishments
+or settings in your app are lost.</p>
<p>For situations where the volume of data is relatively light (less than a
megabyte), like the user's preferences, notes, game high scores or other
stats, the Backup API provides a lightweight solution. This lesson walks you
through integrating the Backup API into your application, and restoring data to
-new devices using the Backup API.</p>
+new devices using the Backup API.
+
+<p class="note">
+<strong>Note:</strong> Devices running Android 6.0 and higher
+<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a>
+nearly all data by default.
+</p>
<h2 id="register">Register for the Android Backup Service</h2>
<p>This lesson requires the use of the <a
@@ -94,23 +100,23 @@
<p>Here's an example that backs up a high scores file.</p>
<pre>
- import android.app.backup.BackupAgentHelper;
- import android.app.backup.FileBackupHelper;
+import android.app.backup.BackupAgentHelper;
+import android.app.backup.FileBackupHelper;
- public class TheBackupAgent extends BackupAgentHelper {
- // The name of the SharedPreferences file
- static final String HIGH_SCORES_FILENAME = "scores";
+public class TheBackupAgent extends BackupAgentHelper {
+ // The name of the SharedPreferences file
+ static final String HIGH_SCORES_FILENAME = "scores";
- // A key to uniquely identify the set of backup data
- static final String FILES_BACKUP_KEY = "myfiles";
+ // A key to uniquely identify the set of backup data
+ static final String FILES_BACKUP_KEY = "myfiles";
- // Allocate a helper and add it to the backup agent
- @Override
- void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
- addHelper(FILES_BACKUP_KEY, helper);
- }
+ // Allocate a helper and add it to the backup agent
+ @Override
+ void onCreate() {
+ FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
+ addHelper(FILES_BACKUP_KEY, helper);
+ }
}
</pre>
<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
@@ -118,11 +124,11 @@
have backed up both a high scores file and a game progress file just by adding
an extra parameter, like this:</p>
<pre>
- @Override
- void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
- addHelper(FILES_BACKUP_KEY, helper);
- }
+@Override
+ void onCreate() {
+ FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
+ addHelper(FILES_BACKUP_KEY, helper);
+ }
</pre>
<p>Backing up preferences is similarly easy. Create a {@link
android.app.backup.SharedPreferencesBackupHelper} the same way you did a {@link
@@ -132,26 +138,26 @@
high scores are implemented as preferences instead of a flat file:</p>
<pre>
- import android.app.backup.BackupAgentHelper;
- import android.app.backup.SharedPreferencesBackupHelper;
+import android.app.backup.BackupAgentHelper;
+import android.app.backup.SharedPreferencesBackupHelper;
- public class TheBackupAgent extends BackupAgentHelper {
- // The names of the SharedPreferences groups that the application maintains. These
- // are the same strings that are passed to getSharedPreferences(String, int).
- static final String PREFS_DISPLAY = "displayprefs";
- static final String PREFS_SCORES = "highscores";
+public class TheBackupAgent extends BackupAgentHelper {
+ // The names of the SharedPreferences groups that the application maintains. These
+ // are the same strings that are passed to getSharedPreferences(String, int).
+ static final String PREFS_DISPLAY = "displayprefs";
+ static final String PREFS_SCORES = "highscores";
- // An arbitrary string used within the BackupAgentHelper implementation to
- // identify the SharedPreferencesBackupHelper's data.
- static final String MY_PREFS_BACKUP_KEY = "myprefs";
+ // An arbitrary string used within the BackupAgentHelper implementation to
+ // identify the SharedPreferencesBackupHelper's data.
+ static final String MY_PREFS_BACKUP_KEY = "myprefs";
- // Simply allocate a helper and install it
- void onCreate() {
- SharedPreferencesBackupHelper helper =
- new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
- addHelper(MY_PREFS_BACKUP_KEY, helper);
- }
- }
+ // Simply allocate a helper and install it
+ void onCreate() {
+ SharedPreferencesBackupHelper helper =
+ new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
+ addHelper(MY_PREFS_BACKUP_KEY, helper);
+ }
+}
</pre>
<p>You can add as many backup helper instances to your backup agent helper as you
@@ -168,13 +174,13 @@
android.app.backup.BackupManager#dataChanged()} method.</p>
<pre>
- import android.app.backup.BackupManager;
- ...
+import android.app.backup.BackupManager;
+...
- public void requestBackup() {
- BackupManager bm = new BackupManager(this);
- bm.dataChanged();
- }
+public void requestBackup() {
+ BackupManager bm = new BackupManager(this);
+ bm.dataChanged();
+}
</pre>
<p>This call notifies the backup manager that there is data ready to be backed
diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd
new file mode 100644
index 0000000..4449fde
--- /dev/null
+++ b/docs/html/training/backup/index.jd
@@ -0,0 +1,47 @@
+page.title=Backing up App Data to the Cloud
+page.tags=cloud,sync,backup
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 2.2 (API level 8) and higher</li>
+</ul>
+</div>
+</div>
+
+<p>Users often invest significant time and effort creating data and setting
+preferences within apps. Preserving that data for users if they replace a broken
+device or upgrade to a new one is an important part of ensuring a great user
+experience.</p>
+
+<p>This class covers techniques for backing up data to the cloud so that
+users can restore their data when recovering from a data loss (such as a factory
+reset) or installing your application on a new device.</p>
+
+<p>It is important to note that the API for cloud backup changed with the
+release of Android 6.0 (API level 23). For your app to support backup both
+on devices running Android 6.0, and those running Android 5.1 (API level
+22) and lower, you must implement both techniques that this class explains.</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt>
+ <dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish
+ seamless app data backup and restore with zero additional lines of application code.</dd>
+</dl>
+
+<dl>
+ <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
+ <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup
+ API into your Android app, so all of that app's user data, such as preferences, notes, and high
+ scores, updates seamlessly across all devices linked to that Google account.</dd>
+</dl>
+
diff --git a/docs/html/training/basics/actionbar/adding-buttons.jd b/docs/html/training/basics/actionbar/adding-buttons.jd
deleted file mode 100644
index caee729..0000000
--- a/docs/html/training/basics/actionbar/adding-buttons.jd
+++ /dev/null
@@ -1,226 +0,0 @@
-page.title=Adding Action Buttons
-page.tags=actionbar
-helpoutsWidget=true
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="tb-wrapper">
- <div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#XML">Specify the Actions in XML</a></li>
- <li><a href="#AddActions">Add the Actions to the Action Bar</a></li>
- <li><a href="#Respond">Respond to Action Buttons</a></li>
- <li><a href="#UpNav">Add Up Button for Low-level Activities</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up
- Navigation</a></li>
- </div>
-</div>
-
-
-
-<p>The action bar allows you to add buttons for the most important action
-items relating to the app's current
-context. Those that appear directly in the action bar with an icon and/or text are known
-as <em>action buttons</em>. Actions that can't fit in the action bar or aren't
-important enough are hidden in the action overflow.</p>
-
-<img src="{@docRoot}images/training/basics/actionbar-actions.png" height="100" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> An action bar with an action button
-for Search and the action overflow, which reveals additional actions.</a>
-
-
-<h2 id="XML">Specify the Actions in XML</h2>
-
-<p>All action buttons and other items available in the action overflow are defined
-in an XML <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. To add
-actions to the action bar, create a new XML file in your project's
-{@code res/menu/} directory.</p>
-
-<p>Add an {@code <item>} element for each item you want to include in the action bar.
-For example:</p>
-
-<p class="code-caption">res/menu/main_activity_actions.xml</p>
-<pre>
-<menu xmlns:android="http://schemas.android.com/apk/res/android" >
- <!-- Search, should appear as action button -->
- <item android:id="@+id/action_search"
- android:icon="@drawable/ic_action_search"
- android:title="@string/action_search"
- android:showAsAction="ifRoom" />
- <!-- Settings, should always be in the overflow -->
- <item android:id="@+id/action_settings"
- android:title="@string/action_settings"
- android:showAsAction="never" />
-</menu>
-</pre>
-
-<div class="sidebox">
-<h3>Download action bar icons</h3>
-<p>To best match the Android <a
-href="{@docRoot}design/style/iconography.html#action-bar">iconography</a> guidelines, you should
-use icons provided in the
-<a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action Bar Icon Pack</a>.</p>
-</div>
-
-<p>This declares that the Search action should appear as an action button when room
-is available in the action bar, but the
-Settings action should always appear in the overflow. (By default, all actions appear in the
-overflow, but it's good practice to explicitly declare your design intentions for each action.)
-
-<p>The {@code icon} attribute requires a resource ID for an
-image. The name that follows {@code @drawable/} must be the name of a bitmap image you've
-saved in your project's {@code res/drawable/} directory. For example,
-{@code "@drawable/ic_action_search"} refers to {@code ic_action_search.png}.
-Likewise, the {@code title} attribute uses a string resource that's defined by an XML
-file in your project's {@code res/values/} directory, as discussed in <a
-href="{@docRoot}training/basics/firstapp/building-ui.html#Strings">Building a Simple User
-Interface</a>.
-
-<p class="note"><strong>Note:</strong> When creating icons and other bitmap images for your app,
-it's important that you provide multiple versions that are each optimized for a different screen
-density. This is discussed more in the lesson about <a
-href="{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different Screens</a>.
-
-<p><strong>If your app is using the Support Library</strong> for compatibility on versions
-as low as Android 2.1, the {@code showAsAction} attribute is not available from
-the {@code android:} namespace. Instead this attribute is provided by the Support Library
-and you must define your own XML namespace and use that namespace as the attribute prefix.
-(A custom XML namespace should be based on your app name, but it can be any
-name you want and is only accessible within the scope of the file in which you declare it.)
-For example:</p>
-
-<p class="code-caption">res/menu/main_activity_actions.xml</p>
-<pre>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- <strong>xmlns:yourapp="http://schemas.android.com/apk/res-auto"</strong> >
- <!-- Search, should appear as action button -->
- <item android:id="@+id/action_search"
- android:icon="@drawable/ic_action_search"
- android:title="@string/action_search"
- <strong>yourapp:showAsAction="ifRoom"</strong> />
- ...
-</menu>
-</pre>
-
-
-
-<h2 id="AddActions">Add the Actions to the Action Bar</h2>
-
-<p>To place the menu items into the action bar, implement the
-{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback
-method in your activity to inflate the menu resource into the given {@link android.view.Menu}
-object. For example:</p>
-
-<pre>
-@Override
-public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu items for use in the action bar
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main_activity_actions, menu);
- return super.onCreateOptionsMenu(menu);
-}
-</pre>
-
-
-
-<h2 id="Respond">Respond to Action Buttons</h2>
-
-<p>When the user presses one of the action buttons or another item in the action overflow,
-the system calls your activity's {@link android.app.Activity#onOptionsItemSelected
-onOptionsItemSelected()} callback method. In your implementation of this method,
-call {@link android.view.MenuItem#getItemId getItemId()} on the given {@link android.view.MenuItem} to
-determine which item was pressed—the returned ID matches the value you declared in the
-corresponding {@code <item>} element's {@code android:id} attribute.</p>
-
-<pre>
-@Override
-public boolean onOptionsItemSelected(MenuItem item) {
- // Handle presses on the action bar items
- switch (item.getItemId()) {
- case R.id.action_search:
- openSearch();
- return true;
- case R.id.action_settings:
- openSettings();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
-}
-</pre>
-
-
-
-<h2 id="UpNav">Add Up Button for Low-level Activities</h2>
-
-<div class="figure" style="width:240px">
- <img src="{@docRoot}images/ui/actionbar-up.png" width="240" alt="">
- <p class="img-caption"><strong>Figure 4.</strong> The <em>Up</em> button in Gmail.</p>
-</div>
-
-<p>All screens in your app that are not the main entrance to your app
-(activities that are not the "home" screen) should
-offer the user a way to navigate to the logical parent screen in the app's hierarchy by pressing
-the <em>Up</em> button in the action bar.</p>
-
-<p>When running on Android 4.1 (API level 16) or higher, or when using {@link
-android.support.v7.app.ActionBarActivity} from the Support Library, performing <em>Up</em>
-navigation simply requires that you declare the parent activity in the manifest file and enable
-the <em>Up</em> button for the action bar.</p>
-
-<p>For example, here's how you can declare an activity's parent in the manifest:</p>
-
-<pre>
-<application ... >
- ...
- <!-- The main/home activity (it has no parent activity) -->
- <activity
- android:name="com.example.myfirstapp.MainActivity" ...>
- ...
- </activity>
- <!-- A child of the main activity -->
- <activity
- android:name="com.example.myfirstapp.DisplayMessageActivity"
- android:label="@string/title_activity_display_message"
- android:parentActivityName="com.example.myfirstapp.MainActivity" >
- <!-- Parent activity meta-data to support 4.0 and lower -->
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="com.example.myfirstapp.MainActivity" />
- </activity>
-</application>
-</pre>
-
- <p>Then enable the app icon as the <em>Up</em> button by calling
-{@link android.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled()}:</p>
-
-<pre>
-{@literal @}Override
-public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_displaymessage);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- // If your minSdkVersion is 11 or higher, instead use:
- // getActionBar().setDisplayHomeAsUpEnabled(true);
-}
-</pre>
-
-<p>Because the system now knows {@code MainActivity} is the parent activity for
-{@code DisplayMessageActivity}, when the user presses the
-<em>Up</em> button, the system navigates to
-the parent activity as appropriate—you <strong>do not</strong> need to handle the
-<em>Up</em> button's event.</p>
-
-<p>For more information about up navigation, see
-<a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up
- Navigation</a>.
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/index.jd b/docs/html/training/basics/actionbar/index.jd
deleted file mode 100644
index 6a8eaff..0000000
--- a/docs/html/training/basics/actionbar/index.jd
+++ /dev/null
@@ -1,69 +0,0 @@
-page.title=Adding the Action Bar
-page.tags=actionbar
-helpoutsWidget=true
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.1 or higher</li>
-</ul>
-
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
- <li><a href="{@docRoot}training/implementing-navigation/index.html">Implementing
- Effective Navigation</a></li>
-</ul>
-
-</div>
-</div>
-
-<a class="notice-designers wide" href="{@docRoot}design/patterns/actionbar.html">
- <div>
- <h3>Design Guide</h3>
- <p>Action Bar</p>
- </div>
-</a>
-
-<p>The action bar is one of the most important design elements you can implement for your
-app's activities. It provides several user interface features that make your app immediately
-familiar to users by offering consistency between other Android apps. Key functions include:</p>
-
-<ul>
- <li>A dedicated space for giving your app an identity and indicating the user's location
- in the app.</li>
- <li>Access to important actions in a predictable way (such as Search).</li>
- <li>Support for navigation and view switching (with tabs or drop-down lists).</li>
-</ul>
-
-<img src="{@docRoot}images/training/basics/actionbar-actions.png" height="100" alt="">
-
-<p>This training class offers a quick guide to the action bar's basics. For more information
-about action bar's various features, see the
-<a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> guide.</p>
-
-
-<h2>Lessons</h2>
-
-<dl>
- <dt><b><a href="setting-up.html">Setting Up the Action Bar</a></b></dt>
- <dd>Learn how to add a basic action bar to your activity, whether your app
- supports only Android 3.0 and higher or also supports versions as low as Android 2.1
- (by using the Android Support Library).</dd>
- <dt><b><a href="adding-buttons.html">Adding Action Buttons</a></b></dt>
- <dd>Learn how to add and respond to user actions in the action bar.</dd>
- <dt><b><a href="styling.html">Styling the Action Bar</a></b></dt>
- <dd>Learn how to customize the appearance of your action bar.</dd>
- <dt><b><a href="overlaying.html">Overlaying the Action Bar</a></b></dt>
- <dd>Learn how to overlay the action bar in front of your layout, allowing for
- seamless transitions when hiding the action bar.</dd>
-</dl>
-
diff --git a/docs/html/training/basics/actionbar/overlaying.jd b/docs/html/training/basics/actionbar/overlaying.jd
deleted file mode 100644
index 634534e..0000000
--- a/docs/html/training/basics/actionbar/overlaying.jd
+++ /dev/null
@@ -1,143 +0,0 @@
-page.title=Overlaying the Action Bar
-page.tags=actionbar
-helpoutsWidget=true
-
-trainingnavtop=true
-
-@jd:body
-
-
-<div id="tb-wrapper">
- <div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#EnableOverlay">Enable Overlay Mode</a>
- <ol>
- <li><a href="#Overlay11">For Android 3.0 and higher only</a></li>
- <li><a href="#Overlay7">For Android 2.1 and higher</a></li>
- </ol>
- </li>
- <li><a href="#TopMargin">Specify Layout Top-margin</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a></li>
-</ul>
- </div>
-</div>
-
-
-<p>By default, the action bar appears at the top of your activity window,
-slightly reducing the amount of space available for the rest of your activity's layout.
-If, during the course of user interaction, you want to hide and show the action bar, you can do so
-by calling {@link android.app.ActionBar#hide()} and
-{@link android.app.ActionBar#show()} on the {@link android.app.ActionBar}. However,
-this causes your activity to recompute and redraw the layout based on its new size.</p>
-
-
-<div class="figure" style="width:280px">
- <img src="{@docRoot}images/training/basics/actionbar-overlay@2x.png" width="280" alt="" />
- <p class="img-caption"><strong>Figure 1.</strong> Gallery's action bar in overlay mode.</p>
-</div>
-
-<p>To avoid resizing your layout when the action bar hides and shows, you can enable <em>overlay
-mode</em> for the action bar. When in overlay mode, your activity layout uses all the space
-available as if the action bar is not there and the system draws the action bar in front of
-your layout. This obscures some of the layout at the top, but now when the action bar hides or
-appears, the system does not need to resize your layout and the transition is seamless.</p>
-
-<p class="note"><strong>Tip:</strong>
-If you want your layout to be partially visible behind the action bar, create a custom
-style for the action bar with a partially transparent background, such as the one shown
-in figure 1. For information about how to define the action bar background, read
-<a href="{@docRoot}training/basics/actionbar/styling.html">Styling the Action Bar</a>.</p>
-
-
-<h2 id="EnableOverlay">Enable Overlay Mode</h2>
-
-<p>To enable overlay mode for the action bar, you need to create a custom theme that
-extends an existing action bar theme and set the {@code android:windowActionBarOverlay} property to
-{@code true}.</p>
-
-
-<h3 id="Overlay11">For Android 3.0 and higher only</h3>
-
-<p>If your
-<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
-is set to {@code 11} or higher, your custom theme should use
-{@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its descendants) as your parent
-theme. For example:</p>
-
-<pre>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@android:style/Theme.Holo">
- <item name="android:windowActionBarOverlay">true</item>
- </style>
-</resources>
-</pre>
-
-
-<h3 id="Overlay7">For Android 2.1 and higher</h3>
-
-<p>If your app is using the Support Library for compatibility on devices
-running versions lower than Android 3.0, your custom theme should use
-{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} theme
-(or one of its descendants) as your parent theme. For example:</p>
-
-<pre>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@android:style/Theme.<strong>AppCompat</strong>">
- <item name="android:windowActionBarOverlay">true</item>
-
- <!-- Support library compatibility -->
- <item name="windowActionBarOverlay">true</item>
- </style>
-</resources>
-</pre>
-
-<p>Also notice that this theme includes two definitions for the {@code windowActionBarOverlay}
-style: one with the {@code android:} prefix and one without. The one with the {@code android:}
-prefix is for versions of Android that include the style in the platform and the one
-without the prefix is for older versions that read the style from the Support Library.</p>
-
-
-
-
-
-<h2 id="TopMargin">Specify Layout Top-margin</h2>
-
-<p>When the action bar is in overlay mode, it might obscure some of your layout that should
-remain visible. To ensure that such items remain below the action bar at all times,
-add either margin or padding to the top of the view(s)
-using the height specified by {@link android.R.attr#actionBarSize}. For example:</p>
-
-<pre>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="?android:attr/actionBarSize">
- ...
-</RelativeLayout>
-</pre>
-
-<p>If you're using the Support Library for the action bar, you need to remove the
-{@code android:} prefix. For example:</p>
-
-<pre>
-<!-- Support library compatibility -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="?attr/actionBarSize">
- ...
-</RelativeLayout>
-</pre>
-
-<p>In this case, the {@code ?attr/actionBarSize} value without the
-prefix works on all versions, including Android 3.0 and higher.</p>
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/setting-up.jd b/docs/html/training/basics/actionbar/setting-up.jd
deleted file mode 100644
index 2cd4140..0000000
--- a/docs/html/training/basics/actionbar/setting-up.jd
+++ /dev/null
@@ -1,114 +0,0 @@
-page.title=Setting Up the Action Bar
-page.tags=actionbar
-helpoutsWidget=true
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="tb-wrapper">
- <div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#ApiLevel11">Support Android 3.0 and Above Only</a></li>
- <li><a href="#ApiLevel7">Support Android 2.1 and Above</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}tools/support-library/setup.html"
->Setting Up the Support Library</a></li>
-</ul>
- </div>
-</div>
-
-
-<p>In its most basic form, the action bar displays the title for the activity
-and the app icon on the left. Even in this simple form, the action bar
-is useful for all activities to inform
-users about where they are and to maintain a consistent identity for your app.</p>
-
-<img src="{@docRoot}images/training/basics/actionbar-basic.png" height="100" alt=""/>
-<p class="img-caption"><strong>Figure 1.</strong> An action bar with the app icon and
-activity title.</a>
-
-<p>Setting up a basic action bar requires that your app use an activity theme that enables
-the action bar. How to request such a theme depends on which version of Android is the
-lowest supported by your app. So this
-lesson is divided into two sections depending on which Android
-version is your lowest supported.</p>
-
-
-<h2 id="ApiLevel11">Support Android 3.0 and Above Only</h2>
-
-<p>Beginning with Android 3.0 (API level 11), the action bar is included in all
-activities that use the {@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its
-descendants), which is the default theme when either the <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> or
-<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
-attribute is set to <code>"11"</code> or greater.</p>
-
-<p>So to add the action bar to your activities, simply set either attribute to
-{@code 11} or higher. For example:</p>
-
-<pre>
-<manifest ... >
- <uses-sdk android:minSdkVersion="11" ... />
- ...
-</manifest>
-</pre>
-
-<p class="note"><strong>Note:</strong> If you've created a custom theme, be sure it uses one
-of the {@link android.R.style#Theme_Holo Theme.Holo} themes as its parent. For details,
-see <a href="{@docRoot}training/basics/actionbar/styling.html">Styling the Action Bar</a>.</p>
-
-<p>Now the {@link android.R.style#Theme_Holo Theme.Holo} theme is applied to your app and
-all activities show the action bar. That's it.</p>
-
-
-
-<h2 id="ApiLevel7">Support Android 2.1 and Above</h2>
-
-<p>Adding the action bar when running on versions older than Android 3.0 (down to Android 2.1)
-requires that you include the Android Support Library in your application.</p>
-
-<p>To get started, read the <a href="{@docRoot}tools/support-library/setup.html"
->Support Library Setup</a> document and set up the <strong>v7 appcompat</strong>
-library (once you've downloaded the library package, follow the instructions for <a
-href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries with
-resources</a>).</p>
-
-<p>Once you have the Support Library integrated with your app project:</p>
-
-<ol>
- <li>Update your activity so that it extends {@link android.support.v7.app.ActionBarActivity}.
- For example:
-<pre>
-public class MainActivity extends ActionBarActivity { ... }
-</pre>
- </li>
- <li>In your manifest file, update either the <a
- href="{@docRoot}guide/topics/manifest/application-element.html">{@code
- <application>}</a> element or individual
- <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <activity>}</a>
- elements to use one of the {@link android.support.v7.appcompat.R.style#Theme_AppCompat
- Theme.AppCompat} themes. For example:
- <pre><activity android:theme="@style/Theme.AppCompat.Light" ... ></pre>
- <p class="note"><strong>Note:</strong> If you've created a custom theme, be sure it uses one
-of the {@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} themes as
-its parent. For details, see <a href="{@docRoot}training/basics/actionbar/styling.html">Styling
-the Action Bar</a>.</p>
- </li>
-</ol>
-
-<p>Now your activity includes the action bar when running on Android 2.1 (API level 7) or higher.
-</p>
-
-<p>Remember to properly set your app's API level support in the manifest:</p>
-<pre>
-<manifest ... >
- <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="18" />
- ...
-</manifest>
-</pre>
\ No newline at end of file
diff --git a/docs/html/training/basics/actionbar/styling.jd b/docs/html/training/basics/actionbar/styling.jd
deleted file mode 100644
index b658423..0000000
--- a/docs/html/training/basics/actionbar/styling.jd
+++ /dev/null
@@ -1,450 +0,0 @@
-page.title=Styling the Action Bar
-page.tags=actionbar
-helpoutsWidget=true
-
-trainingnavtop=true
-
-@jd:body
-
-
-<div id="tb-wrapper">
- <div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#AndroidThemes">Use an Android Theme</a></li>
- <li><a href="#CustomBackground">Customize the Background</a></li>
- <li><a href="#CustomText">Customize the Text Color</a></li>
- <li><a href="#CustomTabs">Customize the Tab Indicator</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a></li>
- <li><a class="external-link" target="_blank"
- href="http://www.actionbarstylegenerator.com">Android Action Bar Style
- Generator</a></li>
-</ul>
-
- </div>
-</div>
-
-
-
-<p>The action bar provides your users a familiar and predictable way to perform
-actions and navigate your app, but that doesn't mean it needs to look exactly the
-same as it does in other apps. If you want to style the action bar to better fit your product
-brand, you can easily do so using Android's <a href="{@docRoot}guide/topics/ui/themes.html">style
-and theme</a> resources.</p>
-
-<p>Android includes a few built-in activity themes that include "dark" or "light" action bar
-styles. You can also extend these themes to further customize the look for your action bar.</p>
-
-<p class="note" style="clear:left"><strong>Note:</strong> If you are using the Support Library APIs
-for the action bar, then you must use (or override) the {@link
-android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} family of styles (rather
-than the {@link android.R.style#Theme_Holo Theme.Holo} family, available in API level 11 and
-higher). In doing so, each style property that you declare must be declared twice: once using
-the platform's style properties (the
-{@link android.R.attr android:} properties) and once using the
-style properties included in the Support Library (the {@link android.support.v7.appcompat.R.attr
-appcompat.R.attr} properties—the context for these properties is actually
-<em>your app</em>). See the examples below for details.</p>
-
-
-
-<h2 id="AndroidThemes">Use an Android Theme</h2>
-
-<div class="figure" style="width:340px">
- <img src="{@docRoot}images/training/basics/actionbar-theme-dark@2x.png" width="340" alt="" />
-</div>
-
-<div class="figure" style="width:340px">
- <img src="{@docRoot}images/training/basics/actionbar-theme-light-solid@2x.png" width="340" alt="" />
-</div>
-
-<p>Android includes two baseline activity themes that dictate the color for the action bar:
-</p>
-<ul>
- <li>{@link android.R.style#Theme_Holo Theme.Holo} for a "dark" theme.
- </li>
- <li>{@link android.R.style#Theme_Holo_Light Theme.Holo.Light} for a "light" theme.
- </li>
-</ul>
-
-<p>You can apply these themes to your entire app or to individual activities by
-declaring them in your manifest file with the {@code android:theme} attribute
-for the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
-<application>}</a> element or individual
-<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <activity>}</a>
-elements.</p>
-
-<p>For example:</p>
-<pre>
-<application android:theme="@android:style/Theme.Holo.Light" ... />
-</pre>
-
-<div class="figure" style="width:340px">
- <img src="{@docRoot}images/training/basics/actionbar-theme-light-darkactionbar@2x.png" width="340" alt="" />
-</div>
-
-<p>You can also use a dark action bar while the rest of the activity uses the light
-color scheme by declaring the {@link android.R.style#Theme_Holo_Light_DarkActionBar
-Theme.Holo.Light.DarkActionBar} theme.</p>
-
-<p>When using the Support Library, you must instead use the
-{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} themes:</p>
-<ul>
- <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat Theme.AppCompat} for the
- "dark" theme.</li>
- <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat_Light Theme.AppCompat.Light}
- for the "light" theme.</li>
- <li>{@link android.support.v7.appcompat.R.style#Theme_AppCompat_Light_DarkActionBar
-Theme.AppCompat.Light.DarkActionBar} for the light theme with a dark action bar.
-</ul>
-
-<p>Be sure that you use action bar icons that properly contrast with the color of your action
-bar. To help you, the <a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action
-Bar Icon Pack</a> includes standard action icons for use with both the Holo light and Holo dark
-action bar.</p>
-
-
-
-
-
-<h2 id="CustomBackground">Customize the Background</h2>
-
-<div class="figure" style="width:340px">
- <img src="{@docRoot}images/training/basics/actionbar-theme-custom@2x.png" width="340" alt="" />
-</div>
-
-<p>To change the action bar background, create a custom theme for your activity that overrides the
-{@link android.R.attr#actionBarStyle} property. This property points to another style
-in which you can override the {@link android.R.attr#background} property to specify
-a drawable resource for the action bar background.</p>
-
-<p>If your app uses <a href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">navigation tabs</a>
-or the <a href="{@docRoot}guide/topics/ui/actionbar.html#SplitBar">split
-action bar</a>, then you can also specify the background for these bars using
-the {@link android.R.attr#backgroundStacked} and
-{@link android.R.attr#backgroundSplit} properties, respectively.</p>
-
-<p class="caution"><strong>Caution:</strong> It's important that you declare an appropriate
-parent theme from which your custom theme and style inherit their styles. Without a parent
-style, your action bar will be without many style properties unless you explicitly declare
-them yourself.</p>
-
-
-<h3 id="CustomBackground11">For Android 3.0 and higher only</h3>
-
-<p>When supporting Android 3.0 and higher only, you can define the action bar's
-background like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@android:style/Theme.Holo.Light.DarkActionBar">
- <item name="android:actionBarStyle">@style/MyActionBar</item>
- </style>
-
- <!-- ActionBar styles -->
- <style name="MyActionBar"
- parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
- <item name="android:background">@drawable/actionbar_background</item>
- </style>
-</resources>
-</pre>
-
-<p>Then apply your theme to your entire app or individual activities:</p>
-<pre>
-<application android:theme="@style/CustomActionBarTheme" ... />
-</pre>
-
-
-
-<h3 id="CustomBackground7">For Android 2.1 and higher</h3>
-
-<p>When using the Support Library, the same theme as above must instead look like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@style/Theme.<strong>AppCompat</strong>.Light.DarkActionBar">
- <item name="android:actionBarStyle">@style/MyActionBar</item>
-
- <!-- Support library compatibility -->
- <item name="actionBarStyle">@style/MyActionBar</item>
- </style>
-
- <!-- ActionBar styles -->
- <style name="MyActionBar"
- parent="@style/Widget.<strong>AppCompat</strong>.Light.ActionBar.Solid.Inverse">
- <item name="android:background">@drawable/actionbar_background</item>
-
- <!-- Support library compatibility -->
- <item name="background">@drawable/actionbar_background</item>
- </style>
-</resources>
-</pre>
-
-<p>Then apply your theme to your entire app or individual activities:</p>
-<pre>
-<application android:theme="@style/CustomActionBarTheme" ... />
-</pre>
-
-
-
-
-
-
-
-<h2 id="CustomText">Customize the Text Color</h2>
-
-<p>To modify the color of text in the action bar, you need to override separate properties
-for each text element:</p>
-<ul>
- <li>Action bar title: Create a custom style that specifies the {@code textColor} property and
- specify that style for the {@link android.R.attr#titleTextStyle} property in your custom
- {@link android.R.attr#actionBarStyle}.
- <p class="note"><strong>Note:</strong>
- The custom style applied to {@link android.R.attr#titleTextStyle} should use
- {@link android.R.style#TextAppearance_Holo_Widget_ActionBar_Title
- TextAppearance.Holo.Widget.ActionBar.Title} as the parent style.</p>
- </li>
- <li>Action bar tabs: Override {@link android.R.attr#actionBarTabTextStyle} in your
- activity theme.</li>
- <li>Action buttons: Override {@link android.R.attr#actionMenuTextColor} in your
- activity theme.</li>
-</ul>
-
-
-<h3 id="CustomText11">For Android 3.0 and higher only</h3>
-
-<p>When supporting Android 3.0 and higher only, your style XML file might look like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@style/Theme.Holo">
- <item name="android:actionBarStyle">@style/MyActionBar</item>
- <item name="android:actionBarTabTextStyle">@style/MyActionBarTabText</item>
- <item name="android:actionMenuTextColor">@color/actionbar_text</item>
- </style>
-
- <!-- ActionBar styles -->
- <style name="MyActionBar"
- parent="@style/Widget.Holo.ActionBar">
- <item name="android:titleTextStyle">@style/MyActionBarTitleText</item>
- </style>
-
- <!-- ActionBar title text -->
- <style name="MyActionBarTitleText"
- parent="@style/TextAppearance.Holo.Widget.ActionBar.Title">
- <item name="android:textColor">@color/actionbar_text</item>
- </style>
-
- <!-- ActionBar tabs text styles -->
- <style name="MyActionBarTabText"
- parent="@style/Widget.Holo.ActionBar.TabText">
- <item name="android:textColor">@color/actionbar_text</item>
- </style>
-</resources>
-</pre>
-
-
-
-
-<h3 id="CustomText7">For Android 2.1 and higher</h3>
-
-<p>When using the Support Library, your style XML file might look like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@style/Theme.<strong>AppCompat</strong>">
- <item name="android:actionBarStyle">@style/MyActionBar</item>
- <item name="android:actionBarTabTextStyle">@style/MyActionBarTabText</item>
- <item name="android:actionMenuTextColor">@color/actionbar_text</item>
-
- <!-- Support library compatibility -->
- <item name="actionBarStyle">@style/MyActionBar</item>
- <item name="actionBarTabTextStyle">@style/MyActionBarTabText</item>
- <item name="actionMenuTextColor">@color/actionbar_text</item>
- </style>
-
- <!-- ActionBar styles -->
- <style name="MyActionBar"
- parent="@style/Widget.<strong>AppCompat</strong>.ActionBar">
- <item name="android:titleTextStyle">@style/MyActionBarTitleText</item>
-
- <!-- Support library compatibility -->
- <item name="titleTextStyle">@style/MyActionBarTitleText</item>
- </style>
-
- <!-- ActionBar title text -->
- <style name="MyActionBarTitleText"
- parent="@style/TextAppearance.<strong>AppCompat</strong>.Widget.ActionBar.Title">
- <item name="android:textColor">@color/actionbar_text</item>
- <!-- The textColor property is backward compatible with the Support Library -->
- </style>
-
- <!-- ActionBar tabs text -->
- <style name="MyActionBarTabText"
- parent="@style/Widget.<strong>AppCompat</strong>.ActionBar.TabText">
- <item name="android:textColor">@color/actionbar_text</item>
- <!-- The textColor property is backward compatible with the Support Library -->
- </style>
-</resources>
-</pre>
-
-
-
-
-
-
-<h2 id="CustomTabs">Customize the Tab Indicator</h2>
-
-<div class="figure" style="width:340px">
- <img src="{@docRoot}images/training/basics/actionbar-theme-custom-tabs@2x.png" width="340" alt="" />
-</div>
-
-<p>To change the indicator used for the <a
-href="{@docRoot}guide/topics/ui/actionbar.html#Tabs">navigation tabs</a>,
-create an activity theme that overrides the
-{@link android.R.attr#actionBarTabStyle} property. This property points to another style
-resource in which you override the {@link android.R.attr#background} property that should specify
-a state-list drawable.</p>
-
-<p class="note"><strong>Note:</strong> A state-list drawable is important so that the tab currently
-selected indicates its state with a background different than the other tabs. For more information
-about how to create a drawable resource that handles multiple button states, read the
-<a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">State List</a>
-documentation.</p>
-
-<p>For example, here's a state-list drawable that declares a specific background image
-for several different states of an action bar tab:</p>
-
-<p class="code-caption">res/drawable/actionbar_tab_indicator.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-<!-- STATES WHEN BUTTON IS NOT PRESSED -->
-
- <!-- Non focused states -->
- <item android:state_focused="false" android:state_selected="false"
- android:state_pressed="false"
- android:drawable="@drawable/tab_unselected" />
- <item android:state_focused="false" android:state_selected="true"
- android:state_pressed="false"
- android:drawable="@drawable/tab_selected" />
-
- <!-- Focused states (such as when focused with a d-pad or mouse hover) -->
- <item android:state_focused="true" android:state_selected="false"
- android:state_pressed="false"
- android:drawable="@drawable/tab_unselected_focused" />
- <item android:state_focused="true" android:state_selected="true"
- android:state_pressed="false"
- android:drawable="@drawable/tab_selected_focused" />
-
-
-<!-- STATES WHEN BUTTON IS PRESSED -->
-
- <!-- Non focused states -->
- <item android:state_focused="false" android:state_selected="false"
- android:state_pressed="true"
- android:drawable="@drawable/tab_unselected_pressed" />
- <item android:state_focused="false" android:state_selected="true"
- android:state_pressed="true"
- android:drawable="@drawable/tab_selected_pressed" />
-
- <!-- Focused states (such as when focused with a d-pad or mouse hover) -->
- <item android:state_focused="true" android:state_selected="false"
- android:state_pressed="true"
- android:drawable="@drawable/tab_unselected_pressed" />
- <item android:state_focused="true" android:state_selected="true"
- android:state_pressed="true"
- android:drawable="@drawable/tab_selected_pressed" />
-</selector>
-</pre>
-
-
-
-<h3 id="CustomTabs11">For Android 3.0 and higher only</h3>
-
-<p>When supporting Android 3.0 and higher only, your style XML file might look like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@style/Theme.Holo">
- <item name="android:actionBarTabStyle">@style/MyActionBarTabs</item>
- </style>
-
- <!-- ActionBar tabs styles -->
- <style name="MyActionBarTabs"
- parent="@style/Widget.Holo.ActionBar.TabView">
- <!-- tab indicator -->
- <item name="android:background">@drawable/actionbar_tab_indicator</item>
- </style>
-</resources>
-</pre>
-
-
-
-<h3 id="CustomTabs7">For Android 2.1 and higher</h3>
-
-<p>When using the Support Library, your style XML file might look like this:</p>
-
-<p class="code-caption">res/values/themes.xml</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActionBarTheme"
- parent="@style/Theme.<strong>AppCompat</strong>">
- <item name="android:actionBarTabStyle">@style/MyActionBarTabs</item>
-
- <!-- Support library compatibility -->
- <item name="actionBarTabStyle">@style/MyActionBarTabs</item>
- </style>
-
- <!-- ActionBar tabs styles -->
- <style name="MyActionBarTabs"
- parent="@style/Widget.<strong>AppCompat</strong>.ActionBar.TabView">
- <!-- tab indicator -->
- <item name="android:background">@drawable/actionbar_tab_indicator</item>
-
- <!-- Support library compatibility -->
- <item name="background">@drawable/actionbar_tab_indicator</item>
- </style>
-</resources>
-</pre>
-
-<div class="note"><p><strong>More resources</strong></p>
-<ul>
- <li>See more style properties for the action bar are listed in the <a
- href="{@docRoot}guide/topics/ui/actionbar.html#Style">Action Bar</a> guide.</li>
- <li>Learn more about how themes work in the <a
- href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> guide.</li>
- <li>For even more complete styling for the action bar,
-try the <a class="external-link" target="_blank"
- href="http://www.actionbarstylegenerator.com">Android Action Bar Style
- Generator</a>.</li>
-</ul>
-</div>
\ No newline at end of file
diff --git a/docs/html/training/basics/activity-lifecycle/pausing.jd b/docs/html/training/basics/activity-lifecycle/pausing.jd
index de2c92a..223e41a 100644
--- a/docs/html/training/basics/activity-lifecycle/pausing.jd
+++ b/docs/html/training/basics/activity-lifecycle/pausing.jd
@@ -86,7 +86,7 @@
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if (mCamera != null) {
- mCamera.release()
+ mCamera.release();
mCamera = null;
}
}
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index dcf3a16..402396e 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -71,10 +71,10 @@
<h2 id="LinearLayout">Create a Linear Layout</h2>
<ol>
-<li>In Android Studio, from the <code>res/layout</code> directory, open the <code>activity_my.xml</code>
+<li>In Android Studio, from the <code>res/layout</code> directory, open the {@code content_my.xml}
file.
<p>The BlankActivity template you chose when you created this project includes the
-<code>activity_my.xml</code> file with a {@link android.widget.RelativeLayout} root view and a
+<code>content_my.xml</code> file with a {@link android.widget.RelativeLayout} root view and a
{@link android.widget.TextView} child view.</p>
</li>
<li>In the <strong>Preview</strong> pane, click the Hide icon <img src="{@docRoot}images/tools/as-hide-side.png"
@@ -90,16 +90,17 @@
<li>Remove the {@code android:padding} attributes and the {@code tools:context} attribute.
</ol>
-</p>The result looks like this:</p>
+<p>The result looks like this:</p>
-<p class="code-caption">res/layout/activity_my.xml</p>
<pre>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal" >
-</LinearLayout>
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:showIn="@layout/activity_my">
</pre>
<p>{@link android.widget.LinearLayout} is a view group (a subclass of {@link
@@ -131,7 +132,7 @@
the {@link android.widget.EditText} object's properties.</p>
<ol>
-<li>In the <code>activity_my.xml</code> file, within the
+<li>In the <code>content_my.xml</code> file, within the
{@link android.widget.LinearLayout <LinearLayout>} element, define an
{@link android.widget.EditText <EditText>} element with the <code>id</code> attribute
set to <code>@+id/edit_message</code>.</li>
@@ -142,7 +143,6 @@
<p>The {@link android.widget.EditText <EditText>} element should read as follows:</p>
-<p class="code-caption">res/layout/activity_my.xml</p>
<pre>
<EditText android:id="@+id/edit_message"
android:layout_width="wrap_content"
@@ -232,12 +232,10 @@
<li>Add a line for a string named <code>"button_send"</code> with the value, "Send".
<p>You'll create the button that uses this string in the next section.</p>
</li>
-<li>Remove the line for the <code>"hello world"</code> string.</li>
</ol>
<p>The result for <code>strings.xml</code> looks like this:</p>
-<p class="code-caption">res/values/strings.xml</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<resources>
@@ -245,7 +243,6 @@
<string name="edit_message">Enter a message</string>
<string name="button_send">Send</string>
<string name="action_settings">Settings</string>
- <string name="title_activity_main">MainActivity</string>
</resources>
</pre>
@@ -264,7 +261,7 @@
<h2 id="Button">Add a Button</h2>
<ol>
-<li>In Android Studio, from the <code>res/layout</code> directory, edit the <code>activity_my.xml</code>
+<li>In Android Studio, from the <code>res/layout</code> directory, edit the <code>content_my.xml</code>
file.</li>
<li>Within the
{@link android.widget.LinearLayout <LinearLayout>} element, define a
@@ -280,21 +277,23 @@
<p>Your {@link android.widget.LinearLayout <LinearLayout>} should look like this:</p>
-<p class="code-caption">res/layout/activity_my.xml</p>
<pre>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal" >
- <EditText android:id="@+id/edit_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:hint="@string/edit_message" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button_send" />
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:showIn="@layout/activity_my">
+ <EditText android:id="@+id/edit_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:hint="@string/edit_message" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/button_send" />
</LinearLayout>
</pre>
@@ -303,8 +302,8 @@
attribute, because it won't be referenced from the activity code.</p>
<p>The layout is currently designed so that both the {@link android.widget.EditText} and {@link
-android.widget.Button} widgets are only as big as necessary to fit their content, as shown in
-figure 2.</p>
+android.widget.Button} widgets are only as big as necessary to fit their content, as Figure 2 shows.
+</p>
<img src="{@docRoot}images/training/firstapp/edittext_wrap.png" />
<p class="img-caption"><strong>Figure 2.</strong> The {@link android.widget.EditText} and {@link
@@ -339,13 +338,12 @@
the following:</p>
<ol>
-<li>In the <code>activity_my.xml</code> file, assign the
+<li>In the <code>content_my.xml</code> file, assign the
{@link android.widget.EditText <EditText>} element's <code>layout_weight</code> attribute a value
of <code>1</code>.</li>
<li>Also, assign {@link android.widget.EditText <EditText>} element's <code>layout_width</code>
attribute a value of <code>0dp</code>.
-<p class="code-caption">res/layout/activity_my.xml</p>
<pre>
<EditText
android:layout_weight="1"
@@ -371,16 +369,18 @@
</li>
</ol>
-<p>Here’s how your complete <code>activity_my.xml</code>layout file should now look:</p>
+<p>Here’s how your complete <code>content_my.xml</code>layout file should now look:</p>
-<p class="code-caption">res/layout/activity_my.xml</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:showIn="@layout/activity_my">
<EditText android:id="@+id/edit_message"
android:layout_weight="1"
android:layout_width="0dp"
@@ -405,9 +405,9 @@
style="vertical-align:baseline;margin:0; max-height:1em" />.</li>
<li>Or from a command line, change directories to the root of your Android project and
execute:
-<pre>
-ant debug
-adb install bin/MyFirstApp-debug.apk
+<pre class="no-pretty-print">
+$ ant debug
+adb install -r app/build/outputs/apk/app-debug.apk
</pre></li>
</ul>
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 4bd92ee..57118ce 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -18,7 +18,6 @@
<ol>
<li><a href="#Studio">Create a Project with Android Studio</a></li>
- <li><a href="#CommandLine">Create a Project with Command Line Tools</a></li>
</ol>
<h2>You should also read</h2>
@@ -53,16 +52,11 @@
<li>If you don't have a project opened, in the <strong>Welcome</strong> screen, click <strong>
New Project</strong>.</li>
<li>If you have a project opened, from the <strong>File</strong> menu, select <strong>New
- Project</strong>.</li>
+ Project</strong>. The <em>Create New Project</em> screen appears.</li>
</ul>
</li>
- <div class="figure" style="width:420px">
- <img src="{@docRoot}images/training/firstapp/studio-setup-1.png" alt="" />
- <p class="img-caption"><strong>Figure 1.</strong> Configuring a new project in Android Studio.</p>
- </div>
- <li>Under <strong>Configure your new project</strong>, fill in the fields as shown in figure 1
- and click <strong>Next</strong>.
- <p>It will probably be easier to follow these lessons if you use the same values as shown.</p>
+ <li>Fill out the fields on the screen, and click <strong>Next</strong>.
+ <p>It is easier to follow these lessons if you use the same values as shown.</p>
<ul>
<li><strong>Application Name</strong> is the app name that appears to users.
For this project, use "My First App."</li>
@@ -102,10 +96,10 @@
</div>
<li>Under <strong>Add an activity to <<em>template</em>></strong>, select <strong>Blank
Activity</strong> and click <strong>Next</strong>.</li>
- <li>Under <strong>Choose options for your new file</strong>, change the
+ <li>Under <strong>Customize the Activity</strong>, change the
<strong>Activity Name</strong> to <em>MyActivity</em>. The <strong>Layout Name</strong> changes
to <em>activity_my</em>, and the <strong>Title</strong> to <em>MyActivity</em>. The
- <strong>Menu Resource Name</strong> is <em>menu_my</em>.
+ <strong>Menu Resource Name</strong> is <em>menu_my</em>.
<li>Click the <strong>Finish</strong> button to create the project.</li>
</ol>
@@ -114,10 +108,18 @@
<dl>
<dt><code>app/src/main/res/layout/activity_my.xml</code></dt>
- <dd>This is the XML layout file for the activity you added when you created the project with Android
- Studio. Following the New Project workflow, Android Studio presents this file with both a text
- view and a preview of the screen UI. The file includes some default settings and a <code>TextView</code>
- element that displays the message, "Hello world!"</dd>
+ <dd>This XML layout file is for the activity you added when you created the project
+ with Android Studio. Following the New Project workflow, Android Studio presents this file
+ with both a text
+ view and a preview of the screen UI. The file contains some default interface elements
+ from the material design library, including the
+ <a href="{@docRoot}training/appbar/index.html">app bar</a> and a floating action button.
+ It also includes a separate layout file with the main content.</dd>
+
+ <dt><code>app/src/main/res/layout/content_my.xml</code></dt>
+ <dd>This XML layout file resides in {@code activity_my.xml}, and contains some settings and
+ a {@code TextView} element that displays the message, "Hello world!".</dd>
+
<dt><code>app/src/main/java/com.mycompany.myfirstapp/MyActivity.java</code></dt>
<dd>A tab for this file appears in Android Studio when the New Project workflow finishes. When you
select the file you see the class definition for the activity you created. When you build and
@@ -159,59 +161,24 @@
<p>Note also the <code>/res</code> subdirectories that contain the
<a href="{@docRoot}guide/topics/resources/overview.html">resources</a> for your application:</p>
<dl>
- <dt><code>drawable<em><density></em>/</code></dt>
- <dd>Directories for drawable objects (such as bitmaps) that are designed for various densities,
- such as medium-density (mdpi) and high-density (hdpi) screens. Other drawable directories
- contain assets designed for other screen densities.
- Here you'll find the ic_launcher.png that appears when you run the default app.</dd>
+ <dt><code>drawable<em>-<density></em>/</code></dt>
+ <dd>Directories for <a href="{@docRoot}guide/topics/resources/drawable-resource.html">
+ drawable resources</a>, other than launcher icons, designed
+ for various <a href="{@docRoot}training/multiscreen/screendensities.html">densities</a>.
+</dd>
<dt><code>layout/</code></dt>
- <dd>Directory for files that define your app's user interface like activity_my.xml,
- discussed above, which describes a basic layout for the MyActivity class.</dd>
+ <dd>Directory for files that define your app's user interface like {@code activity_my.xml},
+ discussed above, which describes a basic layout for the {@code MyActivity}
+ class.</dd>
<dt><code>menu/</code></dt>
<dd>Directory for files that define your app's menu items.</dd>
+ <dt><code>mipmap/</code></dt>
+ <dd>Launcher icons reside in the {@code mipmap/} folder rather than the
+ {@code drawable/} folders. This folder contains the {@code ic_launcher.png} image
+ that appears when you run the default app.</dd>
<dt><code>values/</code></dt>
<dd>Directory for other XML files that contain a collection of resources, such as
- string and color definitions. The strings.xml file defines the "Hello world!" string that
- displays when you run the default app.</dd>
+ string and color definitions.</dd>
</dl>
<p>To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
-
-<h2 id="CommandLine">Create a Project with Command Line Tools</h2>
-
-<p>If you're not using the Android Studio IDE, you can instead create your project
-using the SDK tools from a command line:</p>
-
-<ol>
- <li>Change directories into the Android SDK’s <code>sdk/</code> path.</li>
- <li>Execute:
-<pre class="no-pretty-print">tools/android list targets</pre>
-<p>This prints a list of the available Android platforms that you’ve downloaded for your SDK. Find
-the platform against which you want to compile your app. Make a note of the target ID. We
-recommend that you select the highest version possible. You can still build your app to
-support older versions, but setting the build target to the latest version allows you to optimize
-your app for the latest devices.</p>
-<p>If you don't see any targets listed, you need to
-install some using the Android SDK
-Manager tool. See <a href="{@docRoot}sdk/installing/adding-packages.html">Adding SDK
- Packages</a>.</p></li>
- <li>Execute:
-<pre class="no-pretty-print">
-android create project --target <target-id> --name MyFirstApp \
---path <path-to-workspace>/MyFirstApp --activity MyActivity \
---package com.example.myfirstapp
-</pre>
-<p>Replace <code><target-id></code> with an ID from the list of targets (from the previous step)
-and replace
-<code><path-to-workspace></code> with the location in which you want to save your Android
-projects.</p></li>
-</ol>
-
-<p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
-<code>tools/</code> directory to your <code>PATH</code> environment variable.</p>
-
-<p>Your Android project is now a basic "Hello World" app that contains some default files.
-To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
-
-
-
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
old mode 100644
new mode 100755
index 6e4605f..99b38bf
--- a/docs/html/training/basics/firstapp/running-app.jd
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -54,17 +54,12 @@
If you're developing on Windows, you might need to install the appropriate USB driver for your
device. For help installing drivers, see the <a href="{@docRoot}tools/extras/oem-usb.html">OEM
USB Drivers</a> document.</li>
- <li>Enable <strong>USB debugging</strong> on your device.
- <ul>
- <li>On most devices running Android 3.2 or older, you can find the option under
- <strong>Settings > Applications > Development</strong>.</li>
- <li>On Android 4.0 and newer, it's in <strong>Settings > Developer options</strong>.
+ <li>Enable <strong>USB debugging</strong> on your device. On Android 4.0 and newer, go to
+ <strong>Settings > Developer options</strong>.
<p class="note"><strong>Note:</strong> On Android 4.2 and newer, <strong>Developer
options</strong> is hidden by default. To make it available, go
to <strong>Settings > About phone</strong> and tap <strong>Build number</strong>
seven times. Return to the previous screen to find <strong>Developer options</strong>.</p>
- </li>
- </ul>
</li>
</ol>
@@ -88,7 +83,7 @@
using the Gradle wrapper script (<code>gradlew assembleRelease</code>).
<p>This creates your debug <code>.apk</code> file inside the module <code>build/</code>
- directory, named <code>MyFirstApp-debug.apk</code>. </p>
+ directory, named <code>app-debug.apk</code>. </p>
<p>On Windows platforms, type this command:</p>
@@ -112,7 +107,7 @@
<p>Make sure the Android SDK <code>platform-tools/</code> directory is included in your
<code>PATH</code> environment variable, then execute:
- <pre class="no-pretty-print">adb install app/build/outputs/MyFirstApp-debug.apk</pre><p>
+ <pre class="no-pretty-print">$ adb install app/build/outputs/apk/app-debug.apk</pre><p>
<p>On your device, locate <em>MyFirstApp</em> and open it.</p>
<p>That's how you build and run your Android app on a device!
@@ -134,7 +129,9 @@
<li>Launch the Android Virtual Device Manager:
<ul>
<li>In Android Studio, select <strong>Tools > Android > AVD Manager</strong>, or click
- the AVD Manager icon <img src="{@docRoot}images/tools/avd-manager-studio.png" style="vertical-align:bottom;margin:0;height:19px"> in the toolbar.</li>
+ the AVD Manager icon <img src="{@docRoot}images/tools/avd-manager-studio.png"
+ style="vertical-align:bottom;margin:0;height:19px"> in the toolbar. The
+ <em>AVD Manager</em> screen appears.</li>
<li>Or, from the command line, change directories to
<code>sdk/</code> and execute:
<pre class="no-pretty-print">tools/android avd</pre>
@@ -144,12 +141,8 @@
</li>
</ul>
- <img src="{@docRoot}images/studio-avdmgr-firstscreen.png" alt=""
- style="margin-top:1em">
- <p class="img-caption"><strong>Figure 1.</strong> The AVD Manager main screen shows your current virtual devices.</p>
-
</li>
- <li>On the AVD Manager main screen (figure 1), click <strong>Create Virtual Device</strong>.</li>
+ <li>On the AVD Manager main screen, click <strong>Create Virtual Device</strong>.</li>
<li>In the Select Hardware window, select a device configuration, such as Nexus 6,
then click <strong>Next</strong>.
</li>
@@ -183,8 +176,8 @@
<code>PATH</code> environment variable.</li>
<li>Execute this command:
<p>
- <pre class="no-pretty-print">adb install app/build/outputs/MyFirstApp-debug.apk</pre>
- </p>
+ <pre class="no-pretty-print">$ adb install app/build/outputs/apk/apk-debug.apk</pre>
+ </p>
</li>
<li>On the emulator, locate <em>MyFirstApp</em> and open it.</li>
</ol>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 4f43ea0..69cf6f8 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -47,13 +47,13 @@
<h2 id="RespondToButton">Respond to the Send Button</h2>
<ol>
-<li>In Android Studio, from the <code>res/layout</code> directory, edit the <code>activity_my.xml</code>
+<li>In Android Studio, from the <code>res/layout</code> directory, edit the <code>content_my.xml</code>
file.</li>
-<li>To the {@link android.widget.Button <Button>} element, add the <a
+<li>Add the <a
href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
-attribute.
+attribute to the {@link android.widget.Button <Button>} element.
-<p class="code-caption">res/layout/activity_my.xml</p>
+<p class="code-caption">res/layout/content_my.xml</p>
<pre>
<Button
android:layout_width="wrap_content"
@@ -199,7 +199,7 @@
follows:
<p class="code-caption">java/com.mycompany.myfirstapp/MyActivity.java</p>
<pre>
-public class MyActivity extends ActionBarActivity {
+public class MyActivity extends AppCompatActivity {
public final static String EXTRA_MESSAGE = "com.mycompany.myfirstapp.MESSAGE";
...
}
@@ -253,13 +253,9 @@
<h3>Create a new activity using Android Studio</h3>
-<div class="figure" style="width:400px">
-<img src="{@docRoot}images/training/firstapp/studio-new-activity.png" alt="" />
-<p class="img-caption"><strong>Figure 1.</strong> The new activity wizard in Android Studio.</p>
-</div>
-
<p>Android Studio includes a stub for the
-{@link android.app.Activity#onCreate onCreate()} method when you create a new activity.</p>
+{@link android.app.Activity#onCreate onCreate()} method when you create a new activity. The
+<em>New Android Activity</em> window appears.</p>
<ol>
<li>In Android Studio, in the <code>java</code> directory, select the package,
@@ -279,10 +275,8 @@
<li>Open the {@code DisplayMessageActivity.java} file.
<p>The class already includes an implementation of the required
-{@link android.app.Activity#onCreate onCreate()} method. You will update the implementation of this
-method later. It also includes an implementation of
-{@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}, which handles the action
-bar's <em>Up</em> behavior. Keep these two methods as they are for now.</p>
+{@link android.app.Activity#onCreate onCreate()} method. You update the implementation of this
+method later.</p>
<!-- Android Studio does not create a Fragment placeholder
<p>Also, the file includes a <code>PlaceholderFragment</code> class that extends
@@ -294,10 +288,6 @@
</p>
-->
</li>
-
-<li> Remove the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method.
-<p>You won't need it for this app.</p>
-</li>
</ol>
<!-- Not needed for Android Studio
@@ -322,7 +312,7 @@
<li>Add the following code to the file:
<pre>
-public class DisplayMessageActivity extends ActionBarActivity {
+public class DisplayMessageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -337,8 +327,8 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
+ // Handle app bar item clicks here. The app bar
+ // automatically handles clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
@@ -437,10 +427,6 @@
<ol>
<li>In the <code>java/com.mycompany.myfirstapp</code> directory, edit the
{@code DisplayMessageActivity.java} file.</li>
-<li>In the {@link android.app.Activity#onCreate onCreate()} method, remove the following line:
-<pre>
- setContentView(R.layout.activity_display_message);
-</pre>
<li>Get the intent and assign it to a local variable.
<pre>
Intent intent = getIntent();
@@ -460,6 +446,19 @@
<h2 id="DisplayMessage">Display the Message</h2>
<ol>
+<li>In the res/layout directory, edit the {@code content_display_message.xml} file.</li>
+<li>Add an {@code android:id} attribute to the {@code RelativeLayout}.
+You need this attribute to reference the object from your app code.</li>
+
+<pre>
+< RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+...
+android:id="@+id/content">
+</RelativeLayout>
+</pre>
+<li>Switch back to editing {@code DisplayMessageActivity.java}.</li>
+
+
<li>In the {@link android.app.Activity#onCreate onCreate()} method, create a {@link android.widget.TextView} object.
<pre>
TextView textView = new TextView(this);
@@ -471,10 +470,11 @@
textView.setText(message);
</pre>
</li>
-<li>Then add the {@link android.widget.TextView} as the root view of the activity’s layout by
-passing it to {@link android.app.Activity#setContentView setContentView()}.
+<li>Add the {@link android.widget.TextView} to the {@link android.widget.RelativeLayout}
+identified by {@code R.id.content}.
<pre>
-setContentView(textView);
+RelativeLayout layout = (RelativeLayout) findViewById(R.id.content);
+layout.addView(textView);
</pre>
</li>
<li>At the top of the file, import the {@link android.widget.TextView} class.
@@ -487,29 +487,36 @@
<pre>
@Override
-public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_display_message);
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
- // Get the message from the intent
- Intent intent = getIntent();
- String message = intent.getStringExtra(MyActivity.EXTRA_MESSAGE);
+ FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+ .setAction("Action", null)
+ .show();
+ }
+ });
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- // Create the text view
- TextView textView = new TextView(this);
- textView.setTextSize(40);
- textView.setText(message);
+ Intent intent = getIntent();
+ String message = intent.getStringExtra(MyActivity.EXTRA_MESSAGE);
+ TextView textView = new TextView(this);
+ textView.setTextSize(40);
+ textView.setText(message);
- // Set the text view as the activity layout
- setContentView(textView);
-}
+ RelativeLayout layout = (RelativeLayout) findViewById(R.id.content);
+ layout.addView(textView);
</pre>
-<p>You can now run the app. When it opens, type a message in the text field, click Send,
- and the message appears on the second activity.</p>
-
-<img src="{@docRoot}images/training/firstapp/firstapp.png" />
-<p class="img-caption"><strong>Figure 2.</strong> Both activities in the final app, running
-on Android 4.4.
+<p>You can now run the app. When it opens, type a message in the text field, and click
+<strong>Send</strong>. The second activity replaces the first one on the screen, showing
+the message you entered in the first activity.</p>
<p>That's it, you've built your first Android app!</p>
diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd
old mode 100644
new mode 100755
index 7afb149..49fb883
--- a/docs/html/training/basics/fragments/creating.jd
+++ b/docs/html/training/basics/fragments/creating.jd
@@ -38,18 +38,11 @@
href="{@docRoot}tools/support-library/index.html">Support Library</a> so your app
remains compatible with devices running system versions as low as Android 1.6.</p>
-<p class="note"><strong>Note:</strong> If you decide that the minimum
-API level your app requires is 11 or higher, you don't need to use the Support
-Library and can instead use the framework's built in {@link android.app.Fragment} class and related
-APIs. Just be aware that this lesson is focused on using the APIs from the Support Library, which
-use a specific package signature and sometimes slightly different API names than the versions
-included in the platform.</p>
-
<p>Before you begin this lesson, you must set up your Android project to use the Support Library.
If you have not used the Support Library before, set up your project to use the <strong>v4</strong>
library by following the <a href="{@docRoot}tools/support-library/setup.html">Support Library
Setup</a> document. However, you can also include the <a href=
-"{@docRoot}guide/topics/ui/actionbar.html">action bar</a> in your activities by instead using the
+"{@docRoot}training/appbar/index.html">app bar</a> in your activities by instead using the
<strong>v7 appcompat</strong> library, which is compatible with Android 2.1 (API level 7)
and also includes the {@link android.support.v4.app.Fragment} APIs.</p>
@@ -152,9 +145,9 @@
<p>If you're using the <a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
appcompat library</a>, your activity should instead extend {@link
-android.support.v7.app.ActionBarActivity}, which is a subclass of {@link
-android.support.v4.app.FragmentActivity} (for more information,
-read <a href="{@docRoot}training/basics/actionbar/index.html">Adding the Action Bar</a>).</p>
+android.support.v7.app.AppCompatActivity}, which is a subclass of {@link
+android.support.v4.app.FragmentActivity}. For more information,
+read <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>).</p>
<p class="note"><strong>Note:</strong> When you add a fragment to an activity layout by defining
diff --git a/docs/html/training/basics/intents/filters.jd b/docs/html/training/basics/intents/filters.jd
index 0a6d401..833825f 100644
--- a/docs/html/training/basics/intents/filters.jd
+++ b/docs/html/training/basics/intents/filters.jd
@@ -197,7 +197,7 @@
<pre>
// Create intent to deliver some kind of result data
-Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
+Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));
setResult(Activity.RESULT_OK, result);
finish();
</pre>
diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd
old mode 100644
new mode 100755
index b521488..31d5a7c
--- a/docs/html/training/basics/intents/result.jd
+++ b/docs/html/training/basics/intents/result.jd
@@ -107,8 +107,8 @@
<p>In order to successfully handle the result, you must understand what the format of the result
{@link android.content.Intent} will be. Doing so is easy when the activity returning a result is
one of your own activities. Apps included with the Android platform offer their own APIs that
-you can count on for specific result data. For instance, the People app (Contacts app on some older
-versions) always returns a result with the content URI that identifies the selected contact, and the
+you can count on for specific result data. For instance, the People app always returns a result
+with the content URI that identifies the selected contact, and the
Camera app returns a {@link android.graphics.Bitmap} in the {@code "data"} extra (see the class
about <a href="{@docRoot}training/camera/index.html">Capturing Photos</a>).</p>
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index b9463e4..233cf57 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -54,7 +54,7 @@
one of several other data types, or the intent might not need data at all.</p>
<p>If your data is a {@link android.net.Uri}, there's a simple {@link
-android.content.Intent#Intent(String,Uri) Intent()} constructor you can use define the action and
+android.content.Intent#Intent(String,Uri) Intent()} constructor you can use to define the action and
data.</p>
<p>For example, here's how to create an intent to initiate a phone call using the {@link
diff --git a/docs/html/training/basics/network-ops/connecting.jd b/docs/html/training/basics/network-ops/connecting.jd
index 0601480..798a9ee7 100644
--- a/docs/html/training/basics/network-ops/connecting.jd
+++ b/docs/html/training/basics/network-ops/connecting.jd
@@ -49,14 +49,10 @@
<h2 id="http-client">Choose an HTTP Client</h2>
-<p>Most network-connected Android apps use HTTP to send and receive data.
-Android includes two HTTP clients: {@link java.net.HttpURLConnection} and the Apache HTTP client.
-Both support HTTPS, streaming uploads and downloads, configurable
-timeouts, IPv6, and connection pooling. We recommend using {@link
-java.net.HttpURLConnection} for applications targeted at Gingerbread and higher. For
-more discussion of this topic, see the blog post <a
-href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html"
->Android's HTTP Clients</a>.</p>
+<p>Most network-connected Android apps use HTTP to send and receive data. The
+Android platform includes the {@link java.net.HttpURLConnection} client, which
+supports HTTPS, streaming uploads and downloads, configurable timeouts,
+IPv6, and connection pooling.</p>
<h2 id="connection">Check the Network Connection</h2>
diff --git a/docs/html/training/best-permissions-ids.jd b/docs/html/training/best-permissions-ids.jd
new file mode 100644
index 0000000..e98c095
--- /dev/null
+++ b/docs/html/training/best-permissions-ids.jd
@@ -0,0 +1,9 @@
+page.title=Best Practices for Permissions and Identifiers
+page.trainingcourse=true
+
+@jd:body
+
+
+
+<p>The articles below highlight key guidelines for using permissions
+and identifiers properly in your apps.</p>
\ No newline at end of file
diff --git a/docs/html/training/building-wearables.jd b/docs/html/training/building-wearables.jd
index c9e1856..9044928 100644
--- a/docs/html/training/building-wearables.jd
+++ b/docs/html/training/building-wearables.jd
@@ -12,3 +12,17 @@
<p class="note"><strong>Note:</strong> For more information about the APIs used in these training
classes, see the <a href="{@docRoot}reference/packages-wearable-support.html">Wear API reference
documentation</a>.</p>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-1of2">
+ <p>If you prefer to learn through interactive video training, check out this online course
+ about Android Wear Development.</p>
+ <p><a href="https://www.udacity.com/course/ud875A" class="button">
+ Start the video course</a>
+ </p>
+ </div>
+ <div class="col-1of2">
+ <iframe width="300" height="169" src="//www.youtube.com/embed/t2JaW-8WDok?utm_source=dac&utm_medium=video&utm_content=build_wear&utm_campaign=udacint?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
+ </div>
+</div>
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
deleted file mode 100644
index 082ace5..0000000
--- a/docs/html/training/cloudsync/index.jd
+++ /dev/null
@@ -1,36 +0,0 @@
-page.title=Syncing to the Cloud
-page.tags=cloud,sync,backup
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.2 (API level 8) and higher</li>
-</ul>
-</div>
-</div>
-
-<p>By providing powerful APIs for internet connectivity, the Android framework
-helps you build rich cloud-enabled apps that sync their data to a remote web
-service, making sure all your devices always stay in sync, and your valuable
-data is always backed up to the cloud.</p>
-
-<p>This class covers strategies for backing up data using the cloud so that
-users can restore their data when installing your application on a new device.
-</p>
-
-<h2>Lessons</h2>
-
-<dl>
- <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
- <dd>Learn how to integrate the Backup API into your Android Application, so
- that user data such as preferences, notes, and high scores update seamlessly
- across all of a user's devices</dd>
-</dl>
-
diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
index 041eb58..b00ce0e 100644
--- a/docs/html/training/contacts-provider/display-contact-badge.jd
+++ b/docs/html/training/contacts-provider/display-contact-badge.jd
@@ -293,7 +293,6 @@
/*
* Handle file not found errors
*/
- }
// In all cases, close the asset file descriptor
} finally {
if (afd != null) {
diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
old mode 100644
new mode 100755
index d97b81b..49d6e95
--- a/docs/html/training/contacts-provider/retrieve-names.jd
+++ b/docs/html/training/contacts-provider/retrieve-names.jd
@@ -230,7 +230,7 @@
{@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
- Eclipse with ADK. To turn off this warning, add the annotation
+ Android Studio. To turn off this warning, add the annotation
<code>@SuppressLint("InlinedApi")</code> before the definition of <code>FROM_COLUMNS</code>.
</p>
<h3 id="InitializeFragment">Initialize the Fragment</h3>
diff --git a/docs/html/training/custom-views/create-view.jd b/docs/html/training/custom-views/create-view.jd
old mode 100644
new mode 100755
index a476bbe..7b5cdc3
--- a/docs/html/training/custom-views/create-view.jd
+++ b/docs/html/training/custom-views/create-view.jd
@@ -61,8 +61,7 @@
existing view
subclasses, such as {@link android.widget.Button}.</p>
-<p>To allow the <a href="{@docRoot}guide/developing/tools/adt.html">Android Developer Tools
-</a> to interact with your view, at a minimum you must provide a constructor that takes a
+<p>To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a
{@link android.content.Context} and an {@link android.util.AttributeSet} object as parameters.
This constructor allows the layout editor to create and edit an instance of your view.</p>
diff --git a/docs/html/training/custom-views/index.jd b/docs/html/training/custom-views/index.jd
old mode 100644
new mode 100755
index 87cd0b0..f732adb
--- a/docs/html/training/custom-views/index.jd
+++ b/docs/html/training/custom-views/index.jd
@@ -48,7 +48,7 @@
<dl>
<dt><b><a href="create-view.html">Creating a View Class</a></b></dt>
<dd>Create a class that acts like a built-in view, with custom
- attributes and support from the <a href="http://developer.android.com/sdk/eclipse-adt.html">ADT</a> layout editor.
+ attributes and support from the <a href="http://developer.android.com/sdk/installing/studio-layout.html">Android Studio</a> layout editor.
</dd>
<dt><b><a href="custom-drawing.html">Custom Drawing</a></b></dt>
diff --git a/docs/html/training/custom-views/making-interactive.jd b/docs/html/training/custom-views/making-interactive.jd
old mode 100644
new mode 100755
index 4e9d53a..14163d8
--- a/docs/html/training/custom-views/making-interactive.jd
+++ b/docs/html/training/custom-views/making-interactive.jd
@@ -229,8 +229,8 @@
is not available prior to API level 11, so this technique cannot be used
on devices running Android versions lower than 3.0.</p>
-<p class="note"><strong>Note:</strong> {@link android.animation.ValueAnimator} isn't available
- prior to API level 11, but you can still use it in applications that
+<p class="note"><strong>Note:</strong> You can use {@link android.animation.ValueAnimator} in
+applications that
target lower API levels. You just need to make sure to check the current API level
at runtime, and omit the calls to the view animation system if the current level is less than 11.</p>
diff --git a/docs/html/training/design-navigation/wireframing.jd b/docs/html/training/design-navigation/wireframing.jd
old mode 100644
new mode 100755
index 1801f91..201d9e4
--- a/docs/html/training/design-navigation/wireframing.jd
+++ b/docs/html/training/design-navigation/wireframing.jd
@@ -78,9 +78,6 @@
<li>What's the learning curve? Professional vector illustration tools may have a steep learning curve, while tools designed for wireframing may offer a smaller set of features that are more relevant to the task.</li>
</ul>
-<p>Lastly, the XML Layout Editor that comes with the <a href="{@docRoot}tools/help/adt.html">Android Development Tools (ADT)</a> plugin for Eclipse can often be used for prototyping. However, you should be careful to focus more on the high-level layout and less on visual design details at this point.</p>
-
-
<h2 id="wireframe-digital">Create Digital Wireframes</h2>
<p>After sketching out layouts on paper and choosing a digital wireframing tool that works for you, you can create the digital wireframes that will serve as the starting point for your application's visual design. Below are example wireframes for our news application, corresponding one-to-one with our screen maps from earlier in this lesson.</p>
diff --git a/docs/html/training/efficient-downloads/redundant_redundant.jd b/docs/html/training/efficient-downloads/redundant_redundant.jd
index 674298a..0825b5d 100644
--- a/docs/html/training/efficient-downloads/redundant_redundant.jd
+++ b/docs/html/training/efficient-downloads/redundant_redundant.jd
@@ -37,7 +37,7 @@
<p>To ensure that your caching doesn't result in your app displaying stale data, be sure to extract the time at which the requested content was last updated, and when it expires, from within the HTTP response headers. This will allow you to determine when the associated content should be refreshed.</p>
-<pre>long currentTime = System.currentTimeMillis());
+<pre>long currentTime = System.currentTimeMillis();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
@@ -54,7 +54,7 @@
<p>Using this approach, you can also effectively cache dynamic content while ensuring it doesn't result in your application displaying stale information.</p>
-<p>You can cache non-sensitive data can in the unmanaged external cache directory:</p>
+<p>You can cache non-sensitive data in the unmanaged external cache directory:</p>
<pre>Context.getExternalCacheDir();</pre>
@@ -84,4 +84,4 @@
<p>With the cache installed, fully cached HTTP requests can be served directly from local storage, eliminating the need to open a network connection. Conditionally cached responses can validate their freshness from the server, eliminating the bandwidth cost associated with the download.</p>
-<p>Uncached responses get stored in the response cache for for future requests.</p>
\ No newline at end of file
+<p>Uncached responses get stored in the response cache for future requests.</p>
diff --git a/docs/html/training/enterprise/app-restrictions.jd b/docs/html/training/enterprise/app-restrictions.jd
index dd2c2c0..07b1de7 100644
--- a/docs/html/training/enterprise/app-restrictions.jd
+++ b/docs/html/training/enterprise/app-restrictions.jd
@@ -152,10 +152,10 @@
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >
<restriction
- android:key="downloadOnCellular"
- android:title="App is allowed to download data via cellular"
+ android:key="download_on_cell"
+ android:title="@string/download_on_cell_title"
android:restrictionType="bool"
- android:description="If 'false', app can only download data via Wi-Fi"
+ android:description="@string/download_on_cell_description"
android:defaultValue="true" />
</restrictions>
@@ -166,6 +166,12 @@
documented in the reference for {@link android.content.RestrictionsManager}.
</p>
+<p class="note">
+ <strong>Note:</strong> <code>bundle</code> and
+ <code>bundle_array</code> restriction types are not supported by Google Play
+ for Work.
+</p>
+
<p>
You use each restriction's <code>android:key</code> attribute to read its
value from a restrictions bundle. For this reason, each restriction must have
@@ -211,7 +217,7 @@
</li>
<li>When the app is notified of a restriction change, as described in
- <a href="#listen">Listen for Device Configuration
+ <a href="#listen">Listen for App Configuration
Changes</a>
</li>
</ul>
@@ -254,9 +260,30 @@
the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
change while your app is active, as described in <a href="#listen">Listen for
- Device Configuration Changes</a>.
+ App Restriction Changes</a>.
</p>
+<p>
+ When your app checks for restrictions using
+ {@link android.content.RestrictionsManager#getApplicationRestrictions
+ RestrictionsManager.getApplicationRestrictions()}, we recommend that you
+ check to see if the enterprise administrator has set the key-value pair
+ {@link android.os.UserManager#KEY_RESTRICTIONS_PENDING} to true. If so, you
+ should block the user from using the app, and prompt them to contact their
+ enterprise administrator. The app should then proceed as normal, registering
+ for the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED} broadcast.
+</p>
+
+<img src="{@docRoot}images/training/enterprise/app_restrictions_diagram.png"
+width="620" srcset="{@docRoot}images/training/enterprise/app_restrictions_diagram.png 1x,
+{@docRoot}images/training/enterprise/app_restrictions_diagram_2x.png 2x" />
+
+ <p class="img-caption">
+ <strong>Figure 1.</strong> Checking whether restrictions are pending before
+ registering for the broadcast.
+ </p>
+
<h3 id="read_restrictions">
Reading and applying restrictions
</h3>
@@ -266,11 +293,11 @@
getApplicationRestrictions()} method returns a {@link android.os.Bundle}
containing a key-value pair for each restriction that has been set. The
values are all of type <code>Boolean</code>, <code>int</code>,
- <code>String</code>, and <code>String[]</code>. Once you have the
- restrictions {@link android.os.Bundle}, you can check the current
- restrictions settings with the standard {@link android.os.Bundle} methods for
- those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
- or
+ <code>String</code>, <code>String[]</code>, <code>Bundle</code>, and
+ <code>Bundle[]</code>. Once you have the restrictions {@link android.os.Bundle},
+ you can check the current restrictions settings with the standard
+ {@link android.os.Bundle} methods for those data types, such as
+ {@link android.os.Bundle#getBoolean getBoolean()} or
{@link android.os.Bundle#getString getString()}.
</p>
@@ -284,10 +311,11 @@
<p>
It is up to your app to take appropriate action based on the current
- restrictions settings. For example, if your app has a restriction specifying
- whether it can download data over a cellular connection, and you find that
- the restriction is set to <code>false</code>, you would have to disable data
- download except when the device has a Wi-Fi connection, as shown in the
+ restrictions settings. For example, if your app has a restriction schema
+ to specify whether it can download over a cellular connection (like the
+ example in <a href="#define_restrictions">Define App Restrictions</a>),
+ and you find that the restriction is set to false, you would have to disable
+ data download except when the device has a Wi-Fi connection, as shown in the
following example code:
</p>
@@ -307,6 +335,13 @@
// ...show appropriate notices to user
}</pre>
+<p class="note">
+ <strong>Note:</strong> The restrictions schema should be
+ backward and forward compatible, since Google Play for Work
+ gives the EMM only one version of the App Restrictions
+ Schema per app.
+ </p>
+
<h2 id="listen">
Listen for App Restriction Changes
</h2>
@@ -354,8 +389,8 @@
<strong>Note:</strong> Ordinarily, your app does not need to be notified
about restriction changes when it is paused. Instead, you should unregister
your broadcast receiver when the app is paused. When the app resumes, you
- first check for the current restrictions (as discussed in <a href=
- "#check_restrictions">Check Device Restrictions</a>), then register your
- broadcast receiver to make sure you're notified about restriction changes
+ first check for the current restrictions (as discussed in
+ <a href="#check_restrictions">Check App Restrictions</a>), then register
+ your broadcast receiver to make sure you're notified about restriction changes
that happen while the app is active.
</p>
diff --git a/docs/html/training/enterprise/cosu.jd b/docs/html/training/enterprise/cosu.jd
new file mode 100644
index 0000000..1d6388b
--- /dev/null
+++ b/docs/html/training/enterprise/cosu.jd
@@ -0,0 +1,503 @@
+page.title=Configuring Corporate-Owned, Single-Use Devices
+page.metaDescription=Learn how to develop single-use solutions for Android devices.
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#locktask">How to use LockTask mode</a></li>
+ <li><a href="#cosu-solutions">Build COSU solutions</a></li>
+ <li><a href="#create-dpc">Create your own DPC app</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}training/enterprise/work-policy-ctrl.html">
+Building a Device Policy Controller</a>
+ </li>
+</ul>
+
+</div>
+</div>
+
+<p>
+As an IT administrator, you can configure Android 6.0 Marshmallow and later
+devices as <em>corporate-owned, single-use (COSU)</em> devices. These are Android
+devices used for a single purpose, such as digital signage, ticket printing,
+point of sale, or inventory management. To use Android devices as COSU devices,
+you need to develop Android apps that your customers can manage.
+</p>
+
+<p>
+Your customers can configure COSU devices:
+</p>
+<ul>
+<li>
+To lock a single application to the screen, and hide the
+<strong>Home</strong> and <strong>Recents</strong> buttons to prevent users
+from escaping the app.
+</li>
+
+<li>
+To allow multiple applications to appear on the screen, such as a library kiosk
+with a catalog app and web browser.
+</li>
+</ul>
+
+<h2 id="pinning">
+App pinning vs. lock task mode
+</h2>
+
+<p>Android 5.0 Lollipop introduced two new ways to configure Android devices
+for a single purpose:
+</p>
+
+<ul>
+<li>
+With app pinning, the device user can temporarily pin specific apps to the
+screen.
+</li>
+
+<li>
+With lock task mode, a user can’t escape the app and the Home and Recents
+buttons are hidden. Additionally, lock task mode gives the IT administrator
+a more robust way to manage COSU devices, as discussed below.
+</li>
+</ul>
+
+<p>
+This graphic compares the features of app pinning and lock task mode:
+</p>
+
+<img src="{@docRoot}images/training/enterprise/pinning_vs_locktaskmode.png"
+width="640" srcset="{@docRoot}images/training/enterprise/pinning_vs_locktaskmode.png 1x,
+{@docRoot}images/training/enterprise/pinning_vs_locktaskmode_2x.png 2x" />
+
+ <p class="img-caption">
+ <strong>Figure 1.</strong> Comparing the features of app pinning in Lollipop
+ vs. Lock task mode in Marshmallow and later
+ </p>
+
+<p>
+In Lollipop, you can pin a single application to cover the full screen, but
+only apps whitelisted by the device policy controller (DPC) can be locked.
+</p>
+
+<h2 id="locktask">
+ How to use LockTask mode
+</h2>
+
+<p>
+ To use LockTask mode, and the APIs that manage COSU devices, there must be
+ a device owner application installed on the device. Device owners are a
+ type of device policy controller (DPC) that manages the whole device. For
+ more information about DPCs, see the
+ <a class="external-link" href="https://developers.google.com/android/work/overview">EMM Developer’s Overview</a>.
+</p>
+
+<p>
+If you’re creating a new COSU app, we recommend you develop it for
+Marshmallow or later, which includes the following COSU features:
+</p>
+
+<ul>
+<li>
+Controls system updates
+</li>
+
+<li>
+Sets status and menu bar visibility
+</li>
+
+<li>
+Disables screen lock and sleep functions
+</li>
+
+<li>
+Permits switching between apps while staying in lock task mode
+</li>
+
+<li>
+Prevents restarting in safe mode
+</li>
+</ul>
+
+<p class="note">
+ <strong>Note:</strong> If you develop COSU features targeted for
+ Marshmallow devices, your app can still be compatible with prior
+ versions of Android.
+</p>
+
+<p>
+Additional COSU management features launched with Marshmallow make it easier to
+develop and deploy Android devices as a single-use device. If you want to
+enforce server-side app restrictions or server-side profile policy controls,
+you need to use an EMM or make your application a DPC. Follow the instructions
+below as you create your application.
+</p>
+
+<h2 id="cosu-solutions">
+ Build COSU solutions
+</h2>
+
+<p>
+ There are two different ways to manage COSU devices:
+</p>
+
+<ul>
+<li>
+<strong>Use a third-party enterprise mobility management (EMM)
+solution</strong>: Using an EMM, all you need to do is set up lock task mode.
+For instructions, skip to the next section,
+<a href="#emm-solutions">Solutions managed by a third-party EMM</a>.
+</li>
+
+<li>
+<strong>Advanced setup—Create your own DPC app</strong>: This requires
+more work and is intended for an advanced developer audience. With this
+option, you’ll need to set up the device so that you can manage it, set
+up APIs, and set up a DPC app and test it. For instructions, skip to
+<a href="#create-dpc">Create your own DPC app</a>.
+</li>
+</ul>
+
+<h2 id="emm-solutions">
+Solutions managed by a third-party EMM
+</h2>
+
+<p>
+In this section, you’ll need to do a small amount of development to
+have your device work with a third-party EMM.
+</p>
+
+<h3 id="use-smartlocktask">
+Using startLockTask()
+</h3>
+
+<p>
+If you need to add COSU functionality to an existing app, make sure that
+the customer’s EMM supports {@link android.R.attr#lockTaskMode}.
+</p>
+
+<ul>
+<li>
+The device owner must include your app’s package(s) in
+{@link android.app.admin.DevicePolicyManager#setLockTaskPackages setLockTaskPackages}</li>
+<ul>
+<li>
+Sets the packages that can enter into lock task mode
+</li>
+<li>
+Needs to be set by the EMM
+</li>
+<li>
+You can call {@link android.app.admin.DevicePolicyManager#isLockTaskPermitted isLockTaskPermitted}
+to verify that your package has been whitelisted by
+{@link android.app.admin.DevicePolicyManager#setLockTaskPackages setLockTaskPackages}.
+</li>
+</ul>
+
+<li>
+Your activity calls {@link android.app.Activity#startLockTask()}
+</li>
+<ul>
+<li>
+Requests to lock the user into the current task
+</li>
+<li>
+Prevents launching other apps, settings, and the <strong>Home</strong>
+button
+</li>
+</ul>
+
+<li>
+To exit, your activity must call {@link android.app.Activity#stopLockTask()}
+</li>
+<ul>
+<li>
+Can only be called on an activity that’s previously called
+ {@link android.app.Activity#startLockTask()}
+</li>
+<li>
+Should be called when the app is user-facing between {@link android.app.Activity#onResume()}
+and {@link android.app.Activity#onPause()}
+</li>
+</ul>
+</ul>
+
+<p>
+Starting from Marshmallow, if your app is whitelisted by an EMM using {@link
+android.app.admin.DevicePolicyManager#setLockTaskPackages setLockTaskPackages},
+your activities can automatically start lock task mode when the app is
+launched.
+</p>
+
+<h3 id="locktaskmode-attribute">
+Set the lockTaskMode attribute
+</h3>
+
+<p>
+ The {@link android.R.attr#lockTaskMode} attribute allows you to define
+ your app’s lock task mode behavior in the AndroidManifest.xml file:
+</p>
+
+<ul>
+<li>
+If you set {@link android.R.attr#lockTaskMode} to <code>if_whitelisted</code>,
+you don’t need to call {@link android.app.Activity#startLockTask()}, and the
+app automatically enters into lock task mode.
+</li>
+
+<li>
+System apps and privileged apps can also set {@link android.R.attr#lockTaskMode}
+to always. This setting causes tasks (rooted at your activity) to always
+launch into lock task mode. Non-privileged apps are treated as normal.
+</li>
+
+<li>
+The default value of the {@link android.R.attr#lockTaskMode} attribute is
+normal. When this attribute is set to normal, tasks don’t launch into
+{@link android.R.attr#lockTaskMode}, unless {@link android.app.Activity#startLockTask()}
+is called. To call {@link android.app.Activity#startLockTask()},
+applications still need to be whitelisted using
+{@link android.app.admin.DevicePolicyManager#setLockTaskPackages setLockTaskPackages},
+otherwise, the user sees a dialog to approve entering pinned mode.
+</li>
+</ul>
+
+<p>To have your activity <em>automatically</em> enter {@link android.R.attr#lockTaskMode},
+change the value of this attribute to <code>if_whitelisted</code>.
+Doing so causes your app to behave in this manner:
+</p>
+
+<ul>
+<li>
+If your app isn’t whitelisted for {@link android.R.attr#lockTaskMode},
+it behaves as normal.
+</li>
+
+<li>
+If your app is a system or privileged app, and it’s whitelisted,
+{@link android.R.attr#lockTaskMode} automatically starts when the app is
+launched.
+</li>
+</ul>
+
+<p>
+Example XML as follows:
+</p>
+
+ <pre><activity android:name=".MainActivity" android:lockTaskMode="if_whitelisted"></pre>
+
+<p>
+Given either of these options, you still need to create a mechanism for
+calling {@link android.app.Activity#stopLockTask()} so that users can
+exit {@link android.R.attr#lockTaskMode}.
+</p>
+
+<h2 id="create-dpc">
+ Advanced setup—Create your own DPC app
+</h2>
+
+<p>
+To manage applications in COSU, you need a DPC running as device
+owner to set several policies on the device.
+</p>
+
+<p class="note">
+<strong>Note:</strong> This setup is advanced, and requires
+a thorough understanding of the EMM concepts described in the
+<a class="external-link" href="https://developers.google.com/android/work/prov-devices#implementation_considerations_for_device_owner_mode">EMM developer overview</a>.
+For more information about building a DPC, see
+<a class="external-link"
+href="https://developers.google.com/android/work/prov-devices">Provision Customer Devices</a>.
+</p>
+
+<p>
+To create a DPC app that can manage COSU device configuration,
+the DPC needs to:
+</p>
+
+<ol>
+<li>
+Provision the device into device owner mode. We recommend that
+you support provisioning with near field communication (NFC) bump.
+For more information, see
+<a class="external-link" href="https://developers.google.com/android/work/prov-devices#nfc_method"
+>Device Owner Provisioning via NFC</a>.
+</li>
+
+<li>
+Use the following APIs:
+<ul>
+<li>
+Keep devices from locking with the keyguard using
+{@link android.app.admin.DevicePolicyManager#setKeyguardDisabled setKeyguardDisabled()}
+</li>
+
+<li>
+Disable the status bar using
+{@link android.app.admin.DevicePolicyManager#setStatusBarDisabled setStatusBarDisabled()}
+</li>
+
+<li>
+Keep a device’s screen on while plugged in via
+{@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN}
+</li>
+
+<li>
+Set default user restrictions via
+{@link android.app.admin.DevicePolicyManager#addUserRestriction addUserRestriction()}
+</li>
+
+<li>
+Set system update policies using
+{@link android.app.admin.DevicePolicyManager#setSystemUpdatePolicy setSystemUpdatePolicy()}
+</li>
+
+<li>
+Ensure your app is launched on reboot by setting it as the default launcher
+</li>
+</ul>
+</li>
+</ol>
+
+<p>
+Here’s an example of how to implement an activity that starts lock task mode
+and implements the relevant COSU device management APIs:
+</p>
+
+<pre>
+public class CosuActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mAdminComponentName = DeviceAdminReceiver.getComponentName(this);
+ mDevicePolicyManager = (DevicePolicyManager) getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ mPackageManager = getPackageManager();
+ setDefaultCosuPolicies(true);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // start lock task mode if it's not already active
+ ActivityManager am = (ActivityManager) getSystemService(
+ Context.ACTIVITY_SERVICE);
+ // ActivityManager.getLockTaskModeState api is not available in pre-M.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ if (!am.isInLockTaskMode()) {
+ startLockTask();
+ }
+ } else {
+ if (am.getLockTaskModeState() ==
+ ActivityManager.LOCK_TASK_MODE_NONE) {
+ startLockTask();
+ }
+ }
+ }
+
+ private void setDefaultCosuPolicies(boolean active) {
+ // set user restrictions
+ setUserRestriction(DISALLOW_SAFE_BOOT, active);
+ setUserRestriction(DISALLOW_FACTORY_RESET, active);
+ setUserRestriction(DISALLOW_ADD_USER, active);
+ setUserRestriction(DISALLOW_MOUNT_PHYSICAL_MEDIA, active);
+ setUserRestriction(DISALLOW_ADJUST_VOLUME, active);
+
+ // disable keyguard and status bar
+ mDevicePolicyManager.setKeyguardDisabled(mAdminComponentName, active);
+ mDevicePolicyManager.setStatusBarDisabled(mAdminComponentName, active);
+
+ // enable STAY_ON_WHILE_PLUGGED_IN
+ enableStayOnWhilePluggedIn(active);
+
+ // set System Update policy
+
+ if (active){
+ mDevicePolicyManager.setSystemUpdatePolicy(mAdminComponentName,
+ SystemUpdatePolicy.createWindowedInstallPolicy(60,120));
+ }
+ else
+
+
+ // set this Activity as a lock task package
+
+ mDevicePolicyManager.setLockTaskPackages(mAdminComponentName,
+ active ? new String[]{getPackageName()} : new String[]{});
+
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
+ intentFilter.addCategory(Intent.CATEGORY_HOME);
+ intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
+
+ if (active) {
+ // set Cosu activity as home intent receiver so that it is started
+ // on reboot
+ mDevicePolicyManager.addPersistentPreferredActivity(
+ mAdminComponentName, intentFilter, new ComponentName(
+ getPackageName(), CosuModeActivity.class.getName()))
+ } else {
+ mDevicePolicyManager.clearPackagePersistentPreferredActivities(
+ mAdminComponentName, getPackageName());
+ }
+ }
+
+ private void setUserRestriction(String restriction, boolean disallow) {
+ if (disallow) {
+ mDevicePolicyManager.addUserRestriction(mAdminComponentName,
+ restriction);
+ } else {
+ mDevicePolicyManager.clearUserRestriction(mAdminComponentName,
+ restriction);
+ }
+ }
+
+ private void enableStayOnWhilePluggedIn(boolean enabled) {
+ if (enabled) {
+ mDevicePolicyManager.setGlobalSetting(
+ mAdminComponentName,
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+ BatteryManager.BATTERY_PLUGGED_AC
+ | BatteryManager.BATTERY_PLUGGED_USB
+ | BatteryManager.BATTERY_PLUGGED_WIRELESS);
+ } else {
+ mDevicePolicyManager.setGlobalSetting(
+ mAdminComponentName,
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ }
+
+ }
+
+ // TODO: Implement the rest of the Activity
+}
+</pre>
+
+
+<h2 id="testing-plan">
+ Develop a test plan for COSU
+</h2>
+
+<p>
+ If you’re planning to support a third-party EMM, develop an end-to-end
+ testing plan utilizing the EMM’s app. We also provide testing resources,
+ which you can use to create your own Test Device Policy Client (Test DPC):
+</p>
+
+<ul>
+<li>
+<a class="external-link" href="https://play.google.com/store/search?q=testdpc">TestDPC on Google Play</a>
+</li>
+<li>
+<a class="external-link" href="https://github.com/googlesamples/android-testdpc/tree/master/app/src/main/java/com/afwsamples/testdpc/cosu">TestDPC for COSU source code on GitHub</a>
+</li>
+<li>
+<a class="external-link" href="https://github.com/googlesamples/android-testdpc">Test Device Policy Control app source code on GitHub</a>
+</li>
+</ul>
diff --git a/docs/html/training/enterprise/work-policy-ctrl.jd b/docs/html/training/enterprise/work-policy-ctrl.jd
index 5854e65..8225ea3 100644
--- a/docs/html/training/enterprise/work-policy-ctrl.jd
+++ b/docs/html/training/enterprise/work-policy-ctrl.jd
@@ -1,5 +1,6 @@
-page.title=Building a Work Policy Controller
-page.metaDescription=Learn how to develop a Work Policy Controller to create and administer a managed profile on an employee's device.
+page.title=Building a Device Policy Controller
+page.metaDescription=Learn how to develop a device policy controller to create and administer a managed profile on an employee's device.
+page.tags="work policy controller,WPC,device policy controller,DPC"
@jd:body
<div id="tb-wrapper">
@@ -54,8 +55,9 @@
</p>
<p>
- To handle these tasks, an enterprise develops and deploys a Work Policy
- Controller app. This app is installed on each employee's device. The
+ To handle these tasks, an enterprise develops and deploys
+ a <em>device policy controller</em> app (previously known as a
+ <em>work policy controller</em>). This app is installed on each employee's device. The
controller app installed on each employee's device and creates a work user
profile, which accesses enterprise apps and data separately from the user's
personal account. The controller app also acts as the
@@ -66,7 +68,7 @@
</p>
<p>
- This lesson describes how to develop a Work Policy Controller app for devices
+ This lesson describes how to develop a device policy controller app for devices
in an Android for Work deployment. The lesson describes how to create a work
user profile, how to set device policies, and how to apply
restrictions to other apps running on the managed profile.
@@ -85,13 +87,13 @@
policies to control the behavior of employees' devices and apps. The
enterprise administrator sets these policies with software provided by their
Enterprise Mobility Management (EMM) provider. The EMM software communicates
- with a Work Policy Controller on each device. The Work Policy Controller, in
+ with a device policy controller on each device. The device policy controller, in
turn, manages the settings and behavior of the work user profile on each
individual’s device.
</p>
<p class="note">
- <strong>Note:</strong> A Work Policy Controller is built on the existing
+ <strong>Note:</strong> A device policy controller is built on the existing
model used for device administration applications, as described in <a href=
"{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>.
In particular, your app needs to create a subclass of {@link
@@ -177,7 +179,7 @@
<li>Removes non-required applications from the managed profile.
</li>
- <li>Copies the Work Policy Controller application into the managed profile and
+ <li>Copies the device policy controller app into the managed profile and
sets it as the profile owner.
</li>
</ul>
@@ -209,9 +211,8 @@
<h3 id="after_creating_profile">After Creating the Managed Profile</h3>
-<p>When the profile has been provisioned, the system calls the Work Policy
-Controller app's {@link
-android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+<p>When the profile has been provisioned, the system calls the device policy
+controller app's {@link android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
DeviceAdminReceiver.onProfileProvisioningComplete()} method. Override this
callback method to finish enabling the managed profile.</p>
@@ -257,7 +258,7 @@
<h2 id="set_up_policies">Set Up Device Policies</h2>
<p>
- The Work Policy Controller app is responsible for applying the enterprise's
+ The device policy controller app is responsible for applying the enterprise's
device policies. For example, a particular enterprise might require that all
devices become locked after a certain number of failed attempts to enter the
device password. The controller app queries the EMM to find out what
@@ -273,13 +274,12 @@
<h2 id="apply_restrictions">Apply App Restrictions</h2>
-<p>Enterprise environments may require that approved apps implement apps
-implement security or feature restrictions. App developers must implement these
-restrictions and declare them for use by enterprise administrators, as described
-in <a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
-App Restrictions</a>. The Work Policy Controller receives restriction changes
-from the enterprise administrator, and forwards those restriction changes to the
-apps.</p>
+<p>Enterprise environments may require that approved apps implement security
+or feature restrictions. App developers must implement these restrictions
+and declare them for use by enterprise administrators, as described in
+<a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
+App Restrictions</a>. The device policy controller receives restriction changes
+from the enterprise administrator, and forwards those restriction changes to the apps.</p>
<p>For example, a particular news app might have a restriction setting that
controls whether the app is allowed to download videos over a cellular
@@ -287,9 +287,9 @@
notification to the controller app. The controller app, in turn,
notifies the news app that the restriction setting has changed.</p>
-<p class="note"><strong>Note:</strong> This document covers how the Work Policy
-Controller app changes the restriction settings for the other apps on the
-managed profile. Details on how the Work Policy Controller app communicates with
+<p class="note"><strong>Note:</strong> This document covers how the device policy
+controller app changes the restriction settings for the other apps on the
+managed profile. Details on how the device policy controller app communicates with
the EMM are out of scope for this document.</p>
<p>To change an app's restrictions, call the {@link
@@ -308,7 +308,7 @@
a cellular network; it must use a Wi-Fi network instead.</p>
<p>
- If your Work Policy Controller app needs to turn off cellular downloads, it
+ If your device policy controller app needs to turn off cellular downloads, it
would first fetch the device policy service object, as described above. It
then assembles a restrictions bundle and passes this bundle to {@link
android.app.admin.DevicePolicyManager#setApplicationRestrictions
diff --git a/docs/html/training/game-controllers/compatibility.jd b/docs/html/training/game-controllers/compatibility.jd
old mode 100644
new mode 100755
index f68ab1a..51ae9ee
--- a/docs/html/training/game-controllers/compatibility.jd
+++ b/docs/html/training/game-controllers/compatibility.jd
@@ -13,7 +13,7 @@
Suppport</a></li>
<li><a href="#abstraction">Add an Interface for Backward Compatibility</a></li>
<li><a href="#newer">Implement the Interface on Android 4.1 and Higher</a></li>
- <li><a href="#older">Implement the Interface on Android 2.3 up to Android
+ <li><a href="#older">Implement the Interface on Android 3.1 up to Android
4.0</a></li>
<li><a href="#using">Use the Version-Specific Implementations</a></li>
</ol>
@@ -36,7 +36,7 @@
<p>This lesson demonstrates how to use APIs available in Android 4.1 and higher
in a backward compatible way, enabling your game to support the following
-features on devices running Android 2.3 and higher:</p>
+features on devices running Android 3.1 and higher:</p>
<ul>
<li>The game can detect if a new game controller is added, changed, or removed.</li>
<li>The game can query the capabilities of a game controller.</li>
@@ -48,20 +48,20 @@
above. This sample shows how to implement the {@code InputManagerCompat}
interface to support different versions of Android. To compile the sample, you
must use Android 4.1 (API level 16) or higher. Once compiled, the sample app
-runs on any device running Android 2.3 (API level 9) or higher as the build
+runs on any device running Android 3.1 (API level 12) or higher as the build
target.
</p>
<h2 id="prepare">Prepare to Abstract APIs for Game Controller Support</h2>
<p>Suppose you want to be able to determine if a game controller's connection
-status has changed on devices running on Android 2.3 (API level 9). However,
+status has changed on devices running on Android 3.1 (API level 12). However,
the APIs are only available in Android 4.1 (API level 16) and higher, so you
need to provide an implementation that supports Android 4.1 and higher while
-providing a fallback mechanism that supports Android 2.3 up to Android 4.0.</p>
+providing a fallback mechanism that supports Android 3.1 up to Android 4.0.</p>
<p>To help you determine which features require such a fallback mechanism for
older versions, table 1 lists the differences in game controller support
- between Android 2.3 (API level 9), 3.1 (API level 12), and 4.1 (API level
+ between Android 3.1 (API level 12) and 4.1 (API level
16).</p>
<p class="table-caption" id="game-controller-support-table">
@@ -74,7 +74,6 @@
<tr>
<th>Controller Information</th>
<th>Controller API</th>
-<th>API level 9</th>
<th>API level 12</th>
<th>API level 16</th>
</tr>
@@ -83,34 +82,29 @@
<td rowspan="5">Device Identification</td>
<td>{@link android.hardware.input.InputManager#getInputDeviceIds()}</td>
<td style="text-align: center;"><big> </big></td>
-<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager#getInputDevice(int)
getInputDevice()}</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.view.InputDevice#getVibrator()}</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big> </big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<td>{@link android.view.InputDevice#SOURCE_JOYSTICK}</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.view.InputDevice#SOURCE_GAMEPAD}</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
@@ -119,21 +113,18 @@
<td rowspan="3">Connection Status</td>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceAdded(int) onInputDeviceAdded()}</td>
<td style="text-align: center;"> </td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceChanged(int) onInputDeviceChanged()}</td>
<td style="text-align: center;"> </td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
<td>{@link android.hardware.input.InputManager.InputDeviceListener#onInputDeviceRemoved(int) onInputDeviceRemoved()}</td>
<td style="text-align: center;"> </td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
</tr>
@@ -147,7 +138,6 @@
{@link android.view.KeyEvent#KEYCODE_DPAD_CENTER})</td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
-<td style="text-align: center;"><big>•</big></td>
</tr>
<tr>
@@ -162,7 +152,6 @@
{@link android.view.KeyEvent#KEYCODE_BUTTON_L1 BUTTON_L1},
{@link android.view.KeyEvent#KEYCODE_BUTTON_R2 BUTTON_R2},
{@link android.view.KeyEvent#KEYCODE_BUTTON_L2 BUTTON_L2})</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
@@ -175,7 +164,6 @@
{@link android.view.MotionEvent#AXIS_RZ},
{@link android.view.MotionEvent#AXIS_HAT_X},
{@link android.view.MotionEvent#AXIS_HAT_Y})</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
@@ -184,7 +172,6 @@
<td>Analog trigger press (
{@link android.view.MotionEvent#AXIS_LTRIGGER},
{@link android.view.MotionEvent#AXIS_RTRIGGER})</td>
-<td style="text-align: center;"> </td>
<td style="text-align: center;"><big>•</big></td>
<td style="text-align: center;"><big>•</big></td>
</tr>
@@ -200,7 +187,7 @@
<li>Create a proxy implementation of your interface that uses APIs in Android
4.1 and higher.</li>
<li>Create a custom implementation of your interface that uses APIs available
-between Android 2.3 up to Android 4.0.</li>
+between Android 3.1 up to Android 4.0.</li>
<li>Create the logic for switching between these implementations at runtime,
and begin using the interface in your game.</li>
</ol>
@@ -284,8 +271,9 @@
across different platform versions. If your game is running on Android 4.1 or
higher and calls an {@code InputManagerCompat} method, the proxy implementation
calls the equivalent method in {@link android.hardware.input.InputManager}.
-However, if your game is running on Android 2.3 up to Android 4.0, the custom implementation processes calls to {@code InputManagerCompat} methods by using
-only APIs introduced no later than Android 2.3. Regardless of which
+However, if your game is running on Android 3.1 up to Android 4.0, the custom implementation
+processes calls to {@code InputManagerCompat} methods by using
+only APIs introduced no later than Android 3.1. Regardless of which
version-specific implementation is used at runtime, the implementation passes
the call results back transparently to the game.</p>
@@ -377,11 +365,10 @@
}
</pre>
-<h2 id="older">Implementing the Interface on Android 2.3 up to Android 4.0</h2>
+<h2 id="older">Implementing the Interface on Android 3.1 up to Android 4.0</h2>
-<p>The {@code InputManagerV9} implementation uses APIs introduced no later
-than Android 2.3. To create an implementation of {@code
-InputManagerCompat} that supports Android 2.3 up to Android 4.0, you can use
+<p>To create an implementation of {@code
+InputManagerCompat} that supports Android 3.1 up to Android 4.0, you can use
the following objects:
<ul>
<li>A {@link android.util.SparseArray} of device IDs to track the
@@ -586,7 +573,7 @@
<p>You now have two implementations of {@code InputManagerCompat}: one that
works on devices running Android 4.1 and higher, and another
-that works on devices running Android 2.3 up to Android 4.0.</p>
+that works on devices running Android 3.1 up to Android 4.0.</p>
<h2 id="using">Use the Version-Specific Implementation</h2>
<p>The version-specific switching logic is implemented in a class that acts as
@@ -626,7 +613,7 @@
onGenericMotionEvent()} method in your main view, as described in
<a href="controller-input.html#analog">Handle a MotionEvent from a Game
Controller</a>. Your game should now be able to process game controller events
-consistently on devices running Android 2.3 (API level 9) and higher.
+consistently on devices running Android 3.1 (API level 12) and higher.
<p>
<pre>
@Override
@@ -640,4 +627,4 @@
</pre>
<p>You can find a complete implementation of this compatibility code in the
{@code GameView} class provided in the sample {@code ControllerSample.zip}
-available for download above.</p>
\ No newline at end of file
+available for download above.</p>
diff --git a/docs/html/training/improving-layouts/reusing-layouts.jd b/docs/html/training/improving-layouts/reusing-layouts.jd
index 7b0185d..b277c8b 100644
--- a/docs/html/training/improving-layouts/reusing-layouts.jd
+++ b/docs/html/training/improving-layouts/reusing-layouts.jd
@@ -43,7 +43,7 @@
<p>Reusing layouts is particularly powerful as it allows you create reusable complex layouts. For
example, a yes/no button panel, or custom progress bar with description text.
It also means that any elements of your application that are common across multiple layouts can be
-extracted, managed separately, then included in each layout. So while
+extracted, managed separately, then included in each layout. So while
you can create individual UI components by writing a custom {@link android.view.View}, you can
do it even more easily by re-using a layout file.</p>
@@ -56,14 +56,14 @@
<pre>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width=”match_parent”
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/titlebar_bg">
<ImageView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/gafricalogo" />
-</FrameLayout>
+ android:layout_height="wrap_content"
+ android:src="@drawable/gafricalogo" />
+</FrameLayout>
</pre>
<p>The root {@link android.view.View} should be exactly how you'd like it to appear in each
@@ -80,18 +80,18 @@
<pre>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width=”match_parent”
- android:layout_height=”match_parent”
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:background="@color/app_bg"
- android:gravity="center_horizontal">
+ android:gravity="center_horizontal">
- <strong><include layout="@layout/titlebar"/></strong>
+ <strong><include layout="@layout/titlebar"/></strong>
- <TextView android:layout_width=”match_parent”
+ <TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
- android:padding="10dp" />
+ android:padding="10dp" />
...
@@ -103,10 +103,10 @@
example:</p>
<pre>
-<include android:id=”@+id/news_title”
- android:layout_width=”match_parent”
- android:layout_height=”match_parent”
- layout=”@layout/title”/>
+<include android:id="@+id/news_title"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ layout="@layout/title"/>
</pre>
<p>However, if you want to override layout attributes using
@@ -130,17 +130,17 @@
{@code <merge>} element as the root view for the re-usable layout. For example:</p>
<pre>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
- android:layout_width="fill_parent"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@string/add"/>
+ android:text="@string/add"/>
<Button
- android:layout_width="fill_parent"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@string/delete"/>
+ android:text="@string/delete"/>
</merge>
</pre>
diff --git a/docs/html/training/in-app-billing/preparing-iab-app.jd b/docs/html/training/in-app-billing/preparing-iab-app.jd
old mode 100644
new mode 100755
index 42bc947..2c6e9a0
--- a/docs/html/training/in-app-billing/preparing-iab-app.jd
+++ b/docs/html/training/in-app-billing/preparing-iab-app.jd
@@ -30,18 +30,35 @@
</div>
</div>
+<a class="notice-developers-video wide"
+href="https://www.youtube.com/watch?v=UvCl5Xx7Z5o">
+<div>
+ <h3>Video</h3>
+ <p>Implementing Freemium</p>
+ </div>
+ </a>
+
<p>Before you can start using the In-app Billing service, you'll need to add the library that contains the In-app Billing Version 3 API to your Android project. You also need to set the permissions for your application to communicate with Google Play. In addition, you'll need to establish a connection between your application and Google Play. You should also verify that the In-app Billing API version that you are using in your application is supported by Google Play.</p>
<h2 id="GetSample">Download the Sample Application</h2>
<p>In this training class, you will use a reference implementation for the In-app Billing Version 3 API called the {@code TrivialDrive} sample application. The sample includes convenience classes to quickly set up the In-app Billing service, marshal and unmarshal data types, and handle In-app Billing requests from the main thread of your application.</p>
<p>To download the sample application:</p>
<ol>
-<li>Open the <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.</li>
-<li>In the SDK Manager, expand the {@code Extras} section.</li>
-<li>Select <strong>Google Play Billing Library</strong>.</li>
-<li>Click <strong>Install packages</strong> to complete the download.</li>
+<li>Open Android Studio and then close any open projects until you are
+presented with the welcome screen.</li>
+<li>Choose <strong>Import an Android code sample</strong> from the
+ <strong>Quick Start</strong> list on the right side the window.</li>
+<li>Type {@code Trivial Drive} into the search bar and select the
+ <strong>Trivial Drive</strong> sample.</li>
+<li>Follow the rest of the instructions in the <strong>Import Sample</strong>
+ wizard to import the sample to a directory of your choosing. The sample code
+ is in the <strong>TrivialDrive</strong> subdirectory of the repository.</li>
</ol>
-<p>The sample files will be installed to {@code <sdk>/extras/google/play_billing/}.</p>
+
+<p>Alternatively, you can use {@code git} to manually clone
+ the repository from <a
+ href="https://github.com/googlesamples/android-play-billing"
+ class="external-link">https://github.com/googlesamples/android-play-billing</a></p>
<h2 id="AddToDevConsole">Add Your Application to the Developer Console</h2>
<p>The Google Play Developer Console is where you publish your In-app Billing application and manage the various digital goods that are available for purchase from your application. When you create a new application entry in the Developer Console, it automatically generates a public license key for your application. You will need this key to establish a trusted connection from your application to the Google Play servers. You only need to generate this key once per application, and don’t need to repeat these steps when you update the APK file for your application.</p>
@@ -67,9 +84,9 @@
<p>To add the In-app Billing Version 3 library to your new In-app Billing project:</p>
<ol>
<li>Copy the {@code TrivialDrive} sample files into your Android project.</li>
-<li>Modify the package name in the files you copied to use the package name for your project. In Eclipse, you can use this shortcut: right-click the package name, then select <strong>Refactor</strong> > <strong>Rename</strong>.</li>
+<li>Modify the package name in the files you copied to use the package name for your project. In Android Studio, you can use this shortcut: right-click the package name, then select <strong>Refactor</strong> > <strong>Rename</strong>.</li>
<li>Open the {@code AndroidManifest.xml} file and update the package attribute value to use the package name for your project.</li>
-<li>Fix import statements as needed so that your project compiles correctly. In Eclipse, you can use this shortcut: press <strong>Ctrl+Shift+O</strong> in each file showing errors.</li>
+<li>Fix import statements as needed so that your project compiles correctly. In Android Studio, you can use this shortcut: press <strong>Ctrl+Shift+O</strong> in each file showing errors.</li>
<li>Modify the sample to create your own application. Remember to copy the Base64 public license key for your application from the Developer Console over to your {@code MainActivity.java}.</li>
</ol>
@@ -81,7 +98,6 @@
<li>In Android Studio: Create a directory named {@code aidl} under {@code src/main}, add a new
package {@code com.android.vending.billing} in this directory, and import the
{@code IInAppBillingService.aidl} file into this package.</li>
- <li>In Eclipse: Import the {@code IInAppBillingService.aidl} file into your {@code /src} directory.</li>
<li>In other dev environments: Create the following directory {@code /src/com/android/vending/billing} and copy the {@code IInAppBillingService.aidl} file into this directory.</li>
</ul>
</li>
diff --git a/docs/html/training/index.jd b/docs/html/training/index.jd
index 1b0b1fe..18971ab 100644
--- a/docs/html/training/index.jd
+++ b/docs/html/training/index.jd
@@ -4,39 +4,46 @@
@jd:body
-<p>Welcome to Training for Android developers. Here you'll find sets of lessons within classes
-that describe how to accomplish a specific task with code samples you can re-use in your app.
-Classes are organized into several groups you can see at the top-level of the left navigation.</p>
-
- <p>This first group, <em>Getting Started</em>, teaches you the bare
- essentials for Android app development. If you're a new Android app developer, you should
- complete each of these classes in order.</p>
-
<div class="wrap">
<div class="cols">
<div class="col-1of2">
- <p>If you prefer to learn through interactive video training,
- check out this trailer for a course about the fundamentals of Android development.</p>
- <p><a href="https://www.udacity.com/course/ud853" class="button">
- Start the video course</a>
- </p>
+<p>Welcome to Training for Android developers. Here you'll find
+training classes that describe how to accomplish a specific task with code
+samples you can re-use in your app. Classes are organized into several groups
+you can see at the top-level of the left navigation.</p>
+
+<p>The first <a href="#class-list">training guides below</a>
+teach you the essentials for Android app development. If you're a new
+Android app developer, you should complete each of these classes in order.</p>
+
+<p>Various online video courses are also available if you'd prefer
+an interactive video experience.</p>
+
</div>
- <div class="col-1of2">
- <iframe width="300" height="169" src="//www.youtube.com/embed/LfVBFFoy9Y0?utm_source=dac&utm_medium=video&utm_content=andfuntrain&utm_campaign=udacint?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
+ <div class="col-1of2" style="background:#eee;padding-top:10px">
+ <p>Check out this trailer for a course about the fundamentals of
+ Android development on Udacity.</p>
+ </p>
+ <iframe width="338" height="169" src="//www.youtube.com/embed/LfVBFFoy9Y0?utm_source=dac&utm_medium=video&utm_content=andfuntrain&utm_campaign=udacint?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
+ <p><a href="https://www.udacity.com/course/ud853" class="button"
+ style="width:100%">Start the video course</a>
</div>
</div>
</div>
-<div style="clear:left"></div>
-</div>
+<div style="clear:left" id="classes"></div>
- <div><h2 class="norule">Online video courses</h2>
- <p>If you prefer to learn through interactive video training,
- check out these free courses.</p>
+<section class="dac-section dac-small" id="latest-games"><div class="wrap">
+ <h2 class="norule" style="margin:20px 0">Online video courses</h2>
<div class="resource-widget resource-flow-layout col-16"
data-query="collection:develop/landing/courses"
data-sortOrder="random"
data-cardSizes="6x6"
- data-maxResults="12"
- data-initial-results="3"></div>
-</div>
\ No newline at end of file
+ data-maxResults="24"
+ data-items-per-page="24"
+ data-initial-results="6"></div>
+ </div>
+</section>
+
+<h2 class="norule" id="class-list"
+ style="margin:0 0 -40px">Training guides</h2>
\ No newline at end of file
diff --git a/docs/html/training/location/change-location-settings.jd b/docs/html/training/location/change-location-settings.jd
new file mode 100644
index 0000000..70733eb
--- /dev/null
+++ b/docs/html/training/location/change-location-settings.jd
@@ -0,0 +1,251 @@
+page.title=Changing Location Settings
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you how to</h2>
+ <ol>
+ <li><a href="#connect">Connect to Location Services</a></li>
+ <li><a href="#location-request">Set Up a Location Request</a></li>
+ <li><a href="#get-settings">Get Current Location Settings</a></li>
+ <li><a href="#prompt">Prompt the User to Change Location Settings</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li>
+ <a href="https://developers.google.com/android/guides/setup"
+ class="external-link">Setting up Google Play Services</a>
+ </li>
+ <li>
+ <a href="retrieve-current.html">Getting the Last Known Location</a>
+ </li>
+ </ul>
+ </div>
+</div>
+
+<p>If your app needs to request location or receive permission updates, the
+ device needs to enable the appropriate system settings, such as GPS or Wi-Fi
+ scanning. Rather than directly enabling services such as the device's GPS,
+ your app specifies the required level of accuracy/power consumption and
+ desired update interval, and the device automatically makes the appropriate
+ changes to system settings. These settings are defined by the
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest"
+ class="external-link">{@code LocationRequest}</a>
+ data object. </p>
+
+<p>This lesson shows you how to use the
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/SettingsApi">Settings API</a>
+ to check which settings are enabled, and present the Location Settings
+ dialog for the user to update their settings with a single tap.</p>
+
+<h2 id="connect">Connect to Location Services</h2>
+
+<p>In order to use the location services provided by Google Play Services and
+ the fused location provider, connect your app using the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient">Google API Client</a>,
+ then check the current location settings and prompt the user to enable the
+ required settings if needed. For details on connecting with the
+ Google API client, see <a href="retrieve-current.html">Getting the Last Known Location</a>.</p>
+
+<p>Apps that use location services must request location permissions. For this
+ lesson, coarse location detection is sufficient. Request this permission
+ with the <code>uses-permission</code> element in your app manifest, as shown
+ in the following example:</p>
+
+<pre><code><manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.gms.location.sample.locationupdates" >
+
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+</manifest>
+</code></pre>
+
+<p>If the device is running Android 6.0 or higher, and your app's target
+ SDK is 23 or higher, the app has to list the permissions in the manifest
+ <em>and</em> request those permissions at run time. For more information, see
+<a href="{@docRoot}training/permissions/requesting.html">Requesting Permissions at Run Time</a>.</p>
+
+<h2 id="location-request">Set Up a Location Request</h2>
+
+<p>To store parameters for requests to the fused location provider, create a
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>.
+ The parameters determine the level of accuracy for location requests. For
+ details of all available location request options, see the
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>
+ class reference. This lesson sets the update interval, fastest update
+ interval, and priority, as described below:</p>
+
+<dl>
+ <dt>
+ Update interval
+ </dt>
+ <dd>
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>
+ - This method sets the rate in milliseconds at which your app prefers to
+ receive location updates. Note that the location updates may be faster than
+ this rate if another app is receiving updates at a faster rate, or slower
+ than this rate, or there may be no updates at all (if the device has no
+ connectivity, for example).
+ </dd>
+ <dt>
+ Fastest update interval
+ </dt>
+ <dd>
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
+ - This method sets the <strong>fastest</strong> rate in milliseconds at which
+ your app can handle location updates. You need to set this rate because
+ other apps also affect the rate at which updates are sent. The Google Play
+ services location APIs send out updates at the fastest rate that any app
+ has requested with
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>.
+ If this rate is faster
+ than your app can handle, you may encounter problems with UI flicker or data
+ overflow. To prevent this, call
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
+ to set an upper limit to the update rate.
+ </dd>
+ <dt>Priority</dt>
+ <dd>
+ <p>
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)">{@code setPriority()}</a>
+ - This method sets the priority of the request, which gives the Google Play
+ services location services a strong hint about which location sources to use.
+ The following values are supported:</p>
+ <ul>
+ <li>
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_BALANCED_POWER_ACCURACY">{@code PRIORITY_BALANCED_POWER_ACCURACY}</a>
+ - Use this setting to request location precision to within a city
+ block, which is an accuracy of approximately 100 meters. This is
+ considered a coarse level of accuracy, and is likely to consume less
+ power. With this setting, the location services are likely to use WiFi
+ and cell tower positioning. Note, however, that the choice of location
+ provider depends on many other factors, such as which sources are
+ available.</li>
+ <li>
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>
+ - Use this setting to request the most precise location possible. With
+ this setting, the location services are more likely to use GPS
+ to determine the location.</li>
+ <li><a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_LOW_POWER">{@code PRIORITY_LOW_POWER}</a>
+ - Use this setting to request city-level precision, which is
+ an accuracy of approximately 10 kilometers. This is considered a
+ coarse level of accuracy, and is likely to consume less power.</li>
+ <li><a href="https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_NO_POWER">{@code PRIORITY_NO_POWER}</a>
+ - Use this setting if you need negligible impact on power consumption,
+ but want to receive location updates when available. With this
+ setting, your app does not trigger any location updates, but
+ receives locations triggered by other apps.</li>
+ </ul>
+ </dd>
+</dl>
+
+<p>Create the location request and set the parameters as shown in this
+ code sample:</p>
+
+<pre>
+protected void createLocationRequest() {
+ LocationRequest mLocationRequest = new LocationRequest();
+ mLocationRequest.setInterval(10000);
+ mLocationRequest.setFastestInterval(5000);
+ mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
+}
+</pre>
+
+<p>The priority of
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>,
+ combined with the
+ {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
+ permission setting that you've defined in the app manifest, and a fast update
+ interval of 5000 milliseconds (5 seconds), causes the fused location
+ provider to return location updates that are accurate to within a few feet.
+ This approach is appropriate for mapping apps that display the location in
+ real time.</p>
+
+<p class="note"><strong>Performance hint:</strong> If your app accesses the
+ network or does other long-running work after receiving a location update,
+ adjust the fastest interval to a slower value. This adjustment prevents your
+ app from receiving updates it can't use. Once the long-running work is done,
+ set the fastest interval back to a fast value.</p>
+
+<h2 id="get-settings">Get Current Location Settings</h2>
+
+<p>Once you have connected to Google Play services and the location services
+ API, you can get the current location settings of a user's device. To do
+ this, create a
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationSettingsRequest.Builder"><code>LocationSettingsRequest.Builder</code></a>,
+ and add one or more location requests. The following code snippet shows how
+ to add the location request that was created in the previous step:</p>
+
+<pre>LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
+ .addLocationRequest(mLocationRequest);
+</pre>
+
+<p>Next check whether the current location settings are satisfied:</p>
+
+<pre>PendingResult<LocationSettingsResult> result =
+ LocationServices.SettingsApi.checkLocationSettings(mGoogleClient,
+ builder.build());</pre>
+
+<p>When the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult"><code>PendingResult</code></a>
+ returns, your app can check the location settings by looking at the status
+ code from the <a href="{@docRoot}reference/com/google/android/gms/location/LocationSettingsResult"><code>LocationSettingsResult</code></a>
+ object. To get even more details about the the current state of the relevant
+ location settings, your app can call the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationSettingsResult">{@code LocationSettingsResult}</a>
+ object's
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationSettingsResult#getLocationSettingsStates"><code>getLocationSettingsStates()</code></a>
+ method.</p>
+
+<h2 id="prompt">Prompt the User to Change Location Settings</h2>
+
+<p>To determine whether the location settings are appropriate for the location
+ request, check the status code from the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationSettingsResult">{@code LocationSettingsResult}</a>
+ object. A status code of <code>RESOLUTION_REQUIRED</code> indicates that the
+ settings must be changed. To prompt the user for permission to modify the
+ location settings, call
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/Status#startResolutionForResult(android.app.Activity, int)">
+ {@code startResolutionForResult(Activity, int)}</a>.
+ This method brings up a dialog asking for the user's permission to modify
+ location settings. The following code snippet shows how to check the location
+ settings, and how to call {@code startResolutionForResult(Activity, int)}.
+</p>
+
+<pre>result.setResultCallback(new ResultCallback<LocationSettingsResult>()) {
+ @Override
+ public void onResult(LocationSettingsResult result) {
+ final Status status = result.getStatus();
+ final LocationSettingsStates = result.getLocationSettingsStates();
+ switch (status.getStatusCode()) {
+ case LocationSettingsStatusCodes.SUCCESS:
+ // All location settings are satisfied. The client can
+ // initialize location requests here.
+ ...
+ break;
+ case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
+ // Location settings are not satisfied, but this can be fixed
+ // by showing the user a dialog.
+ try {
+ // Show the dialog by calling startResolutionForResult(),
+ // and check the result in onActivityResult().
+ status.startResolutionForResult(
+ OuterClass.this,
+ REQUEST_CHECK_SETTINGS);
+ } catch (SendIntentException e) {
+ // Ignore the error.
+ }
+ break;
+ case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
+ // Location settings are not satisfied. However, we have no way
+ // to fix the settings so we won't show the dialog.
+ ...
+ break;
+ }
+ }
+ });</pre>
+
+ <p>The next lesson,
+ <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
+ you how to receive periodic location updates.</p>
diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
index 556329c..1cf89fd 100644
--- a/docs/html/training/location/geofencing.jd
+++ b/docs/html/training/location/geofencing.jd
@@ -13,7 +13,8 @@
<li><a href="#CreateAdd">Create and Add Geofences</a></li>
<li><a href="#HandleGeofenceTransitions">Handle Geofence Transitions</a></li>
<li><a href="#StopGeofenceMonitoring">Stop Geofence Monitoring</a></li>
-
+ <li><a href="#BestPractices">Use Best Practices for Geofencing</a></li>
+ <li><a href="#Troubleshooting">Troubleshoot the Geofence Entrance Event</a></li>
</ol>
<h2>You should also read</h2>
@@ -56,6 +57,16 @@
This lesson shows you how to add and remove geofences, and then listen for geofence transitions
using an {@link android.app.IntentService}.</p>
+<p>We recommend upgrading existing apps to use the
+<a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">
+LocationServices</a> class, which contains the
+<a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html">
+GeofencingApi</a> interface. The
+<a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">
+LocationServices</a> class replaces the
+<a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">
+LocationClient</a> (deprecated).</p>
+
<h2 id="RequestGeofences">Set up for Geofence Monitoring</h2>
<p>
The first step in requesting geofence monitoring is to request the necessary permission.
@@ -97,6 +108,8 @@
{@link android.app.PendingIntent} as shown in this section.
</p>
+<p class="note"><strong>Note:</strong> On single-user devices, there is a limit of 100 geofences per app. For multi-user devices, the limit is 100 geofences per app per device user.</p>
+
<h3>Create geofence objects</h3>
<p>
@@ -145,25 +158,30 @@
</pre>
<p>
- This example shows the use of two geofence triggers. The <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+ This example shows the use of two geofence triggers. The <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
GEOFENCE_TRANSITION_ENTER</a></code>
- transition triggers when a device enters a geofence, and the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">
+ transition triggers when a device enters a geofence, and the <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">
GEOFENCE_TRANSITION_EXIT</a></code>
transition triggers when a device exits a geofence. Specifying
- <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER">
+ <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER">
INITIAL_TRIGGER_ENTER</a></code> tells Location services that
- <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+ <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
GEOFENCE_TRANSITION_ENTER</a></code>
should be triggered if the the device is already inside the geofence.</p>
</p>
-<p>In many cases, it may be preferable to use instead <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL">
+<p>In many cases, it may be preferable to use instead <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL">
INITIAL_TRIGGER_DWELL</a></code>,
which triggers events only when the user stops for a defined duration within a geofence.
This approach can help reduce "alert spam" resulting from large numbers notifications when a
device briefly enters and exits geofences. Another strategy for getting best results from your
geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy
- of typical WiFi networks, and also helps reduce device power consumption.
+ of typical Wi-Fi networks, and also helps reduce device power consumption.
</p>
<h3>Define an Intent for geofence transitions</h3>
@@ -195,11 +213,15 @@
<h3>Add geofences</h3>
<p>
- To add geofences, use the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method.
- Provide the Google API client, the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest">
+ To add geofences, use the <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method.
+ Provide the Google API client, the <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest">
GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}.
- The following snippet, which processes the results in <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)">
- onResult()</a></code>, assumes that the main activity implements <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html">
+ The following snippet, which processes the results in <code>
+<a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)">
+ onResult()</a></code>, assumes that the main activity implements <code>
+<a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html">
ResultCallback</a></code>:
</p>
<pre>
@@ -304,3 +326,112 @@
You can combine geofencing with other location-aware features, such as periodic location updates.
For more information, see the other lessons in this class.
</p>
+
+<h2 id="BestPractices">Use Best Practices for Geofencing</h2>
+
+<p>This section outlines recommendations for using geofencing with the location
+APIs for Android.</p>
+
+<h3>Reduce power consumption</h3>
+
+<p>You can use the following techniques to optimize power consumption in your apps that use geofencing:</p>
+
+<ul>
+<li><p>Set the <a href="{@docRoot}android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
+notification responsiveness</a> to a higher value. Doing so improves power consumption by
+increasing the latency of geofence alerts. For example, if you set a responsiveness value of five
+minutes your app only checks for an entrance or exit alert once every five minutes.
+Setting lower values does not necessarily mean that users will be notified within that time period
+(for example, if you set a value of 5 seconds it may take a bit longer than that to receive the
+alert).</p></li>
+<li><p>Use a larger geofence radius for locations where a user spends a significant amount of time,
+such as home or work. While a larger radius doesn't directly reduce power consumption, it reduces
+the frequency at which the app checks for entrance or exit, effectively lowering overall power
+consumption.</p></li>
+</ul>
+
+<h3>Choose the optimal radius for your geofence</h3>
+<p>For best results, the minimium radius of the geofence should be set between 100 - 150 meters.
+When Wi-Fi is available location accuracy is usually between 20 - 50 meters. When indoor
+location is available, the accuracy range can be as small as 5 meters. Unless you know indoor
+location is available inside the geofence, assume that Wi-Fi location accuracy is about
+50 meters.</p>
+
+<p>When Wi-Fi location is not available (for example, when you are driving in rural areas) the
+location accuracy degrades. The accuracy range can be as large as several hundred meters to
+several kilometers. In cases like this, you should create geofences using a larger radius.</p>
+
+<h3>Use the dwell transition type to reduce alert spam</h3>
+
+<p>If you receive a large number of alerts when driving briefly past a geofence, the best way to
+reduce the alerts is to use a transition type of <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_DWELL">
+GEOFENCE_TRANSITION_DWELL</a></code> instead of <code>
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+GEOFENCE_TRANSITION_ENTER</a></code>. This way, the dwelling alert is sent only when the user stops
+inside a geofence for a given period of time. You can choose the duration by setting a
+<a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html#setLoiteringDelay(int)">
+loitering delay</a>.</p>
+
+<h3>Re-register geofences only when required</h3>
+
+<p>Registered geofences are kept in the <code>com.google.process.location</code> process owned by
+the <code>com.google.android.gms</code> package.
+The app doesn’t need to do anything to handle the following events, because the system
+restores geofences after these events:</p>
+<ul>
+<li>Google Play services is upgraded.</li>
+<li>Google Play services is killed and restarted by the system due resource restriction.</li>
+<li>The location process crashes.</li>
+</ul>
+<p>The app must re-register geofences if they're still needed after the following events, since
+the system cannot recover the geofences in the following cases:</p>
+
+<ul>
+<li>The device is rebooted. The app should listen for the device's boot complete action, and then re-
+register the geofences required.</li>
+<li>The app is uninstalled and re-installed.</li>
+<li>The app's data is cleared.</li>
+<li>Google Play services data is cleared.</li>
+<li>The app has received a <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationStatusCodes.html#GEOFENCE_NOT_AVAILABLE">GEOFENCE_NOT_AVAILABLE</a></code>
+alert. This typically happens
+after NLP (Android's Network Location Provider) is disabled.</li>
+</ul>
+
+<h2 id="Troubleshooting">Troubleshoot the Geofence Entrance Event</h2>
+
+<p>If geofences are not being triggered when the device enters a geofence
+(the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
+GEOFENCE_TRANSITION_ENTER</a></code> alert isn’t triggered), first ensure that your geofences are
+registered properly as described in this guide.</p>
+
+<p>Here are some possible reasons for alerts not working as expected:</p>
+
+<ul>
+<li><strong>Accurate location is not available inside your geofence or your geofence is too
+small.</strong> On most devices, the geofence service uses only network location for geofence
+triggering. The service uses this approach because network location consumes much less
+power, it takes less time to get discrete locations, and most importantly it’s available indoors.
+Starting with Google Play services 3.2, the geofence service calculates the overlapping ratio of
+the location circle and the geofence circle and only generates the entrance alert when the ratio
+is at least 85% for a bigger geofence or 75% for a smaller geofence. For an exit alert, the ratio
+threshold used is 15% or 25%. Any ratio between these thresholds makes the geofence service mark
+the geofence state as <code>INSIDE_LOW_CONFIDENCE</code> or <code>OUTSIDE_LOW_CONFIDENCE</code> and
+no alert is sent.</li>
+<li><strong>Wi-Fi is turned off on the device.</strong> Having Wi-Fi on can significantly improve
+the location accuracy, so if Wi-Fi is turned off, your application might never get geofence alerts
+depending on several settings including the radius of the geofence, the device model, or the
+Android version. Starting from Android 4.3 (API level 18), we added the capability of “Wi-Fi scan
+only mode” which allows users to disable Wi-Fi but still get good network location. It’s good
+practice to prompt the user and provide a shortcut for the user to enable Wi-Fi or Wi-Fi scan only
+mode if both of them are disabled. Use <a href="{@docRoot}reference/com/google/android/gms/location/SettingsApi">
+SettingsApi</a> to ensure that the device's system settings are properly configured for optimal
+location detection.</li>
+<li><strong>There is no reliable network connectivity inside your geofence.</strong> If there is
+no reliable data connection, alerts might not be generated. This is because the geofence service
+depends on the network location provider which in turn requires a data connection.</li>
+<li><strong>Alerts can be late.</strong> The geofence service does not continuously query for
+location, so expect some latency when receiving alerts. Usually the latency is less than 2
+minutes, even less when the device has been moving. If the device has been stationary for a
+significant period of time, the latency may increase (up to 6 minutes).</li>
+</ul>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 8ed2071..dd6825c 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -79,6 +79,10 @@
Learn how to retrieve the last known location of an Android device, which
is usually equivalent to the user's current location.
</dd> <dt>
+ <b><a href="change-location-settings.html">Changing Location Settings</a></b>
+ <dt> <dd>
+ Learn how to detect and apply system settings for location features.
+ </dd> <dt>
<b><a href="receive-location-updates.html">Receiving Location
Updates</a></b>
</dt> <dd>
diff --git a/docs/html/training/location/receive-location-updates.jd b/docs/html/training/location/receive-location-updates.jd
index 208dc17..d82905f 100644
--- a/docs/html/training/location/receive-location-updates.jd
+++ b/docs/html/training/location/receive-location-updates.jd
@@ -7,8 +7,7 @@
<h2>This lesson teaches you how to</h2>
<ol>
- <li><a href="#connect">Connect to Location Services</a></li>
- <li><a href="#location-request">Set Up a Location Request</a></li>
+ <li><a href="#get-last-location">Get the Last Known Location</a></li>
<li><a href="#updates">Request Location Updates</a></li>
<li><a href="#callback">Define the Location Update Callback</a></li>
<li><a href="#stop-updates">Stop Location Updates</a></li>
@@ -19,7 +18,7 @@
<ul>
<li>
<a href="{@docRoot}google/play-services/setup.html">Setting up Google Play
- Services</a>
+ Services</a>
</li>
<li>
<a href="retrieve-current.html">Getting the Last Known Location</a>
@@ -64,16 +63,7 @@
<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">{@code requestLocationUpdates()}</a>
method in the fused location provider.
-<h2 id="connect">Connect to Location Services</h2>
-
-<p>Location services for apps are provided through Google Play services and the
- fused location provider. In order to use these services, you connect your app
- using the Google API Client and then request location updates. For details on
- connecting with the
- <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>,
- follow the instructions in
- <a href="retrieve-current.html">Getting the Last Known Location</a>, including
- requesting the current location.</p>
+<h2 id="get-last-location">Get the Last Known Location</h2>
<p>The last known location of the device provides a handy base from which to
start, ensuring that the app has a known location before starting the
@@ -101,112 +91,13 @@
</manifest>
</pre>
-<h2 id="location-request">Set Up a Location Request</h2>
-
-<p>To store parameters for requests to the fused location provider, create a
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>.
- The parameters determine the levels of accuracy requested. For details of all
- the options available in the location request, see the
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a>
- class reference. This lesson sets the update interval, fastest update
- interval, and priority, as described below:</p>
-
-<dl>
- <dt>
- Update interval
- </dt>
- <dd>
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>
- - This method sets the rate in milliseconds at which your app prefers to
- receive location updates. Note that the location updates may be faster than
- this rate if another app is receiving updates at a faster rate, or slower
- than this rate, or there may be no updates at all (if the device has no
- connectivity, for example).
- </dd>
- <dt>
- Fastest update interval
- </dt>
- <dd>
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
- - This method sets the <strong>fastest</strong> rate in milliseconds at which
- your app can handle location updates. You need to set this rate because
- other apps also affect the rate at which updates are sent. The Google Play
- services location APIs send out updates at the fastest rate that any app
- has requested with
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">{@code setInterval()}</a>.
- If this rate is faster
- than your app can handle, you may encounter problems with UI flicker or data
- overflow. To prevent this, call
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">{@code setFastestInterval()}</a>
- to set an upper limit to the update rate.
- </dd>
- <dt>Priority</dt>
- <dd>
- <p>
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)">{@code setPriority()}</a>
- - This method sets the priority of the request, which gives the Google Play
- services location services a strong hint about which location sources to use.
- The following values are supported:</p>
- <ul>
- <li>
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_BALANCED_POWER_ACCURACY">{@code PRIORITY_BALANCED_POWER_ACCURACY}</a>
- - Use this setting to request location precision to within a city
- block, which is an accuracy of approximately 100 meters. This is
- considered a coarse level of accuracy, and is likely to consume less
- power. With this setting, the location services are likely to use WiFi
- and cell tower positioning. Note, however, that the choice of location
- provider depends on many other factors, such as which sources are
- available.</li>
- <li>
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>
- - Use this setting to request the most precise location possible. With
- this setting, the location services are more likely to use GPS
- (Global Positioning System) to determine the location.</li>
- <li><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_LOW_POWER">{@code PRIORITY_LOW_POWER}</a>
- - Use this setting to request city-level precision, which is
- an accuracy of approximately 10 kilometers. This is considered a
- coarse level of accuracy, and is likely to consume less power.</li>
- <li><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_NO_POWER">{@code PRIORITY_NO_POWER}</a>
- - Use this setting if you need negligible impact on power consumption,
- but want to receive location updates when available. With this
- setting, your app does not trigger any location updates, but
- receives locations triggered by other apps.</li>
- </ul>
- </dd>
-</dl>
-
-<p>Create the location request and set the parameters as shown in this
- code sample:</p>
-
-<pre>
-protected void createLocationRequest() {
- LocationRequest mLocationRequest = new LocationRequest();
- mLocationRequest.setInterval(10000);
- mLocationRequest.setFastestInterval(5000);
- mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
-}
-</pre>
-
-<p>The priority of
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">{@code PRIORITY_HIGH_ACCURACY}</a>,
- combined with the
- {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
- permission setting that you've defined in the app manifest, and a fast update
- interval of 5000 milliseconds (5 seconds), causes the fused location
- provider to return location updates that are accurate to within a few feet.
- This approach is appropriate for mapping apps that display the location in
- real time.</p>
-
-<p class="note"><strong>Performance hint:</strong> If your app accesses the
- network or does other long-running work after receiving a location update,
- adjust the fastest interval to a slower value. This adjustment prevents your
- app from receiving updates it can't use. Once the long-running work is done,
- set the fastest interval back to a fast value.</p>
-
<h2 id="updates">Request Location Updates</h2>
-<p>Now that you've set up a location request containing your app's requirements
- for the location updates, you can start the regular updates by calling
+<p>Before requesting location updates, your app must connect to location
+ services and make a location request. The lesson on
+ <a href="change-location-settings.html">Changing Location Settings</a>
+ shows you how to do this. Once a location request is in place you can start
+ the regular updates by calling
<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">{@code requestLocationUpdates()}</a>.
Do this in the
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
diff --git a/docs/html/training/location/retrieve-current.jd b/docs/html/training/location/retrieve-current.jd
index 5bac3fa..c49b666 100644
--- a/docs/html/training/location/retrieve-current.jd
+++ b/docs/html/training/location/retrieve-current.jd
@@ -71,13 +71,13 @@
block.</p>
<p>This lesson requires only coarse location. Request this permission with the
- {@code uses-permission} element in your app manifest, as shown in the
- following example:
+ {@code uses-permission} element in your app manifest, as the following code
+ snippet shows:
<pre>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms.location.sample.basiclocationsample" >
-
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
</manifest>
</pre>
@@ -92,18 +92,15 @@
</p>
<p>In your activity's {@link android.app.Activity#onCreate onCreate()} method,
- create an instance of Google API Client using
- <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code GoogleApiClient.Builder}</a>.
- Use the builder to add the
- <a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">{@code LocationServices}</a>
- API.</p>
-
-<p>The sample app defines a {@code buildGoogleApiClient()} method, called from
- the activity's {@link android.app.Activity#onCreate onCreate()} method,
- which includes the following code.</p>
+ create an instance of Google API Client, using the
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code GoogleApiClient.Builder}</a> class to add the
+ <a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">
+ {@code LocationServices}</a>
+ API, as the following code snippet shows.</p>
<pre>
-protected synchronized void buildGoogleApiClient() {
+// Create an instance of GoogleAPIClient.
+if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
@@ -112,6 +109,31 @@
}
</pre>
+<p>To connect, call
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient#connect()">
+ {@code connect()}</a>
+ from the activity's
+ <a href="{@docRoot}reference/android/app/Activity.html#onStart()">{@code onStart()}</a>
+ method. To disconnect, call
+ <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient#disconnect()">
+ {@code disconnect()}</a> from the activity's
+ <a href="{@docRoot}reference/android/app/Activity.html#onStop()">
+ {@code onStop()}</a> method. The following snippet shows an example of how
+ to use both of these methods.
+ </p>
+
+<pre>
+protected void onStart() {
+ mGoogleApiClient.connect();
+ super.onStart();
+}
+
+protected void onStop() {
+ mGoogleApiClient.disconnect();
+ super.onStop();
+}
+</pre>
+
<h2 id="last-known">Get the Last Known Location</h2>
<p>Once you have connected to Google Play services and the location services
@@ -130,7 +152,7 @@
object. Do this in the
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
callback provided by Google API Client, which is called when the client is
- ready. The following code sample illustrates the request and a simple
+ ready. The following code snippet illustrates the request and a simple
handling of the response:</p>
<pre>
@@ -158,5 +180,6 @@
when the location is not available.</p>
<p>The next lesson,
- <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
- you how to receive periodic location updates.</p>
+ <a href="change-location-settings.html">Changing Location Settings</a>, shows
+ you how to detect the current location settings, and prompt the user to
+ change settings as appropriate for your app's requirements.</p>
diff --git a/docs/html/training/managing-audio/audio-focus.jd b/docs/html/training/managing-audio/audio-focus.jd
index 6dcaa7f..8d820db 100644
--- a/docs/html/training/managing-audio/audio-focus.jd
+++ b/docs/html/training/managing-audio/audio-focus.jd
@@ -11,7 +11,7 @@
@jd:body
-<div id="tb-wrapper">
+<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
@@ -27,21 +27,21 @@
<li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
</ul>
-</div>
</div>
-
+</div>
+
<p>With multiple apps potentially playing audio it's important to think about how they should
interact. To avoid every music app playing at the same time, Android uses audio focus to moderate
audio playback—only apps that hold the audio focus should play audio.</p>
-<p>Before your app starts playing audio it should request—and receive—the audio focus.
+<p>Before your app starts playing audio it should request—and receive—the audio focus.
Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that
happens.</p>
-
-<h2 id="RequestFocus">Request the Audio Focus</h2>
-
+
+<h2 id="RequestFocus">Request the Audio Focus</h2>
+
<p>Before your app starts playing any audio, it should hold the audio focus for the stream
it will be using. This is done with a call to {@link android.media.AudioManager#requestAudioFocus
requestAudioFocus()} which returns
@@ -55,7 +55,7 @@
<p>The following snippet requests permanent audio focus on the music audio stream. You should
request the audio focus immediately before you begin playback, such as when the user presses
play or the background music for the next game level begins.</p>
-
+
<pre>
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
@@ -66,7 +66,7 @@
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
-
+
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
@@ -80,7 +80,7 @@
this allows any interupted app to continue playback.</p>
<pre>
-// Abandon audio focus when playback complete
+// Abandon audio focus when playback complete
am.abandonAudioFocus(afChangeListener);
</pre>
@@ -97,7 +97,7 @@
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
-
+
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Start playback.
}
@@ -111,7 +111,7 @@
registered when requesting focus.</p>
-<h2 id="HandleFocusLoss">Handle the Loss of Audio Focus</h2>
+<h2 id="HandleFocusLoss">Handle the Loss of Audio Focus</h2>
<p>If your app can request audio focus, it follows that it will in turn lose that focus when another
app requests it. How your app responds to a loss of audio focus depends on the manner of that
@@ -139,26 +139,27 @@
unregisters our media button event receiver and stops monitoring audio focus changes.<p>
<pre>
-OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
- public void onAudioFocusChange(int focusChange) {
- if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
- // Pause playback
- } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
- // Resume playback
- } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
- am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
- am.abandonAudioFocus(afChangeListener);
- // Stop playback
+AudioManager.OnAudioFocusChangeListener afChangeListener =
+ new AudioManager.OnAudioFocusChangeListener() {
+ public void onAudioFocusChange(int focusChange) {
+ if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT) {
+ // Pause playback
+ } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+ // Resume playback
+ } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+ am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
+ am.abandonAudioFocus(afChangeListener);
+ // Stop playback
+ }
}
- }
-};
+ };
</pre>
-
+
<p>In the case of a transient loss of audio focus where ducking is permitted, rather than pausing
playback, you can "duck" instead.</p>
-<h2 id="DUCK">Duck!</h2>
+<h2 id="DUCK">Duck!</h2>
<p>Ducking is the process of lowering your audio stream output volume to make transient audio from
another app easier to hear without totally disrupting the audio from your own application.</p>
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index 6f263db..9c78545 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -85,7 +85,7 @@
int cy = myView.getHeight() / 2;
// get the final radius for the clipping circle
-int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
+float finalRadius = (float) Math.hypot(cx, cy);
// create the animator for this view (the start radius is zero)
Animator anim =
@@ -107,7 +107,7 @@
int cy = myView.getHeight() / 2;
// get the initial radius for the clipping circle
-int initialRadius = myView.getWidth();
+float initialRadius = (float) Math.hypot(cx, cy);
// create the animation (the final radius is zero)
Animator anim =
@@ -194,16 +194,16 @@
<strong>Figure 2</strong> - A scene transition with one shared element.
</p>
-<h3>Specify custom transitions</h3>
+<h3 id="custom-trans">Specify custom transitions</h3>
-<p>First, enable window content transitions with the <code>android:windowContentTransitions</code>
+<p>First, enable window content transitions with the <code>android:windowActivityTransitions</code>
attribute when you define a style that inherits from the material theme. You can also specify
enter, exit, and shared element transitions in your style definition:</p>
<pre>
<style name="BaseAppTheme" parent="android:Theme.Material">
<!-- enable window content transitions -->
- <item name="android:windowContentTransitions">true</item>
+ <item name="android:windowActivityTransitions">true</item>
<!-- specify enter and exit transitions -->
<item name="android:windowEnterTransition">@transition/explode</item>
diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd
index c58075e..eb9d273 100644
--- a/docs/html/training/material/drawables.jd
+++ b/docs/html/training/material/drawables.jd
@@ -14,6 +14,8 @@
<ul>
<li><a href="http://www.google.com/design/spec">Material design specification</a></li>
<li><a href="{@docRoot}design/material/index.html">Material design on Android</a></li>
+ <li><a href="{@docRoot}tools/help/vector-asset-studio.html">Vector Asset Studio</a></li>
+ <li><a href="{@docRoot}tools/help/image-asset-studio.html">Image Asset Studio</a></li>
</ul>
</div>
</div>
diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd
index 6e07860..4001e6b 100644
--- a/docs/html/training/material/index.jd
+++ b/docs/html/training/material/index.jd
@@ -59,3 +59,22 @@
<dt><a href="{@docRoot}training/material/compatibility.html">Maintaining Compatibility</a></dt>
<dd>Learn how to maintain compatibility with platform versions earlier than Android 5.0.</dd>
</dl>
+
+<h2>Video Training</h2>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-1of2">
+ <p>If you prefer to learn through interactive video training, check out this online course
+ about material design for Android developers.</p>
+ <p><a href="https://www.udacity.com/course/ud862" class="button">
+ Start the video course</a>
+ </p>
+ </div>
+ <div class="col-1of2">
+ <iframe width="300" height="169"
+ src="//www.youtube.com/embed/eKJ3aMGM-WM?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen="" style="float: right; margin: 0 0 20px 20px;"></iframe>
+ </div>
+ </div>
+</div>
diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
index a202566..db75aaf 100644
--- a/docs/html/training/monitoring-device-state/battery-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
@@ -3,12 +3,14 @@
parent.link=index.html
trainingnavtop=true
-next.title=Determining and Monitoring the Docking State and Type
-next.link=docking-monitoring.html
-
+parent.link=index.html
+previous.title=Optimizing for Doze and App Standby
+previous.link=doze-standby.html
+next.title= Determining and Monitoring the Connectivity Status
+next.link=connectivity-monitoring.html
@jd:body
-
-<div id="tb-wrapper">
+
+<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
@@ -24,9 +26,9 @@
<li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
</ul>
-</div>
</div>
-
+</div>
+
<p>When you're altering the frequency of your background updates to reduce the effect of those
updates on battery life, checking the current battery level and charging state is a good place to
start.</p>
@@ -41,8 +43,8 @@
even stopping—your updates when the battery charge is nearly exhausted.</p>
-<h2 id="DetermineChargeState">Determine the Current Charging State</h2>
-
+<h2 id="DetermineChargeState">Determine the Current Charging State</h2>
+
<p>Start by determining the current charge status. The {@link android.os.BatteryManager}
broadcasts all battery and charging details in a sticky {@link android.content.Intent} that includes
the charging status.</p>
@@ -74,13 +76,13 @@
further if the battery is discharging.</p>
-<h2 id="MonitorChargeState">Monitor Changes in Charging State</h2>
+<h2 id="MonitorChargeState">Monitor Changes in Charging State</h2>
<p>The charging status can change as easily as a device can be plugged in, so it's important to
monitor the charging state for changes and alter your refresh rate accordingly.</p>
<p>The {@link android.os.BatteryManager} broadcasts an action whenever the device is connected or
-disconnected from power. It's important to to receive these events even while your app isn't
+disconnected from power. It's important to receive these events even while your app isn't
running—particularly as these events should impact how often you start your app in order to
initiate a background update—so you should register a {@link
android.content.BroadcastReceiver} in your manifest to listen for both events by defining the
@@ -99,11 +101,11 @@
<pre>public class PowerConnectionReceiver extends BroadcastReceiver {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
-
+
int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
@@ -111,7 +113,7 @@
}</pre>
-<h2 id="CurrentLevel">Determine the Current Battery Level</h2>
+<h2 id="CurrentLevel">Determine the Current Battery Level</h2>
<p>In some cases it's also useful to determine the current battery level. You may choose to reduce
the rate of your background updates if the battery charge is below a certain level.</p>
@@ -125,7 +127,7 @@
float batteryPct = level / (float)scale;</pre>
-<h2 id="MonitorLevel">Monitor Significant Changes in Battery Level</h2>
+<h2 id="MonitorLevel">Monitor Significant Changes in Battery Level</h2>
<p>You can't easily continually monitor the battery state, but you don't need to.</p>
@@ -154,3 +156,6 @@
lesson shows you how to determine the current dock state and monitor for changes in device
docking.</p>
+
+
+
diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
index fb5096d..d5e7a85 100644
--- a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
@@ -87,5 +87,5 @@
It's generally sufficient to simply check for Internet connectivity before beginning an update and,
should there be none, suspend further updates until connectivity is restored.</p>
-<p>This technique requires toggling broadcast receivers you've declard in the manifest, which is
+<p>This technique requires toggling broadcast receivers you've declared in the manifest, which is
described in the next lesson.</p>
diff --git a/docs/html/training/monitoring-device-state/docking-monitoring.jd b/docs/html/training/monitoring-device-state/docking-monitoring.jd
index 5c8bfd6..0994b63 100644
--- a/docs/html/training/monitoring-device-state/docking-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/docking-monitoring.jd
@@ -3,14 +3,14 @@
parent.link=index.html
trainingnavtop=true
-previous.title= Monitoring the Battery Level and Charging State
-previous.link=battery-monitoring.html
+next.title=Optimizing for Power-Saving
+next.link=battery-optimization.html
next.title= Determining and Monitoring the Connectivity Status
next.link=connectivity-monitoring.html
@jd:body
-<div id="tb-wrapper">
+<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
@@ -26,7 +26,7 @@
<li><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
</ul>
-</div>
+</div>
</div>
<p>Android devices can be docked into several different kinds of docks. These include car or home
@@ -42,8 +42,8 @@
query if the device is docked or not, and if so, in which kind of dock.</p>
-<h2 id="CurrentDockState">Determine the Current Docking State</h2>
-
+<h2 id="CurrentDockState">Determine the Current Docking State</h2>
+
<p>The dock-state details are included as an extra in a sticky broadcast of the {@link
android.content.Intent#ACTION_DOCK_EVENT} action. Because it's sticky, you don't need to register a
{@link android.content.BroadcastReceiver}. You can simply call {@link
@@ -59,9 +59,9 @@
boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre>
-<h2 id="DockType">Determine the Current Dock Type</h2>
+<h2 id="DockType">Determine the Current Dock Type</h2>
-<p>If a device is docked, it can be docked in any one of four different type of dock:
+<p>If a device is docked, it can be docked in any one of four different type of dock:
<ul><li>Car</li>
<li>Desk</li>
<li>Low-End (Analog) Desk</li>
@@ -72,12 +72,12 @@
being digital or analog specifically:</p>
<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR;
-boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK ||
+boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK ||
dockState == EXTRA_DOCK_STATE_LE_DESK ||
dockState == EXTRA_DOCK_STATE_HE_DESK;</pre>
-<h2 id="MonitorDockState">Monitor for Changes in the Dock State or Type</h2>
+<h2 id="MonitorDockState">Monitor for Changes in the Dock State or Type</h2>
<p>Whenever the device is docked or undocked, the {@link
android.content.Intent#ACTION_DOCK_EVENT} action is broadcast. To monitor changes in the
diff --git a/docs/html/training/monitoring-device-state/doze-standby.jd b/docs/html/training/monitoring-device-state/doze-standby.jd
new file mode 100644
index 0000000..11e81c1
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/doze-standby.jd
@@ -0,0 +1,493 @@
+page.title=Optimizing for Doze and App Standby
+page.metaDescription=Test and optimize your app for the power-saving features in Android 6.0.
+page.tags=doze, app standby, marshmallow, alarms
+meta.tags="battery", "marshmallow", "alarms"
+page.image=images/cards/card-doze_16-9_2x.png
+
+
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Monitoring the Battery Level and Charging State
+next.link=battery-monitoring.html
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#understand_doze">Understanding Doze</a>
+ <ol>
+ <li><a href="#restrictions">Doze restrictions</a></li>
+ <li><a href="#assessing_your_app">Adapting your app to Doze</a></li>
+ </ol>
+ </li>
+ <li><a href="#understand_app_standby">Understanding App Standby</a></li>
+ <li><a href="#using_gcm">Using GCM to Interact with Your App</a></li>
+ <li><a href="#support_for_other_use_cases">Support for Other Use Cases</a></li>
+ <li><a href="#testing_doze_and_app_standby">Testing with Doze and App
+Standby</a>
+ <ol>
+ <li><a href="#testing_doze">Testing your app with Doze</a></li>
+ <li><a href="#testing_your_app_with_app_standby">Testing your app with App Standby</a></li>
+ </ol>
+ </li>
+ <li><a href="#whitelisting-cases">Acceptable Use Cases for Whitelisting</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Starting from Android 6.0 (API level 23), Android introduces two
+ power-saving features that extend battery life for users by managing how apps behave when a
+ device is not connected to a power source. <em>Doze</em> reduces battery consumption by deferring
+ background CPU and network activity for apps when the device is unused for long periods
+ of time. <em>App Standby</em> defers background network activity for apps
+ with which the user has not recently interacted.
+</p>
+
+<p>
+ Doze and App Standby manage the behavior of all apps running on Android 6.0
+ or higher, regardless whether they are specifically targeting API level 23.
+ To ensure the best experience for users, test your app in Doze and App
+ Standby modes and make any necessary adjustments to your code. The sections
+ below provide details.
+</p>
+
+
+<h2 id="understand_doze">Understanding Doze</h2>
+<p>
+ If a user leaves a device unplugged and stationary for a period of time, with
+ the screen off, the device enters Doze mode. In Doze mode, the system
+ attempts to conserve battery by restricting apps' access to network and
+ CPU-intensive services. It also prevents apps from accessing the network and
+ defers their jobs, syncs, and standard alarms.
+</p>
+
+<p>
+ Periodically, the system exits Doze for a brief time to let apps complete
+ their deferred activities. During this <em>maintenance window</em>, the
+ system runs all pending syncs, jobs, and alarms, and lets apps access the
+ network.
+</p>
+
+<div style="margin:1em 0em;">
+ <img src="{@docRoot}images/training/doze.png">
+ <p class="img-caption" style="text-align:center;">
+ <strong>Figure 1.</strong> Doze provides a recurring maintenance window for apps to use the
+ network and handle pending activities.
+ </p>
+</div>
+
+<p>
+ At the conclusion of each maintenance window, the system again enters Doze,
+ suspending network access and deferring jobs, syncs, and alarms. Over time,
+ the system schedules maintenance windows less and less frequently, helping to
+ reduce battery consumption in cases of longer-term inactivity when the device is not
+ connected to a charger.
+</p>
+
+
+<p>
+ As soon as the user wakes the device by moving it, turning on the screen, or
+ connecting a charger, the system exits Doze and all apps return to normal
+ activity.
+</p>
+
+
+<h3 id="restrictions">Doze restrictions</h3>
+
+<p>
+ The following restrictions apply to your apps while in Doze:
+</p>
+
+<ul>
+ <li>Network access is suspended.
+ </li>
+
+ <li>The system ignores <a href="{@docRoot}reference/android/os/PowerManager.WakeLock.html">
+ wake locks</a>.
+ </li>
+
+ <li>Standard {@link android.app.AlarmManager} alarms (including {@link
+ android.app.AlarmManager#setExact(int, long, android.app.PendingIntent) setExact()} and
+ {@link android.app.AlarmManager#setWindow(int, long, long,
+ android.app.PendingIntent) setWindow()}) are deferred to the next maintenance window.
+ </li>
+
+ <li style="list-style: none; display: inline">
+ <ul>
+ <li>If you need to set alarms that fire while in Doze, use {@link
+ android.app.AlarmManager#setAndAllowWhileIdle(int,long,android.app.PendingIntent)
+ setAndAllowWhileIdle()}
+ or {@link android.app.AlarmManager#setExactAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setExactAndAllowWhileIdle()}.
+ </li>
+
+ <li>Alarms set with {@link
+ android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo,
+ android.app.PendingIntent) setAlarmClock()} continue to fire normally — the system
+ exits Doze shortly before those alarms fire.
+ </li>
+ </ul>
+ </li>
+
+ <li>The system does not perform Wi-Fi scans.
+ </li>
+
+ <li>The system does not allow
+ <a href="{@docRoot}reference/android/content/AbstractThreadedSyncAdapter.html">sync adapters</a>
+ to run.
+ </li>
+
+ <li>The system does not allow {@link android.app.job.JobScheduler} to run.
+ </li>
+</ul>
+
+
+<div id="qv-wrapper">
+<div id="qv" style="width:300px">
+<h2>Doze checklist</h2>
+<ol>
+<ul>
+ <li>If possible, use GCM for <a href=
+ "https://developers.google.com/cloud-messaging/downstream">downstream
+ messaging</a>.
+ </li>
+
+ <li>If your users must see a notification right away, make sure to use a <a href=
+ "https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message">GCM
+ high priority message</a>.
+ </li>
+
+ <li>Provide sufficient information within the initial <a href=
+ "https://developers.google.com/cloud-messaging/concept-options#payload">message
+ payload</a>, so subsequent network access is unnecessary.
+ </li>
+
+ <li>Set critical alarms with {@link
+ android.app.AlarmManager#setAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setAndAllowWhileIdle()} and {@link
+ android.app.AlarmManager#setExactAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setExactAndAllowWhileIdle()}.
+ </li>
+
+ <li>
+ <a href="#testing_doze">Test your app in Doze.</a>
+ </li>
+</ul>
+</ol>
+</div>
+</div>
+
+<h3 id="assessing_your_app">Adapting your app to Doze</h3>
+
+<p>
+ Doze can affect apps differently, depending on the capabilities they offer
+ and the services they use. Many apps function normally across Doze
+ cycles without modification. In some cases, you must optimize the way
+ that your app manages network, alarms, jobs, and syncs. Apps should be able
+ to efficiently manage activities during each maintenance window.
+</p>
+<p>
+ Doze is particularly likely to affect activities that {@link android.app.AlarmManager} alarms and
+ timers manage, because alarms in Android 5.1 (API level 22) or lower do not fire when the system
+ is in Doze.
+</p>
+
+<p>
+ To help with scheduling alarms, Android 6.0 (API level 23) introduces two new
+ {@link android.app.AlarmManager} methods: {@link
+ android.app.AlarmManager#setAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setAndAllowWhileIdle()} and {@link
+ android.app.AlarmManager#setExactAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setExactAndAllowWhileIdle()}. With these methods,
+ you can set alarms that will fire even if the device is in Doze.
+</p>
+
+<p class="note"><strong>Note:</strong> Neither
+{@link
+ android.app.AlarmManager#setAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setAndAllowWhileIdle()} nor {@link
+ android.app.AlarmManager#setExactAndAllowWhileIdle(int, long,
+ android.app.PendingIntent) setExactAndAllowWhileIdle()} can fire alarms more than once per 15
+minutes per app.</p>
+
+<p>
+ The Doze restriction on network access is also likely to affect your app,
+ especially if the app relies on real-time messages such as tickles or
+ notifications. If your app requires a persistent connection to the network to
+ receive messages, you should use <a href="#using_gcm">Google Cloud Messaging (GCM)</a>
+ if possible.
+</p>
+
+<p>
+ To confirm that your app behaves as expected with Doze, you can use adb commands to force the
+ system to enter and exit Doze and observe your app’s behavior. For details, see
+ <a href="#testing_doze_and_app_standby">Testing with Doze and App Standby</a>.
+</p>
+
+<h2 id="understand_app_standby">Understanding App Standby</h2>
+
+<p>
+ App Standby allows the system to determine that an app is idle when the user
+ is not actively using it. The system makes this determination when the user
+ does not touch the app for a certain period of time and none of the following
+ conditions applies:
+</p>
+
+<ul>
+ <li>The user explicitly launches the app.
+ </li>
+
+ <li>The app has a process currently in the foreground (either as an activity
+ or foreground service, or in use by another activity or foreground service).
+ </li>
+
+ <li>The app generates a notification that users see on the lock screen or in
+ the notification tray.
+ </li>
+</ul>
+
+<p>
+ When the user plugs the device into a power supply, the system releases apps
+ from the standby state, allowing them to freely access the network and to
+ execute any pending jobs and syncs. If the device is idle for long periods of
+ time, the system allows idle apps network access around once a day.
+</p>
+
+<h2 id="using_gcm">Using GCM to Interact with Your App While the Device is Idle</h2>
+
+<p>
+ <a href="https://developers.google.com/cloud-messaging/">Google Cloud
+ Messaging (GCM)</a> is a cloud-to-device service that lets you support
+ real-time downstream messaging between backend services and apps on
+ Android devices. GCM provides a single, persistent connection to the cloud; all apps needing
+ real-time messaging can share this connection. This shared
+ connection significantly optimizes battery consumption by making it unnecessary for
+ multiple apps to maintain their own, separate persistent connections, which can
+ deplete the battery rapidly. For this reason, if your app requires messaging integration with a
+ backend service, we strongly recommend that you <strong>use GCM if possible</strong>, rather than
+ maintaining your own persistent network connection.
+</p>
+
+<p>
+ GCM is optimized to work with Doze and App Standby idle modes by means of
+ <a href="https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message">
+ high-priority GCM messages</a>. GCM high-priority messages let you reliably wake your app to
+ access the network, even if the user’s device is in Doze or the app is in App Standby mode.
+ In Doze or App Standby mode, the system delivers the message and gives the
+ app temporary access to network services and partial wakelocks, then returns the device or app
+ to idle state.
+</p>
+
+<p>
+ High-priority GCM messages do not otherwise affect Doze mode, and they don’t
+ affect the state of any other app. This means that your app can use them to communicate
+ efficiently while minimizing battery impacts across the system and device.
+</p>
+
+<p>
+ As a general best practice, if your app requires downstream messaging, it
+ should use GCM. If your server and client already uses GCM, make sure that your service uses
+ high-priority messages for critical messages, since this will reliably
+ wake apps even when the device is in Doze.
+</p>
+
+<h2 id="support_for_other_use_cases">Support for Other Use Cases</h2>
+
+<p>
+ Almost all apps should be able to support Doze by managing network connectivity, alarms,
+ jobs, and syncs properly, and using GCM high-priority messages. For a narrow
+ set of use cases, this might not be sufficient. For such cases, the system
+ provides a configurable whitelist of apps that are <strong>partially
+ exempt</strong> from Doze and App Standby optimizations.
+</p>
+
+<p>
+ An app that is whitelisted can use the network and hold
+
+ <a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
+ partial wake locks</a> during Doze and
+ App Standby. However, <strong>other restrictions still apply</strong> to the
+ whitelisted app, just as they do to other apps. For example, the whitelisted
+ app’s jobs and syncs are deferred, and its regular {@link android.app.AlarmManager} alarms do not
+ fire. An app can check whether it is currently on the exemption whitelist by
+ calling {@link
+ android.os.PowerManager#isIgnoringBatteryOptimizations(java.lang.String)
+ isIgnoringBatteryOptimizations()}.
+ </li>
+</p>
+
+<p>
+ Users can manually configure the whitelist in <strong>Settings > Battery
+ > Battery Optimization.</strong> Alternatively, the system provides
+ ways for apps to ask users to whitelist them.
+
+</p>
+
+<ul>
+ <li>An app can fire the {@link
+ android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS} intent
+ to take the user directly to the <strong>Battery Optimization</strong>, where they can
+ add the app.
+ </li>
+
+ <li>An app holding the {@link
+ android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} permission
+ can trigger a system dialog to let the user add the app to the whitelist
+ directly, without going to settings. The app fires a {@link
+ android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} Intent
+ to trigger the dialog.
+ </li>
+
+ <li>The user can manually remove apps from the whitelist as needed.
+ </li>
+</ul>
+
+<p>Before asking the user to add your app to the whitelist, make sure the app
+
+matches the <a href="#whitelisting-cases">acceptable use cases</a> for whitelisting.</p>
+
+
+<p class="caution">
+ <strong>Note:</strong> Google Play policies prohibit apps from requesting
+ direct exemption from Power Management features in Android 6.0+ (Doze and App
+ Standby) unless the core function of the app is adversely affected.
+</p>
+
+<h2 id="testing_doze_and_app_standby">Testing with Doze and App Standby</h2>
+
+<p>
+ To ensure a great experience for your users, you should test your app fully
+ in Doze and App Standby.
+</p>
+
+<h3 id="testing_doze">Testing your app with Doze</h4>
+
+<p>You can test Doze mode by following these steps:</p>
+<ol>
+ <li>Configure a hardware device or virtual device with an Android 6.0 (API
+ level 23) or higher system image.
+ </li>
+
+ <li>Connect the device to your development machine and install your app.
+ </li>
+
+ <li>Run your app and leave it active.
+ </li>
+
+ <li>Shut off the device screen. (The app remains active.)
+ </li>
+
+ <li>Force the system to cycle through Doze modes by running the following
+ commands:
+
+ <pre class="no-pretty-print">
+$ adb shell dumpsys battery unplug
+$ adb shell dumpsys deviceidle step</pre>
+
+ <p>You may need to run the second command more than once. Repeat it until
+ the device state changes to idle.</p>
+ </li>
+
+ <li> Observe the behavior of your app after you reactivate the device. Make
+ sure the app recovers gracefully when the device exits Doze.
+ </li>
+</ol>
+
+<h3 id="testing_your_app_with_app_standby">Testing your app with App Standby</h4>
+
+<p>To test the App Standby mode with your app:</p>
+
+<ol>
+ <li> Configure a hardware device or virtual device with an Android 6.0 (API level
+ 23) or higher system image.
+ </li>
+ <li> Connect the device to your development machine and install your app.</li>
+ <li> Run your app and leave it active.</li>
+ <li> Force the app into App Standby mode by running the following commands:
+
+ <pre class="no-pretty-print">$ adb shell dumpsys battery unplug
+$ adb shell am set-inactive <packageName> true</pre>
+ <li>Simulate waking your app using the following commands:
+
+ <pre class="no-pretty-print">$ adb shell am set-inactive <packageName> false
+$ adb shell am get-inactive <packageName></pre>
+ </li>
+ <li>Observe the behavior of your app after waking it. Make sure the app recovers gracefully
+ from standby mode. In particular, you should check if your app's Notifications and background
+ jobs continue to function as expected.
+ </li>
+</ol>
+
+
+<h2 id="whitelisting-cases">Acceptable Use Cases for Whitelisting</h2>
+
+<p>The table below highlights the acceptable use cases for requesting or being on
+ the Battery Optimizations exceptions whitelist. In general, your app should not be on the
+ whitelist unless Doze or App Standby break the core function of the app or there is a
+ technical reason why your app cannot use GCM high-priority messages.</p>
+
+ <p>For more information, see <a href="#support_for_other_use_cases">Support for Other Use Cases
+ </a>.</p>
+
+<table>
+ <tr>
+ <th>Type</td>
+ <th>Use-case</td>
+ <th>Can use GCM?</td>
+ <th>Whitelisting acceptable?</td>
+ <th>Notes</td>
+ </tr>
+
+ <tr>
+ <td rowspan="2">Instant messaging, chat, or calling app. </td>
+ <td rowspan="3">Requires delivery of real-time messages to users while device is in Doze or app
+ is in App Standby.</td>
+ <td>Yes, using GCM</td>
+ <td rowspan="2" style="color:red">Not Acceptable</td>
+ <td rowspan="2">Should use GCM high-priority messages to wake the app and access the network.</td>
+ </tr>
+
+ <tr>
+ <td>Yes, but is not using GCM high-priority messages.</td>
+ </tr>
+
+ <tr>
+ <td rowspan="1">Instant messaging, chat, or calling app;
+ enterprise VOIP apps.</td>
+ <td>No, can not use GCM because of technical dependency on another messaging
+ service or Doze and App Standby break the core function of the app.</td>
+ <td style="color:green">Acceptable</td>
+ <td></td>
+ </tr>
+
+ <tr>
+ <td rowspan="1">Task automation app</td>
+ <td>App's core function is scheduling automated actions, such as for instant
+ messaging, voice calling, new photo management, or location actions.</td>
+ <td>If applicable.</td>
+ <td style="color:green">Acceptable</td>
+ <td></td>
+ </tr>
+
+ <tr>
+ <td rowspan="2">Peripheral device companion app</td>
+ <td>App's core function is maintaining a persistent connection with the peripheral
+ device for the purpose of providing the peripheral device internet access.</td>
+ <td >If applicable.</td>
+ <td style="color:green">Acceptable</td>
+ <td rowspan="2"></td>
+ </tr>
+
+ <tr>
+ <td>App only needs to connect to a peripheral device periodically to sync, or only
+ needs to connect to devices, such as wireless headphones, connected via standard
+ Bluetooth profiles.</td>
+ <td >If applicable.</td>
+ <td style="color:red">Not Acceptable</td>
+ </tr>
+</table>
+
+
diff --git a/docs/html/training/monitoring-device-state/index.jd b/docs/html/training/monitoring-device-state/index.jd
index 949c1da..1e1ce20 100644
--- a/docs/html/training/monitoring-device-state/index.jd
+++ b/docs/html/training/monitoring-device-state/index.jd
@@ -1,17 +1,19 @@
page.title=Optimizing Battery Life
-page.tags=network,internet
+page.tags=battery,network,internet
+page.metaDescription=Learn how to optimize your app to reduce battery drain and use power-hungry resources efficiently.
+
+page.article=true
trainingnavtop=true
startpage=true
@jd:body
-<div id="tb-wrapper">
+<div id="tb-wrapper">
<div id="tb">
-<h2>Dependencies and prerequisites</h2>
+<h2>Dependencies and prerequisites</h2>
<ul>
- <li>Android 2.0 (API level 5) or higher</li>
<li>Experience with <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a></li>
</ul>
@@ -20,24 +22,34 @@
<li><a href="{@docRoot}guide/components/services.html">Services</a>
</ul>
-</div>
+</div>
</div>
<p>For your app to be a good citizen, it should seek to limit its impact on the battery life of its
-host device. After this class you will be able to build apps that monitor modify their functionality
-and behavior based on the state of the host device.</p>
+device. After this class you will be able to build apps that modify their functionality
+and behavior based on the state of its device.</p>
-<p>By taking steps such as disabling background service updates when you lose connectivity, or
-reducing the rate of such updates when the battery level is low, you can ensure that the impact of
-your app on battery life is minimized, without compromising the user experience.</p>
+<p>By taking steps such as batching network requests, disabling background service updates when you
+lose connectivity, or reducing the rate of such updates when the battery level is low, you can
+ensure that the impact of your app on battery life is minimized, without compromising the user
+experience.</p>
-<h2>Lessons</h2>
-
+<h2>Lessons</h2>
+
<!-- Create a list of the lessons in this class along with a short description of each lesson.
These should be short and to the point. It should be clear from reading the summary whether someone
-will want to jump to a lesson or not.-->
-
+will want to jump to a lesson or not.-->
+
<dl>
+ <dt><b><a href="{@docRoot}training/performance/battery/network/index.html">Reducing Network Battery
+Drain</a></b></dt>
+ <dd>Learn how to analyze your app's use of network resources and optimize it to reduce
+power consumption.</dd>
+
+ <dt><b><a href="doze-standby.html">Optimizing for Doze and App Standby</a></b></dt>
+ <dd>Learn how to test and optimize your app for the power-management features introduced in
+ Android 6.0 Marshmallow.</dd>
+
<dt><b><a href="battery-monitoring.html">Monitoring the Battery Level and Charging State</a></b></dt>
<dd>Learn how to alter your app's update rate by determining, and monitoring, the current battery
level and changes in charging state.</dd>
@@ -50,7 +62,7 @@
<dt><b><a href="connectivity-monitoring.html">Determining and Monitoring the Connectivity
Status</a></b></dt>
- <dd>Without Internet connectivity you can't update your app from an online source. Learn how to
+ <dd>Without Internet connectivity you can't update your app from an online source. Learn how to
check the connectivity status to alter your background update rate. You'll also learn to check for
Wi-Fi or mobile connectivity before beginning high-bandwidth operations.</dd>
@@ -59,4 +71,4 @@
those that aren't necessary due to the current device state. Learn to improve
efficiency by toggling and cascading state change receivers and delay actions until the device is in
a specific state.</dd>
-</dl>
+</dl>
diff --git a/docs/html/training/monitoring-device-state/manifest-receivers.jd b/docs/html/training/monitoring-device-state/manifest-receivers.jd
index d4aeed3..ca184aa5 100644
--- a/docs/html/training/monitoring-device-state/manifest-receivers.jd
+++ b/docs/html/training/monitoring-device-state/manifest-receivers.jd
@@ -42,7 +42,7 @@
<h2 id="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve Efficiency </h2>
-<p>Use can use the {@link android.content.pm.PackageManager} to toggle the enabled state on any
+<p>You can use the {@link android.content.pm.PackageManager} to toggle the enabled state on any
component defined in the manifest, including whichever broadcast receivers you wish to enable or
disable as shown in the snippet below:</p>
diff --git a/docs/html/training/multiple-apks/api.jd b/docs/html/training/multiple-apks/api.jd
old mode 100644
new mode 100755
index f43dcae..504b4e3
--- a/docs/html/training/multiple-apks/api.jd
+++ b/docs/html/training/multiple-apks/api.jd
@@ -153,11 +153,11 @@
their creation at the following links:</p>
<ul>
<li><a
-href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
-a library project (Eclipse)</a></li>
+href="{@docRoot}sdk/installing/create-project.html#SettingUpLibraryModule">Managing Projects
+from Android Studio</a></li>
<li><a
-href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
-a library project (Command line)</a></li>
+href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Managing Projects
+from the Command Line</a></li>
</ul>
@@ -176,7 +176,7 @@
<h2 id="CreateAPKs">Create New APK Projects</h2>
<p>There should be a separate Android project for each APK you’re going to release. For easy
-organization, place the library project and all related APK projects under the same parent folder.
+organization, place the library project and all related APK projects under the same parent folder.
Also remember that each APK needs to have the same package name, although they don’t necessarily
need to share the package name with the library. If you were to have 3 APKs following the scheme
described earlier, your root directory might look like this:</p>
@@ -278,7 +278,7 @@
</table>
<p>
-Now, let’s further assume that the Red APK has some requirement on it that the other two don’t.
+Now, let’s further assume that the Red APK has some requirement on it that the other two don’t.
<a href="{@docRoot}google/play/filters.html">Filters on Google Play</a> page of
the Android Developer guide has a whole list of possible culprits. For the
sake of example, let’s assume that red requires a front-facing camera. In fact, the entire point of
diff --git a/docs/html/training/multiple-apks/multiple.jd b/docs/html/training/multiple-apks/multiple.jd
old mode 100644
new mode 100755
index ccee397..2501564
--- a/docs/html/training/multiple-apks/multiple.jd
+++ b/docs/html/training/multiple-apks/multiple.jd
@@ -169,7 +169,7 @@
easier to ask your cubie than "Have we tested the 3-to-10 xlarge APK against the Xoom?" Print this
chart out and hand it to every person working on your codebase. Life just got a lot easier.</p>
-<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2>
+<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project</h2>
<p>Whether you’re modifying an existing Android application or starting one from scratch, this is
the first thing that you should do to the codebase, and by the far the most important. Everything
@@ -182,11 +182,11 @@
their creation at the following links:</p>
<ul>
<li><a
-href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
-a library project (Eclipse)</a></li>
+href="{@docRoot}sdk/installing/create-project.html#SettingUpLibraryModule">Managing Projects
+from Android Studio</a></li>
<li><a
-href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
-a library project (Command line)</a></li>
+href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Managing Projects
+from the Command Line</a></li>
</ul>
<p>If you’re converting an existing application to use multiple APK support,
@@ -204,7 +204,7 @@
<h2 id="CreateAPKs">Create New APK Projects</h2>
<p>There should be a separate Android project for each APK you’re going to release. For easy
-organization, place the library project and all related APK projects under the same parent folder.
+organization, place the library project and all related APK projects under the same parent folder.
Also remember that each APK needs to have the same package name, although they don’t necessarily
need to share the package name with the library. If you were to have 3 APKs following the scheme
described earlier, your root directory might look like this:</p>
diff --git a/docs/html/training/multiple-apks/screensize.jd b/docs/html/training/multiple-apks/screensize.jd
old mode 100644
new mode 100755
index c7941c4..a482f67
--- a/docs/html/training/multiple-apks/screensize.jd
+++ b/docs/html/training/multiple-apks/screensize.jd
@@ -58,7 +58,7 @@
though multiple APK support is the best solution, but this often isn’t the case. The <a
href="{@docRoot}google/play/publishing/multiple-apks.html#ApiLevelOptions">Using Single APK
Instead</a> section of the multiple APK developer guide includes some useful information on how to
-accomplish this with a single APK, including use of our support library. You should also read the
+accomplish this with a single APK, including use of our support library. You should also read the
guide to <a href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a>,
and there’s even a <a
href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">support library</a> you
@@ -118,7 +118,7 @@
now simply refer to each APK as "blue", "green", or "red", no matter how many different screen types
it covers.</p>
-<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project.</h2>
+<h2 id="CreateLibrary">Put All Common Code and Resources in a Library Project</h2>
<p>Whether you’re modifying an existing Android application or starting one from scratch, this is
the first thing that you should do to the codebase, and by the far the most important. Everything
that goes into the library project only needs to be updated once (think language-localized strings,
@@ -130,11 +130,11 @@
their creation at the following links:</p>
<ul>
<li><a
-href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
-a library project (Eclipse)</a></li>
+href="{@docRoot}sdk/installing/create-project.html#SettingUpLibraryModule">Managing Projects
+from Android Studio</a></li>
<li><a
-href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
-a library project (Command line)</a></li>
+href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Managing Projects
+from the Command Line</a></li>
</ul>
@@ -156,7 +156,7 @@
<h2 id="CreateAPKs">Create New APK Projects</h2>
<p>There should be a separate Android project for each APK you’re going to release. For easy
-organization, place the library project and all related APK projects under the same parent folder.
+organization, place the library project and all related APK projects under the same parent folder.
Also remember that each APK needs to have the same package name, although they don’t necessarily
need to share the package name with the library. If you were to have 3 APKs following the scheme
described earlier, your root directory might look like this:</p>
@@ -295,7 +295,7 @@
Also note that instead of taking advantage of the default values (small and
normal are always true by default), the manifests explicitly set the value for
each screen size. This can save you headaches down the line. For instance, a manifest with a
-target SDK of < 9 will have xlarge automatically set to false, since that size didn’t exist yet.
+target SDK of < 9 will have xlarge automatically set to false, since that size didn’t exist yet.
So be explicit!
</p>
diff --git a/docs/html/training/multiple-apks/texture.jd b/docs/html/training/multiple-apks/texture.jd
old mode 100644
new mode 100755
index c49cc95..3ffd64f
--- a/docs/html/training/multiple-apks/texture.jd
+++ b/docs/html/training/multiple-apks/texture.jd
@@ -73,7 +73,7 @@
<h2 id="ChartReqs">Chart Your Requirements</h2>
-
+
<p>The Android Developer Guide provides a handy reference of some of common supported textures on
the <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">supports-gl-texture
page</a>. This page also contains some hints as to which phones (or families of phones) support
@@ -113,11 +113,11 @@
their creation at the following links:</p>
<ul>
<li><a
-href="{@docRoot}tools/projects/projects-eclipse.html#SettingUpLibraryProject">Setting up
-a library project (Eclipse)</a></li>
+href="{@docRoot}sdk/installing/create-project.html#SettingUpLibraryModule">Managing Projects
+from Android Studio</a></li>
<li><a
-href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Setting up
-a library project (Command line)</a></li>
+href="{@docRoot}tools/projects/projects-cmdline.html#SettingUpLibraryProject">Managing Projects
+from the Command Line</a></li>
</ul>
<p>If you’re converting an existing application to use multiple APK support,
@@ -135,7 +135,7 @@
<h2 id="CreateAPKs">Create New APK Projects</h2>
<p>There should be a separate Android project for each APK you’re going to release. For easy
-organization, place the library project and all related APK projects under the same parent folder.
+organization, place the library project and all related APK projects under the same parent folder.
Also remember that each APK needs to have the same package name, although they don’t necessarily
need to share the package name with the library. If you were to have 3 APKs following the scheme
described earlier, your root directory might look like this:</p>
@@ -194,7 +194,7 @@
<tr>
<td class="blueCell">ETC1</td>
<td class="blueCell">ETC1</td>
- <td class="blueCell">ETC1</td>
+ <td class="blueCell">ETC1</td>
</tr>
<tr>
<td></td>
@@ -290,7 +290,7 @@
supports-screens and compatible-screens, and that you don’t have unintended "uses-feature" values
that were added as a result of permissions you set in the manifest. In the example above, the APK
will be invisible to most, if not all devices.</p>
-<p>Why? By adding the required permission SEND_SMS, the feature requirement of android.hardware.telephony was implicitly added. Since most (if not all) xlarge devices are tablets without telephony hardware in them, Google Play will filter out this APK in these cases, until future devices come along which are both large enough to report as xlarge screen size, and possess telephony hardware.
+<p>Why? By adding the required permission SEND_SMS, the feature requirement of android.hardware.telephony was implicitly added. Since most (if not all) xlarge devices are tablets without telephony hardware in them, Google Play will filter out this APK in these cases, until future devices come along which are both large enough to report as xlarge screen size, and possess telephony hardware.
</p>
<p>Fortunately this is easily fixed by adding the following to your manifest:</p>
<pre>
diff --git a/docs/html/training/multiscreen/screensizes.jd b/docs/html/training/multiscreen/screensizes.jd
old mode 100644
new mode 100755
index a34c3d5..2cd59ee
--- a/docs/html/training/multiscreen/screensizes.jd
+++ b/docs/html/training/multiscreen/screensizes.jd
@@ -56,9 +56,8 @@
you should use <code>"wrap_content"</code> and <code>"match_parent"</code> for the width
and height of some view components. If you use <code>"wrap_content"</code>, the width
or height of the view is set to the minimum size necessary to fit the content
-within that view, while <code>"match_parent"</code> (also known as
-<code>"fill_parent"</code> before API level 8) makes the component expand to match the size of its
-parent view.</p>
+within that view, while <code>"match_parent"</code> makes the component expand to match the size of
+its parent view.</p>
<p>By using the <code>"wrap_content"</code> and <code>"match_parent"</code> size values instead of
hard-coded sizes, your views either use only the space required for that
diff --git a/docs/html/training/notepad/codelab/NotepadCodeLab.zip b/docs/html/training/notepad/codelab/NotepadCodeLab.zip
deleted file mode 100644
index cd30f29..0000000
--- a/docs/html/training/notepad/codelab/NotepadCodeLab.zip
+++ /dev/null
Binary files differ
diff --git a/docs/html/training/notepad/index.jd b/docs/html/training/notepad/index.jd
deleted file mode 100644
index 507b232..0000000
--- a/docs/html/training/notepad/index.jd
+++ /dev/null
@@ -1,136 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Tutorial
-parent.title=Tutorials
-@jd:body
-
-
-<p>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. </p>
-
-<p>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. </p>
-
-<p><p>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.</p>
-
-<a name="who"></a>
-<h2>Who Should Use this Tutorial</h2>
-
-<p>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. </p>
-
-<p>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. </p>
-
-<a name="preparing"></a>
-<h2>Preparing for the Exercises</h2>
-
-<p>The tutorial assumes that you have some familiarity with basic Android
-application concepts and terminology. If you are not, you
-should read <a href="{@docRoot}guide/components/fundamentals.html">Application
-Fundamentals</a> before continuing. </p>
-
-<p>This tutorial also builds on the introductory information provided in the
-<a href="{@docRoot}training/basics/firstapp/index.html">Building Your First App</a>
-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.</p>
-
-<p>To prepare for this lesson:</p>
-
-<ol>
- <li>Download the <a href="codelab/NotepadCodeLab.zip">project
- exercises archive (.zip)</a>.</li>
- <li>Unpack the archive file to a suitable location on your machine.</li>
- <li>Open the <code>NotepadCodeLab</code> folder.</li>
-</ol>
-
-<p>Inside the <code>NotepadCodeLab</code> folder, you should see six project
-files: <code>Notepadv1</code>,
- <code>Notepadv2</code>, <code>Notepadv3</code>,
- <code>Notepadv1Solution</code>, <code>Notepadv2Solution</code>
- and <code>Notepadv3Solution</code>. The <code>Notepadv#</code> projects are
-the starting points for each of the exercises, while the
-<code>Notepadv#Solution</code> projects are the exercise
- solutions. If you are having trouble with a particular exercise, you
- can compare your current work against the exercise solution.</p>
-
-<a name="exercises"></a>
-<h2> Exercises</h2>
-
- <p>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.</p>
-
- <table border="0" style="padding:4px;spacing:2px;" summary="This
-table lists the
-tutorial examples and describes what each covers. ">
- <tr>
- <th width="120"><a href="{@docRoot}training/notepad/notepad-ex1.html">Exercise
-1</a></th>
- <td>Start here. Construct a simple notes list that lets the user add new notes but not
-edit them. Demonstrates the basics of <code>ListActivity</code> and creating
-and handling
- menu options. Uses a SQLite database to store the notes.</td>
- </tr>
- <tr>
- <th><a href="{@docRoot}training/notepad/notepad-ex2.html">Exercise 2</a></th>
- <td>Add 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
-<code>startActivityForResult()</code>.</td>
- </tr>
- <tr>
- <th><a href="{@docRoot}training/notepad/notepad-ex3.html">Exercise 3</a></th>
- <td>Add handling of life-cycle events to
-the application, to let it
-maintain application state across the life cycle. </td>
- </tr>
- <tr>
- <th><a href="{@docRoot}training/notepad/notepad-extra-credit.html">Extra
-Credit</a></th>
- <td>Demonstrates 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.</td>
- </tr>
-</table>
-
-
-<a name="other"></a>
-<h2>Other Resources and Further Learning</h2>
-<ul>
-<li>For a lighter but broader introduction to concepts not covered in the
-tutorial,
-take a look at <a href="{@docRoot}resources/faq/commontasks.html">Common Android Tasks</a>.</li>
-
-<li>This tutorial draws from the full Notepad application included in the
-<code>samples/legacy/NotePad</code> 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:</li>
- <ul>
- <li>Setting up a custom striped list for the list of notes.</li>
- <li>Creating a custom text edit view that overrides the <code>draw()</code>
- method to make it look like a lined notepad.</li>
- <li>Implementing a full <code>ContentProvider</code> for notes.</li>
- <li>Reverting and discarding edits instead of just automatically saving
- them.</li>
- </ul>
-</ul>
diff --git a/docs/html/training/notepad/notepad-ex1.jd b/docs/html/training/notepad/notepad-ex1.jd
deleted file mode 100644
index f680f15..0000000
--- a/docs/html/training/notepad/notepad-ex1.jd
+++ /dev/null
@@ -1,583 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Exercise 1
-parent.title=Notepad Tutorial
-parent.link=index.html
-@jd:body
-
-
-<p><em>In this exercise, you will construct a simple notes list that lets the
-user add new notes but not edit them. The exercise demonstrates:</em></p>
-<ul>
-<li><em>The basics of <code>ListActivities</code> and creating and handling menu
-options. </em></li>
-<li><em>How to use a SQLite database to store the notes.</em></li>
-<li><em>How to bind data from a database cursor into a ListView using a
-SimpleCursorAdapter.</em></li>
-<li><em>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. </em></li>
-</ul>
-
-<div style="float:right;white-space:nowrap">
-<span style="color:#BBB;">
- [<a href="notepad-ex1.html" style="color:#BBB;">Exercise 1</a>]</span>
- [<a href="notepad-ex2.html">Exercise 2</a>]
- [<a href="notepad-ex3.html">Exercise 3</a>]
- [<a href="notepad-extra-credit.html">Extra Credit</a>]
-</div>
-
-
-
-<h2>Step 1</h2>
-
- <p>Open up the <code>Notepadv1</code> project in Eclipse.</p>
-
- <p><code>Notepadv1</code> 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 <a href="{@docRoot}training/basics/firstapp/index.html">Hello,
- World</a> tutorial.</p>
-
- <ol>
- <li>
- Start a new Android Project by clicking <strong>File</strong> >
- <strong>New</strong> > <strong>Android Project</strong>.</li>
- <li>
- In the New Android Project dialog, select <strong>Create project from existing source</strong>.</li>
- <li>
- Click <strong>Browse</strong> and navigate to where you copied the <code>NotepadCodeLab</code>
- (downloaded during <a href="{@docRoot}training/notepad/index.html#preparing">setup</a>)
- and select <code>Notepadv1</code>.</li>
- <li>
- 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.</li>
- <li>
- Click <strong>Finish</strong>. The <code>Notepadv1</code> project should open and be
- visible in your Eclipse package explorer.</li>
- </ol>
-
- <p>If you see an error about <code>AndroidManifest.xml</code>, or some
- problems related to an Android zip file, right click on the project and
- select <strong>Android Tools</strong> > <strong>Fix Project Properties</strong>.
- (The project is looking in the wrong location for the library file,
- this will fix it for you.)</p>
-
- <h2>Step 2</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>Accessing and modifying data</h2>
- <p>For this
- exercise, we are using a SQLite database to store our data. This is useful
- if only <em>your</em> application will need to access or modify the data. If you wish for
- other activities to access or modify the data, you have to expose the data using a
- {@link android.content.ContentProvider ContentProvider}.</p>
- <p>If you are interested, you can find out more about
- <a href="{@docRoot}guide/topics/providers/content-providers.html">content providers</a> or the
-whole
- subject of <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>.
- The NotePad sample in the <code>samples/</code> folder of the SDK also has an example of how
- to create a ContentProvider.</p>
- </div>
- </div>
-
- <p>Take a look at the <code>NotesDbAdapter</code> 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.</p>
- <p>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.</p>
- <p>Our database will have the name <code>data</code>, and have a single table called
- <code>notes</code>, which in turn has three fields: <code>_id</code>, <code>title</code> and
- <code>body</code>. The <code>_id</code> is named with an underscore convention used in a number of
- places inside the Android SDK and helps keep a track of state. The <code>_id</code>
- 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.
- </p>
- <p>The constructor for <code>NotesDbAdapter</code> 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
- <code>this</code> from your Activity, when needing a Context.</p>
- <p>The <code>open()</code> method calls up an instance of DatabaseHelper, which is our local
- implementation of the SQLiteOpenHelper class. It calls <code>getWritableDatabase()</code>,
- which handles creating/opening a database for us.</p>
- <p><code>close()</code> just closes the database, releasing resources related to the
- connection.</p>
- <p><code>createNote()</code> 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 <code>_id</code> value for the newly created note.</p>
- <p><code>deleteNote()</code> takes a <var>rowId</var> for a particular note, and deletes that note from
- the database.</p>
-
- <p><code>fetchAllNotes()</code> issues a query to return a {@link android.database.Cursor} over all notes in the
- database. The <code>query()</code> call is worth examination and understanding. The first field is the
- name of the database table to query (in this case <code>DATABASE_TABLE</code> is "notes").
- The next is the list of columns we want returned, in this case we want the <code>_id</code>,
- <code>title</code> and <code>body</code> columns so these are specified in the String array.
- The remaining fields are, in order: <code>selection</code>,
- <code>selectionArgs</code>, <code>groupBy</code>, <code>having</code> and <code>orderBy</code>.
- Having these all <code>null</code> means we want all data, need no grouping, and will take the default
- order. See {@link android.database.sqlite.SQLiteDatabase SQLiteDatabase} for more details.</p>
- <p class="note"><b>Note:</b> 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.</p>
-
- <p><code>fetchNote()</code> is similar to <code>fetchAllNotes()</code> but just gets one note
- with the <var>rowId</var> we specify. It uses a slightly different version of the
- {@link android.database.sqlite.SQLiteDatabase} <code>query()</code> method.
- The first parameter (set <em>true</em>) indicates that we are interested
- in one distinct result. The <var>selection</var> parameter (the fourth parameter) has been specified to search
- only for the row "where _id =" the <var>rowId</var> we passed in. So we are returned a Cursor on
- the one row.</p>
- <p>And finally, <code>updateNote()</code> takes a <var>rowId</var>, <var>title</var> and <var>body</var>, and uses a
- {@link android.content.ContentValues ContentValues} instance to update the note of the given
- <var>rowId</var>.</p>
-
-<h2 style="clear:right;">Step 3</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>Layouts and activities</h2>
- <p>Most Activity classes will have a layout associated with them. The layout
- will be the "face" of the Activity to the user. In this case our layout will
- take over the whole screen and provide a list of notes.</p>
- <p>Full screen layouts are not the only option for an Activity however. You
- might also want to use a <a
-href="{@docRoot}resources/faq/commontasks.html#floatingorfull">floating
- layout</a> (for example, a <a
-href="{@docRoot}resources/faq/commontasks.html#dialogsandalerts">dialog
- or alert</a>),
- or perhaps you don't need a layout at all (the Activity will be invisible
- to the user unless you specify some kind of layout for it to use).</p>
- </div>
- </div>
-
- <p>Open the <code>notepad_list.xml</code> file in <code>res/layout</code>
-and
- take a look at it. (You may have to
- hit the <em>xml</em> tab, at the bottom, in order to view the XML markup.)</p>
-
- <p>This is a mostly-empty layout definition file. Here are some
- things you should know about a layout file:</p>
-
-
- <ul>
- <li>
- All Android layout files must start with the XML header line:
- <code><?xml version="1.0" encoding="utf-8"?></code>. </li>
- <li>
- The next definition will often (but not always) be a layout
- definition of some kind, in this case a <code>LinearLayout</code>. </li>
- <li>
- The XML namespace of Android should always be defined in
- the top level component or layout in the XML so that <code>android:</code> tags can
- be used through the rest of the file:
- <p><code>xmlns:android="http://schemas.android.com/apk/res/android"</code></p>
- </li>
- </ul>
-
- <h2 style="clear:right;">Step 4</h2>
- <p>We need to create the layout to hold our list. Add code inside
- of the <code>LinearLayout</code> element so the whole file looks like this: </p>
- <pre>
-<?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>
-</pre>
- <ul>
- <li>
- The <strong>@</strong> symbol in the id strings of the <code>ListView</code> and
- <code>TextView</code> tags means
- that the XML parser should parse and expand the rest of
- the id string and use an ID resource.</li>
- <li>
- The <code>ListView</code> and <code>TextView</code> 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 <code>res/values/strings.xml</code>) will be displayed if there
- aren't any notes to display.</li>
- <li>The <code>list</code> and <code>empty</code> IDs are
- provided for us by the Android platform, so, we must
- prefix the <code>id</code> with <code>android:</code> (e.g., <code>@android:id/list</code>).</li>
- <li>The View with the <code>empty</code> 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.
- <p>
- More broadly, the <code>android.R</code> class is a set of predefined
- resources provided for you by the platform, while your project's
- <code>R</code> class is the set of resources your project has defined.
- Resources found in the <code>android.R</code> resource class can be
- used in the XML files by using the <code>android:</code> name space prefix
- (as we see here).</p>
- </li>
- </ul>
-
- <h2 style="clear:right;">Step 5</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>Resources and the R class</h2>
- <p>The folders under res/ in the Eclipse project are for resources.
- There is a <a href="{@docRoot}resources/faq/commontasks.html#filelist">specific structure</a>
-to the
- folders and files under res/.</p>
- <p>Resources defined in these folders and files will have
- corresponding entries in the R class allowing them to be easily accessed
- and used from your application. The R class is automatically generated using the contents
- of the res/ folder by the eclipse plugin (or by aapt if you use the command line tools).
- Furthermore, they will be bundled and deployed for you as part of the application.</p>
- </p>
- </div>
- </div>
-
- <p>To make the list of notes in the ListView, we also need to define a View for each row:</p>
- <ol>
- <li>
- Create a new file under <code>res/layout</code> called
- <code>notes_row.xml</code>. </li>
- <li>
- Add the following contents (note: again the XML header is used, and the
- first node defines the Android XML namespace)<br>
- <pre style="overflow:auto">
-<?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"/></pre>
- <p>
- This is the View that will be used for each notes title row — it has only
- one text field in it. </p>
- <p>In this case we create a new id called <code>text1</code>. The
- <strong>+</strong> after the <strong>@</strong> 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
- <code>text1</code> on the fly and then using it.</p>
- </li>
- <li>Save the file.</li>
- </ol>
- <p>Open the <code>R.java</code> class in the
- project and look at it, you should see new definitions for
- <code>notes_row</code> and <code>text1</code> (our new definitions)
- meaning we can now gain access to these from the our code. </p>
-
- <h2 style="clear:right;">Step 6</h2>
-<p>Next, open the <code>Notepadv1</code> 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.</p>
-
-<p><code>Notepadv1</code> will inherit from a subclass
- of <code>Activity</code> called a <code>ListActivity</code>,
- 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.</p>
-
-<p>Take a look through the existing code in <code>Notepadv1</code> class.
- There is a currently an unused private field called <code>mNoteNumber</code> that
- we will use to create numbered note titles.</p>
- <p>There are also three override methods defined:
- <code>onCreate</code>, <code>onCreateOptionsMenu</code> and
- <code>onOptionsItemSelected</code>; we need to fill these
- out:</p>
- <ul>
- <li><code>onCreate()</code> 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.</li>
- <li><code>onCreateOptionsMenu()</code> 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"). </li>
- <li><code>onOptionsItemSelected()</code> 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).
- </li>
- </ul>
-
- <h2>Step 7</h2>
- <p>Change the inheritance of <code>Notepadv1</code> from
-<code>Activity</code>
- to <code>ListActivity</code>:</p>
- <pre>public class Notepadv1 extends ListActivity</pre>
- <p>Note: you will have to import <code>ListActivity</code> into the
-Notepadv1
- class using Eclipse, <strong>ctrl-shift-O</strong> on Windows or Linux, or
- <strong>cmd-shift-O</strong> on the Mac (organize imports) will do this for you
- after you've written the above change.</p>
-
- <h2>Step 8</h2>
- <p>Fill out the body of the <code>onCreate()</code> method.</p>
- <p>Here we will set the title for the Activity (shown at the top of the
- screen), use the <code>notepad_list</code> layout we created in XML,
- set up the <code>NotesDbAdapter</code> instance that will
- access notes data, and populate the list with the available note
- titles:</p>
- <ol>
- <li>
- In the <code>onCreate</code> method, call <code>super.onCreate()</code> with the
- <code>savedInstanceState</code> parameter that's passed in.</li>
- <li>
- Call <code>setContentView()</code> and pass <code>R.layout.notepad_list</code>.</li>
- <li>
- At the top of the class, create a new private class field called <code>mDbHelper</code> of class
- <code>NotesDbAdapter</code>.
- </li>
- <li>
- Back in the <code>onCreate</code> method, construct a new
-<code>NotesDbAdapter</code>
- instance and assign it to the <code>mDbHelper</code> field (pass
- <code>this</code> into the constructor for <code>DBHelper</code>)
- </li>
- <li>
- Call the <code>open()</code> method on <code>mDbHelper</code> to open (or create) the
- database.
- </li>
- <li>
- Finally, call a new method <code>fillData()</code>, which will get the data and
- populate the ListView using the helper — we haven't defined this method yet. </li>
- </ol>
- <p>
- <code>onCreate()</code> should now look like this:</p>
- <pre>
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.notepad_list);
- mDbHelper = new NotesDbAdapter(this);
- mDbHelper.open();
- fillData();
- }</pre>
- <p>And be sure you have the <code>mDbHelper</code> field definition (right
- under the mNoteNumber definition): </p>
- <pre> private NotesDbAdapter mDbHelper;</pre>
-
- <h2>Step 9</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>More about menus</h2>
- <p>The notepad application we are constructing only scratches the
- surface with <a href="{@docRoot}resources/faq/commontasks.html#addmenuitems">menus</a>. </p>
- <p>You can also <a href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">add
-shortcut keys for menu items</a>, <a
-href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">create
-submenus</a> and even <a href="{@docRoot}resources/faq/commontasks.html#addingtoothermenus">add
-menu items to other applications!</a>. </p>
- </div>
- </div>
-
-<p>Fill out the body of the <code>onCreateOptionsMenu()</code> method.</p>
-
-<p>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.</p>
-
- <ol>
- <li>
- In <code>strings.xml</code> resource (under <code>res/values</code>), add
- a new string named "menu_insert" with its value set to <code>Add Item</code>:
- <pre><string name="menu_insert">Add Item</string></pre>
- <p>Then save the file and return to <code>Notepadv1</code>.</p>
- </li>
- <li>Create a menu position constant at the top of the class:
- <pre>public static final int INSERT_ID = Menu.FIRST;</pre>
- </li>
- <li>In the <code>onCreateOptionsMenu()</code> method, change the
- <code>super</code> call so we capture the boolean return as <code>result</code>. We'll return this value at the end.</li>
- <li>Then add the menu item with <code>menu.add()</code>.</li>
- </ol>
- <p>The whole method should now look like this:
- <pre>
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- boolean result = super.onCreateOptionsMenu(menu);
- menu.add(0, INSERT_ID, 0, R.string.menu_insert);
- return result;
- }</pre>
- <p>The arguments passed to <code>add()</code> 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.</p>
-
-<h2 style="clear:right;">Step 10</h2>
- <p>Fill out the body of the <code>onOptionsItemSelected()</code> method:</p>
- <p>This is going
- to handle our new "Add Note" menu item. When this is selected, the
- <code>onOptionsItemSelected()</code> method will be called with the
- <code>item.getId()</code> set to <code>INSERT_ID</code> (the constant we
- used to identify the menu item). We can detect this, and take the
- appropriate actions:</p>
- <ol>
- <li>
- The <code>super.onOptionsItemSelected(item)</code> method call goes at the
- end of this method — we want to catch our events first! </li>
- <li>
- Write a switch statement on <code>item.getItemId()</code>.
- <p>In the case of <var>INSERT_ID</var>, call a new method, <code>createNote()</code>,
- and return true, because we have handled this event and do not want to
- propagate it through the system.</p>
- </li>
- <li>Return the result of the superclass' <code>onOptionsItemSelected()</code>
- method at the end.</li>
- </ol>
- <p>
- The whole <code>onOptionsItemSelect()</code> method should now look like
- this:</p>
- <pre>
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case INSERT_ID:
- createNote();
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }</pre>
-
-<h2>Step 11</h2>
- <p>Add a new <code>createNote()</code> method:</p>
- <p>In this first version of
- our application, <code>createNote()</code> 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:</p>
- <ol>
- <li>Construct the name using "Note" and the counter we defined in the class: <code>
- String noteName = "Note " + mNoteNumber++</code></li>
- <li>
- Call <code>mDbHelper.createNote()</code> using <code>noteName</code> as the
- title and <code>""</code> for the body
- </li>
- <li>
- Call <code>fillData()</code> to populate the list of notes (inefficient but
- simple) — we'll create this method next.</li>
- </ol>
- <p>
- The whole <code>createNote()</code> method should look like this: </p>
- <pre>
- private void createNote() {
- String noteName = "Note " + mNoteNumber++;
- mDbHelper.createNote(noteName, "");
- fillData();
- }</pre>
-
-
-<h2>Step 12</h2>
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>List adapters</h2>
- <p>Our example uses a {@link android.widget.SimpleCursorAdapter
- SimpleCursorAdapter} to bind a database {@link android.database.Cursor Cursor}
- into a ListView, and this is a common way to use a {@link android.widget.ListAdapter
- ListAdapter}. Other options exist like {@link android.widget.ArrayAdapter ArrayAdapter} which
- can be used to take a List or Array of in-memory data and bind it in to
- a list as well.</p>
- </div>
- </div>
-
- <p>Define the <code>fillData()</code> method:</p>
- <p>This
- method uses <code>SimpleCursorAdapter,</code> which takes a database <code>Cursor</code>
- and binds it to fields provided in the layout. These fields define the row elements of our list
- (in this case we use the <code>text1</code> field in our
- <code>notes_row.xml</code> layout), so this allows us to easily populate the list with
- entries from our database.</p>
- <p>To do this we have to provide a mapping from the <code>title</code> field in the returned Cursor, to
- our <code>text1</code> TextView, which is done by defining two arrays: the first a string array
- with the list of columns to map <em>from</em> (just "title" in this case, from the constant
- <code>NotesDbAdapter.KEY_TITLE</code>) and, the second, an int array
- containing references to the views that we'll bind the data <em>into</em>
- (the <code>R.id.text1</code> TextView).</p>
- <p>This is a bigger chunk of code, so let's first take a look at it:</p>
-
- <pre>
- 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);
- }</pre>
-
- <p>Here's what we've done:</p>
- <ol>
- <li>
- After obtaining the Cursor from <code>mDbHelper.fetchAllNotes()</code>, we
- use an Activity method called
- <code>startManagingCursor()</code> 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.)</li>
- <li>
- 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).</li>
- <li>
- 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 <code>this</code> for the context (since subclasses of Activity
- implement Context). We pass the <code>notes_row</code> View we created as the receptacle
- for the data, the Cursor we just created, and then our arrays.</li>
- </ol>
- <p>
- In the future, remember that the mapping between the <strong>from</strong> columns and <strong>to</strong> 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 <code>{ NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_BODY }</code> and
- <code>{ R.id.text1, R.id.text2 }</code> 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).</p>
- <p>
- If you get compiler errors about classes not being found, ctrl-shift-O or
- (cmd-shift-O on the mac) to organize imports.
- </p>
-
-<h2 style="clear:right;">Step 13</h2>
- <p>Run it!
- <ol>
- <li>
- Right click on the <code>Notepadv1</code> project.</li>
- <li>
- From the popup menu, select <strong>Run As</strong> >
- <strong>Android Application</strong>.</li>
- <li>
- 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).</li>
- <li>Add new notes by hitting the menu button and selecting <em>Add
- Item</em> from the menu.</li>
- </ol>
-
-<h2 style="clear:right;">Solution and Next Steps</h2>
- <p>You can see the solution to this class in <code>Notepadv1Solution</code>
-from
-the zip file to compare with your own.</p>
-
-<p>Once you are ready, move on to <a href="notepad-ex2.html">Tutorial
-Exercise 2</a> to add the ability to create, edit and delete notes.</p>
-
diff --git a/docs/html/training/notepad/notepad-ex2.jd b/docs/html/training/notepad/notepad-ex2.jd
deleted file mode 100644
index d15499b3..0000000
--- a/docs/html/training/notepad/notepad-ex2.jd
+++ /dev/null
@@ -1,646 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Exercise 2
-parent.title=Notepad Tutorial
-parent.link=index.html
-@jd:body
-
-
-<p><em>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:</em></p>
-<ul>
-<li><em>Constructing a new Activity and adding it to the Android manifest</em></li>
-<li><em>Invoking another Activity asynchronously using <code>startActivityForResult()</code></em></li>
-<li><em>Passing data between Activity in Bundle objects</em></li>
-<li><em>How to use a more advanced screen layout</em></li>
-<li><em>How to create a context menu</em></li>
-</ul>
-
-<div style="float:right;white-space:nowrap">
- [<a href="notepad-ex1.html">Exercise 1</a>]
- <span style="color:#BBB;">
- [<a href="notepad-ex2.html" style="color:#DDD;">Exercise 2</a>]
- </span>
- [<a href="notepad-ex3.html">Exercise 3</a>]
- [<a href="notepad-extra-credit.html">Extra Credit</a>]
-</div>
-
-<h2>Step 1</h2>
-
-<p>Create a new Android project using the sources from <code>Notepadv2</code> under the
-<code>NotepadCodeLab</code> folder, just like you did for the first exercise. If you see an error about
-<code>AndroidManifest.xml</code>, or some problems related to an
-<code>android.zip</code> file, right click on the project and select <strong>Android
-Tools</strong> > <strong>Fix Project Properties</strong>.</p>
-
-<p>Open the <code>Notepadv2</code> project and take a look around:</p>
-<ul>
- <li>
- Open and look at the <code>strings.xml</code> file under
- <code>res/values</code> — there are several new strings which we will use
- for our new functionality
- </li>
- <li>
- Also, open and take a look at the top of the <code>Notepadv2</code> class,
- you will notice several new constants have been defined along with a new <code>mNotesCursor</code>
- field used to hold the cursor we are using.
- </li>
- <li>
- Note also that the <code>fillData()</code> method has a few more comments and now uses
- the new field to store the notes Cursor. The <code>onCreate()</code> method is
- unchanged from the first exercise. Also notice that the member field used to store the
- notes Cursor is now called <code>mNotesCursor</code>. The <code>m</code> denotes a member
- field and is part of the Android coding style standards.
- </li>
- <li>
- There are also a couple of new overridden methods
- (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>,
- <code>onListItemClick()</code> and <code>onActivityResult()</code>)
- which we will be filling in below.
- </li>
-</ul>
-
-
-<h2>Step 2</h2>
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>Context menus should always be used when performing actions upon specific elements in the UI.
-When you register a View to a context menu, the context menu is revealed by performing a "long-click"
-on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p>
-</div>
-</div>
-
-<p>First, let's create the context menu that will allow users to delete individual notes.
-Open the Notepadv2 class.</p>
-
-<ol>
- <li>In order for each list item in the ListView to register for the context menu, we call
- <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of
- the <code>onCreate()</code> method add this line:
- <pre>registerForContextMenu(getListView());</pre>
- <p>Because our Activity extends the ListActivity class, <code>getListView()</code> will return us
- the local ListView object for the Activity. Now, each list item in this ListView will activate the
- context menu.
- <li>
- Now fill in the <code>onCreateContextMenu()</code> 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 <code>menu.add()</code> like so:
- <pre>
-public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- menu.add(0, DELETE_ID, 0, R.string.menu_delete);
-}</pre>
- <p>The <code>onCreateContextMenu()</code> callback passes some 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.</p>
- </li>
-</ol>
-
-<h2>Step 3</h2>
- <p>Now that 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
- <code>onContextItemSelected()</code> method like this:</p>
-<pre>
-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);
-}</pre>
-<p>Here, we retrieve the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo}
-with {@link android.view.MenuItem#getMenuInfo()}. The <var>id</var> field of this object tells us
-the position of the item in the ListView. We then pass this to the <code>deleteNote()</code>
-method of our NotesDbAdapter and the note is deleted. That's it for the context menu — notes
-can now be deleted.</p>
-
-<h2 style="clear:right;">Step 4</h2>
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>Starting Other Activities</h2>
- <p>In this example our Intent uses a class name specifically.
- As well as
- <a href="{@docRoot}resources/faq/commontasks.html#intentexamples">starting intents</a> in
- classes we already know about, be they in our own application or another
- application, we can also create Intents without knowing exactly which
- application will handle it.</p>
- <p>For example, we might want to open a page in a
- browser, and for this we still use
- an Intent. But instead of specifying a class to handle it, we use
- a predefined Intent constant, and a content URI that describes what we
- want to do. See {@link android.content.Intent
- android.content.Intent} for more information.</p>
- </div>
- </div>
-
- <p>Fill in the body of the <code>createNote()</code> method:
- <p>Create a new <code>Intent</code> to create a note
- (<code>ACTIVITY_CREATE</code>) using the <code>NoteEdit</code> class.
- Then fire the Intent using the <code>startActivityForResult()</code> method
- call:</p>
- <pre style="overflow:auto">
-Intent i = new Intent(this, NoteEdit.class);
-startActivityForResult(i, ACTIVITY_CREATE);</pre>
- <p>This form of the Intent call targets a specific class in our Activity, in this case
- <code>NoteEdit</code>. Since the Intent class will need to communicate with the Android
- operating system to route requests, we also have to provide a Context (<code>this</code>).</p>
- <p>The <code>startActivityForResult()</code> 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
- <code>onActivityResult()</code> and we will implement it in a later step. The other way
- to call an Activity is using <code>startActivity()</code> 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 <code>startActivity()</code>.
- <p>Don't worry about the fact that <code>NoteEdit</code> doesn't exist yet,
- we will fix that soon. </p>
- </li>
-
-
-<h2>Step 5</h2>
-
- <p>Fill in the body of the <code>onListItemClick()</code> override.</p>
- <p><code>onListItemClick()</code> 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
- <code>ListView</code> object it was invoked from, the <code>View</code>
- inside the <code>ListView</code> that was clicked on, the
- <code>position</code> in the list that was clicked, and the
- <code>mRowId</code> of the item that was clicked. In this instance we can
- ignore the first two parameters (we only have one <code>ListView</code> it
- could be), and we ignore the <code>mRowId</code> as well. All we are
- interested in is the <code>position</code> that the user selected. We use
- this to get the data from the correct row, and bundle it up to send to
- the <code>NoteEdit</code> Activity.</p>
- <p>In our implementation of the callback, the method creates an
- <code>Intent</code> to edit the note using
- the <code>NoteEdit</code> 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 <code>mRowId</code> for the note we are
- editing. Finally, it will fire the Intent using the
- <code>startActivityForResult()</code> method call. Here's the code that
- belongs in <code>onListItemClick()</code>:</p>
- <pre>
-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);</pre>
- <ul>
- <li>
- <code>putExtra()</code> 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.
- </li>
- <li>
- 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 <code>moveToPosition()</code> method.</li>
- <li>With the extras added to the Intent, we invoke the Intent on the
- <code>NoteEdit</code> class by passing <code>startActivityForResult()</code>
- the Intent and the request code. (The request code will be
- returned to <code>onActivityResult</code> as the <code>requestCode</code> parameter.)</li>
- </ul>
- <p class="note"><b>Note:</b> 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.</p>
-
-
-<h2>Step 6</h2>
-
-<p>The above <code>createNote()</code> and <code>onListItemClick()</code>
- methods use an asynchronous Intent invocation. We need a handler for the callback, so here we fill
- in the body of the <code>onActivityResult()</code>. </p>
-<p><code>onActivityResult()</code> 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 <code>startActivityForResult</code>.) The parameters provided
- to the callback are: </p>
- <ul>
- <li><code>requestCode</code> — the original request code
- specified in the Intent invocation (either <code>ACTIVITY_CREATE</code> or
- <code>ACTIVITY_EDIT</code> for us).
- </li>
- <li><code>resultCode</code> — 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.
- </li>
- <li><code>intent</code> — this is an Intent created by the Activity returning
- results. It can be used to return data in the Intent "extras."
- </li>
- </ul>
- <p>The combination of <code>startActivityForResult()</code> and
- <code>onActivityResult()</code> 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.</p>
- <p>Here's the code that belongs in your <code>onActivityResult()</code>:</p>
- <pre>
-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;
-}</pre>
-
- <ul>
- <li>
- We are handling both the <code>ACTIVITY_CREATE</code> and
- <code>ACTIVITY_EDIT</code> activity results in this method.
- </li>
- <li>
- 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.
- </li>
- <li>
- In the case of an edit, we pull the mRowId as well, and use that to update
- the note in the database.
- </li>
- <li>
- <code>fillData()</code> at the end ensures everything is up to date .
- </li>
- </ul>
-
-
-<h2>Step 7</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>The Art of Layout</h2>
- <p>The provided
- note_edit.xml layout file is the most sophisticated one in the application we will be building,
- but that doesn't mean it is even close to the kind of sophistication you will be likely to want
- in real Android applications.</p>
- <p>Creating a
- good UI is part art and part science, and the rest is work. Mastery of <a
- href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> is an essential part of
-creating
- a good looking Android application.</p>
- <p>Take a look at the
- <a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>
- for some example layouts and how to use them. The ApiDemos sample project is also a
- great resource from which to learn how to create different layouts.</p>
- </div>
- </div>
-
-<p>Open the file <code>note_edit.xml</code> that has been provided and take a
- look at it. This is the UI code for the Note Editor.</p>
- <p>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.)</p>
- <p>There is a new parameter used
- here that we haven't seen before: <code>android:layout_weight</code> (in
- this case set to use the value 1 in each case).</p>
- <p><code>layout_weight</code> is used in LinearLayouts
- to assign "importance" to Views within the layout. All Views have a default
- <code>layout_weight</code> 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 <code>layout_weight</code> and its ratio to the
- overall <code>layout_weight</code> specified in the current layout for this
- and other View elements.</p>
- <p>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
- <code>layout_weight</code> specified, so it takes up the minimum space
- required to render. If the <code>layout_weight</code> 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 <code>layout_weight</code> of 1
- and the second has a <code>layout_weight</code> 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).</p>
- <p>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.</p>
-
-
-<h2 style="clear:right;">Step 8</h2>
-
- <p>Create a <code>NoteEdit</code> class that extends
- <code>android.app.Activity</code>.</p>
- <p>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 <code>onCreate()</code> method is not automatically
- overridden for you. It is hard to imagine an Activity that doesn't override
- the <code>onCreate()</code> method, so this should be the first thing you do.</p>
- <ol>
- <li>Right click on the <code>com.android.demo.notepad2</code> package
- in the Package Explorer, and select <strong>New</strong> > <strong>Class</strong> from the popup
- menu.</li>
- <li>Fill in <code>NoteEdit</code> for the <code>Name:</code> field in the
- dialog.</li>
- <li>In the <code>Superclass:</code> field, enter
- <code>android.app.Activity</code> (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).</li>
- <li>Click <strong>Finish</strong>.</li>
- <li>In the resulting <code>NoteEdit</code> class, right click in the editor
- window and select <strong>Source</strong> > <strong>Override/Implement Methods...</strong></li>
- <li>Scroll down through the checklist in the dialog until you see
- <code>onCreate(Bundle)</code> — and check the box next to it.</li>
- <li>Click <strong>OK</strong>.<p>The method should now appear in your class.</p></li>
- </ol>
-
-<h2>Step 9</h2>
-
-<p>Fill in the body of the <code>onCreate()</code> method for <code>NoteEdit</code>.</p>
-
-<p>This will set the title of our new Activity to say "Edit Note" (one
- of the strings defined in <code>strings.xml</code>). It will also set the
- content view to use our <code>note_edit.xml</code> 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.</p>
- <p>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 <code>mRowId</code> so we can keep
- track of what note the user is editing.</p>
-
- <ol>
- <li>
- Inside <code>onCreate()</code>, set up the layout:<br>
- <pre>setContentView(R.layout.note_edit);</pre>
- </li>
- <li>
- Change the Activity title to the "Edit Note" string:
- <pre>setTitle(R.string.edit_note);</pre>
- </li>
- <li>
- Find the {@link android.widget.EditText} and {@link android.widget.Button} components we need:
- <p>These are found by the
- IDs associated to them in the R class, and need to be cast to the right
- type of <code>View</code> (<code>EditText</code> for the two text views,
- and <code>Button</code> for the confirm button):</p>
- <pre>
-mTitleText = (EditText) findViewById(R.id.title);
-mBodyText = (EditText) findViewById(R.id.body);
-Button confirmButton = (Button) findViewById(R.id.confirm);</pre>
- <p>Note that <code>mTitleText</code> and <code>mBodyText</code> are member
- fields (you need to declare them at the top of the class definition).</p>
- </li>
- <li>At the top of the class, declare a <code>Long mRowId</code> private field to store
- the current <code>mRowId</code> being edited (if any).
- </li>
- <li>Continuing inside <code>onCreate()</code>,
- add code to initialize the <code>title</code>, <code>body</code> and
- <code>mRowId</code> from the extras Bundle in
- the Intent (if it is present):<br>
- <pre>
-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);
- }
-}</pre>
- <ul>
- <li>
- We are pulling the <code>title</code> and
- <code>body</code> out of the
- <code>extras</code> Bundle that was set from the
- Intent invocation.
- </li><li>
- We also null-protect the text field setting (i.e., we don't want to set
- the text fields to null accidentally).</li>
- </ul>
- </li>
- <li>
- Create an <code>onClickListener()</code> for the button:
- <p>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
- <code>onClick()</code> 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:<br>
- <pre>
-confirmButton.setOnClickListener(new View.OnClickListener() {
-
- public void onClick(View view) {
-
- }
-
-});</pre>
- </li>
- </ol>
-<h2>Step 10</h2>
-
-<p>Fill in the body of the <code>onClick()</code> method of the <code>OnClickListener</code> created in the last step.</p>
-
- <p>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 <code>NoteEdit</code> Activity. If the
- operation is an edit rather than a create, we also want to put the
- <code>mRowId</code> into the Bundle so that the
- <code>Notepadv2</code> class can save the changes back to the correct
- note.</p>
- <ol>
- <li>
- Create a <code>Bundle</code> and put the title and body text into it using the
- constants defined in Notepadv2 as keys:<br>
- <pre>
-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);
-}</pre>
- </li>
- <li>
- Set the result information (the Bundle) in a new Intent and finish the Activity:
- <pre>
-Intent mIntent = new Intent();
-mIntent.putExtras(bundle);
-setResult(RESULT_OK, mIntent);
-finish();</pre>
- <ul>
- <li>The Intent is simply our data carrier that carries our Bundle
- (with the title, body and mRowId).</li>
- <li>The <code>setResult()</code> 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.</li>
- <li>The <code>finish()</code> 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.</li>
- </ul>
- </li>
- </ol>
- <p>The full <code>onCreate()</code> method (plus supporting class fields) should
- now look like this:</p>
- <pre>
-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();
- }
- });
-}</pre>
- </li>
- </ol>
-
-<h2>Step 11</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>The All-Important Android Manifest File</h2>
- <p>The AndroidManifest.xml file is the way in which Android sees your
- application. This file defines the category of the application, where
- it shows up (or even if it shows up) in the launcher or settings, what
- activities, services, and content providers it defines, what intents it can
- receive, and more. </p>
- <p>For more information, see the reference document
- <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
-File</a></p>
- </div>
- </div>
-
-<p>Finally, the new Activity has to be defined in the manifest file:</p>
- <p>Before the new Activity can be seen by Android, it needs its own
- Activity entry in the <code>AndroidManifest.xml</code> 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.</p>
- <p>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.<p>
- <ol>
- <li>Double click on the <code>AndroidManifest.xml</code> file in the package explorer to open it.
- </li>
- <li>Click the <strong>Application</strong> tab at the bottom of the Manifest editor.</li>
- <li>Click <strong>Add...</strong> in the Application Nodes section.
- <p>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".</p></li>
- <li>Make sure "(A) Activity" is selected in the selection pane of the dialog, and click <strong>OK</strong>.</li>
- <li>Click on the new "Activity" node, in the Application Nodes section, then
- type <code>.NoteEdit</code> into the <em>Name*</em>
- field to the right. Press Return/Enter.</li>
- </ol>
- <p>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.</p>
-
- <p class="note">If you prefer to edit this file directly, simply open the
- <code>AndroidManifest.xml</code> file and look at the source (use the
- <code>AndroidManifest.xml</code> tab in the eclipse editor to see the source code directly).
- Then edit the file as follows:<br>
- <code><activity android:name=".NoteEdit" /></code><br><br>
- This should be placed just below the line that reads:<br>
- <code></activity></code> for the <code>.Notepadv2</code> activity.</p>
-
-<h2 style="clear:right;">Step 12</h2>
-
-<p>Now Run it!</p>
-<p>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.
-
-<h2>Solution and Next Steps</h2>
-
-<p>You can see the solution to this exercise in <code>Notepadv2Solution</code>
-from the zip file to compare with your own.</p>
-<p>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.</p>
-
-<p>
-Once you are ready, move on to <a href="notepad-ex3.html">Tutorial
-Exercise 3</a> where you will fix the problems with the back button and lost
-edits by introducing a proper life cycle into the NoteEdit Activity.</p>
-
-
diff --git a/docs/html/training/notepad/notepad-ex3.jd b/docs/html/training/notepad/notepad-ex3.jd
deleted file mode 100644
index 648f9f2..0000000
--- a/docs/html/training/notepad/notepad-ex3.jd
+++ /dev/null
@@ -1,367 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Exercise 3
-parent.title=Notepad Tutorial
-parent.link=index.html
-@jd:body
-
-
-<p><em>In this exercise, you will use life-cycle event callbacks to store and
-retrieve application state data. This exercise demonstrates:</em></p>
-<ul>
-<li><em>Life-cycle events and how your application can use them</em></li>
-<li><em>Techniques for maintaining application state</em></li>
-</ul>
-
-<div style="float:right;white-space:nowrap">
- [<a href="notepad-ex1.html">Exercise 1</a>]
- [<a href="notepad-ex2.html">Exercise 2</a>]
- <span style="color:#BBB;">
- [<a href="notepad-ex3.html" style="color:#BBB;">Exercise 3</a>]
- </span>
- [<a href="notepad-extra-credit.html">Extra Credit</a>]
-</div>
-
-<h2>Step 1</h2>
-
-<p>Import <code>Notepadv3</code> into Eclipse. If you see an error about
-<code>AndroidManifest.xml,</code> or some problems related to an Android zip
-file, right click on the project and select <strong>Android Tools</strong> >
-<strong>Fix Project Properties</strong> from the popup menu. The starting point for this exercise is
-exactly where we left off at the end of the Notepadv2. </p>
-<p>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.</p>
-<p>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.</p>
-
- <ol>
- <li>Remove the code in <code>NoteEdit</code> that parses the title and body
- from the extras Bundle.
- <p>Instead, we are going to use the <code>DBHelper</code> class
- to access the notes from the database directly. All we need passed into the
- NoteEdit Activity is a <code>mRowId</code> (but only if we are editing, if creating we pass
- nothing). Remove these lines:</p>
- <pre>
-String title = extras.getString(NotesDbAdapter.KEY_TITLE);
-String body = extras.getString(NotesDbAdapter.KEY_BODY);</pre>
- </li>
- <li>We will also get rid of the properties that were being passed in
- the <code>extras</code> Bundle, which we were using to set the title
- and body text edit values in the UI. So delete:
- <pre>
-if (title != null) {
- mTitleText.setText(title);
-}
-if (body != null) {
- mBodyText.setText(body);
-}</pre>
- </li>
- </ol>
-
-<h2>Step 2</h2>
-
-<p>Create a class field for a <code>NotesDbAdapter</code> at the top of the NoteEdit class:</p>
- <pre> private NotesDbAdapter mDbHelper;</pre>
-<p>Also add an instance of <code>NotesDbAdapter</code> in the
- <code>onCreate()</code> method (right below the <code>super.onCreate()</code> call):</p>
- <pre>
- mDbHelper = new NotesDbAdapter(this);<br>
- mDbHelper.open();</pre>
-
-<h2>Step 3</h2>
-
-<p>In <code>NoteEdit</code>, we need to check the <var>savedInstanceState</var> for the
-<code>mRowId</code>, 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).</p>
- <ol>
- <li>
- Replace the code that currently initializes the <code>mRowId</code>:<br>
- <pre>
- mRowId = null;
-
- Bundle extras = getIntent().getExtras();
- if (extras != null) {
- mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
- }
- </pre>
- with this:
- <pre>
- mRowId = (savedInstanceState == null) ? null :
- (Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
- if (mRowId == null) {
- Bundle extras = getIntent().getExtras();
- mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
- : null;
- }
- </pre>
- </li>
- <li>
- Note the null check for <code>savedInstanceState</code>, and we still need to load up
- <code>mRowId</code> from the <code>extras</code> Bundle if it is not
- provided by the <code>savedInstanceState</code>. This is a ternary operator shorthand
- to safely either use the value or null if it is not present.
- </li>
- <li>
- Note the use of <code>Bundle.getSerializable()</code> instead of
- <code>Bundle.getLong()</code>. The latter encoding returns a <code>long</code> primitive and
- so can not be used to represent the case when <code>mRowId</code> is <code>null</code>.
- </li>
- </ol>
-
-<h2>Step 4</h2>
-
-<p>Next, we need to populate the fields based on the <code>mRowId</code> if we
- have it:</p>
- <pre>populateFields();</pre>
- <p>This goes before the <code>confirmButton.setOnClickListener()</code> line.
- We'll define this method in a moment.</p>
-
-<h2>Step 5</h2>
-
-<p>Get rid of the Bundle creation and Bundle value settings from the
- <code>onClick()</code> 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 <code>setResult()</code>:</p>
- <pre>
-public void onClick(View view) {
- setResult(RESULT_OK);
- finish();
-}</pre>
- <p>We will take care of storing the updates or new notes in the database
- ourselves, using the life-cycle methods.</p>
-
- <p>The whole <code>onCreate()</code> method should now look like this:</p>
- <pre>
-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) ? null :
- (Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
-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();
- }
-
-});</pre>
-
-<h2>Step 6</h2>
-
-<p>Define the <code>populateFields()</code> method.</p>
- <pre>
-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)));
- }
-}</pre>
-<p>This method uses the <code>NotesDbAdapter.fetchNote()</code> method to find the right note to
-edit, then it calls <code>startManagingCursor()</code> from the <code>Activity</code> 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.</p>
-
-
-<h2>Step 7</h2>
-
- <div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>Why handling life-cycle events is important</h2>
- <p>If you are used to always having control in your applications, you
- might not understand why all this life-cycle work is necessary. The reason
- is that in Android, you are not in control of your Activity, the
- operating system is!</p>
- <p>As we have already seen, the Android model is based around activities
- calling each other. When one Activity calls another, the current Activity
- is paused at the very least, and may be killed altogether if the
- system starts to run low on resources. If this happens, your Activity will
- have to store enough state to come back up later, preferably in the same
- state it was in when it was killed.</p>
- <p>
- Activities have a <a
-href="{@docRoot}guide/components/activities.html#Lifecycle">well-defined life
-cycle</a>.
- Lifecycle events can happen even if you are not handing off control to
- another Activity explicitly. For example, perhaps a call comes in to the
- handset. If this happens, and your Activity is running, it will be swapped
- out while the call Activity takes over.</p>
- </div>
- </div>
-
-<p>Still in the <code>NoteEdit</code> class, we now override the methods
- <code>onSaveInstanceState()</code>, <code>onPause()</code> and
- <code>onResume()</code>. These are our life-cycle methods
- (along with <code>onCreate()</code> which we already have).</p>
-
-<p><code>onSaveInstanceState()</code> is called by Android if the
- Activity is being stopped and <strong>may be killed before it is
- resumed!</strong> 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 <code>onCreate()</code> method, and in fact the
- <code>savedInstanceState</code> Bundle passed in to <code>onCreate()</code> is the same
- Bundle that you construct as <code>outState</code> in the
- <code>onSaveInstanceState()</code> method.</p>
-
-<p><code>onPause()</code> and <code>onResume()</code> are also
- complimentary methods. <code>onPause()</code> is always called when the
- Activity ends, even if we instigated that (with a <code>finish()</code> 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
- <code>onPause()</code> as well, to take up less resources when in the
- passive state. <code>onResume()</code> will call our <code>populateFields()</code> method
- to read the note out of the database again and populate the fields.</p>
-
-<p>So, add some space after the <code>populateFields()</code> method
- and add the following life-cycle methods:</p>
- <ol type="a">
- <li><code>
- onSaveInstanceState()</code>:
- <pre>
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- saveState();
- outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
- }</pre>
- <p>We'll define <code>saveState()</code> next.</p>
- </li>
- <li><code>
- onPause()</code>:
- <pre>
- @Override
- protected void onPause() {
- super.onPause();
- saveState();
- }</pre>
- </li>
- <li><code>
- onResume()</code>:
- <pre>
- @Override
- protected void onResume() {
- super.onResume();
- populateFields();
- }</pre>
- </li>
- </ol>
-<p>Note that <code>saveState()</code> must be called in both <code>onSaveInstanceState()</code>
-and <code>onPause()</code> to ensure that the data is saved. This is because there is no
-guarantee that <code>onSaveInstanceState()</code> will be called and because when it <em>is</em>
-called, it is called before <code>onPause()</code>.</p>
-
-
-<h2 style="clear:right;">Step 8</h2>
-
-<p>Define the <code>saveState()</code> method to put the data out to the
-database.</p>
- <pre>
- 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);
- }
- }</pre>
- <p>Note that we capture the return value from <code>createNote()</code> and if a valid row ID is
- returned, we store it in the <code>mRowId</code> 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).</p>
-
-
-<h2 style="clear:right;">Step 9</h2>
-
-<p>Now pull out the previous handling code from the
- <code>onActivityResult()</code> method in the <code>Notepadv3</code>
- class.</p>
-<p>All of the note retrieval and updating now happens within the
- <code>NoteEdit</code> life cycle, so all the <code>onActivityResult()</code>
- method needs to do is update its view of the data, no other work is
- necessary. The resulting method should look like this:</p>
-<pre>
-@Override
-protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
- super.onActivityResult(requestCode, resultCode, intent);
- fillData();
-}</pre>
-
-<p>Because the other class now does the work, all this has to do is refresh
- the data.</p>
-
-<h2>Step 10</h2>
-
-<p>Also remove the lines which set the title and body from the
- <code>onListItemClick()</code> method (again they are no longer needed,
- only the <code>mRowId</code> is):</p>
-<pre>
- Cursor c = mNotesCursor;
- c.moveToPosition(position);</pre>
-<br>
-and also remove:
-<br>
-<pre>
- i.putExtra(NotesDbAdapter.KEY_TITLE, c.getString(
- c.getColumnIndex(NotesDbAdapter.KEY_TITLE)));
- i.putExtra(NotesDbAdapter.KEY_BODY, c.getString(
- c.getColumnIndex(NotesDbAdapter.KEY_BODY)));</pre>
-<br>
-so that all that should be left in that method is:
-<br>
-<pre>
- super.onListItemClick(l, v, position, id);
- Intent i = new Intent(this, NoteEdit.class);
- i.putExtra(NotesDbAdapter.KEY_ROWID, id);
- startActivityForResult(i, ACTIVITY_EDIT);</pre>
-
- <p>You can also now remove the mNotesCursor field from the class, and set it back to using
- a local variable in the <code>fillData()</code> method:
-<br><pre>
- Cursor notesCursor = mDbHelper.fetchAllNotes();</pre></p>
- <p>Note that the <code>m</code> in <code>mNotesCursor</code> denotes a member field, so when we
- make <code>notesCursor</code> a local variable, we drop the <code>m</code>. Remember to rename the
- other occurrences of <code>mNotesCursor</code> in your <code>fillData()</code> method.
-</ol>
-<p>
-Run it! (use <em>Run As -> Android Application</em> on the project right
-click menu again)</p>
-
-<h2>Solution and Next Steps</h2>
-
-<p>You can see the solution to this exercise in <code>Notepadv3Solution</code>
-from
-the zip file to compare with your own.</p>
-<p>
-When you are ready, move on to the <a href="notepad-extra-credit.html">Tutorial
-Extra Credit</a> exercise, where you can use the Eclipse debugger to
-examine the life-cycle events as they happen.</p>
diff --git a/docs/html/training/notepad/notepad-extra-credit.jd b/docs/html/training/notepad/notepad-extra-credit.jd
deleted file mode 100644
index 8ab2021..0000000
--- a/docs/html/training/notepad/notepad-extra-credit.jd
+++ /dev/null
@@ -1,71 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Extra Credit
-parent.title=Notepad Tutorial
-parent.link=index.html
-@jd:body
-
-
-<p><em>In this exercise, you will use the debugger to look at the work you did
-in Exercise 3. This exercise demonstrates:</em></p>
-<ul>
-<li><em>How to set breakpoints to observe execution</em> </li>
-<li><em>How to run your application in debug mode</code></em></li>
-</ul>
-
-<div style="float:right;white-space:nowrap">
-
- [<a href="notepad-ex1.html">Exercise 1</a>]
- [<a href="notepad-ex2.html">Exercise 2</a>]
- [<a href="notepad-ex3.html">Exercise 3</a>]
- <span style="color:#BBB;">
- [<a href="notepad-extra-credit.html" style="color:#BBB;">Extra Credit</a>]
- </span>
-</div>
-
-<h2>Step 1</h2>
-
-<p>Using the working <code>Notepadv3</code>, put breakpoints in the code at the
- beginning of the <code>onCreate()</code>, <code>onPause()</code>,
- <code>onSaveInstanceState()</code> and <code>onResume()</code> methods in the
- <code>NoteEdit</code> 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 <em>Toggle Breakpoint</em>, you
-should see a blue dot appear).</p>
-
-<h2>Step 2</h2>
-
-<p>Now start the notepad demo in debug mode:</p>
-
-<ol type="a">
- <li>
- Right click on the <code>Notepadv3</code> project and from the Debug menu
- select <em>Debug As -> Android Application.</em></li>
- <li>
- The Android emulator should say <em>"waiting for debugger to connect"</em>
- briefly and then run the application.</li>
- <li>
- If it gets stuck on the waiting... screen, quit the emulator and Eclipse,
- from the command line do an <code>adb kill-server</code>, and then restart
-Eclipse and try again.</li></ol>
-
- <h2>Step 3</h2>
-
-<p>When you edit or create a new note you should see the breakpoints getting
- hit and the execution stopping.</p>
-
- <h2>Step 4</h2>
-
-<p>Hit the Resume button to let execution continue (yellow rectangle with a
-green triangle to its right in the Eclipse toolbars near the top).</p>
-
-<h2>Step 5</h2>
-
-<p>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.</p>
-
-<p>The Android Eclipse plugin not only offers excellent debugging support for
-your application development, but also superb profiling support. You can also
-try using <a href="{@docRoot}tools/help/traceview.html">Traceview</a> to profile your application. If your application is running too slow, this can help you
-find the bottlenecks and fix them.</p>
-
diff --git a/docs/html/training/notepad/notepad-index.jd b/docs/html/training/notepad/notepad-index.jd
deleted file mode 100644
index fde43fa..0000000
--- a/docs/html/training/notepad/notepad-index.jd
+++ /dev/null
@@ -1,144 +0,0 @@
-excludeFromSuggestions=true
-page.title=Notepad Tutorial
-@jd:body
-
-
-<p>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. </p>
-
-<p>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. </p>
-
-<p>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
-<a href="{@docRoot}samples/NotePad/index.html">Sample Code</a> documentation. </p>
-
-
-<a name="who"></a>
-<h2>Who Should Use this Tutorial</h2>
-
-<p>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. </p>
-
-<p>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 <a href="{@docRoot}intro/anatomy.html">Overview of an Android
-Application</a> before continuing. </p>
-
-<p>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. </p>
-
-<a name="preparing"></a>
-<h2>Preparing for the Exercises</h2>
-
-<p>This tutorial builds on the information provided in the <a
-href="{@docRoot}intro/installing.html">Installing the SDK</a> and <a
-href="{@docRoot}intro/hello-android.html">Hello Android</a>
-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.</p>
-
-<p>To prepare for this lesson:</p>
-
-<ol>
- <li>Download the <a href="codelab/NotepadCodeLab.zip">project
- exercises archive (.zip)</a></li>
- <li>Unpack the archive file to a suitable location on your machine</li>
- <li>Open the <code>NotepadCodeLab</code> folder</li>
-</ol>
-
-<p>Inside the <code>NotepadCodeLab</code> folder, you should see six project
-files: <code>Notepadv1</code>,
- <code>Notepadv2</code>, <code>Notepadv3</code>,
- <code>Notepadv1Solution</code>, <code>Notepadv2Solution</code>
- and <code>Notepadv3Solution</code>. The <code>Notepadv#</code> projects are
-the starting points for each of the exercises, while the
-<code>Notepadv#Solution</code> projects are the exercise
- solutions. If you are having trouble with a particular exercise, you
- can compare your current work against the exercise solution.</p>
-
-<a name="exercises"></a>
-<h2> Exercises</h2>
-
- <p>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.</p>
-
- <table border="0" style="padding:4px;spacing:2px;" summary="This
-table lists the
-tutorial examples and describes what each covers. ">
- <tr>
- <th width="120"><a href="{@docRoot}intro/tutorial-ex1.html">Exercise
-1</a></th>
- <td>Start here. Construct a simple notes list that lets the user add new notes but not
-edit them. Demonstrates the basics of <code>ListActivity</code> and creating
-and handling
- menu options. Uses a SQLite database to store the notes.</td>
- </tr>
- <tr>
- <th><a href="{@docRoot}intro/tutorial-ex2.html">Exercise 2</a></th>
- <td>Add 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
-<code>startActivityForResult()</code>.</td>
- </tr>
- <tr>
- <th><a href="{@docRoot}intro/tutorial-ex3.html">Exercise 3</a></th>
- <td>Add handling of life-cycle events to
-the application, to let it
-maintain application state across the life cycle. </td>
- </tr>
- <tr>
- <th><a href="{@docRoot}intro/tutorial-extra-credit.html">Extra
-Credit</a></th>
- <td>Demonstrates 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.</td>
- </tr>
-</table>
-
-
-<a name="other"></a>
-<h2>Other Resources and Further Learning</h2>
-<ul>
-<li>For a lighter but broader introduction to concepts not covered in the
-tutorial,
-take a look at <a href="{@docRoot}kb/commontasks.html">Common Android Tasks</a>.</li>
-<li>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 <code>samples/</code> directory of your downloaded SDK.</li>
-<li>This tutorial draws from the full Notepad application included in the
-<code>samples/</code> 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:</li>
- <ul>
- <li>Setting up a custom striped list for the list of notes.</li>
- <li>Creating a custom text edit view that overrides the <code>draw()</code>
-method to
- make it look like a lined notepad.</li>
- <li>Implementing a full <code>ContentProvider</code> for notes.</li>
- <li>Reverting and discarding edits instead of just automatically saving
-them.</li>
-</ul>
-</ul>
diff --git a/docs/html/training/performance/battery/network/action-any-traffic.jd b/docs/html/training/performance/battery/network/action-any-traffic.jd
new file mode 100644
index 0000000..eafb3b8
--- /dev/null
+++ b/docs/html/training/performance/battery/network/action-any-traffic.jd
@@ -0,0 +1,100 @@
+page.title=Optimizing General Network Use
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#compress-data">Compress Data</a>
+ <li><a href="#cache-locally">Cache Files Locally</a></li>
+ <li><a href="#pre-fetch">Optimize Pre-Fetch Cache Size</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+ In general, reducing the amount of network traffic helps reduce battery drain.
+ In addition to the battery-optimization techniques of the previous lessons,
+ you should look at these general-purpose techniques and see if you can apply
+ them to your app.
+</p>
+
+<p>
+ This lesson briefly covers techniques that you can use to lower network traffic and
+ consequently reduce the battery drain caused by your app.
+</p>
+
+<h2 id="compress-data">Compress Data</h2>
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/IwxIIUypnTE?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+
+<p>
+ Reducing the amount of data sent or received over a network connection also
+ reduces the duration of the connection, which conserves battery. You can:
+</p>
+
+<ul>
+ <li>Compress data, using a compression technique such as GZIP compression.</li>
+
+ <li>Use succinct data protocols. While JSON and XML offer human-readability, and
+ language-flexibility, they are bandwidth-heavy formats, with
+ high serialization costs in the Android platform. Binary serialization formats,
+ such as <a href="https://developers.google.com/protocol-buffers/">Protocol Buffers</a> or
+ <a href="https://google.github.io/flatbuffers/">FlatBuffers</a> offer a smaller on-the-wire
+ packet size, as well as faster encoding and decoding time. If your application transfers a lot
+ of serialized data on a regular basis, these formats can yield benefits for decoding time and
+ transfer size.
+ </li>
+</ul>
+
+
+<h2 id="cache-locally">Cache Files Locally</h2>
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/7lxVqqWwTb0?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: left; margin: 0 20px 20px 0;"></iframe>
+
+
+<p>
+ Your app can avoid downloading duplicate data by caching. Always cache static resources,
+ including on-demand downloads such as full size images, and cache them for as long as reasonably
+ possible.
+</p>
+
+<p>
+ For example, you should consider this approach for a networked app that displays data from
+ user-initiated network requests as the primary content on the screen. When the user opens this
+ screen the first time, the app should display a splash screen. Subsequent loads should initially
+ load with the data that was cached from the last network request. The screen reloads with
+ new data once the network request is complete.
+</p>
+
+<p>
+ To learn about caching, watch the video. To implement caching in your app, see <a href=
+ "{@docRoot}training/efficient-downloads/redundant_redundant.html#LocalCache">Cache Files
+ Locally</a>.
+</p>
+
+
+<h2 id="pre-fetch">Optimize Pre-Fetch Cache Size</h2>
+
+<p>
+ Optimize pre-fetch cache size based on local file system size and current network connectivity.
+ You can use the connectivity manager to determine what type of networks (Wi-FI, LTE, HSPAP, EDGE,
+ GPRS) are active and modify your pre-fetching routines to minimize battery load.
+</p>
+
+<p>
+ For more information, see
+ <a href="{@docRoot}training/efficient-downloads/connectivity_patterns.html#Bandwidth">Use
+ Modifying your Download Patterns Based on the Connectivity Type</a>.
+</p>
diff --git a/docs/html/training/performance/battery/network/action-app-traffic.jd b/docs/html/training/performance/battery/network/action-app-traffic.jd
new file mode 100644
index 0000000..d62461e
--- /dev/null
+++ b/docs/html/training/performance/battery/network/action-app-traffic.jd
@@ -0,0 +1,134 @@
+page.title=Optimizing App-Initiated Network Use
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#batch-schedule">Batch and Schedule Network Requests</a>
+ <li><a href="#check-connect">Allow System to Check for Connectivity</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+ Network traffic initiated by your app can usually be significantly optimized, since you can plan
+ for what network resources it needs and set a schedule for accessing them. By applying careful
+ scheduling, you can create significant periods of rest for the device radio and, thereby, save
+ power. There are several Android APIs that can help with network access scheduling, and some of
+ these functions can coordinate network access for other apps, further optimizing battery
+ performance.
+</p>
+
+<p>
+ This lesson teaches you how to reduce battery consumption by applying techniques for
+ optimizing app-initiated network traffic.
+</p>
+
+
+<h2 id="batch-schedule">Batch and Schedule Network Requests</h2>
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/Ecz5WDZoJok?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+
+<p>
+ On a mobile device, the process of turning on the radio, making a connection, and keeping the
+ radio awake uses a large amount of power. For this reason, processing individual requests at
+ random times can consume significant power and reduce battery life. A more efficient approach is
+ to queue a set of network requests and process them together. This allows the system to pay the
+ power cost of turning on the radio just once, and still get all the data requested by an app.
+</p>
+
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/orlRuEwlDoM?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: left; margin: 0 20px 20px 0;"></iframe>
+
+<p>
+ Using a network access scheduler API for queuing and processing your app data requests can
+ significantly increase the power efficiency of your app. Schedulers conserve battery power by
+ grouping requests together for the system to process. They can further improve efficiency by
+ delaying some requests until other requests wake up the mobile radio, or waiting until the
+ device is charging. Schedulers defer and batch network requests system-wide, across all apps on
+ the device, which gives them an optimizing advantage over what any individual app can do.
+</p>
+
+
+<h3 id="choosing-scheduler">Choosing a batch-and-scheduling API</h3>
+
+<p>
+ Android provides three different APIs for your app to batch and schedule network requests. For
+ most operations, these techniques are functionally equivalent. These APIs are listed in the
+ following table with the most highly recommended first.
+</p>
+
+<table>
+ <tr>
+ <th>Scheduler</th>
+ <th>Requirements</th>
+ <th>Implementation Ease</th>
+ </tr>
+ <tr>
+ <td style="white-space: nowrap;"><a href="https://developers.google.com/cloud-messaging/network-manager">
+ GCM Network Manager</a></td>
+ <td>GCM Network Manager requires that your app use the Google Play services client library,
+ version 6.1.11 or higher — use the latest available version.</td>
+ <td>Straightforward</td>
+ </tr>
+ <tr>
+ <td><a href="{@docRoot}reference/android/app/job/JobScheduler.html">Job Scheduler</a></td>
+ <td>Job Scheduler does not require Google Play services, but is available only when targeting
+ Android 5.0 (API level 21) or higher.</td>
+ <td>Straightforward</td>
+ </tr>
+ <tr>
+ <td>
+ <a href="{@docRoot}training/sync-adapters/index.html">Sync Adapter for scheduled syncs</a>
+ </td>
+ <td>Sync Adapter does not require the Google Play services client library and has been
+ available since Android 2.0 (API level 5).</td>
+ <td>Complex</td>
+ </tr>
+</table>
+
+
+<p class="note">
+ <strong>Note:</strong> For scheduled data synchronization, you should <em>always</em> prefer GCM
+ Network Manager or Job Scheduler over Sync Adapter if your requirements allow it.
+</p>
+
+
+<h2 id="check-connect">Allow System to Check for Connectivity</h2>
+
+<p>
+ One of the most serious and unexpected causes of battery drain is when a user travels beyond the
+ reach of any cell tower or access point. In this situation, the user is typically not using their
+ device, but they notice the device getting warm, and then see that the battery is low or has run
+ out.
+</p>
+
+<p>
+ In this scenario, the problem is that an app is running a background process that keeps
+ waking up the mobile radio at regular intervals to search for a cellular signal, but finds none.
+ Searching for a cell signal is one of the most power-draining operations there is.
+</p>
+
+<p>
+ The way to avoid causing this kind of problem for a user with your app is to use a
+ battery-efficient method for checking connectivity. For app-initiated network requests, use a
+ <a href="#choosing-scheduler">scheduler</a>, which automatically uses <a href=
+ "{@docRoot}training/monitoring-device-state/connectivity-monitoring.html">Connectivity
+ Manager</a> to check for connectivity before calling into your app. As a result, if there's no
+ network, the Connectivity Manager conserves battery because it performs the connectivity check
+ itself, without loading the app to run the check. Battery is further conserved because schedulers
+ use <a href="http://en.wikipedia.org/wiki/Exponential_backoff" class="external-link">exponential
+ backoff</a> to check for connectivity less frequently as time progresses.
+</p>
diff --git a/docs/html/training/performance/battery/network/action-server-traffic.jd b/docs/html/training/performance/battery/network/action-server-traffic.jd
new file mode 100644
index 0000000..e568c8a
--- /dev/null
+++ b/docs/html/training/performance/battery/network/action-server-traffic.jd
@@ -0,0 +1,78 @@
+page.title=Optimizing Server-Initiated Network Use
+trainingnavtop=true
+
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#gcm">Send Server Updates with GCM</a>
+</ol>
+
+</div>
+</div>
+
+<p>
+ Network traffic sent by server programs to your app can be challenging to optimize. A
+ solution to this problem is for your appp to periodically poll the server to check for updates.
+ This approach can waste network connection and power when your app starts up a device's radio,
+ only to receive an answer that no new data is available. A far more efficient approach would be
+ for the to notify your app when it has new data, but figuring out how to send a notification
+ from your server to potentially thousands of devices was previously no easy feat.
+</p>
+
+<p>
+ The <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud Messaging</a> (GCM)
+ service solves this communication problem by allowing your servers to send notifications to
+ instances of your app wherever they are installed, enabling greater network efficiency and
+ lowering power usage.
+</p>
+
+<p>
+ This lesson teaches you how to apply the GCM service to reduce network use for server-initiated
+ actions and reduce battery consumption.
+</p>
+
+
+<h2 id="gcm">Send Server Updates with GCM</h2>
+
+<p>
+ Google Cloud Messaging (GCM) is a lightweight mechanism used to transmit brief messages from an
+ app server to your app. Using GCM, your app server uses a message-passing
+ mechanism to notify your app that there is new data available. This approach eliminates network
+ traffic that your app would perform, by not contacting a backend server for new data when no
+ data is available.
+</p>
+
+<p>
+ An example use of GCM is an app that lists speaker sessions at a conference. When sessions are
+ updated on your server, the server sends a brief message to your app telling it updates are
+ available. Your app can then call the server to update the sessions on the device only when
+ the server has new data.
+</p>
+
+<p>
+ GCM is more efficient than having your app poll for changes on the server. The GCM service
+ eliminates unnecessary connections where polling would return no updates, and it avoids running
+ periodic network requests that could cause a device's radio to power up. Since GCM can be used by
+ many apps, using it in your app reduces the total number of network connections needed on a
+ device and allows the device radio to sleep more often.
+</p>
+
+<p>
+ For more information about GCM and how to implement it for your app, see
+ <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud Messaging</a>.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> When using GCM, your app can pass messages in normal or high priority.
+ Your server should typically use <a href=
+ "https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message">
+ normal priority</a> to deliver messages. Using this priority level prevents devices from being
+ woken up if they are inactive and in a low-power <a href=
+ "https://developer.android.com/training/monitoring-device-state/doze-standby.html">Doze</a>
+ state. Use high priority messages only if absolutely required.
+</p>
diff --git a/docs/html/training/performance/battery/network/action-user-traffic.jd b/docs/html/training/performance/battery/network/action-user-traffic.jd
new file mode 100644
index 0000000..e3ddaa2
--- /dev/null
+++ b/docs/html/training/performance/battery/network/action-user-traffic.jd
@@ -0,0 +1,128 @@
+page.title=Optimizing User-Initiated Network Use
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#pre-fetch-data">Pre-fetch Network Data</a>
+ <li><a href="#check-or-listen">Check for Connectivity or Listen for Changes</a></li>
+ <li><a href="#reduce-connections">Reduce the Number of Connections</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+ Quick handling of user requests helps ensure a good user experience, especially when it comes to
+ user actions that require network access. You should prioritize low latency over power
+ conservation to provide the fastest response when optimizing network use that is a direct result
+ of user actions. Attaining an optimal network traffic profile for your app, while making sure
+ that your users get fast responses, can be a bit challenging.
+</p>
+
+<p>
+ This lesson teaches you how to optimize network use for user-initiated
+ actions and reduce battery consumption.
+</p>
+
+
+<h2 id="pre-fetch-data">Pre-fetch Network Data</h2>
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/Rk1u7VVmadE?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+<p>
+ Pre-fetching data is an effective way to reduce the number of independent data transfer sessions
+ that your app runs. With pre-fetching, when the user performs an action in your app, the app
+ anticipates which data will most likely be needed for the next series of user actions and fetches
+ that data in bulk. Battery power consumption is reduced for two reasons:
+ <ul>
+ <li>
+ Because your app pre-fetches data only when the the mobile radio is already awake from
+ the user's action, and so does not incur the overhead of waking up the mobile radio.
+ </li>
+ <li>
+ The app pre-fetches data for anticipated user actions, each of which might otherwise
+ require separate requests that each incur waking up the mobile radio.
+ </li>
+ </ul>
+
+</p>
+
+<p class="note">
+ <strong>Tip:</strong> To explore whether your app might benefit from pre-fetching, review your
+ app's network traffic and look for situations where a specific series of user actions almost
+ always results in multiple network requests over the course of the task. For instance, an app
+ that incrementally downloads article content as a user views it might be able to pre-fetch one or
+ more articles in categories the user is known to view.
+</p>
+
+<p>
+ Watch the video on effective pre-fetching which describes what pre-fetching is, where to
+ use it, and how much data to pre-fetch. For more details, see <a href=
+ "{@docRoot}training/efficient-downloads/efficient-network-access.html#PrefetchData">Optimizing
+ Downloads for Efficient Network Access</a>.
+</p>
+
+
+<h2 id="check-or-listen">Check for Connectivity or Listen for Changes</h2>
+
+<p>
+ Searching for a cell signal is one of the most power-draining operations on a mobile
+ device. Your app should always check for connectivity before sending a user-initiated network
+ request. If you use a scheduling service, <a href=
+ "{@docRoot}training/performance/battery/network/action-app-traffic.html#choosing-scheduler">Schedulers</a>
+ do this automatically for you.
+</p>
+
+<ul>
+ <li>If only certain buttons in your activity depend on a network connection, use <a href=
+ "{@docRoot}reference/android/net/ConnectivityManager.html">Connectivity Manager</a> to check for
+ a network connection before sending the network request, as instructed in <a href=
+ "{@docRoot}training/monitoring-device-state/connectivity-monitoring.html#MonitorChanges">Monitor
+ for Changes in Connectivity</a>. If there's no network, the app can save battery by not forcing
+ the mobile radio to search.
+ </li>
+
+ <li>If your entire activity's user interface is non-functional without network access, then use
+ <a href="{@docRoot}training/monitoring-device-state/manifest-receivers.html">Manipulate Broadcast
+ Receivers on Demand</a>. This technique listens for connectivity changes when your activity is in
+ the foreground, and prevents network requests from proceeding when no connectivity exists. That
+ is, if your app detects that connectivity has been lost, it disables all of its receivers, except
+ for the connectivity-change receiver. An example would be a news app that presents an activity
+ with a full-screen view of news snippets and does no pre-fetching. Any snippet a user taps would
+ require a network connection.
+ </li>
+</ul>
+
+
+<p>
+ A best practice for user-initiated traffic is to first check for a connection using <a href=
+ "{@docRoot}reference/android/net/ConnectivityManager.html">Connectivity Manager</a>, and if there
+ is no connection, <a href="#heading=h.a114i7ic2bxc">schedule</a> the network request for when the
+ connection is made. Schedulers will use techniques such as exponential backoff to save battery,
+ where each time the attempt to connect fails, the scheduler doubles the delay before the next
+ retry.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> To check for connectivity for app-initiated traffic, see <a href=
+ "action-app-traffic.html#check-connect">Optimizing App-Initiated Network Use</a>.
+</p>
+
+
+<h2 id="reduce-connections">Reduce the Number of Connections</h2>
+
+<p>
+ In general, it's more efficient to reuse existing network connections than to initiate new ones.
+ Reusing connections also allows the network to more intelligently react to congestion and related
+ network data issues. For more information on reducing the number of connections used by your app,
+ see <a href="{@docRoot}training/efficient-downloads/efficient-network-access.html#ReduceConnections">
+ Optimizing Downloads for Efficient Network Access</a>.
+</p>
diff --git a/docs/html/training/performance/battery/network/analyze-data.jd b/docs/html/training/performance/battery/network/analyze-data.jd
new file mode 100644
index 0000000..593201a
--- /dev/null
+++ b/docs/html/training/performance/battery/network/analyze-data.jd
@@ -0,0 +1,215 @@
+page.title=Analyzing Network Traffic Data
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#general-traffic">Analyze App Network Traffic</a></li>
+ <li><a href="#traffic-types">Analyze Network Traffic Types</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+ In the previous section, you tagged your app code with traffic identifiers, ran tests, and
+ collected data. This lesson teaches you how to look at the network traffic data you have
+ collected and directs you to actions for improving your app's networking performance and
+ reducing power consumption.
+</p>
+
+
+<h2 id="general-traffic">Analyze App Network Traffic</h2>
+
+<p>
+ Efficient use of network resources by an app is characterized by significant periods where
+ the network hardware is not in use.
+
+ On mobile devices, there is a significant cost associated with starting up the radio
+ to send or receive data, and with keeping the mobile radio active for long periods. If your app
+ is accessing the network efficiently, you should see that its communications over the network are
+ tightly grouped together, well spaced with periods where the app is making no connection requests.
+</p>
+
+<p>
+ Figure 1 shows suboptimal network traffic from app, as measured by the Network Traffic tool. The
+ app is making frequent network requests. This traffic has few periods of
+ rest where the radio could switch to a standby, low-power mode. The network access behavior of
+ this app is likely to keep the radio on for extended periods of time, which is
+ battery-inefficient.
+</p>
+
+<img src="{@docRoot}images/training/performance/suboptimal_network_traffic_pattern.png"
+ alt="" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Battery-inefficient network activity measured from an app.
+</p>
+
+<p>
+ Figure 2 shows an optimal network traffic pattern. The app sends network requests in bursts,
+ separated by long periods of no traffic where the radio can switch to standby. This chart shows
+ the same amount of work being done as Figure 1, but the requests have been shifted and grouped to
+ allow the radio to be in standby most of the time.
+</p>
+
+<img src="{@docRoot}images/training/performance/optimal_network_traffic_pattern.png"
+ alt="" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> Battery-efficient network activity measured from an app.
+</p>
+
+<p>
+ If the network traffic for your app looks similar to the graph in Figure 2, you are in good
+ shape! Congratulations! You may want to pursue further networking efficiency by checking out the
+ techniques described in <a href=
+ "{@docRoot}training/performance/battery/network/action-any-traffic.html">Optimizing General Network
+ Use</a>
+</p>
+
+<p>
+ If the network traffic for your app looks more like the graph in Figure 1, it's time to take a
+ harder look at how your app accesses the network. You should start by analyzing what types of
+ network traffic your app is generating.
+</p>
+
+
+<h2 id="traffic-types">Analyze Network Traffic Types</h2>
+
+<p>
+ When you look at the network traffic generated by your app, you need to understand the source of
+ the traffic, so you can optimize it appropriately. Frequent network activity generated by your
+ app may be entirely appropriate if it is responding to user actions, but completely inappropriate
+ if you app is not in the foreground or if the device in a pocket or purse. This section discusses
+ how to analyze the types of network traffic being generated by your app and directs you to
+ actions you can take to improve performance.
+</p>
+
+<p>
+ In the previous lesson, you tagged your app code for different traffic types and used the Network
+ Traffic tool to collect data on your app and produce a graph of activity, as shown in Figure 3.
+</p>
+<img src="{@docRoot}images/training/performance/network_traffic_colors.png" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> Network traffic tagged for the three categories: user, app, and
+ server.
+</p>
+
+<p>
+ The Network Traffic tool colors traffic based on the tags you created in the previous lesson. The
+ colors are based on the traffic type <a href=
+ "{@docRoot}training/performance/battery/network/gather-data.html#constants">constants you defined</a> in
+ your app code. Refer back to your app code to confirm which constants represent user, app, or
+ server-initiated traffic.
+</p>
+
+<p>
+ The following sections discuss how to look at network traffic types and provides recommendations
+ on how to optimize traffic.
+</p>
+
+
+<h3 id="user">Analyzing user-initiated network traffic</h3>
+
+<p>
+ Network activity initiated by the user may be efficiently grouped together while a user is
+ performing a specific activity with your app, or spread out unevenly as the user requests additional
+ information your app needs to get. Your goal in analyzing user-initiated network traffic is to
+ look for patterns of frequent network use over time and attempt to create, or increase the size
+ of, periods where the network is not accessed.
+</p>
+
+<p>
+ The unpredictability of user requests makes it challenging to optimize this type of network use
+ in your app. In addition, users expect fast responses when they are actively using an app, so
+ delaying requests for efficiency can lead to poor user experiences. In general, you should
+ prioritize a quick response to the user over efficient use of the network while a user is
+ directly interacting with your app.
+</p>
+
+<p>
+ Here are some approaches for optimizing user-initiated network traffic:
+</p>
+
+<ul>
+ <li>
+ <a href="{@docRoot}training/performance/battery/network/action-user-traffic.html#pre-fetch-data">
+ Pre-fetch Network Data</a> - When the user performs an action in your app, the app
+ anticipates which data may be needed for the next user actions, fetches it in bulk
+ in a single connection, and holds it until the user requests it.
+ </li>
+
+ <li>
+ <a href="{@docRoot}training/performance/battery/network/action-user-traffic.html#check-or-listen">
+ Check for Connectivity or Listen for Changes</a> - Check for network connectivity or listen
+ for connectivity changes before performing an update.
+ </li>
+
+ <li>
+ <a href="{@docRoot}training/performance/battery/network/action-user-traffic.html#reduce-connections">
+ Reduce the Number of Connections</a> - Use server APIs that allow data to be downloaded in sets.
+ </li>
+</ul>
+
+<p class="caution">
+ <strong>Caution:</strong> Beware of network activity grouping bias in your user activity test
+ data! If you ran a set of user scenarios with your network testing plan, the graph of
+ user-initiated network access may be unrealistically grouped together, potentially causing you to
+ optimize for user behavior that does not actually occur. Make sure your user network test
+ scenarios reflect realistic use of your app.
+</p>
+
+
+<h3 id="app">Analyzing app-initiated network traffic</h3>
+
+<p>
+ Network activity initiated by your app code is typically an area where you can have a significant
+ impact on the efficient use of network bandwidth. In analyzing the network activity of your app,
+ look for periods of inactivity and determine if they can be increased. If you see patterns of
+ consistent network access from your app, look for ways to space out these accesses to allow the
+ device radio to switch into low power mode.
+</p>
+
+<p>
+ Here are some approaches for optimizing app-initiated network traffic:
+</p>
+
+<ul>
+ <li>
+ <a href="{@docRoot}training/performance/battery/network/action-app-traffic.html#batch-schedule">
+ Batch and Schedule Network Requests</a> - Defer your app's network requests so they can be
+ processed together and at a time which is advantageous for battery life.
+ </li>
+
+ <li>
+ <a href="{@docRoot}training/performance/battery/network/action-app-traffic.html#check-connect">
+ Allow System to Check for Connectivity</a> - Avoid the battery cost of running your app just
+ to check for a network connection when you can let the system run the check while your app
+ sleeps.
+ </li>
+</ul>
+
+
+<h3 id="server">Analyzing server-initiated network traffic</h3>
+
+<p>
+ Network activity initiated by servers communicating with your app is also typically an area where
+ you can have a significant impact on the efficient use of network bandwidth. In analyzing the
+ network activity from server connections, look for periods of inactivity and determine if they
+ can be increased. If you see patterns of consistent network activity from servers, look for ways
+ to space out this activity to allow the device radio to switch into low power mode.
+</p>
+
+<p>
+ Here is an approach for optimizing app-initiated network traffic:
+</p>
+
+<ul>
+ <li>
+ <a href="action-server-traffic.html#gcm">Use GCM for Server Updates</a> - Consider using
+ the Google Cloud Messaging service for server side updates instead of polling.
+ </li>
+</ul>
diff --git a/docs/html/training/performance/battery/network/gather-data.jd b/docs/html/training/performance/battery/network/gather-data.jd
new file mode 100644
index 0000000..32edcd5
--- /dev/null
+++ b/docs/html/training/performance/battery/network/gather-data.jd
@@ -0,0 +1,267 @@
+page.title=Collecting Network Traffic Data
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to </h2>
+<ol>
+ <li><a href="#tag-requests">Tag Network Requests</a></li>
+ <li><a href="#build-type">Configure a Network Test Build Type</a></li>
+ <li><a href="#deploy-apk">Deploy the Network Test APK</a></li>
+ <li><a href="#network-tool">Run Network Traffic Tool</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>
+ The network traffic generated by an app can have a significant impact on the battery life of the
+ device where it is running. In order to optimize that traffic, you need to both measure it and
+ identify its source. Network requests can come directly from a user action, requests from your own
+ app code, or from a server communicating with your app.
+</p>
+
+<p>
+ The <a href="{@docRoot}tools/debugging/ddms.html#network">Network Traffic tool</a> (part of the
+ DDMS tools) enables you to view how and when your app transfers data over a network.
+</p>
+
+<p>
+ This lesson shows you how to measure and categorize network requests by tagging your source code,
+ then shows you how to deploy, test and visualize your apps's network traffic.
+</p>
+
+
+<h2 id="tag-requests">Tag Network Requests</h2>
+
+<p>
+ Apps use the networking hardware on a device for various reasons. In order to properly optimize
+ your app's use of networking resources, you must understand how frequently your app is using the
+ network and for what reasons. For performance analysis purposes, you should break down use of
+ network hardware into these categories:
+</p>
+
+<ul>
+ <li>
+ <strong>User-initiated network requests</strong> - Requests initiated by the user, such as a
+ user request for an updated articles list in a news app.
+ </li>
+
+ <li>
+ <strong>App-initiated network requests</strong> - Requests initiated within Android app code
+ that are not used to immediately satisfy a user action, such as an app request to cache the
+ text of unread articles in a news app.
+ </li>
+
+ <li>
+ <strong>Server-initiated network requests</strong> - Requests initiated by a server to your app
+ that are not used to immediately satisfy a user action, such as notification of a newly
+ available article in a news app.
+ </li>
+</ul>
+
+<p>
+ This procedure shows you how to tag your app's source code with constants to categorize traffic
+ as one of these three request types. The Network Traffic tool represents each type of traffic
+ with a different color, so you can visualize and optimize each traffic stream separately.
+ The technique described here reports network traffic based on the execution of threads in your
+ app which you identify as a user, app or server source.
+</p>
+
+<ol>
+ <li>In your app's development project, define three constants to represent the different types
+ of network use:
+
+<pre id="constants">
+public static final int USER_INITIATED = 0x1000;
+public static final int APP_INITIATED = 0x2000;
+public static final int SERVER_INITIATED =0x3000;
+</pre>
+ </li>
+
+ <li>Find networking code in your app by searching for the most common classes used for
+ this purpose:
+ <ol type="a">
+ <li>In Android Studio, choose <strong>Edit > Find > Find in Path</strong>.</li>
+ <li>Paste the following string into the <strong>Text to find</strong> field:<br>
+ <code>extends GcmTaskService|extends JobService|extends
+ AbstractThreadedSyncAdapter|HttpUrlConnection|Volley|Glide|HttpClient</code>
+ </li>
+ <li>Check <strong>Regular expression</strong>.</li>
+ <li>Check <strong>File mask(s)</strong> and type <code>*.java</code>.</li>
+ <li>Click the <strong>Find</strong> button.</li>
+ </ol>
+ </li>
+
+<li>
+ Based on your findings in the previous step, tag your app's use of network traffic by adding the
+ {@link android.net.TrafficStats#setThreadStatsTag} method to each execution thread in your app
+ that uses network resources, as shown in the following code example.
+
+<pre>
+if (BuildConfig.NETWORK-TEST && Build.VERSION.SDK_INT >= 14) {
+ try {
+ TrafficStats.setThreadStatsTag(USER_INITIATED);
+ // make network request using HttpClient.execute()
+ } finally {
+ TrafficStats.clearThreadStatsTag();
+ }
+}
+</pre>
+
+ <p class="note">
+ <strong>Note:</strong> Ensure the tagging does not get into your production code by making
+ inclusion of this code conditional, based on the build type used to generate the APK.
+ In the example above, the <code>BuildConfig.NETWORK-TEST</code> field identifies this
+ APK as a test version.
+ </p>
+
+ </li>
+</ol>
+
+<p class="note">
+ <strong>Note:</strong> This technique for tagging network traffic from your app depends on
+ how the APIs that you are using access and manage network sockets. Some networking libraries
+ may not allow the {@link android.net.TrafficStats} utilities to tag traffic from your app.
+</p>
+
+<p>
+ For more information about tagging and tracking network traffic with the Network Traffic tool,
+ see <a href="http://tools.android.com/recent/detailednetworkusageinddms">Detailed Network Usage
+ in DDMS</a>.
+</p>
+
+
+<h2 id="build-type">Configure a Network Test Build Type</h2>
+
+<p>
+ When you run performance tests, your APK should be as close as possible to the production
+ build. In order to achieve this for your network testing, create a <code>network-test</code>
+ build type, rather than using <code>debug</code> build type.
+</p>
+
+<ol>
+ <li>Open your app in Android Studio.</li>
+ <li>Create a debuggable build type for your network test by modifying your project's
+ <code>build.gradle</code> file as shown in the following code example:
+
+<pre>
+android {
+ ...
+ buildTypes {
+ debug {
+ // debuggable true is default for the debug buildType
+ }
+ <strong>network-test {
+ debuggable true
+ }</strong>
+ }
+ ...
+}
+</pre>
+ </li>
+</ol>
+
+
+<h2 id="deploy-apk">Deploy the Network Test APK</h2>
+
+<p>
+ To deploy the APK generated by the {@code network-test} build type configured in the previous
+ proceedure:
+</p>
+
+<ol>
+ <li>Check that <strong>Developer Options</strong> are enabled on your test device. For
+ information about how to check and enable this option, see <a href=
+ "{@docRoot}tools/device.html#developer-device-options">Using Hardware Devices</a>.
+ </li>
+
+ <li>Using a USB cable, connect your test device to your development computer.
+ </li>
+
+ <li>In Android Studio, select <strong>Build Variants</strong> on the left edge of the window.
+ </li>
+
+ <li>Click the <strong>Sync Project with Gradle Files</strong> button to populate the
+ Build Variants list with <code>network-test</code> for the app module.
+ </li>
+
+ <li>Choose <code>network-test</code> from the list.
+ </li>
+
+ <li>Deploy the debuggable version of your app to your device by choosing
+ <strong>Run</strong> > <strong>Debug</strong>.
+ </li>
+</ol>
+
+
+<h2 id="network-tool">Run Network Traffic Tool</h2>
+
+<p>
+ The Network Traffic tool in Android Studio helps you see how your app uses network resources
+ in real time, while it is running.
+</p>
+
+<p>
+ To improve the repeatability of your testing, you should start with a known initial state for
+ your app by clearing app data. The following procedure includes a step that shows you how to
+ clear <em>all</em> app data including previously cached data and networking data. This step
+ puts your app back to a state where it must re-cache all previously cached data. Do not skip
+ this step.
+</p>
+
+<p>
+ To start the Network Traffic tool and visualize the network requests:
+</p>
+
+<ol>
+ <li>Start the Network Traffic tool by launching Android Studio and choosing <strong>Tools >
+ Android > Android Device Monitor</strong>. When asked, allow incoming network connections.
+ </li>
+
+ <li>In the Android Device Monitor window, click the <strong>DDMS</strong> button along the top
+ and choose the <strong>Network Statistics</strong> tab. If you don't see this tab, widen the
+ window and then try <strong>Window > Reset Perspective</strong>.
+ </li>
+
+ <li>Select your app to debug from the list of debuggable apps on your device in the
+ <strong>Devices</strong> tab, then click the <strong>Start</strong> button in the
+ <strong>Network Statistics</strong> tab.
+
+ <p class="note">
+ <strong>Note:</strong> You may be prompted to <strong>Allow USB Debugging</strong> on your
+ device. Select <strong>OK</strong> to allow debugging to proceed.
+ </p>
+ </li>
+
+ <li>Clear your app data using the following adb command:
+<pre class="no-pretty-print">
+adb shell pm clear <em>package.name.of.app</em>
+</pre>
+ </li>
+
+ <li>Start your app and run a testing plan that exercises your app's primary use cases. Your plan
+ should also allow for app idle time, where the user is not interacting with the app, to allow
+ app-initiated and server-initiated network access to occur.
+ </li>
+
+ <li>Repeat the test by clearing the app data and running your test plan again. You should repeat
+ the test a few times to verify the repeatability of your performance data.
+ </li>
+</ul>
+</ol>
+
+<p>
+ Use of tagging for network traffic helps you visually distinguish each request category by
+ producing a different color for each network traffic in the Network Traffic tool, as shown in
+ Figure 1.
+</p>
+
+<img src="{@docRoot}images/training/performance/network_traffic_colors.png" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Network traffic tagged for the three categories.
+</p>
+
diff --git a/docs/html/training/performance/battery/network/index.jd b/docs/html/training/performance/battery/network/index.jd
new file mode 100644
index 0000000..1da30cf
--- /dev/null
+++ b/docs/html/training/performance/battery/network/index.jd
@@ -0,0 +1,86 @@
+page.title=Reducing Network Battery Drain
+page.article=true
+
+page.tags=battery
+page.metaDescription=Learn how to optimize your app to reduce battery drain and use network resources efficiently.
+
+@jd:body
+
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/fEEulSk1kNY?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+<p>
+ Requests that your app makes to the network are a major cause of battery drain because they turn
+ on the power-hungry mobile or Wi-Fi radios. Beyond the power needed to send and receive packets,
+ these radios expend extra power just turning on and keeping awake. Something as simple as a
+ network request every 15 seconds can keep the mobile radio on continuously and quickly use up
+ battery power.
+</p>
+
+<p>
+ This lesson shows you how to tag your app's source code to categorize, visualize and color
+ your network requests according to how they are initiated. From there, each category
+ identifies areas of your app that you can make more battery-efficient.
+</p>
+
+
+<h2>Performance Actions</h2>
+
+<dl>
+ <dt>
+ <strong><a href="gather-data.html">
+ Collecting Network Traffic Data</a></strong>
+ </dt>
+ <dd>
+ Learn how to instrument your app's code and gather data on its use of network resources.
+ </dd>
+
+ <dt>
+ <strong><a href="analyze-data.html">
+ Analyzing Network Traffic Data</a></strong>
+ </dt>
+ <dd>
+ Learn how to analyze your app's use of network resources in response to user actions
+ and optimize it to reduce power consumption.
+ </dd>
+
+ <dt>
+ <strong><a href="action-user-traffic.html">
+ Optimizing User-Initiated Network Use</a></strong>
+ </dt>
+ <dd>
+ Learn how to optimize your app's use of network resources in response to user actions
+ to reduce power consumption.
+ </dd>
+
+ <dt>
+ <strong><a href="action-app-traffic.html">
+ Optimizing App-Initiated Network Use</a></strong>
+ </dt>
+ <dd>
+ Learn how to optimize your app's requests for network resources to reduce
+ power consumption.
+ </dd>
+
+ <dt>
+ <strong><a href="action-server-traffic.html">
+ Optimizing Server-Initiated Network Use</a></strong>
+ </dt>
+ <dd>
+ Learn how to optimize your app's requests for network resources and to reduce
+ power consumption.
+ </dd>
+
+ <dt>
+ <strong><a href="action-any-traffic.html">
+ Optimizing General Network Use</a></strong>
+ </dt>
+ <dd>
+ Learn how to optimize your app's requests for network resources and to reduce
+ power consumption.
+ </dd>
+
+</dl>
diff --git a/docs/html/training/permissions/best-practices.jd b/docs/html/training/permissions/best-practices.jd
new file mode 100644
index 0000000..dcdaf94
--- /dev/null
+++ b/docs/html/training/permissions/best-practices.jd
@@ -0,0 +1,247 @@
+page.title=Permissions Best Practices
+page.tags=permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+<h2>In this document</h2>
+<ul>
+ <li><a href="#perms-vs-intents">Consider Using an Intent</a></li>
+
+ <li><a href="#dont-overwhelm">Don't Overwhelm the User</a></li>
+
+ <li><a href="#explain">Explain Why You Need Permissions</a></li>
+
+ <li><a href="#testing">Test for Both Permissions Models</a></li>
+
+</ul>
+
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}training/basics/intents/index.html">Interacting
+ with Other Apps</a></li>
+ </ul>
+
+</div>
+</div>
+
+
+<p>
+It's easy for an app to overwhelm a user with permission requests. If a user
+finds the app frustrating to use, or the user is worried about what the app
+might be doing with the user's information, they may avoid using the app or
+uninstall it entirely. The following best practices can help you avoid such
+bad user experiences.
+</p>
+
+<h2 id="perms-vs-intents">Consider Using an Intent</h2>
+
+<p>
+ In many cases, you can choose between two ways for your app to perform a
+ task. You can have your app ask for permission to perform the operation
+ itself. Alternatively, you can have the app use an <em>intent</em> to have
+ another app perform the task.
+</p>
+
+<p>
+ For example, suppose your app needs to be able to take pictures with the
+ device camera. Your app can request the {@link
+ android.Manifest.permission#CAMERA CAMERA} permission, which allows your app
+ to access the camera directly. Your app would then use the camera APIs to
+ control the camera and take a picture. This approach gives your app full
+ control over the photography process, and lets you incorporate the camera UI
+ into your app.
+</p>
+
+<p>
+ However, if you don't need such complete control, you can use an {@link
+ android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} intent
+ to request an image. When you send the intent, the system prompts the user to
+ choose a camera app (if there isn't already a default camera app).
+ The user takes a picture with the selected camera app, and that app returns
+ the picture to your app's {@link
+ android.app.Activity#onActivityResult onActivityResult()} method.
+</p>
+
+<p>
+ Similarly, if you need to make a phone call, access the user's contacts, and
+ so on, you can do that by creating an appropriate intent, or you can request
+ the permission and access the appropriate objects directly. There are
+ advantages and disadvantages to each approach.
+</p>
+
+<p>
+ If you use permissions:
+</p>
+
+<ul>
+ <li>Your app has full control over the user experience when you perform the
+ operation. However, such broad control adds to the complexity of your task,
+ since you need to design an appropriate UI.
+ </li>
+
+ <li>The user is prompted to give permission once, either at run time or at
+ install time (depending on the user's Android version). After that, your app
+ can perform the operation without requiring additional interaction from the
+ user. However, if the user doesn't grant the permission (or revokes it later
+ on), your app becomes unable to perform the operation at all.
+ </li>
+</ul>
+
+<p>
+ If you use an intent:
+</p>
+
+<ul>
+ <li>You do not have to design the UI for the operation. The app that handles
+ the intent provides the UI. However, this means you have
+ no control over the user experience. The user could be interacting with an
+ app you've never seen.
+ </li>
+
+ <li>If the user does not have a default app for the operation, the system
+ prompts the user to choose an app. If the user does not designate a default
+ handler, they may have to go
+ through an extra dialog every time they perform the operation.
+ </li>
+</ul>
+
+<h2 id="ask-neccessary">Only Ask for Permissions You Need</h2>
+
+<p>
+ Every time you ask for a permission, you force the user to make a decision.
+ You should minimize the number of times you make these requests. If the user
+ is running Android 6.0 (API level 23) or later, every time the user tries
+ some new app feature that requires a permission, the app has to interrupt the
+ user's work with a permission request. If the user is running an earlier
+ version of Android, the user has to grant every one of the app's permissions
+ when installing the app; if the list is too long or seems inappropriate, the
+ user may decide not to install your app at all. For these reasons, you should
+ minimize the number of permissions your app needs.
+</p>
+
+<p>
+ Quite often your app can avoid requesting a permission by using an
+ <em>intent</em> instead. If a feature is not a core part of your app's
+ functionality, you should consider handing the work over to another app, as
+ described in <a href="#perms-vs-intents">Consider Using An Intent</a>.
+</p>
+
+<h2 id="dont-overwhelm">Don't Overwhelm the User</h2>
+
+<p>
+ If the user is running Android 6.0 (API level 23) or later, the user has to
+ grant your app its permissions while they are running the app. If you
+ confront the user with a lot of requests for permissions at once, you may
+ overwhelm the user and cause them to quit your app. Instead, you should ask
+ for permissions as you need them.
+</p>
+
+<p>
+ In some cases, one or more permissions might be absolutely essential to your
+ app. It might make sense to ask for all of those permissions as soon as the
+ app launches. For example, if you make a photography app, the app would need
+ access to the device camera. When the user launches the app for the first
+ time, they won't be surprised to be asked for permission to use the camera.
+ But if the same app also had a feature to share photos with the user's
+ contacts, you probably should <em>not</em> ask for the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission at first
+ launch. Instead, wait until the user tries to use the "sharing" feature and
+ ask for the permission then.
+</p>
+
+<p>
+ If your app provides a tutorial, it may make sense to request the app's
+ essential permissions at the end of the tutorial sequence.
+</p>
+
+<h2 id="explain">Explain Why You Need Permissions</h2>
+
+<p>
+ The permissions dialog shown by the system when you call
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} says what permission your app wants, but doesn't say
+ why. In some cases, the user may find that puzzling. It's a good idea to
+ explain to the user why your app wants the permissions before calling
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ For example, a photography app might want to use location services so it can
+ geotag the photos. A typical user might not understand that a photo can
+ contain location information, and would be puzzled why their photography app
+ wants to know the location. So in this case, it's a good idea for the app to
+ tell the user about this feature <em>before</em> calling
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ One way to inform the user is to incorporate these requests into an app
+ tutorial. The tutorial can show each of the app's features in turn, and as it
+ does this, it can explain what permissions are needed. For example, the
+ photography app's tutorial could demonstrate its "share photos with your
+ contacts" feature, then tell the user that they need to give permission for
+ the app to see the user's contacts. The app could then call {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} to ask the user for that access. Of course, not every
+ user is going to follow the tutorial, so you still need to check for and
+ request permissions during the app's normal operation.
+</p>
+
+<h2 id="testing">Test for Both Permissions Models</h2>
+
+<p>
+ Beginning with Android 6.0 (API level 23), users grant and revoke app
+ permissions at run time, instead of doing so when they install the app. As a
+ result, you'll have to test your app under a wider range of conditions. Prior
+ to Android 6.0, you could reasonably assume that if your app is running at
+ all, it has all the permissions it declares in the app manifest. Under the
+ new permissions model, you can no longer make that assumption.
+</p>
+
+<p>
+ The following tips will help you identify permissions-related code problems
+ on devices running API level 23 or higher:
+</p>
+
+<ul>
+ <li>Identify your app’s current permissions and the related code paths.
+ </li>
+
+ <li>Test user flows across permission-protected services and data.
+ </li>
+
+ <li>Test with various combinations of granted or revoked permissions. For
+ example, a camera app might list {@link android.Manifest.permission#CAMERA
+ CAMERA}, {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS}, and
+ {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
+ in its manifest. You should test the app with each of these permissions
+ turned on and off, to make sure the app can handle all permission
+ configurations gracefully. Remember, beginning with Android 6.0 the user can
+ turn permissions on or off for <em>any</em> app, even an app that targets API
+ level 22 or lower.
+ </li>
+
+ <li>Use the <a href="{@docRoot}tools/help/adb.html">adb</a> tool to manage
+ permissions from the command line:
+ <ul>
+ <li>List permissions and status by group:
+
+ <pre class="no-pretty-print">$ adb shell pm list permissions -d -g</pre>
+ </li>
+
+ <li>Grant or revoke one or more permissions:
+
+ <pre class="no-pretty-print">$ adb shell pm [grant|revoke] <permission-name> ...</pre>
+ </li>
+ </ul>
+ </li>
+
+ <li>Analyze your app for services that use permissions.
+ </li>
+</ul>
diff --git a/docs/html/training/permissions/declaring.jd b/docs/html/training/permissions/declaring.jd
new file mode 100644
index 0000000..ae96f81
--- /dev/null
+++ b/docs/html/training/permissions/declaring.jd
@@ -0,0 +1,115 @@
+page.title=Declaring Permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ul>
+ <li>
+ <a href="#perm-needed">Determine What Permissions Your App Needs</a>
+ </li>
+ <li>
+ <a href="#perm-add">Add Permissions to the Manifest</a>
+ </li>
+ </ul>
+
+<!--
+ <h2>Dependencies and Prerequisites</h2>
+ <ul>
+ <li></li>
+ </ul>
+-->
+
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html#permissions">
+ Using Permissions</a></li> <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html#normal-dangerous">
+ Normal and Dangerous Permissions</a></li>
+ </ul>
+</div>
+</div>
+
+<p>
+ Every Android app runs in a limited-access sandbox. If an app needs to use
+ resources or information outside of its own sandbox, the app has to request
+ the appropriate <i>permission.</i> You declare that your app needs a
+ permission by listing the permission in the <a href=
+ "{@docRoot}guide/topics/manifest/manifest-intro.html">App Manifest</a>.
+</p>
+
+<p>
+ Depending on how sensitive the permission is, the system might grant the
+ permission automatically, or the device user might have to grant
+ the request. For example, if your app requests permission to turn on the
+ device's flashlight, the system grants that permission automatically. But
+ if your app needs to read the user's contacts, the system asks the user
+ to approve that permission. Depending on the platform version, the user
+ grants the permission either when they install the app (on Android 5.1 and
+ lower) or while running the app (on Android 6.0 and higher).
+</p>
+
+<h2 id="perm-needed">Determine What Permissions Your App Needs</h2>
+
+<p>
+ As you develop your app, you should note when your app is using capabilities
+ that require a permission. Typically, an app is going to need permissions
+ whenever it uses information or resources that the app doesn't create, or
+ performs actions that affect the behavior of the device or other apps. For
+ example, if an app needs to access the internet, use the device camera, or
+ turn Wi-Fi on or off, the app needs the appropriate permission. For a list of
+ system permissions, see <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
+
+<p>
+ Your app only needs permissions for actions that it performs directly. Your
+ app does not need permission if it is requesting that another app perform the
+ task or provide the information. For example, if your app needs to read the
+ user's address book, the app needs the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission. But if
+ your app uses an <em>intent</em> to request information from the user's
+ Contacts app, your app does not need any permissions, but the
+ Contacts app <em>does</em> need to have that permission. For more
+ information, see <a href="best-practices.html#perms-vs-intents">Consider
+ Using an Intent</a>.
+</p>
+
+<h2 id="perm-add">Add Permissions to the Manifest</h2>
+
+<p>
+ To declare that your app needs a permission, put a <a href=
+ "{@docRoot}guide/topics/manifest/uses-permission-element.html"
+ ><code><uses-permission></code></a>
+ element in your <a href=
+ "{@docRoot}guide/topics/manifest/manifest-intro.html">app manifest</a>, as a
+ child of the top-level <a href=
+ "{@docRoot}guide/topics/manifest/manifest-element.html"><code><manifest></code></a>
+ element. For example, an app that needs to send SMS messages would have this
+ line in the manifest:
+</p>
+
+<pre><manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.snazzyapp">
+
+ <strong><uses-permission android:name="android.permission.SEND_SMS"/></strong>
+ <!-- other permissions go here -->
+
+ <application ...>
+ ...
+ </application>
+
+</manifest></pre>
+
+<p>
+ The system's behavior after you declare a permission depends on how sensitive
+ the permission is. If the permission does not affect user privacy, the system
+ grants the permission automatically. If the permission might grant access to
+ sensitive user information, the system asks the user to approve the request.
+ For more information about the different kinds of permissions, see
+ <a href="{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
diff --git a/docs/html/training/permissions/index.jd b/docs/html/training/permissions/index.jd
new file mode 100644
index 0000000..d1e7f21
--- /dev/null
+++ b/docs/html/training/permissions/index.jd
@@ -0,0 +1,76 @@
+page.title=Working with System Permissions
+page.tags=permissions
+helpoutsWidget=true
+
+@jd:body
+
+<div id="tb-wrapper">
+
+ <div id="tb">
+<!--
+ <h2>Dependencies and Prerequisites</h2>
+ <ul>
+ <li></li>
+ </ul>
+-->
+<h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/security/permissions.html">
+ System Permissions</a></li>
+ <li><a href="{@docRoot}training/basics/intents/index.html">
+ Interacting with other apps</a></li>
+ </ul>
+ </div>
+</div>
+
+<a class="notice-designers wide"
+ href="https://www.google.com/design/spec/patterns/permissions.html">
+ <div>
+ <h3>Design Patterns</h3>
+ <p>Permissions</p>
+ </div>
+</a>
+
+<p>
+ To protect the system's integrity and the user's privacy, Android runs each
+ app in a limited access sandbox. If the app wants to use resources or
+ information outside of its sandbox, the app has to explicitly request
+ permission. Depending on the type of permission the app requests, the system
+ may grant the permission automatically, or the system may ask the user to
+ grant the permission.
+</p>
+
+<p>
+ This class shows you how to declare and request permissions for your app.
+</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <a href="declaring.html">Declaring Permissions</a>
+ </dt>
+
+ <dd>
+ Learn how to declare the permissions you need in your app manifest.
+ </dd>
+
+ <dt>
+ <a href="requesting.html">Requesting Permissions at Run Time</a>
+ </dt>
+
+ <dd>
+ Learn how to request permissions from the user while the app is running.
+ This lesson only applies to apps on devices running Android 6.0 (API level
+ 23) and higher.
+ </dd>
+
+ <dt>
+ <a href="best-practices.html">Permissions Best Practices</a>
+ </dt>
+
+ <dd>
+ Guidelines for creating the best user experience in requesting and using
+ permissions.
+ </dd>
+</dl>
diff --git a/docs/html/training/permissions/requesting.jd b/docs/html/training/permissions/requesting.jd
new file mode 100644
index 0000000..e173daf
--- /dev/null
+++ b/docs/html/training/permissions/requesting.jd
@@ -0,0 +1,361 @@
+page.title=Requesting Permissions at Run Time
+page.tags="runtime permissions",androidm,marshmallow
+page.image=images/permissions_check.png
+page.metaDescription=Learn about runtime permissions and how they make it easier for users to install and upgrade your apps.
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>This lesson teaches you to</h2>
+
+ <ul>
+ <li>
+ <a href="#perm-check">Check For Permissions</a>
+ </li>
+ <li>
+ <a href="#perm-request">Request Permissions</a>
+ </li>
+ </ul>
+
+ <h2>Dependencies and Prerequisites</h2>
+
+ <ul>
+ <li>Android 6.0 (API level 23)
+ </li>
+ </ul>
+
+ <h2>You should also read</h2>
+
+ <ul>
+ <li>
+ <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>
+ </li>
+ </ul>
+</div>
+</div>
+
+<p>
+ Beginning in Android 6.0 (API level 23), users grant
+ permissions to apps while the app is running, not when they install the app.
+ This approach streamlines the app
+ install process, since the user does not need to grant permissions when they
+ install or update the app. It also gives the user more control over the app's
+ functionality; for example, a user could choose to give a camera app access
+ to the camera but not to the device location. The user can revoke the
+ permissions at any time, by going to the app's Settings screen.
+</p>
+
+<p>
+ System permissions are divided into two categories, <em>normal</em> and
+ <em>dangerous:</em>
+</p>
+
+<ul>
+ <li>Normal permissions do not directly risk the user's privacy. If your app
+ lists a normal permission in its manifest, the system grants the permission
+ automatically.
+ </li>
+
+ <li>Dangerous permissions can give the app access to the user's confidential
+ data. If your app lists a normal permission in its manifest, the system
+ grants the permission automatically. If you list a dangerous permission, the
+ user has to explicitly give approval to your app.
+ </li>
+</ul>
+
+<p>
+ For more information, see <a href=
+ "{@docRoot}guide/topics/security/permissions.html#normal-dangerous">Normal
+ and Dangerous Permissions</a>.
+</p>
+
+<p>
+ On all versions of Android, your app needs to declare both the normal and the
+ dangerous permissions it needs in its app manifest, as described in <a href=
+ "declaring.html">Declaring Permissions</a>. However, the <em>effect</em> of
+ that declaration is different depending on the system version and your
+ app's target SDK level:
+</p>
+
+<ul>
+ <li>If the device is running Android 5.1 or lower, <strong>or</strong> your app's target SDK
+ is 22 or lower: If you list a dangerous permission in your manifest, the user
+ has to grant the permission when they install the app; if they do not grant
+ the permission, the system does not install the app at all.
+ </li>
+
+ <li>If the device is running Android 6.0 or higher, <strong>and</strong> your app's target SDK
+ is 23 or higher: The app has to list the permissions in the manifest,
+ <em>and</em> it must request each dangerous permission it needs while the app
+ is running. The user can grant or deny each permission, and the app can
+ continue to run with limited capabilities even if the user denies a
+ permission request.
+ </li>
+</ul>
+
+<p class="note">
+ <strong>Note:</strong> Beginning with Android 6.0 (API level 23), users can
+ revoke permissions from any app at any time, even if the app targets a lower
+ API level. You should test your app to verify that it behaves properly when
+ it's missing a needed permission, regardless of what API level your app
+ targets.
+</p>
+
+<p>
+ This lesson describes how to use the Android <a href=
+ "{@docRoot}tools/support-library/index.html">Support Library</a> to check
+ for, and request, permissions. The Android framework provides similar methods
+ as of Android 6.0 (API level 23). However, using the support library is
+ simpler, since your app doesn't need to check which version of Android it's
+ running on before calling the methods.
+</p>
+
+<h2 id="perm-check">Check For Permissions</h2>
+
+<p>
+ If your app needs a dangerous permission, you must check whether you have
+ that permission every time you perform an operation that requires that
+ permission. The user is always free to revoke the permission, so even if the
+ app used the camera yesterday, it can't assume it still has that permission
+ today.
+</p>
+
+<p>
+ To check if you have a permission, call the {@link
+ android.support.v4.content.ContextCompat#checkSelfPermission
+ ContextCompat.checkSelfPermission()} method. For example, this snippet shows how to
+ check if the activity has permission to write to the calendar:
+</p>
+
+<pre>// Assume thisActivity is the current activity
+int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
+ Manifest.permission.WRITE_CALENDAR);</pre>
+
+<p>
+ If the app has the permission, the method returns {@link
+ android.content.pm.PackageManager#PERMISSION_GRANTED
+ PackageManager.PERMISSION_GRANTED}, and the app can proceed with the
+ operation. If the app does not have the permission, the method returns {@link
+ android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, and
+ the app has to explicitly ask the user for permission.
+</p>
+
+<h2 id="perm-request">Request Permissions</h2>
+
+<p>
+ If your app needs a dangerous permission that was listed in the app manifest,
+ it must ask the user to grant the permission. Android provides several
+ methods you can use to request a permission. Calling these methods brings up a
+ standard Android dialog, which you cannot customize.
+</p>
+<h3 id="explain">Explain why the app needs permissions</h3>
+
+<div class="figure" style="width:220px" id="fig-perms-dialog">
+ <img src="{@docRoot}images/training/permissions/request_permission_dialog.png"
+ srcset="{@docRoot}images/training/permissions/request_permission_dialog.png 1x,
+ {@docRoot}images/training/permissions/request_permission_dialog_2x.png 2x"
+ alt="" width="220" />
+ <p class="img-caption">
+ <strong>Figure 1.</strong> System dialog prompting the user to grant or deny
+ a permission.
+ </p>
+</div>
+
+<p>
+ In some circumstances, you might want to help the user understand why your
+ app needs a permission. For example, if a user launches a photography app,
+ the user probably won't be surprised that the app asks for permission to use
+ the camera, but the user might not understand why the app wants access to the
+ user's location or contacts. Before you request a permission, you should
+ consider providing an explanation to the user. Keep in mind that you don't
+ want to overwhelm the user with explanations; if you provide too many
+ explanations, the user might find the app frustrating and remove it.
+</p>
+
+<p>
+ One approach you might use is to provide an explanation only if the user has
+ already turned down that permission request. If a user keeps trying to use
+ functionality that requires a permission, but keeps turning down the
+ permission request, that probably shows that the user doesn't understand why
+ the app needs the permission to provide that functionality. In a situation
+ like that, it's probably a good idea to show an explanation.
+</p>
+
+<p>
+ To help find situations where the user might need an explanation, Android
+ provides a utiltity method, {@link
+ android.support.v4.app.ActivityCompat#shouldShowRequestPermissionRationale
+ shouldShowRequestPermissionRationale()}. This method returns <code>true</code> if the app
+ has requested this permission previously and the user denied the request.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> If the user turned down the permission request in the
+ past and chose the <strong>Don't ask again</strong> option in the permission
+ request system dialog, this method returns <code>false</code>. The method
+ also returns <code>false</code> if a device policy prohibits the app from
+ having that permission.
+</p>
+
+<h3 id="make-the-request">Request the permissions you need</h3>
+
+<p>
+ If your app doesn't already have the permission it needs, the app must call
+ one of the {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} methods to request the appropriate
+ permissions. Your app passes the permissions it wants, and also
+ an integer <em>request code</em> that you specify to identify this permission
+ request. This method functions asynchronously: it
+ returns right away, and after the user responds to the dialog box, the system
+ calls the app's callback method with the results, passing the same request
+ code that the app passed to
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}.
+</p>
+
+<p>
+ The following code checks if the app has permission to read the user's
+ contacts, and requests the permission if necessary:
+</p>
+
+<pre>// Here, thisActivity is the current activity
+if (ContextCompat.checkSelfPermission(thisActivity,
+ Manifest.permission.READ_CONTACTS)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ // Should we show an explanation?
+ if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
+ Manifest.permission.READ_CONTACTS)) {
+
+ // Show an expanation to the user *asynchronously* -- don't block
+ // this thread waiting for the user's response! After the user
+ // sees the explanation, try again to request the permission.
+
+ } else {
+
+ // No explanation needed, we can request the permission.
+
+ ActivityCompat.requestPermissions(thisActivity,
+ new String[]{Manifest.permission.READ_CONTACTS},
+ MY_PERMISSIONS_REQUEST_READ_CONTACTS);
+
+ // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
+ // app-defined int constant. The callback method gets the
+ // result of the request.
+ }
+}</pre>
+
+<p class="note">
+ <strong>Note:</strong> When your app calls {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, the system shows a standard dialog box to the user.
+ Your app <em>cannot</em> configure or alter that dialog box. If you need to
+ provide any information or explanation to the user, you should do that before
+ you call {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, as described in <a href="#explain">Explain why the app
+ needs permissions</a>.
+</p>
+
+<h3 id="handle-response">Handle the permissions request response
+</h3>
+
+<p>
+ When your app requests permissions, the system presents a dialog box to the
+ user. When the user responds, the system invokes your app's {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} method, passing it the user response. Your app
+ has to override that method to find out whether the permission was granted.
+ The callback is passed the same request code you passed to
+ {@link android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}. For example, if an app requests {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} access it might have
+ the following callback method:
+</p>
+
+<pre>@Override
+public void onRequestPermissionsResult(int requestCode,
+ String permissions[], int[] grantResults) {
+ switch (requestCode) {
+ case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
+ // If request is cancelled, the result arrays are empty.
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+
+ // permission was granted, yay! Do the
+ // contacts-related task you need to do.
+
+ } else {
+
+ // permission denied, boo! Disable the
+ // functionality that depends on this permission.
+ }
+ return;
+ }
+
+ // other 'case' lines to check for other
+ // permissions this app might request
+ }
+}</pre>
+
+<p>
+ The dialog box shown by the system describes the <a href=
+ "{@docRoot}guide/topics/security/permissions.html#perm-groups">permission
+ group</a> your app needs access to; it does not list the specific permission.
+ For example, if you request the {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission, the
+ system dialog box just says your app needs access to the device's contacts.
+ The user only needs to grant permission once for each permission group. If
+ your app requests any other permissions in that group (that are listed in
+ your app manifest), the system automatically grants them. When you request
+ the permission, the system calls your {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} callback method and passes {@link
+ android.content.pm.PackageManager#PERMISSION_GRANTED PERMISSION_GRANTED}, the
+ same way it would if the user had explicitly granted your request through the
+ system dialog box.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> Your app still needs to explicitly request every
+ permission it needs, even if the user has already granted another permission
+ in the same group. In addition, the grouping of permissions into groups may
+ change in future Android releases. Your code should not rely
+ on the assumption that particular permissions are or are not in the
+ same group.
+</p>
+
+<p>
+ For example, suppose you list both {@link
+ android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and {@link
+ android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS} in your app
+ manifest. If you request
+ {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} and the user
+ grants the permission, and you then request {@link
+ android.Manifest.permission#WRITE_CONTACTS WRITE_CONTACTS}, the system
+ immediately grants you that permission without interacting with the user.
+</p>
+
+<p>
+ If the user denies a permission request, your app should take appropriate
+ action. For example, your app might show a dialog explaining why it could not
+ perform the user's requested action that needs that permission.
+</p>
+
+<p>
+ When the system asks the user to grant a permission, the user has the option
+ of telling the system not to ask for that permission again. In that case, any
+ time an app uses {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()} to ask for that permission again, the system
+ immediately denies the request. The system calls your {@link
+ android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult
+ onRequestPermissionsResult()} callback method and passes {@link
+ android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}, the
+ same way it would if the user had explicitly rejected your request again.
+ This means that when you call {@link
+ android.support.v4.app.ActivityCompat#requestPermissions
+ requestPermissions()}, you cannot assume that any direct interaction with the
+ user has taken place.
+</p>
diff --git a/docs/html/training/scheduling/wakelock.jd b/docs/html/training/scheduling/wakelock.jd
index 0fab7be..61c78a1 100644
--- a/docs/html/training/scheduling/wakelock.jd
+++ b/docs/html/training/scheduling/wakelock.jd
@@ -137,7 +137,7 @@
<pre>
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
-Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();</pre>
diff --git a/docs/html/training/search/setup.jd b/docs/html/training/search/setup.jd
index 044e422..5769293 100644
--- a/docs/html/training/search/setup.jd
+++ b/docs/html/training/search/setup.jd
@@ -10,7 +10,7 @@
<h2>This lesson teaches you to</h2>
<ul>
- <li><a href="{@docRoot}training/search/setup.html#add-sv">Add the Search View to the Action
+ <li><a href="{@docRoot}training/search/setup.html#add-sv">Add the Search View to the App
Bar</a></li>
<li><a href="{@docRoot}training/search/setup.html#create-sc">Create a Searchable
@@ -23,30 +23,30 @@
<h2>You should also read:</h2>
<ul>
- <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+ <li><a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a></li>
</ul>
</div>
</div>
<p>Beginning in Android 3.0, using the {@link android.widget.SearchView} widget as an item in
- the action bar is the preferred way to provide search in your app. Like with all items in
- the action bar, you can define the {@link android.widget.SearchView} to show at all times, only
+ the app bar is the preferred way to provide search in your app. Like with all items in
+ the app bar, you can define the {@link android.widget.SearchView} to show at all times, only
when there is room, or as a collapsible action, which displays the {@link
- android.widget.SearchView} as an icon initially, then takes up the entire action bar as a search
+ android.widget.SearchView} as an icon initially, then takes up the entire app bar as a search
field when the user clicks the icon.</p>
<p class="note"><strong>Note:</strong> Later in this class, you will learn how to make your
app compatible down to Android 2.1 (API level 7) for devices that do not support
{@link android.widget.SearchView}.</p>
- <h2 id="add-sv">Add the Search View to the Action Bar</h2>
+ <h2 id="add-sv">Add the Search View to the App Bar</h2>
- <p>To add a {@link android.widget.SearchView} widget to the action bar, create a file named
+ <p>To add a {@link android.widget.SearchView} widget to the app bar, create a file named
<code>res/menu/options_menu.xml</code> in your project and add the following code to the file.
This code defines how to create the search item, such as the icon to use and the title of the
item. The <code>collapseActionView</code> attribute allows your {@link android.widget.SearchView}
- to expand to take up the whole action bar and collapse back down into a
- normal action bar item when not in use. Because of the limited action bar space on handset devices,
+ to expand to take up the whole app bar and collapse back down into a
+ normal app bar item when not in use. Because of the limited app bar space on handset devices,
using the <code>collapsibleActionView</code> attribute is recommended to provide a better
user experience.</p>
<pre>
@@ -63,7 +63,7 @@
<p class="note"><strong>Note:</strong> If you already have an existing XML file for your menu
items, you can add the <code><item></code> element to that file instead.</p>
- <p>To display the {@link android.widget.SearchView} in the action bar, inflate the XML menu
+ <p>To display the {@link android.widget.SearchView} in the app bar, inflate the XML menu
resource (<code>res/menu/options_menu.xml</code>) in the {@link
android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method of your activity:</p>
<pre>
@@ -76,7 +76,7 @@
}
</pre>
- <p>If you run your app now, the {@link android.widget.SearchView} appears in your app's action
+ <p>If you run your app now, the {@link android.widget.SearchView} appears in your app's app
bar, but it isn't functional. You now need to define <em>how</em> the {@link
android.widget.SearchView} behaves.</p>
@@ -194,4 +194,4 @@
<p>If you run your app now, the {@link android.widget.SearchView} can accept the user's query and
start your searchable activity with the {@link android.content.Intent#ACTION_SEARCH} intent. It
- is now up to you to figure out how to store and search your data given a query.</p>
\ No newline at end of file
+ is now up to you to figure out how to store and search your data given a query.</p>
diff --git a/docs/html/training/secure-file-sharing/share-file.jd b/docs/html/training/secure-file-sharing/share-file.jd
index 6c52770..cc8b2f1 100644
--- a/docs/html/training/secure-file-sharing/share-file.jd
+++ b/docs/html/training/secure-file-sharing/share-file.jd
@@ -78,7 +78,7 @@
...
<activity
android:name=".FileSelectActivity"
- android:label="@"File Selector" >
+ android:label="@File Selector" >
<intent-filter>
<action
android:name="android.intent.action.PICK"/>
diff --git a/docs/html/training/sharing/shareaction.jd b/docs/html/training/sharing/shareaction.jd
index ee811da..53e13d0 100644
--- a/docs/html/training/sharing/shareaction.jd
+++ b/docs/html/training/sharing/shareaction.jd
@@ -21,7 +21,8 @@
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
- <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+ <li><a href="{@docRoot}training/appbar/action-views.html">Action Views and
+ Action Providers</a></li>
</ul>
</div>
@@ -121,7 +122,8 @@
want to set it and then update it as the UI changes. For example, when you view photos full screen
in the Gallery app, the sharing intent changes as you flip between photos.</p>
-<p>For further discussion about the {@link android.widget.ShareActionProvider} object, see the <a
-href="{@docRoot}guide/topics/ui/actionbar.html#ActionProvider">Action Bar</a> guide.</p>
+<p>For further discussion about the {@link android.widget.ShareActionProvider}
+object, see <a href="{@docRoot}training/appbar/action-views.html">Action Views
+and Action Providers</a>.</p>
diff --git a/docs/html/training/snackbar/action.jd b/docs/html/training/snackbar/action.jd
new file mode 100644
index 0000000..58a18a5
--- /dev/null
+++ b/docs/html/training/snackbar/action.jd
@@ -0,0 +1,94 @@
+page.title=Adding an Action to a Message
+page.tags="Snackbar" "action" "popup"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+<!--
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li>
+ <a href="#id">heading</a>
+ </li>
+
+ <li>
+ <a href="#id">heading</a>
+ </li>
+ </ol>
+-->
+
+ <h2>See Also</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/ui/ui-events.html">
+ Input Events</a></li>
+ </ul>
+
+
+ </div>
+</div>
+
+<p>
+ You can add an action to a {@link android.support.design.widget.Snackbar},
+ allowing the user to respond to your message. If you add an action to a
+ {@link android.support.design.widget.Snackbar}, the
+ {@link android.support.design.widget.Snackbar} puts a button
+ next to the message text. The user can trigger your action by pressing the
+ button. For example, an email app might put an <em>undo</em> button on its
+ "email archived" message; if the user clicks the <em>undo</em> button, the
+ app takes the email back out of the archive.
+</p>
+
+<img src="{@docRoot}images/training/snackbar/snackbar_undo_action_2x.png"
+ srcset="{@docRoot}images/training/snackbar/snackbar_undo_action.png 1x,
+ {@docRoot}images/training/snackbar/snackbar_undo_action_2x.png 2x"
+ width="400" alt="">
+
+<p class="img-caption">
+ <strong>Figure 1.</strong> This Snackbar has an <strong>Undo</strong>
+ button, which restores the item that was just removed.
+</p>
+
+<p>
+ To add an action to a {@link android.support.design.widget.Snackbar} message,
+ you need to define a listener object that implements the {@link
+ android.view.View.OnClickListener} interface. The system calls your
+ listener's {@link android.view.View.OnClickListener#onClick onClick()} method
+ if the user clicks on the message action. For example, this snippet shows a
+ listener for an undo action:
+</p>
+
+<pre>public class MyUndoListener implements View.OnClickListener{
+
+ &Override
+ public void onClick(View v) {
+
+ // Code to undo the user's last action
+ }
+}</pre>
+
+<p>
+ Use one of the
+ {@link android.support.design.widget.Snackbar#setAction(int, android.view.View.OnClickListener)
+ SetAction()} methods to attach the listener to your {@link
+ android.support.design.widget.Snackbar}. Be sure to attach the listener
+ before you call {@link android.support.design.widget.Snackbar#show show()},
+ as shown in this code sample:
+</p>
+
+<pre>Snackbar mySnackbar = Snackbar.make(findViewById(R.id.myCoordinatorLayout),
+ R.string.email_archived, Snackbar.LENGTH_SHORT);
+<strong>mySnackbar.setAction(R.string.undo_string, new MyUndoListener());</strong>
+mySnackbar.show();</pre>
+
+<p class="note">
+ <strong>Note:</strong> A {@link android.support.design.widget.Snackbar}
+ automatically goes away after a short time, so you can't count on the user
+ seeing the message or having a chance to press the button. For this reason,
+ you should consider offering an alternate way to perform any {@link
+ android.support.design.widget.Snackbar} action.
+</p>
diff --git a/docs/html/training/snackbar/index.jd b/docs/html/training/snackbar/index.jd
new file mode 100644
index 0000000..312f10c
--- /dev/null
+++ b/docs/html/training/snackbar/index.jd
@@ -0,0 +1,94 @@
+page.title=Showing Pop-Up Messages
+page.tags="Snackbar","Toast"
+helpoutsWidget=true
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li><a href="{@docRoot}tools/support-library/features.html#design">Design
+ Support Library</a></li>
+</ul>
+
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}training/implementing-navigation/index.html">
+ Implementing Effective Navigation</a></li>
+ <li><a href="https://www.google.com/design/spec/components/snackbars-toasts.html">
+ Material Design: Snackbars & toasts</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>
+ There are many situations where you might want your app to show a quick
+ message to the user, without necessarily waiting for the user to respond.
+ For example, when a user performs an action like sending an email or deleting
+ a file, your app should show a quick confirmation to the user. Often the user
+ doesn't need to respond to the message. The message needs to be prominent
+ enough that the user can see it, but not so prominent that it prevents the
+ user from working with your app.
+</p>
+
+<p>
+ Android provides the {@link android.support.design.widget.Snackbar} widget
+ for this common use case.
+ A {@link android.support.design.widget.Snackbar} provides a quick pop-up
+ message to the user. The current activity remains visible and interactive
+ while the {@link android.support.design.widget.Snackbar} is displayed. After a
+ short time, the Snackbar automatically dismisses itself.
+</p>
+
+<p>
+ This class teaches you how to use {@link
+ android.support.design.widget.Snackbar} to show pop-up messages.
+</p>
+
+<div class="figure" style="width:400px">
+ <img src="{@docRoot}images/training/snackbar/snackbar_drive_2x.png"
+ srcset="{@docRoot}images/training/snackbar/snackbar_drive.png 1x,
+ {@docRoot}images/training/snackbar/snackbar_drive_2x.png 2x"
+ width="400" alt="">
+ <p class="img-caption">
+ <strong>Figure 1.</strong> A {@link android.support.design.widget.Snackbar}
+ shows a message at the bottom of the
+ activity, but the rest of the activity is still usable.
+ </p>
+</div>
+
+<p class="note">
+ <strong>Note:</strong> The {@link
+ android.support.design.widget.Snackbar} class supersedes {@link
+ android.widget.Toast}. While {@link android.widget.Toast} is currently still
+ supported, {@link android.support.design.widget.Snackbar} is now the
+ preferred way to display brief, transient messages to the user.
+</p>
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <b><a href="showing.html">Using a Snackbar to Show a Message</a></b>
+ </dt>
+
+ <dd>
+ Learn how to use a {@link android.support.design.widget.Snackbar} to display
+ a brief message to the user.
+ </dd>
+
+ <dt>
+ <b><a href="action.html">Adding an Action to a Message</a></b>
+ </dt>
+
+ <dd>
+ Learn how to add an action to a message, allowing the user to respond to
+ the message.
+ </dd>
+</dl>
diff --git a/docs/html/training/snackbar/showing.jd b/docs/html/training/snackbar/showing.jd
new file mode 100644
index 0000000..c178c0b
--- /dev/null
+++ b/docs/html/training/snackbar/showing.jd
@@ -0,0 +1,204 @@
+page.title=Building and Displaying a Pop-Up Message
+page.tags="Snackbar" "popup" "pop-up"
+helpoutsWidget=true
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#coordinator">Use a CoordinatorLayout</a></li>
+ <li><a href="#display">Display a Message</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}tools/support-library/setup.html"
+ >Support Library Setup</a></li>
+ </ul>
+ </div>
+</div>
+
+
+<p>
+ You can use a {@link android.support.design.widget.Snackbar} to display a brief
+ message to the user. The message automatically goes away after a short
+ period. A {@link android.support.design.widget.Snackbar} is ideal
+ for brief messages that the user doesn't necessarily need to act on. For
+ example, an email app could use a {@link
+ android.support.design.widget.Snackbar} to tell the user that the app
+ successfully sent an email.
+</p>
+
+<h2 id="coordinator">Use a CoordinatorLayout</h2>
+
+<p>
+ A {@link android.support.design.widget.Snackbar} is attached to a view. The
+ {@link android.support.design.widget.Snackbar} provides basic functionality
+ if it is attached to any object derived from the {@link android.view.View}
+ class, such as any of the common layout objects. However, if the
+ {@link android.support.design.widget.Snackbar}
+ is attached to a {@link android.support.design.widget.CoordinatorLayout}, the
+ {@link android.support.design.widget.Snackbar} gains additional features:
+</p>
+
+<ul>
+ <li>The user can dismiss the {@link android.support.design.widget.Snackbar}
+ by swiping it away.
+ </li>
+
+ <li>The layout moves some other UI elements when the {@link
+ android.support.design.widget.Snackbar} appears. For example, if the layout
+ has a {@link android.support.design.widget.FloatingActionButton}, the layout
+ moves the button up when it shows a {@link
+ android.support.design.widget.Snackbar}, instead of drawing the {@link
+ android.support.design.widget.Snackbar} on top of the button. You can see how
+ this looks in Figure 1.
+ </li>
+</ul>
+
+<p>
+ The {@link android.support.design.widget.CoordinatorLayout} class provides a superset
+ of the functionality of {@link android.widget.FrameLayout}. If your app
+ already uses a {@link android.widget.FrameLayout}, you can just replace that
+ layout with a {@link android.support.design.widget.CoordinatorLayout} to
+ enable the full {@link android.support.design.widget.Snackbar} functionality.
+ If your app uses other layout objects, the simplest thing to do is wrap your
+ existing layout elements in a {@link
+ android.support.design.widget.CoordinatorLayout}, as in this example:
+</p>
+
+<pre><android.support.design.widget.CoordinatorLayout
+ android:id="@+id/myCoordinatorLayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Here are the existing layout elements, now wrapped in
+ a CoordinatorLayout -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <!-- …Toolbar, other layouts, other elements… -->
+
+ </LinearLayout>
+
+</android.support.design.widget.CoordinatorLayout></pre>
+
+<p>
+ Make sure to set an <code>android:id</code> tag for your {@link
+ android.support.design.widget.CoordinatorLayout}. You need the layout's ID
+ when you display the message.
+</p>
+
+<div class="framed-nexus5-port-span-5" id="video-coord">
+ <video class="play-on-hover" autoplay loop
+ alt="If the Snackbar is attached to a CoordinatorLayout, the layout
+ moves other elements up when it shows the Snackbar.">
+ <!-- Preferred video size 216x384 (portrait) -->
+ <source src="{@docRoot}images/training/snackbar/snackbar_button_move.mp4">
+ </video>
+</div>
+
+<p class="img-caption">
+ <strong>Figure 1.</strong> The {@link android.support.design.widget.CoordinatorLayout}
+ moves the {@link android.support.design.widget.FloatingActionButton} up
+ when the {@link android.support.design.widget.Snackbar} appears.
+</p>
+
+<h2 id="display">
+ Display a Message
+</h2>
+
+<p>
+ There are two steps to displaying a message. First, you create a {@link
+ android.support.design.widget.Snackbar} object with the message text. Then,
+ you call that object's {@link android.support.design.widget.Snackbar#show
+ show()} method to display the message to the user.
+</p>
+
+<h3 id="create-snackbar">Creating a Snackbar object</h3>
+
+<p>
+ Create a {@link android.support.design.widget.Snackbar} object by
+ calling the static {@link android.support.design.widget.Snackbar#make
+ Snackbar.make()} method. When you create the {@link
+ android.support.design.widget.Snackbar}, you specify both the message it
+ displays, and the length of time to show the message:
+</p>
+
+<pre>Snackbar mySnackbar = Snackbar.make(viewId, stringId, duration);</pre>
+
+<dl>
+ <dt>
+ <em>viewId</em>
+ </dt>
+
+ <dd>
+ The view to attach the {@link android.support.design.widget.Snackbar} to.
+ The method actually searches up the view hierarchy from the passed
+ <em>viewId</em> until it reaches either a {@link
+ android.support.design.widget.CoordinatorLayout}, or the window decor's
+ content view. Ordinarily, it's simplest to just pass the ID of the {@link
+ android.support.design.widget.CoordinatorLayout} enclosing your content.
+ </dd>
+
+ <dt>
+ <em>stringId</em>
+ </dt>
+
+ <dd>
+ The resource ID of the message you want to display. This can be formatted
+ or unformatted text.
+ </dd>
+
+ <dt>
+ <em>duration</em>
+ </dt>
+
+ <dd>
+ The length of time to show the message. This can be either {@link
+ android.support.design.widget.Snackbar#LENGTH_SHORT LENGTH_SHORT} or {@link
+ android.support.design.widget.Snackbar#LENGTH_LONG LENGTH_LONG}.
+ </dd>
+</dl>
+
+<h3 id="show-snackbar">Showing the message to the user</h3>
+
+<p>
+ Once you have created the {@link android.support.design.widget.Snackbar},
+ call its {@link android.support.design.widget.Snackbar#show show()} method to
+ display the {@link android.support.design.widget.Snackbar} to the user:
+</p>
+
+<pre>mySnackbar.show();</pre>
+
+<p>
+ The system does not show multiple {@link
+ android.support.design.widget.Snackbar} objects at the same time, so if the
+ view is currently displaying another {@link
+ android.support.design.widget.Snackbar}, the system queues your {@link
+ android.support.design.widget.Snackbar} and displays it after the current
+ {@link android.support.design.widget.Snackbar} expires or is dismissed.
+</p>
+
+<p>
+ If you just want to show a message to the user and won't need to call any of
+ the {@link android.support.design.widget.Snackbar} object's utility methods,
+ you don't need to keep the reference to the {@link
+ android.support.design.widget.Snackbar} after you call {@link
+ android.support.design.widget.Snackbar#show show()}. For this reason, it's
+ common to use method chaining to create and show a {@link
+ android.support.design.widget.Snackbar} in one statement:
+</p>
+
+<pre>Snackbar.make(findViewById(R.id.myCoordinatorLayout), R.string.email_sent,
+ Snackbar.LENGTH_SHORT)
+ .show();</pre>
diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd
index 9bd17ba..0819c16 100644
--- a/docs/html/training/sync-adapters/creating-sync-adapter.jd
+++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd
@@ -382,7 +382,7 @@
...
// Constants
// The authority for the sync adapter's content provider
- public static final String AUTHORITY = "com.example.android.datasync.provider"
+ public static final String AUTHORITY = "com.example.android.datasync.provider";
// An account type, in the form of a domain name
public static final String ACCOUNT_TYPE = "example.com";
// The account name
@@ -416,7 +416,7 @@
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
- if (accountManager.addAccountExplicitly(newAccount, null, null))) {
+ if (accountManager.addAccountExplicitly(newAccount, null, null)) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
diff --git a/docs/html/training/sync-adapters/running-sync-adapter.jd b/docs/html/training/sync-adapters/running-sync-adapter.jd
index 194e94b..033450f 100644
--- a/docs/html/training/sync-adapters/running-sync-adapter.jd
+++ b/docs/html/training/sync-adapters/running-sync-adapter.jd
@@ -11,7 +11,6 @@
<ol>
<li><a href="#RunByMessage">Run the Sync Adapter When Server Data Changes</a>
<li><a href="#RunDataChange">Run the Sync Adapter When Content Provider Data Changes</a></li>
- <li><a href="#RunByNetwork">Run the Sync Adapter After a Network Message</a></li>
<li><a href="#RunPeriodic">Run the Sync Adapter Periodically</a></li>
<li><a href="#RunOnDemand">Run the Sync Adapter On Demand</a></li>
</ol>
@@ -69,15 +68,6 @@
content provider, detecting data changes may be more difficult.
</dd>
<dt>
- When the system sends out a network message
- </dt>
- <dd>
- Run a sync adapter when the Android system sends out a network message that keeps the
- TCP/IP connection open; this message is a basic part of the networking framework. Using
- this option is one way to run the sync adapter automatically. Consider using it in
- conjunction with interval-based sync adapter runs.
- </dd>
- <dt>
At regular intervals
</dt>
<dd>
@@ -283,60 +273,6 @@
...
}
</pre>
-<h2 id="RunByNetwork">Run the Sync Adapter After a Network Message</h2>
-<p>
- When a network connection is available, the Android system sends out a message
- every few seconds to keep the device's TCP/IP connection open. This message also goes to
- the {@link android.content.ContentResolver} of each app. By calling
- {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()},
- you can run the sync adapter whenever the {@link android.content.ContentResolver}
- receives the message.
-</p>
-<p>
- By scheduling your sync adapter to run when the network message is sent, you ensure that your
- sync adapter is always scheduled to run while the network is available. Use this option if you
- don't have to force a data transfer in response to data changes, but you do want to ensure
- your data is regularly updated. Similarly, you can use this option if you don't want a fixed
- schedule for your sync adapter, but you do want it to run frequently.
-</p>
-<p>
- Since the method
- {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}
- doesn't disable {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}, your
- sync adapter may be triggered repeatedly in a short period of time. If you do want to run
- your sync adapter periodically on a regular schedule, you should disable
- {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}.
-</p>
-<p>
- The following code snippet shows you how to configure your
- {@link android.content.ContentResolver} to run your sync adapter in response to a network
- message:
-</p>
-<pre>
-public class MainActivity extends FragmentActivity {
- ...
- // Constants
- // Content provider authority
- public static final String AUTHORITY = "com.example.android.datasync.provider";
- // Account
- public static final String ACCOUNT = "default_account";
- // Global variables
- // A content resolver for accessing the provider
- ContentResolver mResolver;
- ...
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ...
- // Get the content resolver for your app
- mResolver = getContentResolver();
- // Turn on automatic syncing for the default account and authority
- mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true);
- ...
- }
- ...
-}
-</pre>
<h2 id="RunPeriodic">Run the Sync Adapter Periodically</h2>
<p>
You can run your sync adapter periodically by setting a period of time to wait between runs,
diff --git a/docs/html/training/system-ui/dim.jd b/docs/html/training/system-ui/dim.jd
old mode 100644
new mode 100755
index f28c948..be2e6c2
--- a/docs/html/training/system-ui/dim.jd
+++ b/docs/html/training/system-ui/dim.jd
@@ -20,7 +20,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/index.html">
@@ -53,7 +53,7 @@
<h2 id="dim">Dim the Status and Navigation Bars</h2>
-<p>You can dim the status and notification bars on Android 4.0 and higher using the
+<p>You can dim the status and notification bars using the
{@link android.view.View#SYSTEM_UI_FLAG_LOW_PROFILE} flag, as follows:</p>
<pre>
diff --git a/docs/html/training/system-ui/immersive.jd b/docs/html/training/system-ui/immersive.jd
index 0a1516c..8e4ef09 100644
--- a/docs/html/training/system-ui/immersive.jd
+++ b/docs/html/training/system-ui/immersive.jd
@@ -21,7 +21,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/patterns/fullscreen.html">
diff --git a/docs/html/training/system-ui/index.jd b/docs/html/training/system-ui/index.jd
index 56fa54b..80d6967 100644
--- a/docs/html/training/system-ui/index.jd
+++ b/docs/html/training/system-ui/index.jd
@@ -24,7 +24,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/patterns/fullscreen.html">
diff --git a/docs/html/training/system-ui/navigation.jd b/docs/html/training/system-ui/navigation.jd
old mode 100644
new mode 100755
index 1c73c70..87f52c6
--- a/docs/html/training/system-ui/navigation.jd
+++ b/docs/html/training/system-ui/navigation.jd
@@ -10,7 +10,7 @@
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
- <li><a href="#40">Hide the Navigation Bar on 4.0 and Higher</a></li>
+ <li><a href="#40">Hide the Navigation Bar</a></li>
<li><a href="#behind">Make Content Appear Behind the Navigation Bar</a></li>
</ol>
@@ -20,7 +20,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/index.html">
@@ -56,9 +56,9 @@
-<h2 id="40">Hide the Navigation Bar on 4.0 and Higher</h2>
+<h2 id="40">Hide the Navigation Bar</h2>
-<p>You can hide the navigation bar on Android 4.0 and higher using the
+<p>You can hide the navigation bar using the
{@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} flag. This snippet hides both
the navigation bar and the status bar:</p>
<pre>View decorView = getWindow().getDecorView();
diff --git a/docs/html/training/system-ui/status.jd b/docs/html/training/system-ui/status.jd
old mode 100644
new mode 100755
index 06b6143..8e5b356
--- a/docs/html/training/system-ui/status.jd
+++ b/docs/html/training/system-ui/status.jd
@@ -12,10 +12,7 @@
<ol>
<li><a href="#40">Hide the Status Bar on Android 4.0 and Lower</a></li>
<li><a href="#41">Hide the Status Bar on Android 4.1 and Higher</a></li>
- <li><a href="#44">Hide the Status Bar on Android 4.4 and Higher</a></li>
-
<li><a href="#behind">Make Content Appear Behind the Status Bar</a></li>
- <li><a href="#action-bar">Synchronize the Status Bar with Action Bar Transition</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
@@ -23,7 +20,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/index.html">
@@ -104,7 +101,7 @@
super.onCreate(savedInstanceState);
// If the Android version is lower than Jellybean, use this call to hide
// the status bar.
- if (Build.VERSION.SDK_INT < 16) {
+ if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
@@ -194,33 +191,3 @@
view hierarchy when the content insets for a window have changed, to allow the window to
adjust its content accordingly. By overriding this method you can handle the
insets (and hence your app's layout) however you want. </p>
-
- <h2 id="action-bar">Synchronize the Status Bar with Action Bar Transition</h2>
-
- <p>On Android 4.1 and higher, to avoid resizing your layout when the action bar hides and
- shows, you can enable overlay mode for the <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>.
- When in overlay mode, your activity layout uses all the
- space available as if the action bar is not there and the system draws the action bar in
- front of your layout. This obscures some of the layout at the top, but now when the
- action bar hides or appears, the system does not need to resize your layout and the
- transition is seamless.</p>
-
- <p>To enable overlay mode for the action bar, you need to create a custom theme that
- extends an existing theme with an action bar and set the
- {@code android:windowActionBarOverlay} attribute
- to {@code true}. For more discussion of this topic, see
- <a href="{@docRoot}training/basics/actionbar/overlaying.html#EnableOverlay">
- Overlaying the Action Bar</a> in the <a href="{@docRoot}training/basics/actionbar/index.html">
- Adding the Action Bar</a> class.</p>
-
-
-<p>Then use
-{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN},
-as described above,
-to set your activity layout to use the same screen area that's available when you've enabled
-{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}.
-
-When you want to hide the system UI, use
-{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}.
-This also hides the action bar (because {@code windowActionBarOverlay=”true”)} and does
-so with a coordinated animation when both hiding and showing the two.</p>
diff --git a/docs/html/training/system-ui/visibility.jd b/docs/html/training/system-ui/visibility.jd
index b562add..14c139e 100644
--- a/docs/html/training/system-ui/visibility.jd
+++ b/docs/html/training/system-ui/visibility.jd
@@ -19,7 +19,7 @@
<ul>
<li>
- <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+ <a href="{@docRoot}training/appbar/index.html">Adding the App Bar</a>
</li>
<li>
<a href="{@docRoot}design/index.html">
diff --git a/docs/html/training/testing/index.jd b/docs/html/training/testing/index.jd
new file mode 100644
index 0000000..d6405c8
--- /dev/null
+++ b/docs/html/training/testing/index.jd
@@ -0,0 +1,72 @@
+page.title=Best Practices for Testing
+page.article=true
+page.image=images/testing/hwtest_junit_success.png
+
+meta.tags="testing"
+page.tags="testing"
+
+page.metaDescription=Starting point for testing Android apps, with guidelines, information, and examples.
+
+@jd:body
+
+<img src="/images/testing/testing-icon.png"
+style="float:right; margin:0 0 20px 30px" width="245" height="229" />
+
+<p>
+ Testing your app is an integral part of the app development process. Testing allows you to verify
+ the correctness, functional behavior, and usability of your app before it is released publicly.
+</p>
+<br>
+<br>
+
+<h2 id="start">Get Started</h2>
+
+<p>
+ Learn the basics of testing your app, with information about building and running your tests with
+ Android Studio:
+</p>
+
+<div class="resource-widget resource-flow-layout col-12"
+ data-query="collection:training/testing/overview"
+ data-cardSizes="6x3"
+ data-maxresults="3">
+</div>
+
+
+<h2 id="tools">Testing Tools and APIs</h2>
+
+<p>
+ Learn about the tools provided by the Android platform that help you test every aspect of your app
+ at every level:
+</p>
+
+<div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/testing/tools"
+ data-cardSizes="15x3, 9x2, 9x2, 9x2, 9x2"
+ data-maxResults="5">
+</div>
+
+
+<h2 id="techniques">App Testing Techniques</h2>
+
+<p>
+ Learn techniques for testing your apps:
+</p>
+
+<div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/testing/techniques"
+ data-cardSizes="6x3
+ data-maxResults="3">
+</div>
+
+<h2 id="resources">Other Resources</h2>
+
+<p>
+ More resources for app testing:
+</p>
+
+<div class="resource-widget resource-flow-layout landing col-12"
+ data-query="collection:training/testing/resources"
+ data-cardSizes="9x3"
+ data-maxResults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/training/testing/integration-testing/content-provider-testing.jd b/docs/html/training/testing/integration-testing/content-provider-testing.jd
new file mode 100644
index 0000000..75869d9
--- /dev/null
+++ b/docs/html/training/testing/integration-testing/content-provider-testing.jd
@@ -0,0 +1,174 @@
+page.title=Testing Your Content Provider
+page.tags=testing, content provider
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>Dependencies and Prerequisites</h2>
+
+ <ul>
+ <li>Android 2.2 (API level 8) or higher</li>
+ <li><a href="{@docRoot}tools/testing-support-library/index.html">
+ Android Testing Support Library</a></li>
+ <li><a href="{@docRoot}tools/studio/index.html">Android Studio 1.4.1 or higher</a>.</li>
+ </ul>
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#build">Create Integration Tests for Content Providers</a></li>
+ <li><a href="#WhatToTest">What to Test</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
+ </li>
+ </ul>
+</div>
+</div>
+
+<p>
+ If you are implementing a <a href="{@docRoot}guide/topics/providers/content-providers.html">
+ content provider</a> to store and retrieve data or to make data
+ accessible to other apps, you should test your provider to ensure that it doesn't behave in an
+ unexpected way. This lesson describes how to test public content providers, and is also
+ applicable to providers that you keep private to your own app.
+</p>
+<h2 id="build">Create Integration Tests for Content Providers</h2>
+<p>
+In Android, apps view content providers as data APIs that provide
+tables of data, with their internals hidden from view. A content provider may have many
+public constants, but it usually has few if any public methods and no public variables.
+For this reason, you should write your tests based only on the provider's public members.
+A content provider that is designed like this is offering a contract between itself and its users.
+</p>
+<p>
+Content providers let you access actual user data, so it's important to ensure
+that you test the content provider in an isolated testing environment. This approach allows you to
+only run against data dependencies set explicitly in the test case. It also means that your tests
+do not modify actual user data. For example, you should avoid writing a test that fails because
+there was data left over from a previous test. Similarly, your test should avoid adding or deleting
+actual contact information in a provider.
+</p>
+
+<p>
+To test your content provider in isolation, use the {@link android.test.ProviderTestCase2} class.
+This class allows you to use Android mock object classes such as {@link android.test.IsolatedContext}
+and {@link android.test.mock.MockContentResolver} to access file and database information without
+affecting the actual user data.
+</p>
+
+<p>Your integration test should be written as a JUnit 4 test class. To learn more about creating
+JUnit 4 test classes and using JUnit 4 assertions, see
+<a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html#build">
+Create a Local Unit Test Class</a>.</p>
+
+<p>To create an integration test for your content provider, you must perform these steps:</p>
+<ul>
+ <li>Create your test class as a subclass of {@link android.test.ProviderTestCase2}.</li>
+ <li>Add the
+{@code @RunWith(AndroidJUnit4.class)} annotation at the beginning of your test class
+definition.</li>
+ <li>Specify the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+{@code AndroidJUnitRunner}</a> class that the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+provides as your default test runner. This step is described in more detail in
+<a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</a>.</li>
+ <li>Set the {@link android.content.Context} object from the
+<a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+{@code InstrumentationRegistry}</a> class. See the snippet below for an example.
+ <pre>
+@Override
+protected void setUp() throws Exception {
+ setContext(InstrumentationRegistry.getTargetContext());
+ super.setUp();
+}</pre>
+ </li>
+</ul>
+
+<h3 id="ProviderTestCase2">How ProviderTestCase2 works</h3>
+<p>
+ You test a provider with a subclass of {@link android.test.ProviderTestCase2}. This base class
+ extends {@link android.test.AndroidTestCase}, so it provides the JUnit testing framework as well
+ as Android-specific methods for testing application permissions. The most important
+ feature of this class is its initialization, which creates the isolated test environment.
+</p>
+<p>
+ The initialization is done in the constructor for {@link android.test.ProviderTestCase2}, which
+ subclasses call in their own constructors. The {@link android.test.ProviderTestCase2}
+ constructor creates an {@link android.test.IsolatedContext} object that allows file and
+ database operations but stubs out other interactions with the Android system.
+ The file and database operations themselves take place in a directory that is local to the
+ device or emulator and has a special prefix.
+</p>
+<p>
+ The constructor then creates a {@link android.test.mock.MockContentResolver} to use as the
+ resolver for the test.
+</p>
+<p>
+ Lastly, the constructor creates an instance of the provider under test. This is a normal
+ {@link android.content.ContentProvider} object, but it takes all of its environment information
+ from the {@link android.test.IsolatedContext}, so it is restricted to
+ working in the isolated test environment. All of the tests done in the test case class run
+ against this isolated object.
+</p>
+
+<p>
+You run integration tests for content providers the same way as instrumented unit tests. To run the
+integration test for your content provider, follow the steps described in <a
+href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#run">
+Run Instrumented Unit Tests</a>.
+</p>
+
+<h2 id="WhatToTest">What to Test</h2>
+<p>
+Here are some specific guidelines for testing content providers.
+</p>
+<ul>
+ <li>
+ Test with resolver methods: Even though you can instantiate a provider object in
+ {@link android.test.ProviderTestCase2}, you should always test with a resolver object
+ using the appropriate URI. Doing so ensures that you are testing the provider by performing
+ the same interaction that a regular application would use.
+ </li>
+ <li>
+ Test a public provider as a contract: If you intend your provider to be public and
+ available to other applications, you should test it as a contract. Some examples of how to
+ do so are as follows:
+ <ul>
+ <li>
+ Test with constants that your provider publicly exposes. For
+ example, look for constants that refer to column names in one of the provider's
+ data tables. These should always be constants publicly defined by the provider.
+ </li>
+ <li>
+ Test all the URIs that your provider offers. Your provider may offer several URIs,
+ each one referring to a different aspect of the data.
+ </li>
+ <li>
+ Test invalid URIs: Your unit tests should deliberately call the provider with an
+ invalid URI, and look for errors. A good provider design is to throw an
+ {@code IllegalArgumentException} for invalid URIs.
+
+ </li>
+ </ul>
+ </li>
+ <li>
+ Test the standard provider interactions: Most providers offer six access methods:
+ {@code query()}, {@code insert()}, {@code delete()}, {@code update()},
+ {@code getType()}, and {@code onCreate()}. Your tests should verify that all
+ of these methods work. These methods are described in more detail in the topic
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
+ </li>
+ <li>
+ Test business logic: If the content provider implements business logic, you should test it.
+ Business logic includes handling of invalid values, financial or arithmetic calculations,
+ elimination or combining of duplicates.
+ </li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/training/testing/integration-testing/index.jd b/docs/html/training/testing/integration-testing/index.jd
new file mode 100644
index 0000000..d7ce899
--- /dev/null
+++ b/docs/html/training/testing/integration-testing/index.jd
@@ -0,0 +1,55 @@
+page.title=Testing App Component Integrations
+page.tags=testing,integration
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>
+ You should also read
+ </h2>
+ <ul>
+ <li>
+ <a href="{@docRoot}tools/testing-support-library/index.html">Testing Support Library</a>
+ </li>
+ </ul>
+</div>
+</div>
+
+<p>
+If your app uses components that users do not directly interact with, such as
+a <a href="{@docRoot}guide/components/services.html">Service</a> or
+<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a>, you
+should validate that these components behave in a correct way with your app.</p>
+<p>When developing such components, you should get into the habit of writing
+<em>integration tests</em> in order to validate the component's behavior when your app runs on a
+device or an emulator.</p>
+
+<p class="note"><strong>Note:</strong> Android does not provide a separate test case class for
+{@link android.content.BroadcastReceiver}. To verify that a
+{@link android.content.BroadcastReceiver} responds correctly, you can test the component that sends
+it an {@link android.content.Intent} object. Alternatively, you can create an instance of your
+{@link android.content.BroadcastReceiver} by calling
+<a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getContext()">
+{@code InstrumentationRegistry.getTargetContext()}</a>, then call the
+{@link android.content.BroadcastReceiver} method that you want to test (usually, this is
+the
+{@link android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
+onReceive()} method).</p>
+
+<p>This class teaches you to build automated integration tests using the testing APIs and tools
+that the Android platform provides.</p>
+<h2>Lessons</h2>
+<dl>
+ <dt><strong><a href="service-testing.html">
+Testing Your Service</a></strong></dt>
+ <dd>Learn how to build integration tests to verify that a service works correctly with your
+ app.</dd>
+ <dt><strong><a href="content-provider-testing.html">
+Testing Your Content Provider</a></strong></dt>
+ <dd>Learn how to build integration tests to verify that a content provider works correctly with
+ your app.</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/training/testing/integration-testing/service-testing.jd b/docs/html/training/testing/integration-testing/service-testing.jd
new file mode 100644
index 0000000..7b420ac
--- /dev/null
+++ b/docs/html/training/testing/integration-testing/service-testing.jd
@@ -0,0 +1,140 @@
+page.title=Testing Your Service
+page.tags=testing, service
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>Dependencies and Prerequisites</h2>
+
+ <ul>
+ <li>Android 2.2 (API level 8) or higher</li>
+ <li><a href="{@docRoot}tools/testing-support-library/index.html">
+ Android Testing Support Library</a></li>
+ <li><a href="{@docRoot}tools/studio/index.html">Android Studio 1.4.1 or higher</a>.</li>
+ </ul>
+
+ <h2>This lesson teaches you to</h2>
+
+ <ol>
+ <li><a href="#setup">Set Up Your Testing Environment</a></li>
+ <li><a href="#build">Create an Integrated Test for Services</a></li>
+ <li><a href="#run">Run Integration Tests for Services</a></li>
+ </ol>
+
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}guide/components/services.html">Services</a></li>
+ </ul>
+
+ <h2>Try it out</h2>
+
+ <ul>
+ <li>
+<a href="https://github.com/googlesamples/android-testing/tree/master/integration/ServiceTestRuleSample"
+class="external-link">Service Test Code Samples</a></li>
+ </ul>
+</div>
+</div>
+
+<p>
+If you are implementing a local {@link android.app.Service} as a component of
+your app, you should test the {@link android.app.Service} to ensure that it doesn't behave in an
+unexpected way. You can create
+<a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html">
+instrumented unit tests</a> to verify that the behavior in the {@link android.app.Service}
+is correct; for example, the service stores and returns valid data values and performs
+data operations correctly.
+</p>
+
+<p>
+The <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+provides an API for testing your {@link android.app.Service} objects in isolation.
+The
+<a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">ServiceTestRule</a>
+class is a JUnit 4 rule that starts your service before your unit test methods
+run, and shuts down the service after tests complete. By using this test rule, you ensure that the
+connection to the service is always established before your test method runs. To
+learn more about JUnit 4 rules, see the <a href="https://github.com/junit-team/junit/wiki/Rules"
+class="external-link">JUnit documentation</a>.
+</p>
+
+<p style="note">
+<strong>Note</strong>: The
+<a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">ServiceTestRule</a>
+class does not support testing of {@link android.app.IntentService} objects.
+If you need to test a {@link android.app.IntentService} object, you should encapsulate the logic
+in a separate class and create a corresponding unit test instead.
+</p>
+
+<h2 id="setup">Set Up Your Testing Environment</h2>
+<p>Before building your integration test for the service, make sure to configure your project for
+ instrumented tests, as described in
+<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
+Getting Started with Testing</a>.</p>
+
+<h2 id="build">Create an Integration Test for Services</h2>
+<p>Your integration test should be written as a JUnit 4 test class. To learn more about creating
+JUnit 4 test classes and using JUnit 4 assertion methods, see
+<a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#build">
+Create an Instrumented Unit Test Class</a>.</p>
+
+<p>To create an integration test for your service, add the {@code @RunWith(AndroidJUnit4.class)}
+annotation at the beginning of your test class definition. You also need to specify the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+{@code AndroidJUnitRunner}</a> class that the Android Testing Support Library provides as your
+default test runner. This step is described in more detail in
+<a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#run">
+Run Instrumented Unit Tests</a>.</p>
+
+<p>Next, create a
+<a href="{@docRoot}reference/android/support/test/rule/ServiceTestRule.html">ServiceTestRule</a>
+instance in your test by using the {@code @Rule} annotation.</p>
+
+<pre>
+@Rule
+public final ServiceTestRule mServiceRule = new ServiceTestRule();
+</pre>
+
+<p>The following example shows how you might implement an integration test for a service.
+The test method {@code testWithBoundService} verifies that the app binds successfully to a
+local service and that the service interface behaves correctly.</p>
+
+<pre>
+@Test
+public void testWithBoundService() throws TimeoutException {
+ // Create the service Intent.
+ Intent serviceIntent =
+ new Intent(InstrumentationRegistry.getTargetContext(),
+ LocalService.class);
+
+ // Data can be passed to the service via the Intent.
+ serviceIntent.putExtra(LocalService.SEED_KEY, 42L);
+
+ // Bind the service and grab a reference to the binder.
+ IBinder binder = mServiceRule.bindService(serviceIntent);
+
+ // Get the reference to the service, or you can call
+ // public methods on the binder directly.
+ LocalService service =
+ ((LocalService.LocalBinder) binder).getService();
+
+ // Verify that the service is working correctly.
+ assertThat(service.getRandomInt(), is(any(Integer.class)));
+}
+</pre>
+
+<h2 id="run">Run Integration Tests for Services</h2>
+<p>
+You can run integration tests from <a href="{@docRoot}sdk/index.html">Android Studio</a> or
+from the command-line. Make sure to specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
+</p>
+<p>
+To run the integration test for your service, follow the steps for running instrumented tests
+described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</a>.
+</p>
diff --git a/docs/html/training/testing/performance.jd b/docs/html/training/testing/performance.jd
new file mode 100644
index 0000000..8592c0f
--- /dev/null
+++ b/docs/html/training/testing/performance.jd
@@ -0,0 +1,686 @@
+page.title=Testing Display Performance
+page.article=true
+page.image=images/cards/card-test-performance_2x.png
+page.keywords=performance, fps, tools
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#measure">Measuring UI Performance</a>
+ <ul>
+ <li><a href="#aggregate">Aggregate frame stats</a></li>
+ <li><a href="#timing-info">Precise frame timing info</a></li>
+ <li><a href="#timing-dump">Simple frame timing dump</a></li>
+ <li><a href="#collection-window">Controlling the window of stat collection</a></li>
+ <li><a href="#diagnose">Diagnosing performance regressions</a></li>
+ <li><a href="#resources">Additional resources</a></li>
+ </ul>
+ </li>
+ <li><a href="#automate">Automating UI Perfomance Tests</a>
+ <ul>
+ <li><a href="#ui-tests">Setting up UI tests</a></li>
+ <li><a href="#automated-tests">Setting up automated UI testing</a></li>
+ <li><a href="#triage">Triaging and fixing observed problems</a></li>
+ </ul>
+ </li>
+ </ol>
+
+ </div>
+</div>
+
+
+<p>
+ User interface (UI) performance testing ensures that your app not only meets its functional
+ requirements, but that user interactions with your app are buttery smooth, running at a
+ consistent 60 frames per second (<a href=
+ "https://www.youtube.com/watch?v=CaMTIgxCSqU&index=25&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">why
+ 60fps?</a>), without any dropped or delayed frames, or as we like to call it, <em>jank</em>. This
+ document explains tools available to measure UI performance, and lays out an approach to
+ integrate UI performance measurements into your testing practices.
+</p>
+
+
+<h2 id="measure">Measuring UI Performance</h2>
+
+<p>
+ In order to improve performance you first need the ability to measure the performance of
+ your system, and then diagnose and identify problems that may arrive from various parts of your
+ pipeline.
+</p>
+
+<p>
+ <em><a href="https://source.android.com/devices/tech/debug/dumpsys.html">dumpsys</a></em> is an
+ Android tool that runs on the device and dumps interesting information about the status of system
+ services. Passing the <em>gfxinfo</em> command to dumpsys provides an output in logcat with
+ performance information relating to frames of animation that are occurring during the recording
+ phase.
+</p>
+
+<pre>
+> adb shell dumpsys gfxinfo <PACKAGE_NAME>
+</pre>
+
+<p>
+ This command can produce multiple different variants of frame timing data.
+</p>
+
+<h3 id="aggregate">Aggregate frame stats</h3>
+
+<p>
+ With the M Preview the command prints out aggregated analysis of frame data to logcat, collected
+ across the entire lifetime of the process. For example:
+</p>
+
+<pre class="noprettyprint">
+Stats since: 752958278148ns
+Total frames rendered: 82189
+Janky frames: 35335 (42.99%)
+90th percentile: 34ms
+95th percentile: 42ms
+99th percentile: 69ms
+Number Missed Vsync: 4706
+Number High input latency: 142
+Number Slow UI thread: 17270
+Number Slow bitmap uploads: 1542
+Number Slow draw: 23342
+</pre>
+
+<p>
+ These high level statistics convey at a high level the rendering performance of the app, as well
+ as its stability across many frames.
+</p>
+
+
+<h3 id="timing-info">Precise frame timing info</h3>
+
+<p>
+ With the M Preview comes a new command for gfxinfo, and that’s <em>framestats</em> which provides
+ extremely detailed frame timing information from recent frames, so that you can track down and
+ debug problems more accurately.
+</p>
+
+<pre>
+>adb shell dumpsys gfxinfo <PACKAGE_NAME> framestats
+</pre>
+
+<p>
+ This command prints out frame timing information, with nanosecond timestamps, from the last 120
+ frames produced by the app. Below is example raw output from adb dumpsys gfxinfo
+ <PACKAGE_NAME> framestats:
+</p>
+
+<pre class="noprettyprint">
+0,27965466202353,27965466202353,27965449758000,27965461202353,27965467153286,27965471442505,27965471925682,27965474025318,27965474588547,27965474860786,27965475078599,27965479796151,27965480589068,
+0,27965482993342,27965482993342,27965465835000,27965477993342,27965483807401,27965486875630,27965487288443,27965489520682,27965490184380,27965490568703,27965491408078,27965496119641,27965496619641,
+0,27965499784331,27965499784331,27965481404000,27965494784331,27965500785318,27965503736099,27965504201151,27965506776568,27965507298443,27965507515005,27965508405474,27965513495318,27965514061984,
+0,27965516575320,27965516575320,27965497155000,27965511575320,27965517697349,27965521276151,27965521734797,27965524350474,27965524884536,27965525160578,27965526020891,27965531371203,27965532114484,
+</pre>
+
+<p>
+ Each line of this output represents a frame produced by the app. Each line has a fixed number of
+ columns describing time spent in each stage of the frame-producing pipeline. The next section
+ describes this format in detail, including what each column represents.
+</p>
+
+
+<h4 id="fs-data-format">Framestats data format</h4>
+
+<p>
+ Since the block of data is output in CSV format, it's very straightforward to paste it to your
+ spreadsheet tool of choice, or collect and parse with a script. The following table explains the
+ format of the output data columns. All timestamps are in nanoseconds.
+</p>
+
+<ul>
+ <li>FLAGS
+ <ul>
+ <li>Rows with a ‘0’ for the FLAGS column can have their total frame time computed by
+ subtracting the INTENDED_VSYNC column from the FRAME_COMPLETED column.
+ </li>
+
+ <li>If this is non-zero the row should be ignored, as the frame has been determined as being
+ an outlier from normal performance, where it is expected that layout & draw take longer
+ than 16ms. Here are a few reasons this could occur:
+ <ul>
+ <li>The window layout changed (such as the first frame of the application or after a
+ rotation)
+ </li>
+
+ <li>It is also possible the frame was skipped in which case some of the values will have
+ garbage timestamps. A frame can be skipped if for example it is out-running 60fps or if
+ nothing on-screen ended up being dirty, this is not necessarily a sign of a problem in
+ the app.
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+
+ <li>INTENDED_VSYNC
+ <ul>
+ <li>The intended start point for the frame. If this value is different from VSYNC, there
+ was work occurring on the UI thread that prevented it from responding to the vsync signal
+ in a timely fashion.
+ </li>
+ </ul>
+ </li>
+
+ <li>VSYNC
+ <ul>
+ <li>The time value that was used in all the vsync listeners and drawing for the frame
+ (Choreographer frame callbacks, animations, View.getDrawingTime(), etc…)
+ </li>
+
+ <li>To understand more about VSYNC and how it influences your application, check out the
+ <a href=
+ "https://www.youtube.com/watch?v=1iaHxmfZGGc&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=23">
+ Understanding VSYNC</a> video.
+ </li>
+ </ul>
+ </li>
+
+ <li>OLDEST_INPUT_EVENT
+ <ul>
+ <li>The timestamp of the oldest input event in the input queue, or Long.MAX_VALUE if
+ there were no input events for the frame.
+ </li>
+
+ <li>This value is primarily intended for platform work and has limited usefulness to app
+ developers.
+ </li>
+ </ul>
+ </li>
+
+ <li>NEWEST_INPUT_EVENT
+ <ul>
+ <li>The timestamp of the newest input event in the input queue, or 0 if there were no
+ input events for the frame.
+ </li>
+
+ <li>This value is primarily intended for platform work and has limited usefulness to app
+ developers.
+ </li>
+
+ <li>However it’s possible to get a rough idea of how much latency the app is adding by
+ looking at (FRAME_COMPLETED - NEWEST_INPUT_EVENT).
+ </li>
+ </ul>
+ </li>
+
+ <li>HANDLE_INPUT_START
+ <ul>
+ <li>The timestamp at which input events were dispatched to the application.
+ </li>
+
+ <li>By looking at the time between this and ANIMATION_START it is possible to measure how
+ long the application spent handling input events.
+ </li>
+
+ <li>If this number is high (>2ms), this indicates the app is spending an unusually
+ long time processing input events, such as View.onTouchEvent(), which may indicate this
+ work needs to be optimized, or offloaded to a different thread. Note that there are some
+ scenarios, such as click events that launch new activities or similar, where it is
+ expected and acceptable that this number is large.
+ </li>
+ </ul>
+ </li>
+
+ <li>ANIMATION_START
+ <ul>
+ <li>The timestamp at which animations registered with Choreographer were run.
+ </li>
+
+ <li>By looking at the time between this and PERFORM_TRANVERSALS_START it is possible to
+ determine how long it took to evaluate all the animators (ObjectAnimator,
+ ViewPropertyAnimator, and Transitions being the common ones) that are running.
+ </li>
+
+ <li>If this number is high (>2ms), check to see if your app has written any custom
+ animators or what fields ObjectAnimators are animating and ensure they are appropriate
+ for an animation.
+ </li>
+
+ <li>To learn more about Choreographer, check out the <a href=
+ "https://www.youtube.com/watch?v=Q8m9sHdyXnE">For Butter or Worse</a>
+ video.
+ </li>
+ </ul>
+ </li>
+
+ <li>PERFORM_TRAVERSALS_START
+ <ul>
+ <li>If you subtract out DRAW_START from this value, you can extract how long the layout
+ & measure phases took to complete. (note, during a scroll, or animation, you would
+ hope this should be close to zero..)
+ </li>
+
+ <li>To learn more about the measure & layout phases of the rendering pipeline, check
+ out the <a href=
+ "https://www.youtube.com/watch?v=we6poP0kw6E&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=27">
+ Invalidations, Layouts and Performance</a> video
+ </li>
+ </ul>
+ </li>
+
+ <li>DRAW_START
+ <ul>
+ <li>The time at which the draw phase of performTraversals started. This is the start
+ point of recording the display lists of any views that were invalidated.
+ </li>
+
+ <li>The time between this and SYNC_START is how long it took to call View.draw() on all
+ the invalidated views in the tree.
+ </li>
+
+ <li>For more information on the drawing model, see <a href=
+ "{@docRoot}guide/topics/graphics/hardware-accel.html#hardware-model">Hardware Acceleration</a>
+ or the <a href=
+ "https://www.youtube.com/watch?v=we6poP0kw6E&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu&index=27">
+ Invalidations, Layouts and Performance</a> video
+ </li>
+ </ul>
+ </li>
+
+ <li>SYNC_QUEUED
+ <ul>
+ <li>The time at which a sync request was sent to the RenderThread.
+ </li>
+
+ <li>This marks the point at which a message to start the sync
+ phase was sent to the RenderThread. If the time between this and
+ SYNC_START is substantial (>0.1ms or so), it means that
+ the RenderThread was busy working on a different frame. Internally
+ this is used to differentiate between the frame doing too much work
+ and exceeding the 16ms budget and the frame being stalled due to
+ the previous frame exceeding the 16ms budget.
+ </li>
+ </ul>
+ </li>
+
+ <li>SYNC_START
+ <ul>
+ <li>The time at which the sync phase of the drawing started.
+ </li>
+
+ <li>If the time between this and ISSUE_DRAW_COMMANDS_START is substantial (>0.4ms or
+ so), it typically indicates a lot of new Bitmaps were drawn which must be uploaded to the
+ GPU.
+ </li>
+
+ <li>To understand more about the sync phase, check out the <a href=
+ "https://www.youtube.com/watch?v=VzYkVL1n4M8&index=24&list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu">
+ Profile GPU Rendering</a> video
+ </li>
+ </ul>
+ </li>
+
+ <li>ISSUE_DRAW_COMMANDS_START
+ <ul>
+ <li>The time at which the hardware renderer started issuing drawing commands to the GPU.
+ </li>
+
+ <li>The time between this and FRAME_COMPLETED gives a rough idea of how much GPU work the
+ app is producing. Problems like too much overdraw or inefficient rendering effects show
+ up here.
+ </li>
+ </ul>
+ </li>
+
+ <li>SWAP_BUFFERS
+ <ul>
+ <li>The time at which eglSwapBuffers was called, relatively uninteresting outside of
+ platform work.
+ </li>
+ </ul>
+ </li>
+
+ <li>FRAME_COMPLETED
+ <ul>
+ <li>All done! The total time spent working on this frame can be computed by doing
+ FRAME_COMPLETED - INTENDED_VSYNC.
+ </li>
+ </ul>
+ </li>
+
+</ul>
+
+<p>
+ You can use this data in different ways. One simple but useful visualization is a
+ histogram showing the distribution of frames times (FRAME_COMPLETED - INTENDED_VSYNC) in
+ different latency buckets, see figure below. This graph tells us at a glance that most
+ frames were very good - well below the 16ms deadline (depicted in red), but a few frames
+ were significantly over the deadline. We can look at changes in this histogram over time
+ to see wholesale shifts or new outliers being created. You can also graph input latency,
+ time spent in layout, or other similar interesting metrics based on the many timestamps
+ in the data.
+</p>
+
+<img src="{@docRoot}images/performance-testing/perf-test-framestats.png">
+
+
+<h3 id="timing-dump">Simple frame timing dump</h3>
+
+<p>
+ If <strong>Profile GPU rendering</strong> is set to <strong>In adb shell dumpsys gfxinfo</strong>
+ in Developer Options, the <code>adb shell dumpsys gfxinfo</code> command prints out timing
+ information for the most recent 120 frames, broken into a few different categories with
+ tab-separated-values. This data can be useful for indicating which parts of the drawing pipeline
+ may be slow at a high level.
+</p>
+
+<p>
+ Similar to <a href="#fs-data-format">framestats</a> above, it's very
+ straightforward to paste it to your spreadsheet tool of choice, or collect and parse with
+ a script. The following graph shows a breakdown of where many frames produced by the app
+ were spending their time.
+</p>
+
+<img src="{@docRoot}images/performance-testing/perf-test-frame-latency.png">
+
+<p>
+ The result of running gfxinfo, copying the output, pasting it into a spreadsheet
+ application, and graphing the data as stacked bars.
+</p>
+
+<p>
+ Each vertical bar represents one frame of animation; its height represents the number of
+ milliseconds it took to compute that frame of animation. Each colored segment of the bar
+ represents a different stage of the rendering pipeline, so that you can see what parts of
+ your application may be creating a bottleneck. For more information on understanding the
+ rendering pipeline, and how to optimize for it, see the <a href=
+ "https://www.youtube.com/watch?v=we6poP0kw6E&index=27&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+ Invalidations Layouts and Performance</a> video.
+</p>
+
+
+<h3 id="collection-window">Controlling the window of stat collection</h3>
+
+<p>
+ Both the framestats and simple frame timings gather data over a very short window - about
+ two seconds worth of rendering. In order to precisely control this window of time - for
+ example, to constrain the data to a particular animation - you can reset all counters,
+ and aggregate statistics gathered.
+</p>
+
+<pre>
+>adb shell dumpsys gfxinfo <PACKAGE_NAME> reset
+</pre>
+
+<p>
+ This can also be used in conjunction with the dumping commands themselves to collect and
+ reset at a regular cadence, capturing less-than-two-second windows of frames
+ continuously.
+</p>
+
+
+<h3 id="diagnose">Diagnosing performance regressions</h3>
+
+<p>
+ Identification of regressions is a good first step to tracking down problems, and
+ maintaining high application health. However, dumpsys just identifies the existence and
+ relative severity of problems. You still need to diagnose the particular cause of the
+ performance problems, and find appropriate ways to fix them. For that, it’s highly
+ recommended to use the <a href="{@docRoot}tools/help/systrace.html">systrace</a> tool.
+</p>
+
+
+<h3 id="resources">Additional resources</h3>
+
+<p>
+ For more information on how Android’s rendering pipeline works, common problems that you
+ can find there, and how to fix them, some of the following resources may be useful to
+ you:
+</p>
+
+<ul>
+ <li>Rendering Performance 101
+ </li>
+ <li>Why 60fps?
+ </li>
+ <li>Android UI and the GPU
+ </li>
+ <li>Invalidations Layouts and performance
+ </li>
+ <li>Analyzing UI Performance with Systrace
+ </li>
+</ul>
+
+
+<h2 id="automate">Automating UI Perfomance Tests</h2>
+
+<p>
+ One approach to UI Performance testing is to simply have a human tester perform a set of
+ user operations on the target app, and either visually look for jank, or spend an very
+ large amount of time using a tool-driven approach to find it. But this manual approach is
+ fraught with peril - human ability to perceive frame rate changes varies tremendously,
+ and this is also time consuming, tedious, and error prone.
+</p>
+
+<p>
+ A more efficient approach is to log and analyze key performance metrics from automated UI
+ tests. The Android M developer preview includes new logging capabilities which make it
+ easy to determine the amount and severity of jank in your application’s animations, and
+ that can be used to build a rigorous process to determine your current performance and
+ track future performance objectives.
+</p>
+
+<p>
+ This article walks you through a recommended approach to using that data to automate your
+ performance testing.
+</p>
+
+<p>
+ This is mostly broken down into two key actions. Firstly, identifying what you're
+ testing, and how you’re testing it. and Secondly, setting up, and maintaining an
+ automated testing environment.
+</p>
+
+
+<h3 id="ui-tests">Setting up UI tests</h3>
+
+<p>
+ Before you can get started with automated testing, it’s important to determine a few high
+ level decisions, in order to properly understand your test space, and needs you may have.
+</p>
+
+<h4>
+ Identify key animations / flows to test
+</h4>
+
+<p>
+ Remember that bad performance is most visible to users when it interrupts a smooth
+ animation. As such, when identifying what types of UI actions to test for, it’s useful to
+ focus on the key animations that users see most, or are most important to their
+ experience. For example, here are some common scenarios that may be useful to identify:
+</p>
+
+<ul>
+ <li>Scrolling a primary ListView or RecyclerView
+ </li>
+
+ <li>Animations during async wait cycles
+ </li>
+
+ <li>Any animation that may have bitmap loading / manipulation in it
+ </li>
+
+ <li>Animations including Alpha Blending
+ </li>
+
+ <li>Custom View drawing with Canvas
+ </li>
+</ul>
+
+<p>
+ Work with engineers, designers, and product managers on your team to prioritize these key
+ product animations for test coverage.
+</p>
+
+<h4>
+ Define your future objectives and track against them
+</h4>
+
+<p>
+ From a high-level, it may be critical to identify your specific performance goals, and
+ focus on writing tests, and collecting data around them. For example:
+</p>
+
+<ul>
+ <li>Do you just want to begin tracking UI performance for the first time to learn more?
+ </li>
+
+ <li>Do you want to prevent regressions that might be introduced in the future?
+ </li>
+
+ <li>Are you at 90% of smooth frames today and want to get to 98% this quarter?
+ </li>
+
+ <li>Are you at 98% smooth frames and don’t want to regress?
+ </li>
+
+ <li>Is your goal to improve performance on low end devices?
+ </li>
+</ul>
+
+<p>
+ In all of these cases, you’ll want historical tracking which shows performance across
+ multiple versions of your application.
+</p>
+
+<h4>
+ Identify devices to test on
+</h4>
+
+<p>
+ Application performance varies depending on the device it's running on. Some devices may
+ contain less memory, less powerful GPUs, or slower CPU chips. This means that animations
+ which may perform well on one set of hardware, may not on others, and worse, may be a
+ result of a bottleneck in a different part of the pipeline. So, to account for this
+ variation in what a user might see, pick a range of devices to execute tests on, both
+ current high end devices, low end devices, tablets, etc. Look for variation in CPU
+ performance, RAM, screen density, size, and so on. Tests that pass on a high end device
+ may fail on a low end device.
+</p>
+
+<h4>
+ Basic frameworks for UI Testing
+</h4>
+
+<p>
+ Tool suites, like <a href=
+ "{@docRoot}training/testing/ui-testing/uiautomator-testing.html">UI Automator</a> and
+ <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso</a>, are
+ built to help automate the action of a user moving through your application. These are simple
+ frameworks which mimic user interaction with your device. To use these frameworks, you
+ effectively create unique scripts, which run through a set of user-actions, and play them
+ out on the device itself.
+</p>
+
+<p>
+ By combining these automated tests, alongside <code>dumpsys gfxinfo</code> you can quickly
+ create a reproducible system that allows you to execute a test, and measure the
+ performance information of that particular condition.
+</p>
+
+
+<h3 id="automated-tests">Setting up automated UI testing</h3>
+
+<p>
+ Once you have the ability to execute a UI test, and a pipeline to gather the data from a
+ single test, the next important step is to embrace a framework which can execute that
+ test multiple times, across multiple devices, and aggregate the resulting performance
+ data for further analysis by your development team.
+</p>
+
+<h4>
+ A framework for test automation
+</h4>
+
+<p>
+ It’s worth noting that UI testing frameworks (like <a href=
+ "{@docRoot}training/testing/ui-testing/uiautomator-testing.html">UI Automator</a>)
+ run on the target device/emulator directly. While performance gathering information done
+ by <em>dumpsys gfxinfo</em> is driven by a host machine, sending commands over ADB. To
+ help bridge the automation of these separate entities, <a href=
+ "{@docRoot}tools/help/monkeyrunner_concepts.html">MonkeyRunner</a> framework was
+ developed; A scripting system that runs on your host machine, which can issue commands to
+ a set of connected devices, as well as receive data from them.
+</p>
+
+<p>
+ Building a set of scripts for proper automation of UI Performance testing, at a minimum,
+ should be able to utilize monkeyRunner to accomplish the following tasks:
+</p>
+
+<ul>
+ <li>Load & Launch a desired APK to a target device, devices, or emulator.
+ </li>
+
+ <li>Launch a UI Automator UI test, and allow it to be executed
+ </li>
+
+ <li>Collect performance information through <em>dumpsys gfxinfo</em><em>.</em>
+ </li>
+
+ <li>Aggregate information and display it back in a useful fashion to the developer.
+ </li>
+</ul>
+
+
+<h3 id="triage">Triaging and fixing observed problems</h3>
+
+<p>
+ Once problem patterns or regressions are identified, the next step is identifying and
+ applying the fix. If your automated test framework preserves precise timing breakdowns
+ for frames, it can help you scrutinize recent suspicious code/layout changes (in the case
+ of regression), or narrow down the part of the system you’re analyzing when you switch to
+ manual investigation. For manual investigation, <a href=
+ "{@docRoot}tools/help/systrace.html">systrace</a> is a great place to start, showing
+ precise timing information about every stage of the rendering pipeline, every thread and
+ core in the system, as well as any custom event markers you define.
+</p>
+
+<h4>
+ Properly profiling temporal timings
+</h4>
+
+<p>
+ It is important to note the difficulties in obtaining and measuring timings that come from
+ rendering performance. These numbers are, by nature, non deterministic, and often
+ fluctuate depending on the state of the system, amount of memory available, thermal
+ throttling, and the last time a sun flare hit your area of the earth. The point is that
+ you can run the same test, twice and get slightly different numbers that may be close to
+ each other, but not exact.
+</p>
+
+<p>
+ Properly gathering and profiling data in this manner means running the same test,
+ multiple times, and accumulating the results as an average, or median value. (for the
+ sake of simplicity, let’s call this a ‘batch’) This gives you the rough approximation of
+ the performance of the test, while not needing exact timings.
+</p>
+
+<p>
+ Batches can be used between code changes to see the relative impact of those changes on
+ performance. If the average frame rate for the pre-change Batch is larger than the
+ post-change batch, then you generally have an overall win wrt performance for that
+ particular change.
+</p>
+
+<p>
+ This means that any Automated UI testing you do should take this concept into
+ consideration, and also account for any anomalies that might occur during a test. For
+ example, if your application performance suddenly dips, due to some device issue (that
+ isn’t caused by your application) then you may want to re-run the batch in order to get
+ less chaotic timings.
+</p>
+
+<p>
+ So, how many times should you run a test, before the measurements become meaningful? 10
+ times should be the minimum, with higher numbers like 50 or 100 yielding more accurate
+ results (of course, you’re now trading off time for accuracy)
+</p>
diff --git a/docs/html/training/testing/start/index.jd b/docs/html/training/testing/start/index.jd
new file mode 100644
index 0000000..a4b4aea
--- /dev/null
+++ b/docs/html/training/testing/start/index.jd
@@ -0,0 +1,252 @@
+page.title=Getting Started with Testing
+page.tags="testing"
+page.article=true
+page.image=images/tools/studio-main-screen.png
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li><a href="{@docRoot}tools/studio/index.html">Android Studio (latest version)</a>.</li>
+</ul>
+
+<h2>This lesson teaches you to</h2>
+<ol>
+<li><a href="#setup">Set Up Your Testing Environment</a></li>
+<li><a href="#build">Build and Run Your Tests</a></li>
+</ol>
+
+<h2>You Should Also Read</h2>
+<ul>
+<li><a href="{@docRoot}tools/testing/testing_android.html">Testing Concepts</a></li>
+<li><a href="https://github.com/googlesamples/android-testing"
+ class="external-link">Android Testing Samples</a></li>
+<li><a href="{@docRoot}about/dashboards/index.html">Android Dashboards</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>You should be writing and running tests as part of your Android app development cycle.
+Well-written tests can help you catch bugs early in development and give you confidence in your
+code.</p>
+
+<p>To verify specific behavior in your app, and to check for consistency across different Android
+devices, you can write a <a href="//en.wikipedia.org/wiki/Test_case"
+class="external-link">test case</a>. This lesson teaches you how to build a test case using the
+JUnit 4 framework and the testing APIs and tools provided by Google, and how to run your
+tests.</p>
+
+<h2 id="setup">Set Up Your Testing Environment</h2>
+
+<p>Before you start writing and running your tests, you must set up your test
+development environment. Android Studio provides an integrated development environment for you to
+create, build, and run Android app test cases from a graphical user interface (GUI).</p>
+
+<p>You must first download the prerequisite Android development tools before proceeding:
+<ul>
+<li><a href="{@docRoot}sdk/index.html">Android Studio</a> (latest version).</li>
+<li>The latest Android Support Repository using the
+ <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>. </li>
+</ul>
+
+<p>Based on the type of test you want to create, configure the test code source location and the
+ project dependencies in Android Studio as described in the following sections.</p>
+
+<h3 id="config-local-tests">Configure Your Project for Local Unit Tests</h3>
+<p><em>Local unit tests</em> are tests that run on your local machine, without needing access to the
+Android framework or an Android device. To learn how to develop local units tests, see
+<a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html">
+Building Local Unit Tests</a>.</p>
+<p>In your Android Studio project, you must store the source files for local unit tests under a
+specific source directory ({@code src/test/java}). This feature improves your project organization
+by letting you group your unit tests together into a single source set.</p>
+<p>As with production code, you can create local unit tests for a
+<a href="http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants"
+class="external-link">specific flavor or build type</a>. Keep your unit tests in a test
+source tree location that corresponds to your production source tree, such as:</p>
+
+<table>
+<tr>
+<th>Path to Production Class</th>
+<th>Path to Local Unit Test Class</th>
+</tr>
+<tr>
+<td>{@code src/main/java/Foo.java}</td>
+<td>{@code src/test/java/FooTest.java}</td>
+</tr>
+<tr>
+<td>{@code src/debug/java/Foo.java}</td>
+<td>{@code src/testDebug/java/FooTest.java}</td>
+</tr>
+<tr>
+<td>{@code src/myFlavor/java/Foo.java}</td>
+<td>{@code src/testMyFlavor/java/FooTest.java}</td>
+</tr>
+</table>
+
+<p>You'll need to configure the testing dependencies for your project to use the
+ standard APIs provided by the JUnit 4 framework. To simplify your local unit test development,
+ we recommend that you include the <a href="https://github.com/mockito/mockito"
+ class="external-link">Mockito</a> library if your test needs to interact with Android
+ dependencies. To learn more about using mock objects in your local unit tests, see
+<a href="{@docRoot}training/testing/unit-testing/local-unit-tests.html#mocking-dependencies">
+ Mocking Android dependencies</a>.</p>
+<p>In the {@code build.gradle} file of your Android app module, specify your dependencies like
+this:</p>
+
+<pre>
+dependencies {
+ // Required -- JUnit 4 framework
+ testCompile 'junit:junit:4.12'
+ // Optional -- Mockito framework
+ testCompile 'org.mockito:mockito-core:1.10.19'
+}
+</pre>
+
+<h3 id="config-instrumented-tests">Configure Your Project for Instrumented Tests</h3>
+<p><em>Instrumented tests</em> are tests that run on an Android device or emulator. These tests
+have access to {@link android.app.Instrumentation} information, such as the
+{@link android.content.Context} for the app under test. Instrumented tests can be used for unit,
+user interface (UI), or app component integration testing. To learn how to develop instrumented
+tests for your specific needs, see these additional topics:
+<ul>
+<li><a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html">
+ Building Instrumented Unit Tests</a> - Build more complex unit tests that have Android
+ dependencies which cannot be easily filled by using mock objects.</li>
+<li><a href="{@docRoot}training/testing/ui-testing/index.html">
+ Automating User Interface Tests</a> - Create tests to verify that the user interface behaves
+ correctly for user interactions within a single app or for interactions across multiple apps.</li>
+<li><a href="{@docRoot}training/testing/integration-testing/index.html">
+ Testing App Component Integrations</a> - Verify the behavior of components that users do not
+directly interact with, such as a <a href="{@docRoot}guide/components/services.html">Service</a> or
+a <a href="guide/topics/providers/content-providers.html">Content Provider</a>.</li>
+</ul>
+</p>
+<p>
+In your Android Studio project, you must place the source code for your instrumentated tests under
+a specific directory (<code>src/androidTest/java</code>).
+</p>
+<p>
+Download the Android Testing Support Library, which provides APIs that allow you to quickly build and
+run instrumented test code for your apps. The Testing Support Library includes a JUnit 4 test runner
+(<a href="{@docRoot}tools/testing-support-library/index.html#AndroidJUnitRunner">AndroidJUnitRunner
+</a>) and APIs for functional UI tests
+(<a href="{@docRoot}tools/testing-support-library/index.html#Espresso">Espresso</a> and
+<a href="{@docRoot}tools/testing-support-library/index.html#UIAutomator">UI Automator</a>). To
+learn how to install the library, see
+<a href="{@docRoot}tools/testing-support-library/index.html#setup">Testing Support Library Setup</a>.
+</p>
+<p>You'll need to configure the Android testing dependencies for your project to use the test runner
+and the rules APIs provided by the Testing Support Library. To simplify your test development,
+we also recommend that you include the <a href="https://github.com/hamcrest"
+class="external-link">Hamcrest</a> library, which lets you create more flexible assertions using the
+Hamcrest matcher APIs.</p>
+<p>In the {@code build.gradle} file of your Android app module, specify your dependencies like
+this:</p>
+<pre>
+dependencies {
+ androidTestCompile 'com.android.support:support-annotations:23.0.1'
+ androidTestCompile 'com.android.support.test:runner:0.4.1'
+ androidTestCompile 'com.android.support.test:rules:0.4.1'
+ // Optional -- Hamcrest library
+ androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
+ // Optional -- UI testing with Espresso
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
+ // Optional -- UI testing with UI Automator
+ androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
+}
+</pre>
+
+<h2 id="build">Build and Run Your Tests</h2>
+
+<p>You can run build and run your tests in a similar way to how you run your Android apps --
+ graphically in Android Studio or from the command-line using the
+<a href="{@docRoot}tools/building/plugin-for-gradle.html">
+Android Plugin for Gradle</a>.</p>
+
+<h3 id="run-local-tests">Run Local Unit Tests</h3>
+<p>
+The Android Plugin for Gradle compiles the local unit test code located in the default directory
+({@code src/test/java}), builds a test app, and executes it locally
+using the default test runner class.
+</p>
+<p>
+To run local unit tests in your Gradle project from Android Studio:
+</p>
+<ol>
+<li>In the <strong>Project</strong> window, right click on the project and synchronize your project.
+</li>
+<li>Open the <strong>Build Variants</strong> window by clicking the left-hand tab, then change the
+test artifact to <em>Unit Tests</em>.
+</li>
+<li>In the <strong>Project</strong> window, drill down to your unit test class or method,
+then right-click and run it. To run all tests in the unit test directory, select the directory then
+right-click and press <strong>Run tests</strong>.
+</li>
+</ol>
+
+<p>Android Studio displays the results of the unit test execution in the <strong>Run</strong>
+window.</p>
+
+<p>To run local unit tests in your Gradle project from the command-line, call the {@code test} task
+command.</p>
+
+<pre>
+./gradlew test
+</pre>
+
+<p>If there are failing tests, the command will display links to HTML reports (one per build
+variant). You can find the generated HTML test result reports in the
+{@code <path_to_your_project>/app/build/reports/tests/} directory, and the corresponding XML
+files in the {@code <path_to_your_project>/app/build/test-results/} directory.</p>
+
+<h3 id="run-instrumented-tests">Run Instrumented Tests</h3>
+<p>
+The Android Plugin for Gradle compiles the instrumented test code located in the default directory
+({@code src/androidTest/java}), builds a test APK and production APK, installs both APKs on the
+connected device or emulator, and executes the tests.</p>
+
+<p>Make sure to specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+{@code AndroidJUnitRunner}</a> as the default test instrumentation runner in your project. To do
+this, add the following setting in your {@code build.gradle} file:</p>
+
+<pre>
+android {
+ defaultConfig {
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+}
+</pre>
+
+<p>To run your instrumented tests in Android Studio:</p>
+<ol>
+<li>Open the <strong>Build Variants</strong> window by clicking the left-hand tab, then set the
+test artifact to <em>Android Instrumentation Tests</em>.
+</li>
+<li>In the <strong>Project</strong> window, drill down to your instrumented test class or method,
+ then right-click and run it using the Android Test configuration. To run all tests in the
+instrumented test directory, select the directory then right-click and press
+<strong>Run tests</strong>.
+</li>
+</ol>
+
+<p>Android Studio displays the results of the instrumented test execution in the
+<strong>Run</strong> window.</p>
+
+<p>To run your instrumented tests from the command-line via Gradle, call the
+ {@code connectedAndroidTest} (or {@code cAT}) task:</p>
+
+<pre>
+./gradlew cAT
+</pre>
+
+<p>You can find the generated HTML test result reports in the
+{@code <path_to_your_project>/app/build/outputs/reports/androidTests/connected/} directory,
+and the corresponding XML files in the
+{@code <path_to_your_project>/app/build/outputs/androidTest-results/connected/} directory.</p>
\ No newline at end of file
diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
index 7637547..45a4ceb 100644
--- a/docs/html/training/testing/ui-testing/espresso-testing.jd
+++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
@@ -55,6 +55,8 @@
<a href="https://github.com/googlesamples/android-testing"
class="external-link">Espresso Code Samples</a>
</li>
+ <li><a href="https://www.code-labs.io/codelabs/android-testing/index.html?index=..%2F..%2Findex#0"
+ class="external-link">Android Testing Codelab</a></li>
</ul>
</div>
</div>
@@ -90,72 +92,51 @@
Set Up Espresso
</h2>
- <p>
- Before you begin using Espresso, you must:
- </p>
+<p>Before building your UI test with Espresso, make sure to configure your test source code
+location and project dependencies, as described in
+<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
+Getting Started with Testing</a>.</p>
- <ul>
- <li>
- <strong>Install the Android Testing Support Library</strong>. The Espresso API is
- located under the {@code com.android.support.test.espresso} package. These classes allow
- you to create tests that use the Espresso testing framework. To learn how to install the
- library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
- Testing Support Library Setup</a>.
- </li>
+<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
+ reference to the Espresso library:</p>
- <li>
- <strong>Set up your project structure.</strong> In your Gradle project, the source code for
- the target app that you want to test is typically placed under the {@code app/src/main}
- folder. The source code for instrumentation tests, including
- your Espresso tests, must be placed under the <code>app/src/androidTest</code> folder. To
- learn more about setting up your project directory, see
- <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
- </li>
-
- <li>
- <strong>Specify your Android testing dependencies</strong>. In order for the
- <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
- correctly build and run your Espresso tests, you must specify the following libraries in
- the {@code build.gradle} file of your Android app module:
-
- <pre>
+<pre>
dependencies {
- androidTestCompile 'com.android.support.test:runner:0.3'
- androidTestCompile 'com.android.support.test:rules:0.3'
- androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
+ ...
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
}
</pre>
- </li>
- <li>
- <strong>Turn off animations on your test device.</strong> Leaving system animations turned
- on in the test device might cause unexpected results or may lead your test to fail. Turn
- off animations from <em>Settings</em> by opening <em>Developing Options</em> and
- turning all the following options off:
+<p>Turn off animations on your test device — leaving system animations turned on in the test
+device might cause unexpected results or may lead your test to fail. Turn off animations from
+<em>Settings</em> by opening <em>Developing Options</em> and turning all the following options off:
+</p>
<ul>
<li>
- <em>Window animation scale</em>
+ <strong>Window animation scale</strong>
</li>
<li>
- <em>Transition animation scale</em>
+ <strong>Transition animation scale</strong>
</li>
<li>
- <em>Animator duration scale</em>
+ <strong>Animator duration scale</strong>
</li>
</ul>
</li>
</ul>
+<p>If you want to set up your project to use Espresso features other than what the core API
+ provides, see this
+ <a href="https://google.github.io/android-testing-support-library/docs/espresso/index.html"
+ class="external-link">resource</a>.</p>
<h2 id="build">
Create an Espresso Test Class
</h2>
<p>
- To create an Espresso test, create a Java class or an
- {@link android.test.ActivityInstrumentationTestCase2}
- subclass that follows this programming model:
+ To create an Espresso test, create a Java class that follows this programming model:
</p>
<ol>
@@ -200,11 +181,70 @@
.perform(click()) // click() is a ViewAction
.check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
</pre>
+<h3 id="espresso-atr">Using Espresso with ActivityTestRule</h3>
+<p>
+The following section describes how to create a new Espresso test in the JUnit 4 style and use
+<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+{@code ActivityTestRule}</a> to reduce the amount of boilerplate code you need to write. By using
+<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+{@code ActivityTestRule}</a>, the testing framework launches the activity under test
+before each test method annotated with {@code @Test} and before any method annotated with
+{@code @Before}. The framework handles shutting down the activity after the test finishes
+and all methods annotated with {@code @After} are run.</p>
+
+<pre>
+package com.example.android.testing.espresso.BasicSample;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+...
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ChangeTextBehaviorTest {
+
+ private String mStringToBetyped;
+
+ @Rule
+ public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
+ MainActivity.class);
+
+ @Before
+ public void initValidString() {
+ // Specify a valid string.
+ mStringToBetyped = "Espresso";
+ }
+
+ @Test
+ public void changeText_sameActivity() {
+ // Type text and then press the button.
+ onView(withId(R.id.editTextUserInput))
+ .perform(typeText(mStringToBetyped), closeSoftKeyboard());
+ onView(withId(R.id.changeTextBt)).perform(click());
+
+ // Check that the text was changed.
+ onView(withId(R.id.textToBeChanged))
+ .check(matches(withText(mStringToBetyped)));
+ }
+}
+</pre>
<h3 id="espresso-aitc2">
Using Espresso with ActivityInstrumentationTestCase2
</h3>
-
+<p>The following section describes how to migrate to Espresso if you have existing test classes
+subclassed from {@link android.test.ActivityInstrumentationTestCase2} and you don't want to rewrite
+them to use JUnit4.</p>
+<p class="note"><strong>Note:</strong> For new UI tests, we strongly recommend that you write your
+test in the JUnit 4 style and use the
+<a href="{@docRoot}reference/android/support/test/rule/ActivityTestRule.html">
+{@code ActivityTestRule}</a> class, instead of
+{@link android.test.ActivityInstrumentationTestCase2}.</p>
<p>
If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
to create your Espresso test class, you must inject an
@@ -541,40 +581,13 @@
</pre>
<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
-
- <p>
- To run Espresso tests, you must use the
- <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
- class provided in the
- <a href="{@docRoot}tools/testing-support-library/index.html">
- Android Testing Support Library</a> as your default test runner. The
- <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for
- Gradle</a> provides a default directory ({@code src/androidTest/java}) for you to store the
- instrumented test classes and test suites that you want to run on a device. The
- plug-in compiles the test code in that directory and then executes the test app using
- the configured test runner class.
- </p>
-
- <p>
- To run Espresso tests in your Gradle project:
- </p>
-
- <ol>
- <li>Specify
- <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
- as the default test instrumentation runner in
- your {@code build.gradle} file:
-
- <pre>
-android {
- defaultConfig {
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
-}</pre>
- </li>
- <li>Run your tests from the command-line by calling the the {@code connectedCheck}
- (or {@code cC}) task:
- <pre>
-./gradlew cC</pre>
- </li>
- </ol>
\ No newline at end of file
+<p>
+You can run Espresso tests from <a href="{@docRoot}sdk/index.html">Android Studio</a> or
+from the command-line. Make sure to specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
+</p>
+<p>
+To run your Espresso test, follow the steps for running instrumented tests
+described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</a>.</p>
diff --git a/docs/html/training/testing/ui-testing/index.jd b/docs/html/training/testing/ui-testing/index.jd
index d660c60..1aa95a4 100644
--- a/docs/html/training/testing/ui-testing/index.jd
+++ b/docs/html/training/testing/ui-testing/index.jd
@@ -1,5 +1,6 @@
page.title=Automating User Interface Tests
page.tags=testing
+page.image=images/testing/UIAutomatorViewer.png
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/testing/ui-testing/uiautomator-testing.jd b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
index d0defd8..9dac5aa 100644
--- a/docs/html/training/testing/ui-testing/uiautomator-testing.jd
+++ b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
@@ -61,41 +61,21 @@
</p>
<h2 id="setup">Set Up UI Automator</h2>
-<p>Before you begin using UI Automator, you must:</p>
- <ul>
- <li>
- <strong>Install the Android Testing Support Library</strong>. The UI Automator API is
- located under the {@code com.android.support.test.uiautomator} package. These classes allow
- you to create tests that use the Espresso testing framework. To learn how to install the
- library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
- Testing Support Library Setup</a>.
- </li>
+<p>Before building your UI test with UI Automator, make sure to configure your test source code
+location and project dependencies, as described in
+<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
+Getting Started with Testing</a>.</p>
- <li>
- <strong>Set up your project structure.</strong> In your Gradle project, the source code for
- the target app that you want to test is typically placed under the {@code app/src/main}
- folder. The source code for instrumentation tests, including
- your UI Automator tests, must be placed under the <code>app/src/androidTest</code> folder.
- To learn more about setting up your project directory, see
- <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
- </li>
+<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
+ reference to the UI Automator library:</p>
- <li>
- <strong>Specify your Android testing dependencies</strong>. In order for the
- <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
- correctly build and run your UI Automator tests, you must specify the following libraries in
- the {@code build.gradle} file of your Android app module:
-
- <pre>
+<pre>
dependencies {
- androidTestCompile 'com.android.support.test:runner:0.3'
- androidTestCompile 'com.android.support.test:rules:0.3'
+ ...
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}
</pre>
- </li>
- </ul>
<p>To optimize your UI Automator testing, you should first inspect the target app’s UI components
and ensure that they are accessible. These optimization tips are described in the next two
@@ -186,9 +166,21 @@
<h2 id="build">Create a UI Automator Test Class</h2>
-<p>To build a UI Automator test, create a class that extends
-{@link android.test.InstrumentationTestCase}. Implement the following programming model in your
-UI Automator test class:</p>
+<p>
+Your UI Automator test class should be written the same way as a JUnit 4 test class. To learn more
+about creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see
+<a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#build">
+Create an Instrumented Unit Test Class</a>.
+</p>
+<p>Add the {@code @RunWith(AndroidJUnit4.class)} annotation at the beginning of your test class
+definition. You also need to specify the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+{@code AndroidJUnitRunner}</a> class
+provided in the Android Testing Support Library as your default test runner. This step is described
+in more detail in <a href="#run">Run UI Automator Tests on a Device or Emulator</a>.
+</p>
+
+<p>Implement the following programming model in your UI Automator test class:</p>
<ol>
<li>Get a
@@ -241,25 +233,56 @@
and simulate a Home button press:</p>
<pre>
-import android.test.InstrumentationTestCase;
+import org.junit.Before;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Until;
+...
-public class CalculatorUiTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 18)
+public class ChangeTextBehaviorTest {
+ private static final String BASIC_SAMPLE_PACKAGE
+ = "com.example.android.testing.uiautomator.BasicSample";
+ private static final int LAUNCH_TIMEOUT = 5000;
+ private static final String STRING_TO_BE_TYPED = "UiAutomator";
private UiDevice mDevice;
- public void setUp() {
+ @Before
+ public void startMainActivityFromHomeScreen() {
// Initialize UiDevice instance
- mDevice = UiDevice.getInstance(getInstrumentation());
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// Start from the home screen
mDevice.pressHome();
- mDevice.wait(Until.hasObject(By.pkg(getHomeScreenPackage()).depth(0)),
+
+ // Wait for launcher
+ final String launcherPackage = mDevice.getLauncherPackageName();
+ assertThat(launcherPackage, notNullValue());
+ mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
+ LAUNCH_TIMEOUT);
+
+ // Launch the app
+ Context context = InstrumentationRegistry.getContext();
+ final Intent intent = context.getPackageManager()
+ .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
+ // Clear out any previous instances
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ context.startActivity(intent);
+
+ // Wait for the app to appear
+ mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
+ LAUNCH_TIMEOUT);
}
}
</pre>
+<p>In the example, the {@code @SdkSuppress(minSdkVersion = 18)} statement helps to ensure that
+ tests will only run on devices with Android 4.3 (API level 18) or higher, as required by the
+ UI Automator framework.</p>
+
<p>Use the
<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">{@code findObject()}</a>
method to retrieve a
@@ -292,8 +315,7 @@
<h4 id="specifying-selector">Specifying a selector</h4>
<p>If you want to access a specific UI component in an app, use the
<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
-class. This class represents a query for specific elements in the
-currently displayed UI. </p>
+class. This class represents a query for specific elements in the currently displayed UI. </p>
<p>If more than one matching element is found, the first matching element in the layout hierarchy
is returned as the target
@@ -306,8 +328,8 @@
{@code UiAutomatorObjectNotFoundException}</a> is thrown. </p>
<p>You can use the
-<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)">{@code childSelector()}</a>
-method to nest multiple
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)">
+{@code childSelector()}</a> method to nest multiple
<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
instances. For example, the following code example shows how your test might specify a search to
find the first {@link android.widget.ListView} in the currently displayed UI, then search within that
@@ -489,33 +511,14 @@
</pre>
<h2 id="run">Run UI Automator Tests on a Device or Emulator</h2>
-<p>UI Automator tests are based on the {@link android.app.Instrumentation} class. The
-<a href="https://developer.android.com/tools/building/plugin-for-gradle.html">
- Android Plug-in for Gradle</a>
-provides a default directory ({@code src/androidTest/java}) for you to store the instrumented test
-classes and test suites that you want to run on a device. The plug-in compiles the test
-code in that directory and then executes the test app using a test runner class. You are
-strongly encouraged to use the
-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
-class provided in the
-<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
-as your default test runner. </p>
-
-<p>To run UI Automator tests in your Gradle project:</p>
-
-<ol>
-<li>Specify
-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
-as the default test instrumentation runner in your {@code build.gradle} file:
-<pre>
-android {
- defaultConfig {
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
-}</pre>
-</li>
-<li>Run your tests from the command-line by calling the {@code connectedCheck}
- (or {@code cC}) task:
-<pre>./gradlew cC</pre>
-</li>
-</ol>
\ No newline at end of file
+<p>
+You can run UI Automator tests from <a href="{@docRoot}sdk/index.html">Android Studio</a> or
+from the command-line. Make sure to specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+ {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
+</p>
+<p>
+To run your UI Automator test, follow the steps for running instrumented tests
+described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/training/testing/unit-testing/index.jd b/docs/html/training/testing/unit-testing/index.jd
index a35ba80..6610761 100644
--- a/docs/html/training/testing/unit-testing/index.jd
+++ b/docs/html/training/testing/unit-testing/index.jd
@@ -1,5 +1,6 @@
page.title=Building Effective Unit Tests
page.tags=testing,androidjunitrunner,junit,unit test
+page.image=images/testing/hwtest_junit_success.png
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
index 9906d8c..38321ee 100644
--- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd
@@ -13,6 +13,7 @@
<li>Android 2.2 (API level 8) or higher</li>
<li><a href="{@docRoot}tools/testing-support-library/index.html">
Android Testing Support Library</a></li>
+ <li><a href="{@docRoot}tools/studio/index.html">Android Studio (latest version)</a>.</li>
</ul>
<h2>This lesson teaches you to</h2>
@@ -27,8 +28,10 @@
<ul>
<li>
-<a href="https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicUnitAndroidTest"
+<a href="https://github.com/googlesamples/android-testing/tree/master/unit/BasicUnitAndroidTest"
class="external-link">Instrumented Unit Tests Code Samples</a></li>
+ <li><a href="https://www.code-labs.io/codelabs/android-studio-testing/index.html?index=..%2F..%2Findex#0"
+class="external-link">Unit and UI Testing in Android Studio (codelab)</a></li>
</ul>
</div>
</div>
@@ -46,44 +49,10 @@
</p>
<h2 id="setup">Set Up Your Testing Environment</h2>
-<p>Before building instrumented unit tests, you must:</p>
-
- <ul>
- <li>
- <strong>Install the Android Testing Support Library</strong>. The
- <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
- {@code AndroidJUnitRunner}</a> API, located under the
- {@code com.android.support.test.runner} package, allows you to
- create and run instrumented unit tests. To learn how to install the
- library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
- Testing Support Library Setup</a>.
- </li>
-
- <li>
- <strong>Set up your project structure.</strong> In your Gradle project, the source code for
- the target app that you want to test is typically placed under the {@code app/src/main/java}
- folder. The source code for instrumentatation tests, including your unit tests, must be
- placed under the <code>app/src/androidTest/java</code> folder.
- To learn more about setting up your project directory, see
- <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
- </li>
-
- <li>
- <strong>Specify your Android testing dependencies</strong>. In order for the
- <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
- correctly build and run your instrumented unit tests, you must specify the following
- libraries in the {@code build.gradle} file of your Android app module:
-
- <pre>
-dependencies {
- androidTestCompile 'com.android.support.test:runner:0.3'
- androidTestCompile 'com.android.support.test:rules:0.3'
- // Set this dependency if you want to use Hamcrest matching
- androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
-}
-</pre>
- </li>
- </ul>
+<p>Before building your instrumented unit test, make sure to configure your test source code
+location and project dependencies, as described in
+<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
+Getting Started with Testing</a>.</p>
<h2 id="build">Create an Instrumented Unit Test Class</h2>
<p>
@@ -91,13 +60,13 @@
creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see
<a href="local-unit-tests.html#build">Create a Local Unit Test Class</a>.
</p>
-<p>To create an instrumented JUnit 4 test class, add the {@code @RunWith(AndroidJUnit4.class)}
+<p>To create an instrumented JUnit 4 test class, add the {@code @RunWith(AndroidJUnit4.class)}
annotation at the beginning of your test class definition. You also need to specify the
<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
{@code AndroidJUnitRunner}</a> class
provided in the Android Testing Support Library as your default test runner. This step is described
-in more detail in <a href="#run">Run Instrumented Unit Tests</a>.
-</p>
+in more detail in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</p>
<p>The following example shows how you might write an instrumented unit test to test that
the {@link android.os.Parcelable} interface is implemented correctly for the
@@ -114,6 +83,7 @@
import static org.junit.Assert.assertThat;
@RunWith(AndroidJUnit4.class)
+@SmallTest
public class LogHistoryAndroidUnitTest {
public static final String TEST_STRING = "This is a string";
@@ -168,8 +138,8 @@
class="external-link">{@code RunWith}</a> and
<a href="http://junit.sourceforge.net/javadoc/org/junit/runners/Suite.html"
class="external-link">{@code Suite}</a> classes. In your test suite, add the
-{@code @RunWith(Suite.class)} and the {@code @Suite.SuitClasses()} annotations. In
-the {@code @Suite.SuiteClasses()} annotation, list the individual test classes or test
+{@code @RunWith(Suite.class)} and the {@code @Suite.SuitClasses()} annotations. In
+the {@code @Suite.SuiteClasses()} annotation, list the individual test classes or test
suites as arguments.
</p>
@@ -194,57 +164,7 @@
<h2 id="run">Run Instrumented Unit Tests</h2>
<p>
-The
-<a href="https://developer.android.com/tools/building/plugin-for-gradle.html">
- Android Plug-in for Gradle</a>
-provides a default directory ({@code src/androidTest/java}) for you to store the instrumented unit
-and integration test classes and test suites that you want to run on a device. The plug-in compiles
-the test code in that directory and then executes the test app using a test runner class. You must
-set the
-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
-{@code AndroidJUnitRunner}</a> class provided in the
-<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
-as your default test runner.</p>
-</p>
-
-<p>To specify
-<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
-{@code AndroidJUnitRunner}</a> as the default test instrumentation runner, add the following
-setting in your {@code build.gradle} file:</p>
-<pre>
-android {
- defaultConfig {
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
-}
-</pre>
-
-<h3 id="run-from-Android-Studio">Running instrumented unit tests from Android Studio</h3>
-<p>
-To run instrumented unit tests in your Gradle project from Android Studio:
-</p>
-<ol>
-<li>Open the <strong>Build Variants</strong> window by clicking the left-hand tab, then set the
-test artifact to <em>Android Instrumentation Tests</em>.
-</li>
-<li>In the <strong>Project</strong> window, drill down to your unit test class or method, then
- right-click and run it using the Android Test configuration.
-</li>
-</ol>
-
-<p>Android Studio displays the results of the unit test execution in the <strong>Run</strong>
-window.</p>
-
-<h3 id="run-from-commandline">Running instrumented unit tests from the command-line</h3>
-
-<p>To run instrumented unit tests in your Gradle project from the command-line, call the
- {@code connectedCheck} (or {@code cC}) task:</p>
-
-<pre>
-./gradlew cC
-</pre>
-
-<p>You can find the generated HTML test result reports in the
-{@code <path_to_your_project>/app/build/outputs/reports/androidTests/connected/} directory,
-and the corresponding XML files in the
-{@code <path_to_your_project>/app/build/outputs/androidTest-results/connected/} directory.</p>
\ No newline at end of file
+To run your test, follow the steps for running instrumented tests
+described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
+Getting Started with Testing</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/training/testing/unit-testing/local-unit-tests.jd b/docs/html/training/testing/unit-testing/local-unit-tests.jd
index 8221a6d..893d957 100644
--- a/docs/html/training/testing/unit-testing/local-unit-tests.jd
+++ b/docs/html/training/testing/unit-testing/local-unit-tests.jd
@@ -10,7 +10,7 @@
<h2>Dependencies and Prerequisites</h2>
<ul>
- <li>Android Plug-in for Gradle 1.1.0 or higher</li>
+ <li><a href="{@docRoot}tools/studio/index.html">Android Studio (latest version)</a>.</li>
</ul>
<h2>This lesson teaches you to</h2>
@@ -25,8 +25,10 @@
<ul>
<li>
-<a href="https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicSample"
+<a href="https://github.com/googlesamples/android-testing/tree/master/unit/BasicSample"
class="external-link">Local Unit Tests Code Samples</a></li>
+ <li><a href="https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex#0"
+class="external-link">Android Testing Codelab</a></li>
</ul>
</div>
</div>
@@ -36,47 +38,15 @@
you avoid the overhead of loading the target app and unit test code onto a physical device or
emulator every time your test is run. Consequently, the execution time for running your unit
test is greatly reduced. With this approach, you normally use a mocking framework, like
-<a href="https://code.google.com/p/mockito/" class="external-link">Mockito</a>, to fulfill any
+<a href="https://github.com/mockito/mockito" class="external-link">Mockito</a>, to fulfill any
dependency relationships.</p>
-<p><a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a>
-version 1.1.0 and higher allows you to create a source directory ({@code src/test/java}) in your
-project to store JUnit tests that you want to run on a local machine. This feature improves your
-project organization by letting you group your unit tests together into a single source set. You
-can run the tests from Android Studio or the command-line, and the plugin executes them on the
-local Java Virtual Machine (JVM) on your development machine. </p>
-
<h2 id="setup">Set Up Your Testing Environment</h2>
-<p>Before building local unit tests, you must:</p>
+<p>Before building your local unit test, make sure to configure your test source code location and
+project dependencies, as described in
+<a href="{@docRoot}training/testing/start/index.html#config-local-tests">
+Getting Started with Testing</a>.</p>
- <ul>
- <li>
- <strong>Set up your project structure.</strong> In your Gradle project, the source code for
- the target app that you want to test is typically placed under the {@code app/src/main/java}
- folder. The source code for your local unit tests must be placed under the
- <code>app/src/test/java</code> folder.
- To learn more about setting up your project directory, see
- <a href="#run">Run Local Unit Tests</a> and
- <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
- </li>
-
- <li>
- <strong>Specify your Android testing dependencies</strong>. In order to use JUnit 4 and
- Mockito with your local unit tests, specify the following libraries in
- the {@code build.gradle} file of your Android app module:
-
- <pre>
-dependencies {
- // Unit testing dependencies
- testCompile 'junit:junit:4.12'
- // Set this dependency if you want to use Mockito
- testCompile 'org.mockito:mockito-core:1.10.19'
- // Set this dependency if you want to use Hamcrest matching
- androidTestCompile 'org.hamcrest:hamcrest-library:1.1'
-}
-</pre>
- </li>
- </ul>
<h2 id="build">Create a Local Unit Test Class</h2>
<p>Your local unit test class should be written as a JUnit 4 test class.
@@ -89,7 +59,7 @@
{@code junit.extensions} package.</p>
<p>To create a basic JUnit 4 test class, create a Java class that contains one or more test methods.
-A test method begins with the {@code @Test} annotation and contains the code to exercise
+A test method begins with the {@code @Test} annotation and contains the code to exercise
and verify a single functionality in the component that you want to test.</p>
<p>The following example shows how you might implement a local unit test class. The test method
@@ -116,44 +86,10 @@
<a href="http://junit.org/javadoc/latest/org/junit/Assert.html" class="external-link">
junit.Assert</a> methods to perform validation checks (or <em>assertions</em>) to compare the state
of the component under test against some expected value. To make tests more readable, you
-can use <a href="https://code.google.com/p/hamcrest/wiki/Tutorial" class="external-link">
+can use <a href="https://github.com/hamcrest" class="external-link">
Hamcrest matchers</a> (such as the {@code is()} and {@code equalTo()} methods) to match the
returned result against the expected result.</p>
-<p>In your JUnit 4 test class, you can use annotations to call out sections in your test code for
-special processing, such as:</p>
-
-<ul>
-<li>
-{@code @Before}: Use this annotation to specify a block of code with test setup operations. This
-code block will be invoked before each test. You can have multiple {@code @Before} methods but
-the order which these methods are called is not fixed.
-</li>
-<li>
-{@code @After}: This annotation specifies a block of code with test tear-down operations. This
-code block will be called after every test method. You can define multiple {@code @After}
-operations in your test code. Use this annotation to release any resources from memory.
-</li>
-<li>
-{@code @Test}: Use this annotation to mark a test method. A single test class can contain
-multiple test methods, each prefixed with this annotation.
-</li>
-<li>
-{@code @BeforeClass}: Use this annotation to specify static methods to be invoked only once per
-test class. This testing step is useful for expensive operations such as connecting to a database.
-</li>
-<li>
-{@code @AfterClass}: Use this annotation to specify static methods to be invoked only after all
-tests in the class have been run. This testing step is useful for releasing any resources allocated
-in the {@code @BeforeClass} block.
-</li>
-<li>
-{@code @Test(timeout=<milliseconds>)}: Specifies a timeout period for the test. If the
-test starts but does not complete within the given timeout period, it automatically fails. You must
-specify the timeout period in milliseconds, for example: {@code @Test(timeout=5000)}.
-</li>
-</ul>
-
<h3 id="mocking-dependencies">Mocking Android dependencies</h3>
<p>
By default, the <a href="{@docRoot}tools/building/plugin-for-gradle.html">
@@ -166,7 +102,7 @@
your component interacts with a dependency in an expected way. By substituting Android dependencies
with mock objects, you can isolate your unit test from the rest of the Android system while
verifying that the correct methods in those dependencies are called. The
-<a href="https://code.google.com/p/mockito/" class="external-link">Mockito</a> mocking framework
+<a href="https://github.com/mockito/mockito" class="external-link">Mockito</a> mocking framework
for Java (version 1.9.5 and higher) offers compatibility with Android unit testing.
With Mockito, you can configure mock objects to return some specific value when invoked.</p>
@@ -179,11 +115,11 @@
<a href="#setup">Set Up Your Testing Environment</a>.
</li>
<li>At the beginning of your unit test class definition, add the
-{@code @RunWith(MockitoJUnitRunner.class)} annotation. This annotation tells the Mockito test
+{@code @RunWith(MockitoJUnitRunner.class)} annotation. This annotation tells the Mockito test
runner to validate that your usage of the framework is correct and simplifies the initialization of
your mock objects.
</li>
-<li>To create a mock object for an Android dependency, add the {@code @Mock} annotation before
+<li>To create a mock object for an Android dependency, add the {@code @Mock} annotation before
the field declaration.</li>
<li>To stub the behavior of the dependency, you can specify a condition and return
value when the condition is met by using the {@code when()} and {@code thenReturn()} methods.
@@ -234,69 +170,14 @@
<a href="http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html"
class="external-link">Mockito API reference</a> and the
{@code SharedPreferencesHelperTest} class in the
-<a href="https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicSample"
+<a href="https://github.com/googlesamples/android-testing/tree/master/unit/BasicSample"
class="external-link">sample code</a>.
</p>
<h2 id="run">Run Local Unit Tests</h2>
<p>
-The Android Plug-in for Gradle provides a default directory ({@code src/test/java}) for you to
-store unit test classes that you want to run on a local JVM. The plug-in compiles the test code in
-that directory and then executes the test app locally using the default test runner class.
+To run your tests, follow the steps for running local unit tests
+described in <a href="{@docRoot}training/testing/start/index.html#run-local-tests">
+Getting Started with Testing</a>.
</p>
-<p>
-As with production code, you can create unit tests for a
-<a href="http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants"
-class="external-link">specific flavor or build type</a>. You should keep unit tests in a test
-source tree location that corresponds to your production source tree, such as:
-<table>
-<tr>
-<th>Path to Production Class</th>
-<th>Path to Local Unit Test Class</th>
-</tr>
-<tr>
-<td>{@code src/main/java/Foo.java}</td>
-<td>{@code src/test/java/FooTest.java}</td>
-</tr>
-<tr>
-<td>{@code src/debug/java/Foo.java}</td>
-<td>{@code src/testDebug/java/FooTest.java}</td>
-</tr>
-<tr>
-<td>{@code src/myFlavor/java/Foo.java}</td>
-<td>{@code src/testMyFlavor/java/FooTest.java}</td>
-</tr>
-</table>
-
-<h3 id="run-from-Android-Studio">Running local unit tests from Android Studio</h3>
-<p>
-To run local unit tests in your Gradle project from Android Studio:
-</p>
-<ol>
-<li>In the <strong>Project</strong> window, right click on the project and synchronize your project.
-</li>
-<li>Open the <strong>Build Variants</strong> window by clicking the left-hand tab, then change the
-test artifact to <em>Unit Tests</em>.
-</li>
-<li>In the <strong>Project</strong> window, drill down to your unit test class or method, then
-right-click and run it.
-</li>
-</ol>
-
-<p>Android Studio displays the results of the unit test execution in the <strong>Run</strong>
-window.</p>
-
-<h3 id="run-from-commandline">Running local unit tests from the command-line</h3>
-
-<p>To run local unit tests in your Gradle project from the command-line, call the {@code test} task
-command with the {@code --continue} option.</p>
-
-<pre>
-./gradlew test --continue
-</pre>
-
-<p>If there are failing tests, the command will display links to HTML reports (one per build
-variant). You can find the generated HTML test result reports in the
-{@code <path_to_your_project>/app/build/reports/tests/} directory, and the corresponding XML
-files in the {@code <path_to_your_project>/app/build/test-results/} directory.</p>
\ No newline at end of file
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 2963345..7561254 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -37,35 +37,6 @@
<li class="nav-section">
<div class="nav-section-header">
- <a href="<?cs var:toroot ?>training/basics/actionbar/index.html"
- description=
- "The action bar is one of the most important design elements you can implement for your
-app's activities. Although first introduced with API level 11, you can use the Support Library to
-include the action bar on devices running Android 2.1 or higher."
- >Adding the Action Bar</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>training/basics/actionbar/setting-up.html">
- Setting Up the Action Bar
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/basics/actionbar/adding-buttons.html">
- Adding Action Buttons
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/basics/actionbar/styling.html">
- Styling the Action Bar
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/basics/actionbar/overlaying.html">
- Overlaying the Action Bar
- </a>
- </li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header">
<a href="<?cs var:toroot ?>training/basics/supporting-devices/index.html"
description=
"How to build your app with alternative resources that provide an
@@ -91,7 +62,6 @@
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/basics/activity-lifecycle/index.html"
- es-lang=""
ja-lang="アクティビティのライフサイクル 管理"
ko-lang="액티비티 수명 주기 관리하기"
pt-br-lang="Como gerenciar o ciclo de vida da atividade"
@@ -105,7 +75,6 @@
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/basics/activity-lifecycle/starting.html"
- es-lang=""
ja-lang="アクティビティを開始する"
ko-lang="액티비티 시작하기"
pt-br-lang="Iniciando uma atividade"
@@ -115,19 +84,11 @@
Starting an Activity
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/basics/activity-lifecycle/pausing.html"
- es-lang=""
- ja-lang=""
- ko-lang=""
- pt-br-lang=""
- ru-lang=""
- zh-cn-lang=""
- zh-tw-lang="">
+ <li><a href="<?cs var:toroot ?>training/basics/activity-lifecycle/pausing.html">
Pausing and Resuming an Activity
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/activity-lifecycle/stopping.html"
- es-lang=""
ja-lang="アクティビティの一時停止と再開"
ko-lang="액티비티 일시정지 및 재개하기"
pt-br-lang="Pausando e reiniciando uma atividade"
@@ -138,7 +99,6 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/activity-lifecycle/recreating.html"
- es-lang=""
ja-lang="アクティビティを再作成する"
ko-lang="액티비티 재생성하기"
pt-br-lang="Recriando uma atividade"
@@ -179,7 +139,6 @@
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot?>training/basics/data-storage/index.html"
- es-lang=""
ja-lang="データの保存"
ko-lang="데이터 저장하기"
pt-br-lang="Salvando dados"
@@ -193,7 +152,6 @@
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/basics/data-storage/shared-preferences.html"
- es-lang=""
ja-lang="キー値セットを保存する"
ko-lang="키-값 세트 저장하기"
pt-br-lang="Salvando conjuntos de valor-chave"
@@ -204,7 +162,6 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/data-storage/files.html"
- es-lang=""
ja-lang="ファイルを保存する"
ko-lang="파일 저장하기"
pt-br-lang="Salvando arquivos"
@@ -215,7 +172,6 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/data-storage/databases.html"
- es-lang=""
ja-lang="SQL データベースにデータを保存する"
ko-lang="SQL 데이터베이스에 데이터 저장하기"
pt-br-lang="Salvando dados em bancos de dados do SQL"
@@ -231,7 +187,6 @@
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/basics/intents/index.html"
- es-lang=""
ja-lang="他のアプリとの相互操作"
ko-lang="액티비티 수명 주기 관리하기"
pt-br-lang="Interagindo com outros aplicativos"
@@ -246,7 +201,6 @@
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/basics/intents/sending.html"
- es-lang=""
ja-lang="別のアプリにユーザーを送る"
ko-lang="다른 앱으로 사용자 보내기"
pt-br-lang="Enviando o usuário para outro aplicativo"
@@ -257,7 +211,6 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/intents/result.html"
- es-lang=""
ja-lang="アクティビティから結果を取得する"
ko-lang="액티비티로부터 결과 가져오기"
pt-br-lang="Obtendo resultados de uma atividade"
@@ -268,7 +221,6 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/basics/intents/filters.html"
- es-lang=""
ja-lang="他のアプリからのアクティビティの開始を許可する"
ko-lang="다른 앱이 자신의 액티비티를 시작하도록 허용하기"
pt-br-lang="Permitindo que outros aplicativos iniciem sua atividade"
@@ -280,6 +232,30 @@
</li>
</ul>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/permissions/index.html"
+ description=
+ "How to declare that your app needs access to features and
+ resources outside of its 'sandbox', and how to request those
+ privileges at runtime."
+ >Working with System Permissions</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/permissions/declaring.html">
+ Declaring Permissions
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/permissions/requesting.html">
+ Requesting Permissions at Run Time
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/permissions/best-practices.html">
+ Best Practices for Runtime Permissions
+ </a>
+ </li>
+ </ul>
+ </li>
</ul>
</li><!-- end getting started -->
@@ -676,14 +652,18 @@
<li class="nav-section">
<div class="nav-section-header">
- <a href="<?cs var:toroot ?>training/cloudsync/index.html"
+ <a href="<?cs var:toroot ?>training/backup/index.html"
description=
"How to sync and back up app and user data to remote web services in the
cloud and how to restore the data back to multiple devices."
>Syncing to the Cloud</a>
</div>
<ul>
- <li><a href="<?cs var:toroot ?>training/cloudsync/backupapi.html">
+ <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html">
+ Configuring Auto Backup
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/backup/backupapi.html">
Using the Backup API
</a>
</li>
@@ -781,6 +761,11 @@
</a>
</li>
<li>
+ <a href="<?cs var:toroot ?>training/location/change-location-settings.html">
+ Changing Location Settings
+ </a>
+ </li>
+ <li>
<a href="<?cs var:toroot ?>training/location/receive-location-updates.html">
Receiving Location Updates
</a>
@@ -811,7 +796,7 @@
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/building-userinfo.html">
<span class="small">Building Apps with</span><br/>
- Contacts & Sign-In
+ User Info & Sign-In
</a>
</div>
<ul>
@@ -1009,6 +994,21 @@
"How to detect location data on Android Wear devices."
>Detecting Location</a>
</li>
+
+ <li>
+ <a href="<?cs var:toroot ?>training/articles/wear-permissions.html"
+ description=
+ "How to request permissions on Android Wear devices."
+ >Requesting Permissions</a>
+ </li>
+
+ <li>
+ <a href="<?cs var:toroot ?>training/wearables/wearable-sounds.html"
+ description=
+ "How to use the speaker on Android Wear devices."
+ >Using the Speaker</a>
+ </li>
+
</ul>
</li>
<!-- End Building for wearables -->
@@ -1084,6 +1084,14 @@
ja-lang="再生中カードを表示する">
Displaying a Now Playing Card</a>
</li>
+ <li>
+ <a href="<?cs var:toroot ?>training/tv/playback/guided-step.html">
+ Adding a Guided Step</a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/tv/playback/options.html">
+ Enabling Background Playback</a>
+ </li>
</ul>
</li>
@@ -1193,7 +1201,11 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/enterprise/work-policy-ctrl.html">
- Building a Work Policy Controller
+ Building a Device Policy Controller
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/enterprise/cosu.html">
+ Configuring Corporate-Owned, Single-Use Devices
</a>
</li>
</ul>
@@ -1311,6 +1323,8 @@
</li>
</ul>
</li>
+
+
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/swipe/index.html"
@@ -1329,6 +1343,8 @@
</li>
</ul>
</li>
+
+
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/search/index.html"
@@ -1367,17 +1383,30 @@
</a>
</li>
<li><a href="<?cs var:toroot ?>training/app-indexing/enabling-app-indexing.html">
- Specifying App Content for Indexing
+ Specifying App Content for Indexing
</a>
</li>
</ul>
- </li>
- </ul>
</li>
+
+ <li>
+ <a href="<?cs var:toroot ?>training/articles/assistant.html"
+ description=
+ "Support contextually relevant actions through the Assist API."
+ >Optimizing Content for the Assistant</a>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section">
+ <a href="<?cs var:toroot ?>training/app-links/index.html"
+ description=
+ "How to enable the system to handle web requests by taking the user directly
+ to your app instead of your website."
+ >Handling App Links</a>
+ </div>
+ </li>
<!-- End Interaction and Engagement -->
-
-
+</ul>
<li class="nav-section">
<div class="nav-section-header">
@@ -1426,6 +1455,48 @@
<li class="nav-section">
<div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/appbar/index.html"
+ description=
+ "How to use the support library's toolbar widget to implement an
+ app bar that displays properly on a wide range of devices."
+ >Adding the App Bar</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/appbar/setting-up.html"
+ >Setting Up the App Bar</a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/appbar/actions.html"
+ >Adding and Handling Actions</a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/appbar/up-action.html"
+ >Adding an Up Action</a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/appbar/action-views.html"
+ >Action Views and Action Providers</a>
+ </li>
+ </ul>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/snackbar/index.html"
+ description=
+ "How to use the support library's Snackbar widget to display a
+ brief pop-up message."
+ >Showing Pop-Up Messages</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/snackbar/showing.html"
+ >Building and Displaying a Pop-Up Message</a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/snackbar/action.html"
+ >Adding an Action to a Message</a>
+ </li>
+ </ul>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section-header">
<a href="<?cs var:toroot ?>training/custom-views/index.html"
description=
"How to build custom UI widgets that are interactive and smooth."
@@ -1496,6 +1567,10 @@
Developing Accessibility Services
</a>
</li>
+ <li><a href="<?cs var:toroot ?>training/accessibility/testing.html">
+ Accessibility Testing Checklist
+ </a>
+ </li>
</ul>
</li>
@@ -1536,34 +1611,113 @@
<a href="<?cs var:toroot ?>training/material/index.html"
description=
"How to implement material design on Android."
+ zh-cn-lang="面向开发者的材料设计"
+ zh-tw-lang="開發人員材料設計"
+ ja-lang="マテリアル デザインでのアプリ作成"
+ es-lang="Crear aplicaciones con Material Design"
+ pt-br-lang="Material Design para desenvolvedores"
+ ko-lang="개발자를 위한 머티리얼 디자인"
+ ru-lang="Создание приложений с помощью Material Design"
+ in-lang="Desain Bahan untuk Pengembang"
+ vi-lang="Material Design cho Nhà phát triển"
>Creating Apps with Material Design</a>
</div>
<ul>
- <li><a href="<?cs var:toroot ?>training/material/get-started.html">
+ <li><a href="<?cs var:toroot ?>training/material/get-started.html"
+ zh-cn-lang="入门指南"
+ zh-tw-lang="開始使用"
+ ja-lang="スタート ガイド"
+ es-lang="Comencemos"
+ pt-br-lang="Como iniciar"
+ ko-lang="시작하기"
+ ru-lang="Начало работы"
+ in-lang="Memulai"
+ vi-lang="Bắt đầu"
+ >
Getting Started
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/theme.html">
+ <li><a href="<?cs var:toroot ?>training/material/theme.html"
+ zh-cn-lang="使用材料主题"
+ zh-tw-lang="使用材料設計風格"
+ ja-lang="マテリアル テーマの使用"
+ es-lang="Usar el tema Material"
+ pt-br-lang="Como usar o tema do Material"
+ ko-lang="머티어리얼 테마 사용"
+ ru-lang="Использование темы Material Design"
+ in-lang="Menggunakan Tema Bahan"
+ vi-lang="Sử dụng Chủ đề Material"
+ >
Using the Material Theme
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/lists-cards.html">
+ <li><a href="<?cs var:toroot ?>training/material/lists-cards.html"
+ zh-cn-lang="创建列表与卡片"
+ zh-tw-lang="建立清單和卡片"
+ ja-lang="リストとカードの作成"
+ es-lang="Crear listas y tarjetas"
+ pt-br-lang="Como criar listas e cartões"
+ ko-lang="목록 및 카드 생성"
+ ru-lang="Создание списков и подсказок"
+ in-lang="Membuat Daftar dan Kartu"
+ vi-lang="Tạo Danh sách và Thẻ"
+ >
Creating Lists and Cards
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/shadows-clipping.html">
+ <li><a href="<?cs var:toroot ?>training/material/shadows-clipping.html"
+ zh-cn-lang="定义阴影与裁剪视图"
+ zh-tw-lang="定義陰影和裁剪檢視"
+ ja-lang="シャドウとクリッピング ビューの定義"
+ es-lang="Definir vistas de recorte y sombras"
+ pt-br-lang="Como definir sombras e recortar visualizações"
+ ko-lang="그림자 정의 및 뷰 클리핑"
+ ru-lang="Определение теней и обрезка представлений"
+ in-lang="Mendefinisikan Bayangan dan Memangkas Tampilan"
+ vi-lang="Định nghĩa Đổ bóng và Dạng xem Cắt hình"
+ >
Defining Shadows and Clipping Views
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/drawables.html">
+ <li><a href="<?cs var:toroot ?>training/material/drawables.html"
+ zh-cn-lang="使用 Drawables"
+ zh-tw-lang="使用可繪項目"
+ ja-lang="ドローアブルの使用"
+ es-lang="Trabajar con interfaces dibujables"
+ pt-br-lang="Como trabalhar com desenháveis"
+ ko-lang="Drawable 사용"
+ ru-lang="Работа с элементами дизайна"
+ in-lang="Bekerja dengan Drawable"
+ vi-lang="Làm việc với Nội dung vẽ được"
+ >
Working with Drawables
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/animations.html">
+ <li><a href="<?cs var:toroot ?>training/material/animations.html"
+ zh-cn-lang="定义定制动画"
+ zh-tw-lang="定義自訂動畫"
+ ja-lang="カスタム アニメーションの定義"
+ es-lang="Definir animaciones personalizadas"
+ pt-br-lang="Como definir animações personalizadas"
+ ko-lang="사용자지정 애니메이션 정의"
+ ru-lang="Определение настраиваемой анимации"
+ in-lang="Mendefinisikan Animasi Custom"
+ vi-lang="Định nghĩa Hoạt hình Tùy chỉnh"
+ >
Defining Custom Animations
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/material/compatibility.html">
+ <li><a href="<?cs var:toroot ?>training/material/compatibility.html"
+ zh-cn-lang="维护兼容性"
+ zh-tw-lang="維持相容性"
+ ja-lang="互換性の維持"
+ es-lang="Mantener la compatibilidad"
+ pt-br-lang="Como manter a compatibilidade"
+ ko-lang="호환성 유지"
+ ru-lang="Обеспечение совместимости"
+ in-lang="Mempertahankan Kompatibilitas"
+ vi-lang="Duy trì Tính tương thích"
+ >
Maintaining Compatibility
</a>
</li>
@@ -1793,6 +1947,7 @@
</li>
</ul>
</li>
+
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/monitoring-device-state/index.html"
@@ -1806,6 +1961,44 @@
</a>
</div>
<ul>
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/performance/battery/network/index.html">
+ Reducing Network Battery Drain
+ </a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/gather-data.html">
+ Collecting Network Traffic Data
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/analyze-data.html">
+ Analyzing Network Traffic Data
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/action-user-traffic.html">
+ Optimizing User-Initiated Network Use
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/action-app-traffic.html">
+ Optimizing App-Initiated Network Use
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/action-server-traffic.html">
+ Optimizing Server-Initiated Network Use
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/performance/battery/network/action-any-traffic.html">
+ Optimizing General Network Use
+ </a>
+ </li>
+ </ul>
+ </li> <!-- End of Reducing Network Battery Drain -->
+
+ <li><a href="<?cs var:toroot ?>training/monitoring-device-state/doze-standby.html"
+ >Optimizing for Doze and App Standby</a>
+ </li>
<li><a href="<?cs var:toroot ?>training/monitoring-device-state/battery-monitoring.html"
zh-cn-lang="监控电池电量和充电状态"
ja-lang="電池残量と充電状態の監視"
@@ -1930,42 +2123,64 @@
<li class="nav-section">
<div class="nav-section-header">
- <a href="<?cs var:toroot ?>training/testing.html">
+ <a href="<?cs var:toroot ?>training/best-permissions-ids.html">
+ <span class="small">Best Practices for</span><br/>
+ Permissions & Identifiers
+ </a>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/articles/user-data-overview.html"
+ description=
+ "Overview of app permissions on Android and how they affect your users."
+ >Permissions and User Data</a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/articles/user-data-permissions.html"
+ description=
+ "How to manage permissions the right way for users."
+ >Best Practices for App Permissions</a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/articles/user-data-ids.html"
+ description=
+ "Unique identifiers available and how to choose the right one for your use case."
+ >Best Practices for Unique Identifiers</a>
+ </li>
+ </ul>
+ </li>
+ <!-- End Permissions and identifiers -->
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/testing/index.html">
<span class="small">Best Practices for</span><br/>
Testing
</a>
</div>
<ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/testing/start/index.html"
+ description="How to get started with testing your Android applications.">
+ Getting Started with Testing
+ </a>
+ </li>
<li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>training/activity-testing/index.html"
- description="How to test Activities in your Android applications.">
- Testing Your Activity
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/unit-testing/index.html"
+ description="How to build effective unit tests for Android apps.">
+ Building Effective Unit Tests
</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>training/activity-testing/preparing-activity-testing.html">
- <span class="en">Setting Up Your Test Environment</span>
- </a>
+ <li><a href="<?cs var:toroot ?>training/testing/unit-testing/local-unit-tests.html">
+ <span class="en">Building Local Unit Tests</span>
+ </a>
</li>
- <li><a href="<?cs var:toroot ?>training/activity-testing/activity-basic-testing.html">
- <span class="en">Creating and Running a Test Case</span>
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/activity-testing/activity-ui-testing.html">
- <span class="en">Testing UI Components</span>
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/activity-testing/activity-unit-testing.html">
- <span class="en">Creating Unit Tests</span>
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/activity-testing/activity-functional-testing.html">
- <span class="en">Creating Functional Tests</span>
- </a>
+ <li><a href="<?cs var:toroot ?>training/testing/unit-testing/instrumented-unit-tests.html">
+ <span class="en">Building Instrumented Unit Tests</span>
+ </a>
</li>
</ul>
</li>
- </ul>
- <ul>
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/ui-testing/index.html"
description="How to automate your user interface tests for Android apps.">
@@ -1982,24 +2197,21 @@
</li>
</ul>
</li>
- </ul>
- <ul>
<li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/unit-testing/index.html"
- description="How to build effective unit tests for Android apps.">
- Building Effective Unit Tests
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/integration-testing/index.html"
+ description="How to build effective integration tests for Android apps.">
+ Testing App Component Integrations
</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>training/testing/unit-testing/local-unit-tests.html">
- <span class="en">Building Local Unit Tests</span>
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/testing/unit-testing/instrumented-unit-tests.html">
- <span class="en">Building Instrumented Unit Tests</span>
- </a>
- </li>
+ <li><a href="<?cs var:toroot ?>training/testing/integration-testing/service-testing.html">
+ <span class="en">Testing Your Service</span></a></li>
+ <li><a href="<?cs var:toroot ?>training/testing/integration-testing/content-provider-testing.html">
+ <span class="en">Testing Your Content Provider</span></a></li>
</ul>
</li>
+ <li><a href="<?cs var:toroot ?>training/testing/performance.html"
+ description="How to automate UI performance testing.">Testing Display Performance</a>
+ </li>
</ul>
</li>
<!-- End best Testing -->
diff --git a/docs/html/training/tv/discovery/recommendations.jd b/docs/html/training/tv/discovery/recommendations.jd
index ffe33f2..0b0b270 100644
--- a/docs/html/training/tv/discovery/recommendations.jd
+++ b/docs/html/training/tv/discovery/recommendations.jd
@@ -63,10 +63,13 @@
<ul>
<li><strong>Continuation content</strong> recommendations for the next episode for users to resume
-watching a series.</li>
+watching a series. Or, use continuation recommendations for paused movies, TV shows, or podcasts
+so users can get back to watching paused content in just a few clicks.</li>
<li><strong>New content</strong> recommendations, such as for a new first-run episode, if the user
-finished watching another series.
-<li><strong>Related content</strong> recommendations based on the users historic viewing behavior.
+finished watching another series. Also, if your app lets users subscribe to, follow, or track
+content, use new content recommendations for unwatched items in their list of tracked content.</li>
+<li><strong>Related content</strong> recommendations based on the users' historic viewing behavior.
+</li>
</ul>
<p>For more information on how to design recommendation cards for the best user experience, see
@@ -88,6 +91,25 @@
<a href="https://www.google.com/design/spec-tv/system-overview/recommendation-row.html#recommendation-row-card-customization"
class="external-link">Recommendation Row</a> in the Android TV Design Spec.</p>
+<h3 id="grouping">Grouping Recommendations</h3>
+
+<p>
+You can optionally group recommendations based on recommendation source. For example, your app
+might provide two groups of recommendations: recommendations for content the user is subscribed to,
+and recommendations for new trending content the user might not be aware of.
+</p>
+<p>
+The system ranks and orders recommendations for each group separately when creating or updating
+the recommendation row. By providing group information for your recommendations, you can ensure
+that your recommendations don’t get ordered below unrelated recommendations.
+</p>
+<p>
+Use
+{@link android.support.v4.app.NotificationCompat.Builder#setGroup
+NotificationCompat.Builder.setGroup()} to set the group key string of a recommendation. For
+example, to mark a recommendation as belonging to a group that contains new trending content,
+you might call <code>setGroup("trending")</code>.
+</p>
<h2 id="service">Create a Recommendations Service</h2>
diff --git a/docs/html/training/tv/games/index.jd b/docs/html/training/tv/games/index.jd
index 7a3365d..73336d0 100644
--- a/docs/html/training/tv/games/index.jd
+++ b/docs/html/training/tv/games/index.jd
@@ -225,24 +225,20 @@
<p>
Games controllers may not be available or active for users of a TV device. In order to properly
- inform users that your game requires (or just supports) a game controller, you must include
- entries in the app manifest. If your game requires a game controller, you must include the
- following entry in your app manifest:
-</p>
-
-<pre>
- <uses-feature android:name="android.hardware.gamepad"/>
-</pre>
-
-<p>
- If your game uses, but does not require, a game controller, include the following feature
- entry in your app manifest:
+ inform users that your game supports a game controller, you must include the following entry in
+ your app manifest:
</p>
<pre>
<uses-feature android:name="android.hardware.gamepad" android:required="false"/>
</pre>
+<p class="note">
+ <strong>Note:</strong> When specifying {@code android:hardware:gamepad} support, do not set the
+ {@code android:required} attribute to {@code "true"}. If you do this, users won’t be able to
+ install your app on TV devices.
+</p>
+
<p>For more information about manifest entries, see
<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">App Manifest</a>.
</p>
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
index ff9f111..4a6bcb8 100644
--- a/docs/html/training/tv/index.jd
+++ b/docs/html/training/tv/index.jd
@@ -9,4 +9,21 @@
<p>These classes teach you how to build apps for TV devices.</p>
<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play,
-see <a href="{@docRoot}distribute/googleplay/tv.html">Distribute to Android TV</a>.</p>
\ No newline at end of file
+see <a href="{@docRoot}distribute/googleplay/tv.html">Distribute to Android TV</a>.</p>
+
+<div class="wrap">
+ <div class="cols">
+ <div class="col-1of2">
+ <p>If you prefer to learn through interactive video training, check out this online course
+ about extending your apps to work with Android TV.</p>
+ <p><a href="https://www.udacity.com/course/ud875B" class="button">
+ Start the video course</a>
+ </p>
+ </div>
+ <div class="col-1of2">
+ <iframe width="300" height="169"
+ src="//www.youtube.com/embed/anJtq2rtrA8?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen="" style="float: right; margin: 0 0 20px 20px;"></iframe>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/training/tv/playback/browse.jd b/docs/html/training/tv/playback/browse.jd
index 9c81597..fee6a74 100644
--- a/docs/html/training/tv/playback/browse.jd
+++ b/docs/html/training/tv/playback/browse.jd
@@ -11,25 +11,35 @@
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#layout">Create a Media Browse Layout</a></li>
+ <li><a href="#header">Customize the Header Views</a></li>
<li><a href="#lists">Display Media Lists</a></li>
<li><a href="#background">Update the Background</a></li>
</ol>
+ <h2>Try it out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
+ Leanback sample app</a></li>
+ </ul>
</div>
</div>
<p>
- Media apps that run on TV need to allow users to browse its content offerings, make a
+ A media app that runs on a TV needs to allow users to browse its content offerings, make a
selection, and start playing content. The content browsing experience for apps of this type
should be simple and intuitive, as well as visually pleasing and engaging.
</p>
<p>
This lesson discusses how to use the classes provided by the <a href=
- "{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support library</a> to
- implement a user interface for browsing music or videos from your app's media catalog.
+ "{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support library</a>
+ to implement a user interface for browsing music or videos from your app's media catalog.
</p>
+<img itemprop="image" src="{@docRoot}images/tv/app-browse.png" alt="App main screen"/>
+<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
+Leanback sample app</a> browse fragment displays video catalog data.</p>
+
<h2 id="layout">Create a Media Browse Layout</h2>
@@ -37,69 +47,270 @@
The {@link android.support.v17.leanback.app.BrowseFragment} class in the leanback library
allows you to create a primary layout for browsing categories and rows of media items with a
minimum of code. The following example shows how to create a layout that contains a {@link
- android.support.v17.leanback.app.BrowseFragment}:
+ android.support.v17.leanback.app.BrowseFragment} object:
</p>
<pre>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- >
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/main_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <fragment
- <strong>android:name="android.support.v17.leanback.app.BrowseFragment"</strong>
- android:id="@+id/browse_fragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
+ <fragment
+ android:name="com.example.android.tvleanback.ui.MainFragment"
+ android:id="@+id/main_browse_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</FrameLayout>
+</pre>
+
+<p>The application's main activity sets this view, as shown in the following example:</p>
+
+<pre>
+public class MainActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+...
+</pre>
+
+<p>The {@link android.support.v17.leanback.app.BrowseFragment} methods populate the view with the
+video data and UI elements and set the layout parameters such as the icon, title, and whether
+category headers are enabled.</p>
+
+<ul>
+ <li>See <a href="#set-ui">Set UI Elements</a> for more information about setting up UI elements.</li>
+ <li>See <a href="#hide-heads">Hide or Disable Headers</a> for more information about hiding the
+ headers.</li>
+</ul>
+
+<p>The application's subclass that implements the
+{@link android.support.v17.leanback.app.BrowseFragment} methods also sets
+up event listeners for user actions on the UI elements, and prepares the background
+manager, as shown in the following example:</p>
+
+<pre>
+public class MainFragment extends BrowseFragment implements
+ LoaderManager.LoaderCallbacks<HashMap<String, List<Movie>>> {
+
+...
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ loadVideoData();
+
+ prepareBackgroundManager();
+ setupUIElements();
+ setupEventListeners();
+ }
+...
+
+ private void prepareBackgroundManager() {
+ mBackgroundManager = BackgroundManager.getInstance(getActivity());
+ mBackgroundManager.attach(getActivity().getWindow());
+ mDefaultBackground = getResources()
+ .getDrawable(R.drawable.default_background);
+ mMetrics = new DisplayMetrics();
+ getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
+ }
+
+ private void setupUIElements() {
+ setBadgeDrawable(getActivity().getResources()
+ .getDrawable(R.drawable.videos_by_google_banner));
+ // Badge, when set, takes precedent over title
+ setTitle(getString(R.string.browse_title));
+ setHeadersState(HEADERS_ENABLED);
+ setHeadersTransitionOnBackEnabled(true);
+ // set headers background color
+ setBrandColor(getResources().getColor(R.color.fastlane_background));
+ // set search icon color
+ setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
+ }
+
+ private void loadVideoData() {
+ VideoProvider.setContext(getActivity());
+ mVideosUrl = getActivity().getResources().getString(R.string.catalog_url);
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ private void setupEventListeners() {
+ setOnSearchClickedListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(getActivity(), SearchActivity.class);
+ startActivity(intent);
+ }
+ });
+
+ setOnItemViewClickedListener(new ItemViewClickedListener());
+ setOnItemViewSelectedListener(new ItemViewSelectedListener());
+ }
+...
+</pre>
+
+<h3 id="set-ui">Set UI Elements</h2>
+
+<p>In the sample above, the private method <code>setupUIElements()</code> calls several of the
+{@link android.support.v17.leanback.app.BrowseFragment} methods to style the media catalog browser:
+</p>
+
+<ul>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#setBadgeDrawable(android.graphics.drawable.Drawable) setBadgeDrawable()}
+ places the specified drawable resource in the upper-right corner of the browse fragment, as
+ shown in figures 1 and 2. This method replaces the title string with the
+ drawable resource, if {@code setTitle()} is also called. The drawable resource should be 52dps
+ tall.</li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#setTitle(java.lang.String) setTitle()}
+ sets the title string in the upper-right corner of the browse fragment, unless
+ {@code setBadgeDrawable()} is called.</li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) setHeadersState()}
+ and {@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()} hide or disable the headers. See
+ <a href="#hide-heads">Hide or Disable Headers</a> for more information.
+ </li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#setBrandColor(int) setBrandColor()}
+ sets the background color for UI elements in the browse fragment, specifically the header
+ section background color, with the specified color value.</li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#setSearchAffordanceColor(int) setSearchAffordanceColor()}
+ sets the color of the search icon with the specified color value. The search icon
+ appears in the upper-left corner of the browse fragment, as shown in figures 1 and 2.</li>
+</ul>
+
+<h2 id="header">Customize the Header Views</h2>
+
+<p>The browse fragment shown in figure 1 lists the video category names (the row headers) in the
+left pane. Text views display these category names from the video database. You can customize the
+header to include additional views in a more complex layout. The following sections show how to
+include an image view that displays an icon next to the category name, as shown in figure 2.</p>
+
+<img itemprop="image" src="{@docRoot}images/tv/custom-head.png" alt="App main screen"/>
+<p class="img-caption"><b>Figure 2.</b> The row headers in the browse fragment, with both an icon
+and a text label.</p>
+
+<p>The layout for the row header is defined as follows:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/header_icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp" />
+ <TextView
+ android:id="@+id/header_label"
+ android:layout_marginTop="6dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
</LinearLayout>
</pre>
-<p>
- In order to work with this layout in an activity, retrieve the {@link
- android.support.v17.leanback.app.BrowseFragment} element from the layout. Use the methods in this
- class to set display parameters such as the icon, title, and whether category headers are enabled.
- The following code sample demonstrates how to set the layout parameters for a {@link
- android.support.v17.leanback.app.BrowseFragment} in a layout:
+<p>Use a {@link android.support.v17.leanback.widget.Presenter} and implement the
+abstract methods to create, bind, and unbind the view holder. The following
+example shows how to bind the viewholder with two views, an
+{@link android.widget.ImageView} and a {@link android.widget.TextView}.
</p>
<pre>
-public class BrowseMediaActivity extends Activity {
+public class IconHeaderItemPresenter extends Presenter {
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {
+ LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- public static final String TAG ="BrowseActivity";
+ View view = inflater.inflate(R.layout.icon_header_item, null);
- protected BrowseFragment mBrowseFragment;
+ return new ViewHolder(view);
+ }
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.browse_fragment);
+ public void onBindViewHolder(ViewHolder viewHolder, Object o) {
+ HeaderItem headerItem = ((ListRow) o).getHeaderItem();
+ View rootView = viewHolder.view;
- final FragmentManager fragmentManager = getFragmentManager();
- <strong>mBrowseFragment = (BrowseFragment) fragmentManager.findFragmentById(
- R.id.browse_fragment);</strong>
+ ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);
+ Drawable icon = rootView.getResources().getDrawable(R.drawable.ic_action_video, null);
+ iconView.setImageDrawable(icon);
- // Set display parameters for the BrowseFragment
- mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
- mBrowseFragment.setTitle(getString(R.string.app_name));
- mBrowseFragment.setBadgeDrawable(getResources().getDrawable(
- R.drawable.ic_launcher));
- mBrowseFragment.setBrowseParams(params);
+ TextView label = (TextView) rootView.findViewById(R.id.header_label);
+ label.setText(headerItem.getName());
+ }
+ @Override
+ public void onUnbindViewHolder(ViewHolder viewHolder) {
+ // no op
}
}
</pre>
+<p>This example shows how to define the presenter for a complex layout with
+multiple views, and you could use this pattern to do something even more complex.
+However, an easier way to combine a {@link android.widget.TextView} with a
+drawable resource is to use the <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:drawableLeft">
+{@code TextView.drawableLeft}</a> attribute. Doing it this way, you don't need the
+{@link android.widget.ImageView} shown here.</p>
-<h2 id="lists">Displaying Media Lists</h2>
+<p>In the {@link android.support.v17.leanback.app.BrowseFragment} implementation that displays the
+catalog browser, use the {@link android.support.v17.leanback.app.BrowseFragment#setHeaderPresenterSelector(android.support.v17.leanback.widget.PresenterSelector) setHeaderPresenterSelector()}
+method to set the presenter for the row header, as shown in the following example.</p>
+
+<pre>
+setHeaderPresenterSelector(new PresenterSelector() {
+ @Override
+ public Presenter getPresenter(Object o) {
+ return new IconHeaderItemPresenter();
+ }
+});
+</pre>
+
+<h3 id="hide-heads">Hide or Disable Headers</h3>
+
+<p>Sometimes you may not want the row headers to appear: when there aren't enough categories to
+require a scrollable list, for example. Call the {@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) BrowseFragment.setHeadersState()}
+method during the fragment's {@link android.app.Fragment#onActivityCreated(android.os.Bundle) onActivityCreated()}
+method to hide or disable the row headers. The {@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) setHeadersState()}
+method sets the initial state of the headers in the browse fragment given one of the following
+constants as a parameter:</p>
+
+<ul>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_ENABLED} - When the browse
+ fragment activity is created, the headers are enabled and shown by default. The headers appear as
+ shown in figures 1 and 2 on this page.</li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_HIDDEN} - When the browse
+ fragment activity is created, headers are enabled and hidden by default. The header section of the
+ screen is collapsed, as shown in <a href="{@docRoot}training/tv/playback/card.html#collapsed">
+ figure 1</a> of <a href="{@docRoot}training/tv/playback/card.html">Providing a Card View</a>. The
+ user can select the collapsed header section to expand it.</li>
+ <li>{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_DISABLED} - When the browse
+ fragment activity is created, headers are disabled by default and are never displayed.</li>
+</ul>
+
+<p>If either {@link android.support.v17.leanback.app.BrowseFragment#HEADERS_ENABLED} or
+{@link android.support.v17.leanback.app.BrowseFragment#HEADERS_HIDDEN} is set, you can call
+{@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()}
+to support moving back to the row header from a selected content item in the row. This is enabled by
+default (if you don't call the method), but if you want to handle the back movement yourself, you
+should pass the value <code>false</code> to {@link android.support.v17.leanback.app.BrowseFragment#setHeadersTransitionOnBackEnabled(boolean) setHeadersTransitionOnBackEnabled()}
+and implement your own back stack handling.</p>
+
+<h2 id="lists">Display Media Lists</h2>
<p>
- The {@link android.support.v17.leanback.app.BrowseFragment} allows you to define and display
- browsable media content categories and media items from a media catalog using adapters and
- presenters. Adapters enable you to connect to local or online data sources that contain your
- media catalog information. Presenters hold data about media items and provide layout information
- for displaying an item on screen.
+ The {@link android.support.v17.leanback.app.BrowseFragment} class allows you
+ to define and display browsable media content categories and media items from
+ a media catalog using adapters and presenters. Adapters enable you to connect
+ to local or online data sources that contain your media catalog information.
+ Adapters use presenters to create views and bind data to those views for
+ displaying an item on screen.
</p>
<p>
@@ -131,11 +342,12 @@
</pre>
<p>
- Once you have constructed a presenter class for your media items, you can build and attach an
- adapter to the {@link android.support.v17.leanback.app.BrowseFragment} to display those items on
- screen for browsing by the user. The following example code demonstrates how to construct an
- adapter to display categories and items in those categories using the {@code StringPresenter}
- class shown in the previous code example:
+ Once you have constructed a presenter class for your media items, you can build
+ an adapter and attach it to the {@link android.support.v17.leanback.app.BrowseFragment}
+ to display those items on screen for browsing by the user. The following example
+ code demonstrates how to construct an adapter to display categories and items
+ in those categories using the {@code StringPresenter} class shown in the
+ previous code example:
</p>
<pre>
@@ -158,7 +370,7 @@
listRowAdapter.add("Media Item 1");
listRowAdapter.add("Media Item 2");
listRowAdapter.add("Media Item 3");
- HeaderItem header = new HeaderItem(i, "Category " + i, null);
+ HeaderItem header = new HeaderItem(i, "Category " + i);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
@@ -170,15 +382,15 @@
This example shows a static implementation of the adapters. A typical media browsing application
uses data from an online database or web service. For an example of a browsing application that
uses data retrieved from the web, see the
- <a href="http://github.com/googlesamples/androidtv-leanback">Android TV</a> sample app.
+ <a href="http://github.com/googlesamples/androidtv-leanback">Android Leanback sample app</a>.
</p>
<h2 id="background">Update the Background</h2>
<p>
In order to add visual interest to a media-browsing app on TV, you can update the background
- image as users browse through content. This technique can make interaction with your app feel
- more cinematic and enjoyable for users.
+ image as users browse through content. This technique can make interaction with your app more
+ cinematic and enjoyable.
</p>
<p>
@@ -211,8 +423,8 @@
@Override
public void onItemSelected(Object item, Row row) {
if (item instanceof Movie ) {
- URI uri = ((Movie)item).getBackdropURI();
- updateBackground(uri);
+ Drawable background = ((Movie)item).getBackdropDrawable();
+ updateBackground(background);
} else {
clearBackground();
}
diff --git a/docs/html/training/tv/playback/card.jd b/docs/html/training/tv/playback/card.jd
index 8ac75fd..a3a9872 100644
--- a/docs/html/training/tv/playback/card.jd
+++ b/docs/html/training/tv/playback/card.jd
@@ -32,9 +32,10 @@
Android Leanback sample app</a>, available on GitHub. Use this sample code to start your own
app.</p>
-<img itemprop="image" src="{@docRoot}images/tv/app-browse.png" alt="App main screen"/>
+<img itemprop="image" src="{@docRoot}images/tv/card-view.png" alt="App card view" id="collapsed"/>
<p class="img-caption"><b>Figure 1.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
-Leanback sample app</a> browse fragment with a card presenter displaying card view objects.</p>
+Leanback sample app</a> image card view when selected.</p>
+
<h2 id="presenter">Create a Card Presenter</h2>
@@ -147,10 +148,7 @@
</pre>
<p>When the user selects the {@link android.support.v17.leanback.widget.ImageCardView}, it expands
-to reveal its text area with the background color you specify, as shown in figure 2.</p>
+to reveal its text area with the background color you specify, as shown in figure 1.</p>
-<img itemprop="image" src="{@docRoot}images/tv/card-view.png" alt="App card view"/>
-<p class="img-caption"><b>Figure 2.</b> The <a href="https://github.com/googlesamples/androidtv-Leanback">
-Leanback sample app</a> image card view when selected.</p>
diff --git a/docs/html/training/tv/playback/details.jd b/docs/html/training/tv/playback/details.jd
index bd6d67a..dbe2c84 100644
--- a/docs/html/training/tv/playback/details.jd
+++ b/docs/html/training/tv/playback/details.jd
@@ -111,8 +111,9 @@
private void buildDetails() {
ClassPresenterSelector selector = new ClassPresenterSelector();
// Attach your media item details presenter to the row presenter:
- DetailsOverviewRowPresenter rowPresenter =
- new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
+ FullWidthDetailsOverviewRowPresenter rowPresenter =
+ new FullWidthDetailsOverviewRowPresenter(
+ new DetailsDescriptionPresenter());
selector.addClassPresenter(DetailsOverviewRow.class, rowPresenter);
selector.addClassPresenter(ListRow.class,
diff --git a/docs/html/training/tv/playback/guided-step.jd b/docs/html/training/tv/playback/guided-step.jd
new file mode 100644
index 0000000..121961f
--- /dev/null
+++ b/docs/html/training/tv/playback/guided-step.jd
@@ -0,0 +1,259 @@
+page.title=Adding a Guided Step
+page.tags=tv, guided step
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#details">Provide Details for a Step</a></li>
+ <li><a href="#actions">Create and Handle User Actions</a></li>
+ <li><a href="#sequence">Group Guided Steps Into a Sequence</a></li>
+ <li><a href="#presentation">Customize Step Presentation</a></li>
+ </ol>
+ <h2>Try it out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android
+ Leanback sample app</a></li>
+ </ul>
+</div>
+</div>
+
+<p>
+Your application might have multi-step tasks for users. For example, your app might need to guide
+users through purchasing additional content, or setting up a complex configuration setting, or
+simply confirming a decision. All of these tasks require walking users through one or more ordered
+steps or decisions.
+</p>
+
+<p>
+The <a href=
+"{@docRoot}tools/support-library/features.html#v17-leanback">v17 Leanback support library</a>
+provides classes to implement multi-step user tasks. This lesson discusses how to use the
+{@link android.support.v17.leanback.app.GuidedStepFragment} class to guide a user through a series
+of decisions to accomplish a task. {@link android.support.v17.leanback.app.GuidedStepFragment} uses
+TV UI best practices to make multi-step tasks easy to understand and navigate on TV devices.
+</p>
+
+<h2 id="details">Provide Details for a Step</h2>
+
+<p>
+A {@link android.support.v17.leanback.app.GuidedStepFragment} represents a single step in a series
+of steps. Visually it provides a guidance view on the left with step information. On the right,
+{@link android.support.v17.leanback.app.GuidedStepFragment} provides a view containing a
+list of possible actions or decisions for this step.
+</p>
+
+<img src="{@docRoot}images/training/tv/playback/guided-step-screen.png"
+srcset="{@docRoot}images/training/tv/playback/guided-step-screen.png 1x,
+{@docRoot}images/training/tv/playback/guided-step-screen-2x.png 2x" />
+<p class="img-caption"><strong>Figure 1.</strong> An example guided step.</p>
+
+<p>
+For each step in your multi-step task, extend
+{@link android.support.v17.leanback.app.GuidedStepFragment} and provide context information about
+the step and actions the user can take. Override
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateGuidance onCreateGuidance()}
+and return a new
+{@link android.support.v17.leanback.widget.GuidanceStylist.Guidance} that contains context
+information, such as the step title, description, and icon.
+</p>
+
+<pre>
+@Override
+public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.guidedstep_first_title);
+ String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
+ String description = getString(R.string.guidedstep_first_description);
+ Drawable icon = getActivity().getDrawable(R.drawable.guidedstep_main_icon_1);
+ return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
+}
+</pre>
+
+<p>
+Add your {@link android.support.v17.leanback.app.GuidedStepFragment} subclass to your desired
+activity by calling
+{@link android.support.v17.leanback.app.GuidedStepFragment#add GuidedStepFragment.add()}
+in your activity’s {@link android.app.Activity#onCreate onCreate()} method.
+
+If your activity contains only {@link android.support.v17.leanback.app.GuidedStepFragment}
+objects, use {@link android.support.v17.leanback.app.GuidedStepFragment#addAsRoot
+GuidedStepFragment.addAsRoot()} instead of
+{@link android.support.v17.leanback.app.GuidedStepFragment#add add()} to add the first
+{@link android.support.v17.leanback.app.GuidedStepFragment}. Using
+{@link android.support.v17.leanback.app.GuidedStepFragment#addAsRoot
+addAsRoot()} ensures that if the user presses the Back button on the TV remote when viewing
+the first {@link android.support.v17.leanback.app.GuidedStepFragment}, both the
+{@link android.support.v17.leanback.app.GuidedStepFragment} and the parent activity will close.
+</p>
+
+<p class="note"<strong>Note:</strong> Add
+{@link android.support.v17.leanback.app.GuidedStepFragment} objects programmatically
+and not in your layout XML files.</p>
+
+<h2 id="actions">Create and Handle User Actions</h2>
+
+<p>
+Add user actions by overriding
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateActions onCreateActions()}.
+In your override, add a new {@link android.support.v17.leanback.widget.GuidedAction} for each
+action item, and provide the action string, description, and ID. Use
+{@link android.support.v17.leanback.widget.GuidedAction.Builder} to add new actions.
+</p>
+
+<pre>
+@Override
+public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ // Add "Continue" user action for this step
+ actions.add(new GuidedAction.Builder()
+ .id(CONTINUE)
+ .title(getString(R.string.guidedstep_continue))
+ .description(getString(R.string.guidedstep_letsdoit))
+ .hasNext(true)
+ .build());
+...
+</pre>
+
+<p>
+Actions aren’t limited to single-line selections. Use
+{@link android.support.v17.leanback.widget.GuidedAction} attributes
+to add the following additional types of actions:
+</p>
+
+<ul>
+<li>
+Add a information label action by setting
+{@link android.support.v17.leanback.widget.GuidedAction.Builder#infoOnly infoOnly(true)}.
+If <code>infoOnly</code> is set to true, the action can't be selected by the user. Use label
+actions to provide additional information about user choices.
+</li>
+<li>
+Add an editable text action by setting
+{@link android.support.v17.leanback.widget.GuidedAction.Builder#editable editable(true)}. If
+<code>editable</code> is true, when the action is selected the user can enter text using the
+remote or a connected keyboard.
+</li>
+<li>
+Add a set of actions that behave as checkable radio buttons by using
+{@link android.support.v17.leanback.widget.GuidedAction.Builder#checkSetId checkSetId()}
+with a common ID value to group actions into a set. All actions in the same list with the same
+check-set ID are considered linked. When one of the actions within that set is selected, that
+action becomes checked, while all other actions become unchecked.
+</li>
+</ul>
+
+<p>
+You can also add a visual indicator that indicates selecting the action leads to a new step by
+setting
+{@link android.support.v17.leanback.widget.GuidedAction#hasNext hasNext(true)}.
+See {@link android.support.v17.leanback.widget.GuidedAction} for all the different attributes
+you can set.
+</p>
+
+<p>
+To respond to actions, override
+{@link android.support.v17.leanback.app.GuidedStepFragment#onGuidedActionClicked
+onGuidedActionClicked()} and process the passed-in
+{@link android.support.v17.leanback.widget.GuidedAction}. Identify the selected action by
+examining {@link android.support.v17.leanback.widget.GuidedAction#getId GuidedAction.getId()}.
+</p>
+
+<h2 id="sequence">Group Guided Steps Into a Guided Sequence</h2>
+
+<p>
+A {@link android.support.v17.leanback.app.GuidedStepFragment} represents a single step, however
+you might have several steps in an ordered sequence. Group multiple
+{@link android.support.v17.leanback.app.GuidedStepFragment} objects together by using
+{@link android.support.v17.leanback.app.GuidedStepFragment#add GuidedStepFragment.add()} to add
+the next step in the sequence to the fragment stack.
+</p>
+
+<pre>
+@Override
+public void onGuidedActionClicked(GuidedAction action) {
+ FragmentManager fm = getFragmentManager();
+ if (action.getId() == CONTINUE) {
+ GuidedStepFragment.add(fm, new SecondStepFragment());
+ }
+...
+</pre>
+
+<p>
+If the user presses the Back button on the TV remote, the device shows the previous
+{@link android.support.v17.leanback.app.GuidedStepFragment} on the fragment stack. If you
+decide to provide your own {@link android.support.v17.leanback.widget.GuidedAction} that
+returns to the previous step, you can implement the Back behavior by calling
+{@link android.app.FragmentManager#popBackStack getFragmentManager().popBackStack()}.
+</p>
+
+<h2 id="presentation">Customize Step Presentation</h2>
+
+<p>
+The {@link android.support.v17.leanback.app.GuidedStepFragment} class can use custom
+themes that control presentation aspects such as title text formatting or step transition
+animations. Custom themes must inherit from
+{@link android.support.v17.leanback.R.style#Theme_Leanback_GuidedStep}, and can provide
+overriding values for attributes defined in
+{@link android.support.v17.leanback.widget.GuidanceStylist} and
+{@link android.support.v17.leanback.widget.GuidedActionsStylist}.
+</p>
+
+<p>
+To apply a custom theme to your GuidedStepFragment, do one of the following:
+</p>
+
+<ul>
+<li>
+Apply the theme to the parent activity by setting the <code>android:theme</code> attribute to the
+activity element in the Android manifest. Setting this attribute applies the theme to all child
+views and is the easiest way to apply a custom theme if the parent activity contains only
+{@link android.support.v17.leanback.app.GuidedStepFragment} objects.
+</li>
+<li>
+If your activity already uses a custom theme and you don’t want to apply
+{@link android.support.v17.leanback.app.GuidedStepFragment} styles to other views in the activity,
+add the
+{@link android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepTheme}
+attribute to your existing custom activity theme. This attribute points to the custom theme that
+only the {@link android.support.v17.leanback.app.GuidedStepFragment} objects in your
+activity will use.
+</li>
+<li>
+If you use {@link android.support.v17.leanback.app.GuidedStepFragment} objects in different
+activities that are part of the same overall multi-step task, and want to use a consistent
+visual theme across all steps, override
+{@link android.support.v17.leanback.app.GuidedStepFragment#onProvideTheme
+GuidedStepFragment.onProvideTheme()} and return your custom theme.
+</li>
+</ul>
+
+<p>
+For more information on how to add styles and themes, see
+<a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a>.
+</p>
+
+<p>
+The {@link android.support.v17.leanback.app.GuidedStepFragment} class uses special
+<em>stylist classes</em> to access and apply theme attributes.
+The {@link android.support.v17.leanback.widget.GuidanceStylist} class uses theme information
+to control presentation of the left guidance view, while the
+{@link android.support.v17.leanback.widget.GuidedActionsStylist} class uses theme information
+to control presentation of the right actions view.
+</p>
+
+<p>
+To customize the visual style of your steps beyond what theme customization can provide, subclass
+{@link android.support.v17.leanback.widget.GuidanceStylist} or
+{@link android.support.v17.leanback.widget.GuidedActionsStylist} and return your subclass in
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateGuidanceStylist
+GuidedStepFragment.onCreateGuidanceStylist()} or
+{@link android.support.v17.leanback.app.GuidedStepFragment#onCreateActionsStylist
+GuidedStepFragment.onCreateActionsStylist()}.
+For details on what you can customize in these subclasses, see the documentation on
+{@link android.support.v17.leanback.widget.GuidanceStylist} and
+{@link android.support.v17.leanback.widget.GuidedActionsStylist}.
+</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
index e39e34a..d5e4e67 100644
--- a/docs/html/training/tv/playback/index.jd
+++ b/docs/html/training/tv/playback/index.jd
@@ -64,4 +64,11 @@
<dt><b><a href="now-playing.html">Displaying a Now Playing Card</a></b></dt>
<dd>Learn how to use a MediaSession to display a Now Playing card on the home screen.</dd>
+
+ <dt><b><a href="guided-step.html">Adding a Guided Step</a></b></dt>
+ <dd>Learn how to use the Leanback support library to guide a user through a series of
+ decisions.</dd>
+
+ <dt><b><a href="options.html">Enabling Background Playback</a></b></dt>
+ <dd>Learn how to continue playback when the user clicks on <strong>Home</strong>.</dd>
</dl>
diff --git a/docs/html/training/tv/playback/now-playing.jd b/docs/html/training/tv/playback/now-playing.jd
index e158697..2bb628a 100644
--- a/docs/html/training/tv/playback/now-playing.jd
+++ b/docs/html/training/tv/playback/now-playing.jd
@@ -19,52 +19,45 @@
</div>
</div>
-<p>TV apps may allow users to play music or other media in the background while using other
-applications. If your app allows this type of use, it must must
-provide a means for the user to return to the app to pause the music or switch to a new song. The
-Android framework enables TV apps to do this by displaying a <em>Now Playing</em> card on the home
-screen in the recommendations row.</p>
+<p>TV apps must display a <em>Now Playing</em> card when playing media behind the launcher or in the
+background. This card allows users to return to the app that is currently playing media.</p>
-<p>The Now Playing card is a system artifact that displays on the
-home screen in the recommendations row for an active media session. It includes the media metadata
-such as the album art, title, and app icon. When the user selects it, the system opens the the app
-that owns the session.</p>
+<p>The Android framework displays a <em>Now Playing</em> card on the home
+screen when there is an active {@link android.media.session.MediaSession}.
+The card includes media metadata such as album art, title, and app icon.
+When the user selects the card, the system opens the app.</p>
<p>This lesson shows how to use the {@link android.media.session.MediaSession} class to implement
-the Now Playing card.</p>
+the <em>Now Playing</em> card.</p>
+
+<img src="{@docRoot}images/training/tv/playback/now-playing-screen.png" />
+<p class="img-caption"><strong>Figure 1.</strong> Display a <em>Now Playing</em> card when playing
+media in the background.</p>
<h2 id="session">Start a Media Session</h2>
-<p>A playback app can run as an <a href="{@docRoot}guide/components/activities">activity</a> or
-as a <a href="{@docRoot}guide/components/services">service</a>. The service is required for
-background playback because it can continue to play media even after the activity that launched it
-has been destroyed. For this discussion, the media playback app is assumed to be running in a
-{@link android.service.media.MediaBrowserService}.</p>
-
-<p>In your service's {@link android.service.media.MediaBrowserService#onCreate() onCreate()}
-method, create a new {@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession},
-set the callback and flags appropriate to a media app, and set the session token for the
-{@link android.service.media.MediaBrowserService}.</p>
+<p>Create a
+{@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession}
+when your app is preparing to play media. The following code snippet
+is an example of how to set the appropriate callback and flags:</p>
<pre>
mSession = new MediaSession(this, "MusicService");
mSession.setCallback(new MediaSessionCallback());
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
-
-// for the MediaBrowserService
-setSessionToken(mSession.getSessionToken());
</pre>
-<p class="note"<strong>Note:</strong> The Now Playing card will display only for a media session with
+<p class="note"<strong>Note:</strong> The <em>Now Playing</em> card will display
+only for a media session with
the {@link android.media.session.MediaSession#FLAG_HANDLES_TRANSPORT_CONTROLS} flag set.</p>
<h2 id="card">Display a Now Playing Card</h2>
-<p>The Now Playing card shows up after {@link android.media.session.MediaSession#setActive(boolean) setActive(true)}
-is called, if the session is the highest priority session in the system. Also, note that your app
-must request the audio focus, as described in <a href="{@docRoot}training/managing-audio/audio-focus">
-Managing Audio Focus</a>.</p>
+<p>The <em>Now Playing</em> card only appears for active sessions. You must call
+{@link android.media.session.MediaSession#setActive(boolean) setActive(true)}
+when playback begins. Your app must also request audio focus, as described in
+<a href="{@docRoot}training/managing-audio/audio-focus.html">Managing Audio Focus</a>.</p>
<pre>
private void handlePlayRequest() {
@@ -77,15 +70,19 @@
...
</pre>
-<p>The card is removed from the home screen when {@link android.media.session.MediaSession#setActive(boolean) setActive(false)}
-is called or if another app initiates media playback. You may want to remove the card from the home
-screen some time after playback is paused, depending on how long you want to keep the card up,
-usually 5 to 30 minutes.</p>
+<p>The card is removed from the launcher screen when a
+{@link android.media.session.MediaSession#setActive(boolean) setActive(false)}
+call deactivates the media session,
+or when another app initiates media playback.
+If playback is completely stopped and there is no active media,
+your app should deactivate the media session immediately.
+If playback is paused, your app should deactivate the media session
+after a delay, usually between 5 to 30 minutes.</p>
<h2 id="state">Update the Playback State</h2>
-<p>As with any media app, update the playback state in the {@link android.media.session.MediaSession}
-so that the card can display the current metadata, as shown in the following example:</p>
+<p>Update the playback state in the {@link android.media.session.MediaSession}
+so the card can show the state of the current media.</p>
<pre>
private void updatePlaybackState() {
@@ -98,8 +95,9 @@
stateBuilder.setState(mState, position, 1.0f);
mSession.setPlaybackState(stateBuilder.build());
}
+
private long getAvailableActions() {
- long actions = PlaybackState.ACTION_PLAY |
+ long actions = PlaybackState.ACTION_PLAY_PAUSE |
PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
PlaybackState.ACTION_PLAY_FROM_SEARCH;
if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
@@ -107,6 +105,8 @@
}
if (mState == PlaybackState.STATE_PLAYING) {
actions |= PlaybackState.ACTION_PAUSE;
+ } else {
+ actions |= PlaybackState.ACTION_PLAY;
}
if (mCurrentIndexOnQueue > 0) {
actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
@@ -120,10 +120,11 @@
<h2 id="metadata">Display the Media Metadata</h2>
-<p>For the track currently playing, set the {@link android.media.MediaMetadata} with the
+<p>Set the {@link android.media.MediaMetadata} with the
{@link android.media.session.MediaSession#setMetadata(android.media.MediaMetadata) setMetadata()}
-method. This method of the media session object lets you provide information to the Now Playing card
-about the track such as the title, subtitle, and various icons. The following example assumes your
+method. This method of the media session object lets you provide information to
+the <em>Now Playing</em> card about the track such as the title, subtitle,
+and various icons. The following example assumes your
track's data is stored in a custom data class, {@code MediaData}.</p>
<pre>
@@ -143,7 +144,7 @@
metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST,
myData.artist);
// A small bitmap for the artwork is also recommended
- metadataBuilder.putString(MediaMetadata.METADATA_KEY_ART,
+ metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ART,
myData.artBitmap);
// Add any other fields you have for your data as well
mSession.setMetadata(metadataBuilder.build());
@@ -152,8 +153,9 @@
<h2 id="respond">Respond to User Action</h2>
-<p>When the user selects the Now Playing card, the system opens the app that owns the session.
-If your app provides a {@link android.app.PendingIntent} to pass to
+<p>When the user selects the <em>Now Playing</em> card, the system
+opens the app that owns the session.
+If your app provides a {@link android.app.PendingIntent} to
{@link android.media.session.MediaSession#setSessionActivity(android.app.PendingIntent) setSessionActivity()},
the system launches the activity you specify, as demonstrated below. If not, the default system
intent opens. The activity you specify must provide playback controls that allow users to pause or
diff --git a/docs/html/training/tv/playback/options.jd b/docs/html/training/tv/playback/options.jd
new file mode 100644
index 0000000..c65343d
--- /dev/null
+++ b/docs/html/training/tv/playback/options.jd
@@ -0,0 +1,66 @@
+page.title=Enabling Background Playback
+page.tags=tv, play, playback, background
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#background">Request Background Playback</a></li>
+ </ol>
+</div>
+</div>
+
+<p>
+A user watching content on a TV device may decide to switch to the TV launcher at any time.
+If a user switches to the launcher while using a TV playback app, by default the app is paused.
+Since the user did not explicitly request to pause playback, the default behavior might seem
+abrupt and unexpected. This lesson describes how to enable background playback in your app,
+which provides a better user experience.
+</p>
+
+<h2 id="background">Request Background Playback</h2>
+
+<p>Normally, when the user clicks on <strong>Home</strong> to display the TV
+launcher, the activity pauses. However, your app can request background playback, in
+which the activity continues playing behind the TV launcher.</p>
+
+<p>To request background playback, call
+{@link android.app.Activity#requestVisibleBehind requestVisibleBehind()}.
+Be sure to clean up media resources if the activity stops being
+visible. For example, you should free media resources if
+{@link android.app.Activity#requestVisibleBehind requestVisibleBehind()}
+returns <code>false</code> to indicate that the request failed, or if the system calls
+your override of {@link android.app.Activity#onVisibleBehindCanceled onVisibleBehindCanceled()}.
+</p>
+
+<pre>
+@Override
+public void onPause() {
+ super.onPause();
+ if (mVideoView.isPlaying()) {
+ // Argument equals true to notify the system that the activity
+ // wishes to be visible behind other translucent activities
+ if (! requestVisibleBehind(true)) {
+ // App-specific method to stop playback and release resources
+ // because call to requestVisibleBehind(true) failed
+ stopPlayback();
+ }
+ } else {
+ // Argument equals false because the activity is not playing
+ requestVisibleBehind(false);
+ }
+}
+
+@Override
+public void onVisibleBehindCanceled() {
+ // App-specific method to stop playback and release resources
+ stopPlayback();
+ super.onVisibleBehindCanceled();
+}
+</pre>
+
diff --git a/docs/html/training/tv/publishing/checklist.jd b/docs/html/training/tv/publishing/checklist.jd
index 6259721..c044f0e 100644
--- a/docs/html/training/tv/publishing/checklist.jd
+++ b/docs/html/training/tv/publishing/checklist.jd
@@ -137,6 +137,11 @@
<p>See <a href="{@docRoot}training/tv/start/layouts.html#advertising">Provide Effective Advertising</a>.</p>
</li>
+<li>
+ Use the Leanback library for guiding the user through a series of decisions.
+ <p>See <a href="{@docRoot}training/tv/playback/guided-step.html">Adding a Guided Step</a>.</p>
+</li>
+
</ol>
diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd
index 5747b56..9a66c09 100644
--- a/docs/html/training/tv/start/hardware.jd
+++ b/docs/html/training/tv/start/hardware.jd
@@ -100,10 +100,6 @@
<td>{@code android.hardware.camera}</td>
</tr>
<tr>
- <td>Bluetooth</td>
- <td>{@code android.hardware.bluetooth}</td>
- </tr>
- <tr>
<td>Near Field Communications (NFC)</td>
<td>{@code android.hardware.nfc}</td>
</tr>
@@ -159,8 +155,6 @@
android:required="false"/>
<uses-feature android:name="android.hardware.camera"
android:required="false"/>
-<uses-feature android:name="android.hardware.bluetooth"
- android:required="false"/>
<uses-feature android:name="android.hardware.nfc"
android:required="false"/>
<uses-feature android:name="android.hardware.location.gps"
@@ -172,7 +166,7 @@
</pre>
<p class="note"><strong>Note:</strong> Some features have subfeatures like {@code android.hardware.camera.front},
- as described in the <a href="guide/topics/manifest/uses-feature-element.html#features-reference">
+ as described in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#features-reference">
Feature Reference</a>. Be sure to mark as {@code required="false"} any subfeatures also used in
your app.</p>
diff --git a/docs/html/training/tv/start/layouts.jd b/docs/html/training/tv/start/layouts.jd
index 2b190b4..4ca77d0 100644
--- a/docs/html/training/tv/start/layouts.jd
+++ b/docs/html/training/tv/start/layouts.jd
@@ -117,25 +117,43 @@
This behavior is generally referred to as <em>overscan</em>.
</p>
-<p>
- Avoid screen elements being clipped due to overscan and by incorporating a 10% margin
- on all sides of your layout. This translates into a 48dp margin on the left and right edges and
- a 27dp margin on the top and bottom of your base layouts for activities. The following
- example layout demonstrates how to set these margins in the root layout for a TV app:
+<p>Screen elements that must be visible to the user at all times should be positioned within the
+overscan safe area. Adding a 5% margin of 48dp on the left and right edges and 27dp on the top and
+bottom edges to a layout ensures that screen elements in that layout will be within the overscan
+safe area.
+</p>
+
+<p>Background screen elements that the user doesn't directly interact with should not be adjusted or
+clipped to the overscan safe area. This approach ensures that background screen elements look
+correct on all screens.
+</p>
+
+<p>The following example shows a root layout that can contain background elements, and a nested
+child layout that has a 5% margin and can contain elements within the overscan safe area:
</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/base_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:layout_marginTop="27dp"
- android:layout_marginLeft="48dp"
- android:layout_marginRight="48dp"
- android:layout_marginBottom="27dp" >
-</LinearLayout>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+
+ <!-- Screen elements that can render outside the overscan safe area go here -->
+
+ <!-- Nested RelativeLayout with overscan-safe margin -->
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="27dp"
+ android:layout_marginBottom="27dp"
+ android:layout_marginLeft="48dp"
+ android:layout_marginRight="48dp">
+
+ <!-- Screen elements that need to be within the overscan safe area go here -->
+
+ </RelativeLayout>
+</RelativeLayout>
</pre>
<p class="caution">
diff --git a/docs/html/training/tv/start/start.jd b/docs/html/training/tv/start/start.jd
old mode 100644
new mode 100755
index 4d04ad6..0c04bfa
--- a/docs/html/training/tv/start/start.jd
+++ b/docs/html/training/tv/start/start.jd
@@ -228,6 +228,27 @@
design guide.
</p>
+<h3 id="transition-color">Change the launcher color</h3>
+
+<p>When a TV app launches, the system displays an animation that resembles an expanding, filled
+ circle. To customize the color of this animation, set the <code>android:colorPrimary</code>
+ attribute of your TV app or activity to a specific color. You should also set two additional
+ transition overlap attributes to <code>true</code>, as shown in the following snippet from a
+ theme resource XML file:</p>
+
+<pre>
+<resources>
+ <style ... >
+ <item name="android:colorPrimary">@color/primary</item>
+ <item name="android:windowAllowReturnTransitionOverlap">true</item>
+ <item name="android:windowAllowEnterTransitionOverlap">true</item>
+ </style>
+</resources>
+</pre>
+
+<p>For more information about working with themes and styles, see
+<a href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a>.</p>
+
<h2 id="tv-libraries">Add TV Support Libraries</h3>
<p>
@@ -346,7 +367,5 @@
For more information about using emulators see, <a href="{@docRoot}tools/devices/emulator.html">
Using the Emulator</a>. For more information on deploying apps from Android Studio to virtual
devices, see <a href="{@docRoot}sdk/installing/studio-debug.html">Debugging with Android
- Studio</a>. For more information about deploying apps to emulators from Eclipse with ADT, see
- <a href="{@docRoot}tools/building/building-eclipse.html">Building and Running from Eclipse with
- ADT</a>.
+ Studio</a>.
</p>
diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
index 91f8ded..1a53398 100644
--- a/docs/html/training/tv/tif/tvinput.jd
+++ b/docs/html/training/tv/tif/tvinput.jd
@@ -12,7 +12,7 @@
<ol>
<li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
<li><a href="#tvinput">Define Your TV Input Service</a></li>
- <li><a href="#setup">Define Setup and Settings Activities</a></li>
+ <li><a href="#setup">Define Your Setup Activity</a></li>
</ol>
<h2>You should also read</h2>
<ul>
@@ -82,18 +82,14 @@
<p>Define the service meta data in separate XML file, as shown in the following example. The service
meta data must include a setup interface that describes the TV input's initial configuration and
-channel scan. Also, the service meta data may (optionally) describe a settings activity for users to
-modify the TV input's behavior. The service meta data file is located in the XML resources directory
+channel scan. The service meta data file is located in the XML resources directory
for your application and must match the name of the resource in the manifest. Using the example
manifest entries above, you would create an XML file in the location
<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
<pre>
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
- <!-- Required: activity for setting up the input -->
- android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity"
- <!-- Optional: activity for controlling the settings -->
- android:settingsActivity="com.example.sampletvinput.SampleTvInputSettingsActivity" />
+ android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity" />
</pre>
<h2 id="tvinput">Define Your TV Input Service</h2>
@@ -157,21 +153,16 @@
<p>The {@link android.media.tv.TvInputService.Session} handles the
{@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
event when the user selects a channel, and notifies the system TV app for changes in the content and
-content meta data. These <code>notify()</code>code> methods are described in
+content meta data. These <code>notify()</code> methods are described in
<a href="{@docRoot}training/tv/tif/ui.html#control">
-Control Content</a> and <a href="training/tv/tif/ui.html#track">Handle Track Selection</a> further
-in this training.</p>
+Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a>
+further in this training.</p>
-<h2 id="setup">Define Setup and Settings Activities</h2>
+<h2 id="setup">Define Your Setup Activity</h2>
-<p>The system TV app works with the setup and settings activities you define for your TV input. The
+<p>The system TV app works with the setup activity you define for your TV input. The
setup activity is required and must provide at least one channel record for the system database. The
system TV app will invoke the setup activity when it cannot find a channel for the TV input.
<p>The setup activity describes to the system TV app the channels made available through the TV
input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
and Updating Channel Data</a>.</p>
-
-<p>The settings activity is optional. You can define a settings activity to turn on parental
-controls, enable closed captions, set the display attributes, and so forth.</p>
-
-
diff --git a/docs/html/training/volley/index.jd b/docs/html/training/volley/index.jd
old mode 100644
new mode 100755
index ff74634..31c0ed0
--- a/docs/html/training/volley/index.jd
+++ b/docs/html/training/volley/index.jd
@@ -23,7 +23,7 @@
</div>
</div>
-<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
+<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
<div>
<h3>Video</h3>
<p>Volley: Easy, Fast Networking for Android</p>
@@ -77,9 +77,9 @@
</pre>
</li>
-<li>Import the downloaded source into your app project as an Android library project
-(as described in <a href="{@docRoot}tools/projects/projects-eclipse.html">
-Managing Projects from Eclipse with ADT</a>, if you're using Eclipse) or make a
+<li>Import the downloaded source into your app project as an Android library module
+(as described in <a href="{@docRoot}sdk/installing/create-project.html#SettingUpLibraryModule">
+Managing Projects from Android Studio</a>, if you're using Android Studio) or make a
<a href="{@docRoot}guide/faq/commontasks.html#addexternallibrary"><code>.jar</code> file</a>.</li>
</ol>
diff --git a/docs/html/training/volley/request-custom.jd b/docs/html/training/volley/request-custom.jd
index c62c254..9c3eb57 100644
--- a/docs/html/training/volley/request-custom.jd
+++ b/docs/html/training/volley/request-custom.jd
@@ -16,7 +16,7 @@
</div>
</div>
-<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
+<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
<div>
<h3>Video</h3>
<p>Volley: Easy, Fast Networking for Android</p>
diff --git a/docs/html/training/volley/request.jd b/docs/html/training/volley/request.jd
index 8a7dc62..a2b2ecd 100644
--- a/docs/html/training/volley/request.jd
+++ b/docs/html/training/volley/request.jd
@@ -17,7 +17,7 @@
</div>
</div>
-<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
+<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
<div>
<h3>Video</h3>
<p>Volley: Easy, Fast Networking for Android</p>
diff --git a/docs/html/training/volley/requestqueue.jd b/docs/html/training/volley/requestqueue.jd
index 6d19cee..f8c61aa 100644
--- a/docs/html/training/volley/requestqueue.jd
+++ b/docs/html/training/volley/requestqueue.jd
@@ -17,7 +17,7 @@
</div>
</div>
-<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
+<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
<div>
<h3>Video</h3>
<p>Volley: Easy, Fast Networking for Android</p>
@@ -39,36 +39,11 @@
of the requests, and a cache to handle caching. There are standard implementations of these
available in the Volley toolbox: {@code DiskBasedCache} provides a one-file-per-response
cache with an in-memory index, and {@code BasicNetwork} provides a network transport based
-on your choice of the Apache HTTP client {@code android.net.http.AndroidHttpClient} or
-{@link java.net.HttpURLConnection}.</p>
+on your preferred HTTP client.</p>
<p>{@code BasicNetwork} is Volley's default network implementation. A {@code BasicNetwork}
must be initialized with the HTTP client your app is using to connect to the network.
-Typically this is a {@link java.net.HttpURLConnection}:</p>
-<ul>
-<li>Use {@code android.net.http.AndroidHttpClient} for apps targeting Android API levels
-lower than API Level 9 (Gingerbread). Prior to Gingerbread, {@link java.net.HttpURLConnection}
-was unreliable. For more discussion of this topic, see
-<a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">
-Android's HTTP Clients</a>. </li>
-
-<li>Use {@link java.net.HttpURLConnection} for apps targeting Android API Level 9
-(Gingerbread) and higher.</li>
-</ul>
-<p>To create an app that runs on all versions of Android, you can check the version of
-Android the device is running and choose the appropriate HTTP client, for example:</p>
-
-<pre>
-HttpStack stack;
-...
-// If the device is running a version >= Gingerbread...
-if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- // ...use HttpURLConnection for stack.
-} else {
- // ...use AndroidHttpClient for stack.
-}
-Network network = new BasicNetwork(stack);
-</pre>
+Typically this is an {@link java.net.HttpURLConnection}.</p>
<p>This snippet shows you the steps involved in setting up a
{@code RequestQueue}:</p>
@@ -88,7 +63,7 @@
// Start the queue
mRequestQueue.start();
-String url ="http://www.myurl.com";
+String url ="http://www.example.com";
// Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
@@ -107,7 +82,8 @@
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
-...
+
+// ...
</pre>
<p>If you just need to make a one-time request and don't want to leave the thread pool
@@ -198,7 +174,8 @@
// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
-...
+
+// ...
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
diff --git a/docs/html/training/volley/simple.jd b/docs/html/training/volley/simple.jd
index ecb5fde..ab61b9b 100644
--- a/docs/html/training/volley/simple.jd
+++ b/docs/html/training/volley/simple.jd
@@ -19,7 +19,7 @@
</div>
</div>
-<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
+<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
<div>
<h3>Video</h3>
<p>Volley: Easy, Fast Networking for Android</p>
@@ -101,7 +101,7 @@
parsed on the cache thread and the parsed response is delivered on the main thread. If the
request cannot be serviced from cache, it is placed on the network queue. The first
available network thread takes the request from the queue, performs the HTTP transaction,
-parsse the response on the worker thread, writes the response to cache, and posts the parsed
+parses the response on the worker thread, writes the response to cache, and posts the parsed
response back to the main thread for delivery.</p>
<p>Note that expensive operations like blocking I/O and parsing/decoding are done on worker
diff --git a/docs/html/training/wearables/apps/always-on.jd b/docs/html/training/wearables/apps/always-on.jd
index d384974..9f28b70 100644
--- a/docs/html/training/wearables/apps/always-on.jd
+++ b/docs/html/training/wearables/apps/always-on.jd
@@ -140,11 +140,16 @@
<p>If the user does not interact with your app for a period of time while it is displayed, or if
the user covers the screen with their palm, the system switches the activity to ambient mode.
After the app switches to ambient mode, update the activity UI to a more basic layout to reduce
-power consumption. You should use a black background with minimal white graphics and text. To
-ease a user into the transition from interactive to ambient mode, try to maintain similar placement
-of items on the screen. For more information on presenting content on an ambient screen, see the
+power consumption. You should use a black background with minimal white graphics and text.
+ To ease a user into the transition from interactive to ambient mode, try to maintain similar
+ placement of items on the screen. For more information on presenting content on an ambient screen,
+ see the
<a href="{@docRoot}design/wear/watchfaces.html#DisplayModes">Watch Faces for Android Wear</a>
-design guide.
+design guide.</p>
+<p> Note that when your app runs on a device without a hardware button, palming the screen does not
+switch an app into ambient mode. Rather, it causes the app to exit and the home screen to appear.
+This behavior is intended to ensure that users can exit apps gracefully. However, these devices still
+ go to ambient mode when the screen times out.
</p>
<p class="note"><b>Note:</b> In ambient mode, disable any interactive elements on the
diff --git a/docs/html/training/wearables/apps/creating-app-china.jd b/docs/html/training/wearables/apps/creating-app-china.jd
new file mode 100644
index 0000000..d4b3ab7
--- /dev/null
+++ b/docs/html/training/wearables/apps/creating-app-china.jd
@@ -0,0 +1,157 @@
+page.title=Creating Android Wear Apps for China
+parent.title=Training
+parent.link=creating.html
+page.tags= "wearable", "apps", "china"
+page.article=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#ChinaSDK">Support Your App on Android Wear for China</a></li>
+ <li><a href="#other-services">Use Other Google Play Services APIs</a></li>
+</ol>
+<h2>Dependencies and prerequisites</h2>
+<ol>
+<li> Android 4.3 (API Level 18) or higher on the handset and wearable device</li>
+</ol>
+<h2>Downloads</h2>
+<ol>
+<div class="download-box">
+<a href="https://dl.google.com/androidwear/developers/china/google-play-services-7-8-87.zip"
+ class="button">Standalone Client Library</a>
+<p class="filename">google-play-services-7-8-87.zip</p>
+</div>
+</ol>
+</div>
+</div>
+
+
+<p>
+Handsets sold in China do not have Google Play services preinstalled. For this reason, wearable
+apps running on devices in China must communicate with paired handsets through the Android Wear
+companion app. To enable you to develop a single APK that works with both Android Wear for China and
+ Android Wear in the rest of the world, we provide a special variant of the Google Play services
+client library.</p>
+
+<p>
+This client library is compatible with Android 4.3 (API level 18) and higher, and you can simply
+drop it into your app. You do not need to write any new code. Instead, you change several project
+configuration settings, and re-compile your app.
+</p>
+
+
+<p>The rest of this page explains how to perform this process.</p>
+
+
+
+<h2 id = "ChinaSDK">Support Your App on Android Wear for China</h2>
+
+<p>
+<p>In order to support your wearable app on all handsets, you must download and add the Google Play
+Services 7.8.87 client library as a Maven repository in your project, configure your
+development project to use it, and re-compile your app.
+</p>
+
+<h3>Add the Google Play Services 7.8.87 library</h3>
+
+<p>The Google Play services 7.8.87 client library is distributed as a Maven repository. To add this
+repository to your project:</p>
+
+<ol>
+<li><a href="https://dl.google.com/androidwear/developers/china/google-play-services-7-8-87.zip">
+Download</a> the client library.
+The filename is {@code google-play-services-7-8-87.zip}.</li>
+<li>Create a local Maven repository by extracting the {@code google-play-services-7-8-87/} directory
+from the downloaded zip file, and placing it into the root directory of your project.
+</li>
+<li>In your top-level project {@code build.gradle} file, specify the location of the newly created
+local Maven {@code google-play-services-7-8-87} repository.
+</li>
+<p>
+The following example shows how to do so:
+</p>
+<pre>
+allprojects {
+ repositories {
+
+ maven {
+ url "${rootProject.projectDir}/google-play-services-7-8-87"
+ }
+ // ... other repositories may go here ...
+
+ }</pre>
+</ol>
+<h3>Configure your app to use the library</h3>
+<p>In the {@code build.gradle} file of your <em>mobile</em> module replace the Google Play
+ services dependency with a reference to the client library from the newly added repository. The
+ following example shows how to do so:
+</p>
+
+
+<pre>
+dependencies{
+ ...
+ wearApp project(':wear')
+ compile 'com.google.android.gms:play-services-wearable:7.8.87'
+ ...
+ }
+</pre>
+<p>The {@code build.gradle} file of your <em>wear</em> module must also use this version of the
+client library, for example:
+</p>
+<pre>
+dependencies {
+ compile 'com.google.android.support:wearable:1.3.0'
+ compile 'com.google.android.gms:play-services-wearable:7.8.87'
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> If you are using any other Google Play services APIs in your
+wearable app, you must selectively add those Google Play service APIs into your app and explicitly
+ specify the 7.8.87 version. For example to include the Google location API in your wearable app,
+ add the following line in your {@code build.gradle} file:
+</p>
+<pre>
+compile 'com.google.android.gms:play-services-location:7.8.87'
+</pre>
+</p>
+<h3>Build the project</h3>
+
+
+<p>You can now <a href="{@docRoot}training/wearables/apps/packaging.html">build
+</a>a new version of your app and deploy it to Android handsets globally.</p>
+</ol>
+
+
+<h2 id= "other-services">Use Other Google Play services APIs</h2>
+
+<p>
+If your app uses Google Play services APIs other than the Wearable API, then your app needs to check
+whether these APIs are available to use during runtime and respond appropriately. There are two ways
+to check the availability of Google Play service APIs:
+</p>
+
+<ol>
+<li>Use a separate <a href="https://developers.google.com/android/reference/com/google/android/gms/
+common/api/GoogleApiClient.html">{@code GoogleApiClient}</a> instance for connecting to other APIs.
+This interface contains callbacks to alert your app to the success or failure of the connection.
+To learn how to handle connection failures,
+see <a href="https://developers.google.com/android/guides/api-client">Accessing Google APIs</a>.</li>
+
+<li>Use the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/
+api/GoogleApiClient.Builder.html#addApiIfAvailable(com.google.android.gms.common.api.Api<O>, O,
+com.google.android.gms.common.api.Scope...)"> {@code addApiIfAvailable()}</a> method of
+<a href="https://developers.google.com/android/
+reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code GoogleApiClient.Builder}
+</a>
+to connect to the required APIs. After the <a href = "https://developers.google.com/android/reference/
+com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks#onConnected(android.os.Bundle)">
+{@code onConnected()}</a> callback fires, check if each of the requested API is connected correctly
+using the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/
+GoogleApiClient.html#hasConnectedApi(com.google.android.gms.common.api.Api<?>)">
+ {@code hasConnectedApi()}</a> method.
+
+</ol>
diff --git a/docs/html/training/wearables/apps/creating.jd b/docs/html/training/wearables/apps/creating.jd
index f1491e4..db91b67 100644
--- a/docs/html/training/wearables/apps/creating.jd
+++ b/docs/html/training/wearables/apps/creating.jd
@@ -51,6 +51,13 @@
<p>To update your SDK with these components, see
<a href="{@docRoot}sdk/installing/adding-packages.html#GetTools"> Get the latest SDK tools</a>.</p>
+<p class="note"><strong>Note:</strong> If you plan to make your Wear apps available for China,
+ you must use the special release version 7.8.87 of the Google Play services client library to handle
+ communication between handset and wearable.
+
+ For information on how to configure Wear apps for China, see
+ <a href="{@docRoot}training/wearables/apps/creating-app-china.html"> Creating Android Wear Apps for
+ China</a>.</p>
<h2 id="SetupEmulator">Set Up an Android Wear Emulator or Device</h2>
<p>We recommend that you develop on real hardware so you can better
diff --git a/docs/html/training/wearables/apps/index.jd b/docs/html/training/wearables/apps/index.jd
old mode 100644
new mode 100755
index e2a71de..da83cfa
--- a/docs/html/training/wearables/apps/index.jd
+++ b/docs/html/training/wearables/apps/index.jd
@@ -66,10 +66,9 @@
need to show persistent content on versions prior to Android 5.1, create a notification in the
context stream instead.</p>
-<p class="note"><b>Note:</b> We recommend using Android Studio for Android Wear development
-as it provides project setup, library inclusion, and packaging conveniences that aren't available
-in ADT. The rest of this training assumes you're using Android Studio.
-</p>
+<p class="note"><b>Note:</b> We recommend using Android Studio for Android Wear development,
+as it provides project setup, library inclusion, and packaging conveniences. The rest of this
+training assumes you're using Android Studio.</p>
<h2>Lessons</h2>
<dl>
@@ -92,4 +91,4 @@
users install the companion handheld app from the Google Play store.</dd>
<dt><a href="{@docRoot}training/wearables/apps/bt-debugging.html">Debugging over Bluetooth</a></dt>
<dd>Learn how to debug your wearable over Bluetooth instead of USB.</dd>
- </dl>
\ No newline at end of file
+ </dl>
diff --git a/docs/html/training/wearables/apps/layouts.jd b/docs/html/training/wearables/apps/layouts.jd
old mode 100644
new mode 100755
index 197b94b0c..6480e63
--- a/docs/html/training/wearables/apps/layouts.jd
+++ b/docs/html/training/wearables/apps/layouts.jd
@@ -199,12 +199,6 @@
<a href="{@docRoot}reference/android/support/wearable/view/package-summary.html">Wear API
reference documentation</a> for the classes above.</p>
-<h3 id="UiLibEclipse">Download the Wearable UI library for Eclipse ADT</h3>
-
-<p>If you are using the ADT plugin for Eclipse, download the
-<a href="{@docRoot}shareables/training/wearable-support-lib.zip">Wearable UI library</a> to
-include the Wearable UI library as a dependency in your project.</p>
-
-<p class="note"><strong>Note:</strong> We recommend
-<a href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear app
-development.</p>
+<p class="note"><strong>Note:</strong> We recommend using <a
+href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development, as
+it provides project setup, library inclusion, and packaging conveniences.</p>
diff --git a/docs/html/training/wearables/data-layer/data-items.jd b/docs/html/training/wearables/data-layer/data-items.jd
index 49a8d32..b526946 100644
--- a/docs/html/training/wearables/data-layer/data-items.jd
+++ b/docs/html/training/wearables/data-layer/data-items.jd
@@ -38,25 +38,34 @@
<li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">
<code>setData()</code></a> to set the payload.
</li>
+
+ <li>
+ If a delay in syncing would negatively impact user experience, call
+ <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest#setUrgent()">
+ {@code setUrgent()}</a>.
+ </li>
+
<li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>DataApi.putDataItem()</code></a> to request the system to create the data item.
</li>
- <li>When requesting data items, the system returns objects
- that properly implement the <a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code></a> interface.
- </li>
-</ol>
+ </ol>
<p>
-However, instead of working with raw bytes using <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])"><code>setData()</code></a>,
-we recommend you <a href="#SyncData">use a data map</a>, which exposes
+When requesting data items, the system returns objects that properly implement the
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem.html"><code>DataItem</code>
+</a> interface. However, instead of working with raw bytes using
+<a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html#setData(byte[])">
+<code>setData()</code></a>, we recommend you <a href="#SyncData">use a data map</a>, which exposes
a data item in an easy-to-use {@link android.os.Bundle}-like interface.
</p>
<h2 id="SyncData">Sync Data with a Data Map</h2>
<p>
-When possible, use the <a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html"><code>DataMap</code></a> class.
+When possible, use the <a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html">
+<code>DataMap</code></a> class.
This approach lets you work with data items in the form of an Android {@link android.os.Bundle},
-so object serialization and de-serialization is done for you, and you can manipulate data with key-value pairs.
+so the system does object serialization and deserialization for you, and you can manipulate data
+with key-value pairs.
</p>
<p>To use a data map:</p>
@@ -77,11 +86,23 @@
<li>Set any desired values for the data map using the <code>put...()</code> methods, such as
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataMap.html#putString(java.lang.String, java.lang.String)"><code>putString()</code></a>.
</li>
+
+ <li>
+ If a delay in syncing would negatively impact user experience, call
+ <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest#setUrgent()">
+ {@code setUrgent()}</a>.
+ </li>
+
+
<li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataMapRequest.html#asPutDataRequest()"><code>PutDataMapRequest.asPutDataRequest()</code></a>
to obtain a <a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest.html"><code>PutDataRequest</code></a> object.
</li>
+
+
<li>Call <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>DataApi.putDataItem()</code></a> to request the system to create the data item.
+
<p class="note"><b>Note:</b>
+
If the handset and wearable devices are disconnected,
the data is buffered and synced when the connection is re-established.
</p>
@@ -124,6 +145,40 @@
Layer Calls</a>.</p>
+<h3>Set DataItem priority</h3>
+
+<p>
+In <a href="https://developers.google.com/android/guides/releases">Google Play services 8.3 and later</a>,
+the
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi">{@code DataApi}</a> interface
+allows urgent requests for syncing of
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem">{@code DataItems}</a>.
+Normally, the system may delay delivery of
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem">{@code DataItems}</a>
+to the Wear network in order to improve battery life
+for user devices, but if a delay in syncing
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem">{@code DataItems}</a>
+would negatively impact user experience, you
+can mark them as urgent. For example, in a remote control app where the user expects their actions to be
+reflected immediately, you can have the system sync your
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem">{@code DataItems}</a>
+immediately by calling
+<a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest#setUrgent()">
+{@code setUrgent()}</a>.
+</p>
+
+<p>
+If you do not call
+<a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest#setUrgent()">
+{@code setUrgent()}</a>, the system may delay up to 30 minutes before syncing non-urgent
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataItem">{@code DataItems}</a>,
+but you can usually expect the delay to be a few minutes, if at all.
+The default urgency is now non-urgent, so you must use
+<a href="{@docRoot}reference/com/google/android/gms/wearable/PutDataRequest#setUrgent()">
+{@code setUrgent()}</a> if you wish to retain the immediate-sync behavior that
+existed in previous versions of the Wear API.
+</p>
+
<h2 id="ListenEvents">Listen for Data Item Events</h2>
<p>If one side of the data layer connection changes a data item, you probably want
@@ -158,7 +213,7 @@
@Override
protected void onResume() {
- super.onStart();
+ super.onResume();
mGoogleApiClient.connect();
}
diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd
index c797f68..9bed9d5 100644
--- a/docs/html/training/wearables/data-layer/events.jd
+++ b/docs/html/training/wearables/data-layer/events.jd
@@ -68,72 +68,100 @@
</pre>
-<h2 id="Listen">Listen for Data Layer Events </h2>
-<p>Because the data layer synchronizes and sends data across the handheld and
-wearable, you normally want to listen for important events, such as when data items
-are created, messages are received, or when the wearable and handset are connected.
+<h2 id="Listen">Listen for Data Layer Events</h2>
+<p>
+Because the data layer synchronizes and sends data across the handheld and
+wearable, it is usually necessary to listen for important events. Examples of
+such events include creation of data items and receipt of messages.
</p>
-<p>To listen for data layer events, you have two options:</p>
-
+<p>
+To listen for data layer events, you have two options:
+</p>
<ul>
- <li>Create a service that extends
- <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
- </li>
- <li>Create an activity that implements
- <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>.
- </li>
+ <li>Create a service that extends <a href
+="https://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html">
+{@code WearableListenerService}</a>.</li>
+ <li>Create an activity that implements <a
+href="https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.DataListener.html">
+{@code DataApi.DataListener}</a>.</li>
</ul>
-
-<p>With both these options, you override the data event callback methods for the events you
-are interested in handling.</p>
-
-<h3 id="listener-service">With a WearableListenerService</h3>
+<p>
+With both these options, you override the data event callback methods for the
+events you are interested in handling.
+</p>
+<h3>With a WearableListenerService</h3>
+<p>
+You typically create instances of this service in both your wearable and
+handheld apps. If you are not interested in data events in one of these apps,
+then you don't need to implement this service in that particular app.
+</p>
+<p>
+For example, you can have a handheld app that sets and gets data item objects
+and a wearable app that listens for these updates to update its UI. The
+wearable never updates any of the data items, so the handheld app doesn't
+listen for any data events from the wearable app.
+</p>
+<p>
+Some of the events you can listen for using <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+{@code WearableListenerService}</a> are as follows:
+</p>
+<ul>
+ <li><a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
+{@code onDataChanged()}</a>:
+Whenever a data item object is created, deleted, or changed, the system triggers
+this callback on all connected nodes.
+</li>
+<li><a
+href="http://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
+{@code onMessageReceived()}</a>: A message sent from a node triggers
+this callback on the target node.</li>
+<li><a
+href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
+{@code onCapabilityChanged()}</a>:
+When a capability that an instance of your app advertises becomes available
+on the network, that event triggers this callback. If you're looking for a
+nearby node you can query the
+<a
+href="https://developers.google.com/android/reference/com/google/android/gms/wearable/Node.html#isNearby()">
+{@code isNearby()}</a> method of the nodes provided in the callback.</li>
<p>
-You typically create instances of this service in both your wearable and handheld apps. If you
-are not interested in data events in one of these apps, then you don't need to implement this
-service in that particular app.</p>
-
-<p>For example, you can have a handheld app that sets and gets data item objects and a wearable app
-that listens for these updates to update it's UI. The wearable never updates any of the data items,
-so the handheld app doesn't listen for any data events from the wearable app.</p>
-
-<p>You can listen for the following events with
-<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:</p>
-
-<ul>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>
-- Called when data item objects are created, changed, or deleted. An event on one side of a connection
-triggers this callback on both sides.</li>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onMessageReceived()</code></a>
-- A message sent from one side of a connection triggers this callback on the other side of the connection.</li>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)"><code>onPeerConnected()</code></a>
- and <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a> -
- Called when the connection with the handheld or wearable is connected or disconnected.
- Changes in connection state on one side of the connection trigger these callbacks on both sides
- of the connection.
- </li>
+In addition to those on this list, you can listen for events from
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener">
+{@code ChannelApi.ChannelListener}</a>, such as
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html#onChannelOpened(com.google.android.gms.wearable.Channel)">
+{@code onChannelOpened()}</a>.
+</p>
</ul>
-
-<p>To create a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:</p>
+<p>To create a <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>, follow these steps:</p>
<ol>
<li>Create a class that extends
- <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
+ <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
</li>
<li>Listen for the events that you're interested in, such as
- <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code></a>.
+ <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
+<code>onDataChanged()</code></a>.
</li>
- <li>Declare an intent filter in your Android manifest to notify the system about your
- <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>.
- This allows the system to bind your service as needed.
+ <li>Declare an intent filter in your Android manifest to notify the system
+about your
+ <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
+WearableListenerService</code></a>.
+ This declaration allows the system to bind your service as needed.
</li>
</ol>
<p>The following example shows how to implement a simple
- <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>:
+ <a
+href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
+WearableListenerService</code></a>:
</p>
-
<pre>
public class DataLayerListenerService extends WearableListenerService {
@@ -146,7 +174,7 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onDataChanged: " + dataEvents);
}
- final List<DataEvent> events = FreezableUtils
+ final List events = FreezableUtils
.freezeIterable(dataEvents);
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
@@ -179,85 +207,139 @@
}
</pre>
-<p>Here's the corresponding intent filter in the Android manifest file:</p>
+<p>
+The next section explains how to use an intent filter with this listener.
+</p>
+
+<h3>Using filters with WearableListenerService</h3>
+
+<p>
+An intent filter for the
+<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+{@code WearableListenerService}</a> example shown in the previous section might look like this:
<pre>
<service android:name=".DataLayerListenerService">
- <intent-filter>
- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
+ <intent-filter>
+ <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
+ <data android:scheme="wear" android:host="*"
+ android:path="/start-activity" />
</intent-filter>
</service>
</pre>
-
-<h4>Permissions within Data Layer Callbacks</h4>
-
<p>
-To deliver callbacks to your application for data layer events, Google Play services
-binds to your <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>,
-and calls your callbacks via IPC. This has the consequence
-that your callbacks inherit the permissions of the calling process.</p>
-
-<p>If you try to perform a privileged operation within a callback, the security check fails because your callback is
-running with the identity of the calling process, instead of the identity of your app's
-process.</p>
-
-<p>To fix this, call {@link android.os.Binder#clearCallingIdentity} </a>,
-to reset identity after crossing the IPC boundary, and then restore identity with
-{@link android.os.Binder#restoreCallingIdentity restoreCallingIdentity()} when
-you've completed the privileged operation:
+In this filter, the {@code DATA_CHANGED} action replaces the
+previously recommended {@code BIND_LISTENER} action so that only specific
+events wake or launch your application. This change improves system efficiency
+and reduces battery consumption and other overhead associated with your
+application. In this example, the watch listens for the
+{@code /start-activity} data item, and the
+phone listens for the {@code /data-item-received} message response.
+</p>
+<p>
+Standard Android filter matching rules apply. You can specify multiple services
+per manifest, multiple intent filters per service, multiple actions per filter,
+and multiple data stanzas per filter. Filters can match on a wildcard host or on
+a specific one. To match on a wildcard host, use {@code host="*"}. To match
+on a specific host, specify {@code host=<node_id>}.
</p>
-<pre>
-long token = Binder.clearCallingIdentity();
-try {
- performOperationRequiringPermissions();
-} finally {
- Binder.restoreCallingIdentity(token);
-}
-</pre>
-
-<h3 id="Listen">With a Listener Activity</h3>
-
<p>
-If your app only cares about data layer events when the user is interacting
-with the app and does not need a long-running service to handle every data
-change, you can listen for events in an activity by implementing one or more
-of the following interfaces:
+You can also match a literal path or path prefix. If you are matching by path
+or path prefix, you must specify a wildcard or specific host.
+If you do not do so, the system ignores the path you specified.
+</p>
+<p>
+For more information on the filter types that Wear supports, see the
+API reference documentation for <a
+href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService">
+{@code WearableListenerService}</a>.
+
+</p>
+<p>
+For more information on data filters and matching rules, see the API reference
+documentation for the <a
+href="{@docRoot}guide/topics/manifest/data-element.html">{@code data}</a>
+manifest element.
+</p>
+
+
+<p>When matching intent filters, there are two important rules to remember:</p>
<ul>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a></li>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html"><code>MessageApi.MessageListener</code></a></li>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html"><code>NodeApi.NodeListener</code></a></li>
+ <li>If a scheme is not specified for the intent filter, the system ignores
+ all the other URI attributes.</li>
+ <li>If no host is specified for the filter, the system ignores the
+ port attribute and all the path attributes.</li>
</ul>
+
+<h3>With a listener activity</h3>
+<p>
+If your app only cares about data-layer events when the user is interacting
+with the app, it may not need a long-running service to handle every data
+change. In such a case, you can listen for events in an activity by
+implementing one or more of the following interfaces:
</p>
+<ul>
+ <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
+ DataApi.DataListener</code></a></li>
+
+ <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
+ <code>MessageApi.MessageListener</code></a></li>
+
+ <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html">{@code CapabilityApi.CapabilityListener}</a></li>
+</ul>
<p>To create an activity that listens for data events:</p>
<ol>
<li>Implement the desired interfaces.</li>
-<li>In {@link android.app.Activity#onCreate}, create an instance of
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code></a>
-to work with the Data Layer API.
+<li>In {@link android.app.Activity#onCreate onCreate()}, create an instance of
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
+</a>to work with the Data Layer API.</li>
+
<li>
-In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"><code>connect()</code></a> to connect the client to Google Play services.
+In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
+<code>connect()</code></a> to connect the client to Google Play services.
</li>
+
<li>When the connection to Google Play services is established, the system calls
<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.addListener()</code></a>,
- <a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.addListener()</code></a>,
- or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.NodeApi.NodeListener)"><code>NodeApi.addListener()</code></a>
- to notify Google Play services that your activity is interested in listening for data layer events.
-</li>
+
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
+<code>DataApi.addListener()</code></a>,
+
+<a href="{@docRoot}android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener">
+<code>MessageApi.addListener()</code></a>, or
+
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.CapabilityApi.CapabilityListener,%20android.net.Uri,%20int)">
+{@code CapabilityApi.addListener()}</a> to notify Google Play services that your activity is
+interested in listening for data layer events.</li>
+
<li>In {@link android.app.Activity#onStop onStop()}, unregister any listeners with
<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
-<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>,
-or <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.NodeApi.NodeListener)"><code>NodeApi.removeListener()</code></a>.
-</li>
-<li>Implement <a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)"><code>onDataChanged()</code>,
- <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerConnected(com.google.android.gms.wearable.Node)"><code>onMessageReceived()</code></a>,
- <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerConnected(com.google.android.gms.wearable.Node)"><code>onPeerConnected()</code></a>, and
- <a href="{@docRoot}reference/com/google/android/gms/wearable/NodeApi.NodeListener.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"><code>onPeerDisconnected()</code></a>, depending on the interfaces that you implemented.
-</li>
+<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
+<a href="http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.MessageApi.MessageListener)">
+{@code CapabilityApi.removeListener()}</a>.</li>
+
+
+<p>An alternative to adding listeners in
+<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
+and removing them in
+{@link android.app.Activity#onStop onStop()} is to add a filtered listener in an activity’s {@link android.app.Activity#onResume onResume()} and
+remove it in {@link android.app.Activity#onPause onPause()}, so as to only receive data that is relevant to the
+current application state.</p>
+
+
+<li>Implement
+<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
+<code>onDataChanged()</code></a>,
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
+ <code>onMessageReceived()</code></a>,
+ <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
+{@code onCapabilityChanged()}</a>,
+or methods from <a href="http://developer.android.com/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
+Channel API listener methods</a>, depending on the interfaces that you implemented.</li>
</ol>
<p>Here's an example that implements
@@ -318,3 +400,19 @@
}
}
</pre>
+<h3>Using Filters with Listener Activities</h3>
+<p>
+Just as you can specify intent filters for manifest-based
+<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+<code>WearableListenerService</code></a> objects, you can also use intent filters when registering a
+listener through the Wearable API. The same rules are applicable to both
+API-based listeners manifest-based listeners.
+</p>
+
+<p>
+A common pattern is to register a listener with a specific path or path prefix
+in an activity’s{@link android.app.Activity#onResume onResume()} method, and to
+remove the listener in the activity’s {@link android.app.Activity#onPause onPause()} method.
+Implementing listeners in this fashion allows your application to more selectively receive events,
+improving its design and efficiency.
+</p>
diff --git a/docs/html/training/wearables/ui/index.jd b/docs/html/training/wearables/ui/index.jd
old mode 100644
new mode 100755
index f82d29c..c43e165
--- a/docs/html/training/wearables/ui/index.jd
+++ b/docs/html/training/wearables/ui/index.jd
@@ -36,9 +36,9 @@
provides classes that help you implement these patterns and create layouts that work on
both round and square Android Wear devices.</p>
-<p class="note"><b>Note:</b> We recommend using Android Studio for Android Wear development
-as it provides project setup, library inclusion, and packaging conveniences that aren't available
-in ADT. This training assumes you are using Android Studio.</p>
+<p class="note"><b>Note:</b> We recommend using Android Studio for Android Wear development,
+as it provides project setup, library inclusion, and packaging conveniences. This training assumes
+you are using Android Studio.</p>
<h2>Lessons</h2>
@@ -55,4 +55,4 @@
<dd>Learn how to display confirmation animations when users complete actions.</dd>
<dt><a href="{@docRoot}training/wearables/ui/exit.html">Exiting Full-Screen Activities</a></dt>
<dd>Learn how to implement the long-press-to-dismiss UI pattern to exit full-screen activities.</dd>
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/training/wearables/watch-faces/designing.jd b/docs/html/training/wearables/watch-faces/designing.jd
index 1033fed..564203c 100644
--- a/docs/html/training/wearables/watch-faces/designing.jd
+++ b/docs/html/training/wearables/watch-faces/designing.jd
@@ -65,7 +65,7 @@
technology, you may need to avoid large blocks of white pixels, use only black and white, and
disable anti-aliasing.</dd>
-<dt><em>Accomodate system UI elements</em></dt>
+<dt><em>Accommodate system UI elements</em></dt>
<dd>Your design should ensure that system indicators remain visible and that users can still
read the time when notification cards appear on the screen.</dd>
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
old mode 100644
new mode 100755
index a329fda..aac49d3
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -45,9 +45,9 @@
designs integrate with system UI elements and are power-efficient.</p>
<p class="note"><strong>Note:</strong> We recommend using <a
-href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development as
-it provides project setup, library inclusion, and packaging conveniences that aren't available
-in the Eclipse Android Developer Tools. This training assumes you are using Android Studio.</p>
+href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development, as
+it provides project setup, library inclusion, and packaging conveniences. This training assumes
+you are using Android Studio.</p>
<h2>Lessons</h2>
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index c2c411c..4a96545 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -15,6 +15,8 @@
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
+ <li><a href="http://android-developers.blogspot.com/2014/12/making-performant-watch-face.html">
+Making a performant watch face</a></li>
</ul>
</div>
</div>
diff --git a/docs/html/training/wearables/watch-faces/service.jd b/docs/html/training/wearables/watch-faces/service.jd
old mode 100644
new mode 100755
index 578e8c0..e94ee56
--- a/docs/html/training/wearables/watch-faces/service.jd
+++ b/docs/html/training/wearables/watch-faces/service.jd
@@ -87,11 +87,9 @@
<a href="{@docRoot}reference/android/support/wearable/watchface/package-summary.html">API reference
documentation</a> for the Wearable Support Library.</p>
-<h3 id="LibEclipse">Download the Wearable Support Library for Eclipse ADT</h3>
-
-<p>If you are using the ADT plugin for Eclipse, download the
-<a href="{@docRoot}shareables/training/wearable-support-lib.zip">Wearable Support Library</a> and
-include it as a dependency in your project.</p>
+<p class="note"><strong>Note:</strong> We recommend using <a
+href="{@docRoot}sdk/index.html">Android Studio</a> for Android Wear development, as
+it provides project setup, library inclusion, and packaging conveniences.</p>
<h3 id="Permissions">Declare Permissions</h3>
diff --git a/docs/html/training/wearables/wearable-sounds.jd b/docs/html/training/wearables/wearable-sounds.jd
new file mode 100644
index 0000000..3c3c135
--- /dev/null
+++ b/docs/html/training/wearables/wearable-sounds.jd
@@ -0,0 +1,63 @@
+page.title=Using Speakers on Wearables
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#Detect">Detect the Speaker</a></li>
+ <li><a href="#Play">Play Sounds</a></li>
+</ol>
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
+</ul>
+</div>
+</div>
+
+<p>Some Android Wear devices include speakers, enabling them to incorporate sound into their
+apps and offer an extra dimension of engagement with the user. A speaker-equipped Wear device might
+trigger a clock or timer alarm, complete with audio notification. Games on Wear become become more
+entertaining by offering not just sight, but sound.</p>
+
+<p>This page describes how apps on Wear devices running Android 6.0 (API level 23) can use
+familiar Android APIs to play sounds through the device speaker.</p>
+
+<h2 id="Detect">Detect the Speaker</h2>
+
+<p>A Wear app must first detect whether the wearable device has a speaker. In the following example,
+the app uses the {@link android.media.AudioManager#getDevices(int) getDevices() } method in
+conjunction with the value of {@link android.content.pm.PackageManager#FEATURE_AUDIO_OUTPUT} to
+confirm that the device is equipped with a speaker.</p>
+
+<pre>
+PackageManager packageManager = context.getPackageManager();
+AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+// Check whether the device has a speaker.
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ // Check FEATURE_AUDIO_OUTPUT to guard against false positives.
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT)) {
+ return false;
+ }
+
+ AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ for (AudioDeviceInfo device : devices) {
+ if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+ return true;
+ }
+ }
+}
+return false;
+</pre>
+
+<h2 id="Play">Play Sounds</h2>
+
+<p>Once you've detected the speaker, the process for playing sound on Android Wear is the
+same as for a handset or other device. For more information, see
+<a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a>.</p>
+
+<p>If you also want to record audio from the microphone on the wearable, your app must also get
+permission to use the microphone. To learn more, see
+<a href="{@docRoot}training/articles/wear-permissions.html">Permissions on Android Wear.</a></p>
\ No newline at end of file