diff options
Diffstat (limited to 'docs/html')
26 files changed, 1748 insertions, 1223 deletions
diff --git a/docs/html/design/tv/index.jd b/docs/html/design/tv/index.jd index d79e279..def1286 100644 --- a/docs/html/design/tv/index.jd +++ b/docs/html/design/tv/index.jd @@ -38,7 +38,7 @@ see <a href="/distribute/googleplay/tv.html">Distributing to Android TV</a>.</p> <p>To learn more about searching within your app, see <a href="{@docRoot}training/tv/discovery/in-app-search.html">Searching within TV Apps</a>. -<h2>Recommendations</h2> +<h2 id="recommendations">Recommendations</h2> <p>The recommendations row on Android TV is a central feature of the Home Screen that allows users quick access to dynamic and relevant content for their media-consumption activities. The diff --git a/docs/html/design/tv/patterns.jd b/docs/html/design/tv/patterns.jd index be7ae31..e786ee5 100644 --- a/docs/html/design/tv/patterns.jd +++ b/docs/html/design/tv/patterns.jd @@ -15,24 +15,16 @@ page.title=UI Patterns for TV <img src="{@docRoot}design/tv/images/focus.png" alt="TV navigation and focus diagram" /> -<p>A key aspect of making your application work well with a D-Pad controller is to make sure +<p>A key aspect of making your application work well with a D-pad controller is to make sure that there is always an object that is obviously in focus. Your app must clearly indicate what object is focused, so users can easily see what action they can take. Use scale, shadow brightness, opacity, animation or a combination of these attributes to help users see a focused object.</p> +<h2 id="banner">App and Game Banners</h3> -<h2>Icons</h2> - -<p>Apps on TV devices require some additional icon images for presentation in the system - user interface, including home screen launcher images (banners) and recommendation icons. - The visual specifications for these icons are shown below.</p> - - -<h3 id="banner">Banners</h3> - -<p>App Banners represent your app on the home screen of TV devices and serve and as a way for - users to launch your app. Here are specific requirements for a banner image: +<p>App Banners represent your app or game on the home screens of TV devices and serve and as a way for + users to launch your app. Here are the specific requirements for a banner image: </p> <ul> @@ -44,45 +36,97 @@ page.title=UI Patterns for TV <p>See <a href="{@docRoot}training/tv/start/start.html#banner">Provide a home screen banner</a> in Get Started with TV Apps for more information.</p> -<h3>Recommendation Icons</h3> +<h2 id="recommendation">Recommendations</h2> -<p>Recommendation cards include a small icon that is imposed over a colored background. - An example and specifications for this icon are shown below:</p> +<p>The first row of the Android TV home screen displays cards for content recommended by applications. +Your application provides these recommendations, as described in <a href="{@docRoot}training/tv/discovery/recommendations.html"> +</a>. For a visual overview of recommendations, see <a href="design/tv/index.html#recommendations"> +Design for Android TV</a>.</p> -<img src="{@docRoot}design/tv/images/icon.png" alt="Recommendation icon examples" /> +<div class="layout-content-row"> + <div class="layout-content-col span-8 with-callouts"> + + <p>The design elements of the recommendation card are as follows:</p> + <ol> + <li><strong>Large icon</strong></li> + <li><strong>Content title</strong></li> + <li><strong>Content text</strong></li> + <li><strong>Small icon</strong></li> + </ol> + + <p>The design specifications for these elements are described below.</p> + + <p>You can also set a background image (not shown) and the color of the card's text area in the + recommendation notification. See <a href="{@docRoot}training/tv/discovery/recommendations.html"> + Recommendations</a> for more information.</p> -<p>Here are the requirements for recommendation icons:</p> + </div> + <div class="layout-content-col span-5"> + + <img src="{@docRoot}images/tv/recommend-card.png"> + + </div> +</div> + +<h3>Background Image</h3> + +<p>The background image also appears behind the recommendations +row and fills the Android TV home screen when the user selects the recommendation card. This image +should be different than the one provided for the large icon, and meet the following specifications:</p> <ul> - <li>Monocolor: size 16x16dp, white (#fff) icon with transparent background, PNG format</li> - <li>Graphics should be centered within the icon image</li> + <li>Measure 2016 x 1134 pixels (1920 x 1080 plus 5% margin for for motion)</li> + <li id="solid-background">Must not be transparent</li> </ul> <p class="note"> - <strong>Note:</strong> Your app icon image may be desaturated and blended for some card - displays. + <strong>Note:</strong> If the background image does not meet the size requirements, the system + scales it to fit. </p> - -<h2>Background Images</h2> - -<p>Background images are displayed in the background of your app to provide additional visual - interest, information, or branding. The user interface widgets provided in the <a href="{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support +<p>The user interface widgets provided in the + <a href="{@docRoot}tools/support-library/features.html#v17-leanback">v17 leanback support library</a> provide specific support for background images and for updating them as items gain - and lose focus. The specific requirements for background images on TV devices is that they - should be full color and a size of 1920 x 1080 pixels. + and lose focus. </p> -<p class="note" id="solid-background"> - <strong>Important:</strong> Background images must not be transparent. Your must not allow any - portion of another app to be seen through your app. -</p> +<h3 id="icons">Icons</h3> + +<h4>Large icon</h4> + +<p>Typically, the large icon is an image of the content for the recommendation. It appears +above a colored area that contains the recommendation content title and text. This image should be +different from that which you provide for the background image, and conform to the following +specifications:</p> + +<ul> + <li>Height: 176dp or more</li> + <li>Minimum width: 2/3 of the height (117dp for an image 176dp in height)</li> + <li>Max width: 4/3 of the height (234dp for an image 176dp in height)</li> + <li>Must not be transparent</li> +</ul> <p class="note"> - <strong>Note:</strong> If you background image does not meet the size requirements, it is scaled - to fit. + <strong>Note:</strong> If the large icon does not meet the size requirements, the system + scales it to fit. </p> +<h4>Small icon</h4> + +<p>Recommendation cards include a small icon that is imposed over a colored background. The icon and +background color display at 100% opacity when the card is selected, and at 50% opacity when not +selected.</p> + +<img src="{@docRoot}design/tv/images/icon.png" alt="Recommendation icon examples" /> + +<p>Here are the requirements for recommendation small icons:</p> + +<ul> + <li>Flat image</li> + <li>Monocolor: size 16x16dp, white (#fff) icon with transparent background, PNG format</li> + <li>Graphics should be centered within the icon image</li> +</ul> + <h2>Audio Feedback</h2> <p>Sounds on Android TV bring a cinematic quality to the interaction experience. You should diff --git a/docs/html/design/wear/watchfaces.jd b/docs/html/design/wear/watchfaces.jd index 1a4b1f9..99dc3dd 100644 --- a/docs/html/design/wear/watchfaces.jd +++ b/docs/html/design/wear/watchfaces.jd @@ -112,17 +112,17 @@ designs should take these modes into account. Generally, if your watch face desi in ambient mode, it will look even better in interactive mode. The opposite is not always true.</p> -<p>In ambient mode, the screen is only updated once every minute. Only show hours and minutes -in ambient mode; do not show seconds in this mode.</p> - <h3>Interactive mode</h3> <p>When the user moves their wrist to glance at their watch, the screen goes into interactive mode. Your design can use full color with fluid animation in this mode.</p> <h3>Ambient mode</h3> -<p>Ambient mode helps the device conserve power. In this mode, the screen only displays shades -of grey, black, and white. Your watch face is notified when the device switches to ambient mode, -and you should thoughtfully design for it.</p> +<p>Ambient mode helps the device conserve power. Your design should make clear to the user that +the screen is in ambient mode by using only grayscale colors. Do not use a lot of white in ambient +mode, since this distracting and hurts battery life on some screens. In this mode, the screen +is only updated once every minute. Only show hours and minutes in ambient mode; do not show +seconds. Your watch face is notified when the device switches to ambient mode, and you should +thoughtfully design for it.</p> diff --git a/docs/html/google/play-services/maps.jd b/docs/html/google/play-services/maps.jd index 7a61d6c..9bf5f80 100644 --- a/docs/html/google/play-services/maps.jd +++ b/docs/html/google/play-services/maps.jd @@ -13,7 +13,7 @@ header.hide=1 <div class="col-6"> <h1 itemprop="name" style="margin-bottom:0;">Google Maps Android API v2</h1> - <p itemprop="description">Allow your users explore the world with rich maps provided by + <p itemprop="description">Allow your users to explore the world with rich maps provided by Google. Identify locations with <b>custom markers</b>, augment the map data with <b>image overlays</b>, embed <b>one or more maps</b> as fragments, and much more.</p> diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd index 413000f..cb3fa17 100644 --- a/docs/html/google/play-services/setup.jd +++ b/docs/html/google/play-services/setup.jd @@ -62,7 +62,7 @@ to <a href="{@docRoot}sdk/installing/adding-packages.html">Adding SDK Packages</ <li>Add a new build rule under <code>dependencies</code> for the latest version of <code>play-services</code>. For example: <pre class="no-pretty-print"> -apply plugin: 'android' +apply plugin: 'com.android.application' ... dependencies { diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd index fc13c04..9d2fa94 100644 --- a/docs/html/guide/topics/search/searchable-config.jd +++ b/docs/html/guide/topics/search/searchable-config.jd @@ -32,26 +32,26 @@ Android uses the filename as the resource ID.</dd> <pre class="stx"> <?xml version="1.0" encoding="utf-8"?> <<a href="#searchable-element">searchable</a> xmlns:android="http://schemas.android.com/apk/res/android" - android:label="<em>string resource</em>" - android:hint="<em>string resource</em>" - android:searchMode=["queryRewriteFromData" | "queryRewriteFromText"] - android:searchButtonText="<em>string resource</em>" - android:inputType="<em>{@link android.R.attr#inputType}</em>" - android:imeOptions="<em>{@link android.R.attr#imeOptions}</em>" - android:searchSuggestAuthority="<em>string</em>" - android:searchSuggestPath="<em>string</em>" - android:searchSuggestSelection="<em>string</em>" - android:searchSuggestIntentAction="<em>string</em>" - android:searchSuggestIntentData="<em>string</em>" - android:searchSuggestThreshold="<em>int</em>" - android:includeInGlobalSearch=["true" | "false"] - android:searchSettingsDescription="<em>string resource</em>" - android:queryAfterZeroResults=["true" | "false"] - android:voiceSearchMode=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"] - android:voiceLanguageModel=["free-form" | "web_search"] - android:voicePromptText="<em>string resource</em>" - android:voiceLanguage="<em>string</em>" - android:voiceMaxResults="<em>int</em>" + android:<a href="#label">label</a>="<em>string resource</em>" + android:<a href="#hint">hint</a>="<em>string resource</em>" + android:<a href="#searchMode">searchMode</a>=["queryRewriteFromData" | "queryRewriteFromText"] + android:<a href="#searchButtonText">searchButtonText</a>="<em>string resource</em>" + android:<a href="#inputType">inputType</a>="<em>{@link android.R.attr#inputType}</em>" + android:<a href="#imeOptions">imeOptions</a>="<em>{@link android.R.attr#imeOptions}</em>" + android:<a href="#searchSuggestAuthority">searchSuggestAuthority</a>="<em>string</em>" + android:<a href="#searchSuggestPath">searchSuggestPath</a>="<em>string</em>" + android:<a href="#searchSuggestSelection">searchSuggestSelection</a>="<em>string</em>" + android:<a href="#searchSuggestIntentAction">searchSuggestIntentAction</a>="<em>string</em>" + android:<a href="#searchSuggestIntentData">searchSuggestIntentData</a>="<em>string</em>" + android:<a href="#searchSuggestThreshold">searchSuggestThreshold</a>="<em>int</em>" + android:<a href="#includeInGlobalSearch">includeInGlobalSearch</a>=["true" | "false"] + android:<a href="#searchSettingsDescription">searchSettingsDescription</a>="<em>string resource</em>" + android:<a href="#queryAfterZeroResults">queryAfterZeroResults</a>=["true" | "false"] + android:<a href="#voiceSearchMode">voiceSearchMode</a>=["showVoiceSearchButton" | "launchWebSearch" | "launchRecognizer"] + android:<a href="#voiceLanguageModel">voiceLanguageModel</a>=["free-form" | "web_search"] + android:<a href="#voicePromptText">voicePromptText</a>="<em>string resource</em>" + android:<a href="#voiceLanguage">voiceLanguage</a>="<em>string</em>" + android:<a href="#voiceMaxResults">voiceMaxResults</a>="<em>int</em>" > <<a href="#actionkey-element">actionkey</a> android:keycode="<em>{@link android.view.KeyEvent KEYCODE}</em>" @@ -69,7 +69,7 @@ Android uses the filename as the resource ID.</dd> <dd>Defines all search configurations used by the Android system to provide assisted search. <p class="caps">attributes:</p> <dl class="atn-list"> - <dt><code>android:label</code></dt> + <dt><a name="label"></a><code>android:label</code></dt> <dd><em>String resource</em>. (Required.) The name of your application. It should be the same as the name applied to the {@code android:label} attribute of your <a href="{@docRoot}guide/topics/manifest/activity-element.html#label">{@code <activity>}</a> or @@ -78,14 +78,14 @@ href="{@docRoot}guide/topics/manifest/activity-element.html#label">{@code <ac <code>android:includeInGlobalSearch</code> to "true", in which case, this label is used to identify your application as a searchable item in the system's search settings.</dd> - <dt><code>android:hint</code></dt> + <dt><a name="hint"></a><code>android:hint</code></dt> <dd><em>String resource</em>. (Recommended.) The text to display in the search text field when no text has been entered. It provides a hint to the user about what content is searchable. For consistency with other Android applications, you should format the string for {@code android:hint} as "Search <em><content-or-product></em>". For example, "Search songs and artists" or "Search YouTube".</dd> - <dt><code>android:searchMode</code></dt> + <dt><a name="searchMode"></a><code>android:searchMode</code></dt> <dd><em>Keyword</em>. Sets additional modes that control the search presentation. Currently available modes define how the query text should be rewritten when a custom suggestion receives focus. The following mode values are accepted: @@ -109,19 +109,19 @@ inspection and editing, typically HTTP URI's.</td> href="adding-custom-suggestions.html#RewritingQueryText">Adding Custom Suggestions</a>.</p> </dd> - <dt><code>android:searchButtonText</code></dt> + <dt><a name="searchButtonText"></a><code>android:searchButtonText</code></dt> <dd><em>String resource</em>. The text to display in the button that executes search. By default, the button shows a search icon (a magnifying glass), which is ideal for internationalization, so you should not use this attribute to change the button unless the behavior is something other than a search (such as a URL request in a web browser).</dd> - <dt><code>android:inputType</code></dt> + <dt><a name="inputType"></a><code>android:inputType</code></dt> <dd><em>Keyword</em>. Defines the type of input method (such as the type of soft keyboard) -to use. For most searches, in which free-form text is expected, you don't +to use. For most searches, in which free-form text is expected, you don't need this attribute. See {@link android.R.attr#inputType} for a list of suitable values for this attribute.</dd> - <dt><code>android:imeOptions</code></dt> + <dt><a name="imeOptions"></a><code>android:imeOptions</code></dt> <dd><em>Keyword</em>. Supplies additional options for the input method. For most searches, in which free-form text is expected, you don't need this attribute. The default IME is "actionSearch" (provides the "search" button instead of a carriage @@ -139,12 +139,12 @@ for this attribute. {@code <searchable>} attributes:</p><br/> <dl class="atn-list"> - <dt><code>android:searchSuggestAuthority</code></dt> + <dt><a name="searchSuggestAuthority"></a><code>android:searchSuggestAuthority</code></dt> <dd><em>String</em>. (Required to provide search suggestions.) This value must match the authority string provided in the {@code android:authorities} attribute of the Android manifest {@code <provider>} element.</dd> - <dt><code>android:searchSuggestPath</code></dt> + <dt><a name="searchSuggestPath"></a><code>android:searchSuggestPath</code></dt> <dd><em>String</em>. This path is used as a portion of the suggestions query {@link android.net.Uri}, after the prefix and authority, but before the standard suggestions path. @@ -152,7 +152,7 @@ the standard suggestions path. of suggestions (such as for different data types) and you need a way to disambiguate the suggestions queries when you receive them.</dd> - <dt><code>android:searchSuggestSelection</code></dt> + <dt><a name="searchSuggestSelection"></a><code>android:searchSuggestSelection</code></dt> <dd><em>String</em>. This value is passed into your query function as the {@code selection} parameter. Typically this is a WHERE clause for your database, and should contain a single question mark, which is a placeholder for the @@ -160,22 +160,22 @@ actual query string that has been typed by the user (for example, {@code "query= can also use any non-null value to trigger the delivery of the query text via the {@code selectionArgs} parameter (and then ignore the {@code selection} parameter).</dd> - <dt><code>android:searchSuggestIntentAction</code></dt> + <dt><a name="searchSuggestIntentAction"></a><code>android:searchSuggestIntentAction</code></dt> <dd><em>String</em>. The default intent action to be used when a user clicks on a custom search suggestion (such as {@code "android.intent.action.VIEW"}). If this is not overridden by the selected suggestion (via the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value is placed in the action field of the {@link android.content.Intent} when the user clicks a suggestion.</dd> - <dt><code>android:searchSuggestIntentData</code></dt> + <dt><a name="searchSuggestIntentData"></a><code>android:searchSuggestIntentData</code></dt> <dd><em>String</em>. The default intent data to be used when a user clicks on a custom search suggestion. If not overridden by the selected suggestion (via the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value is - placed in the data field of the {@link android.content.Intent} when the user clicks + placed in the data field of the {@link android.content.Intent} when the user clicks a suggestion.</dd> - <dt><code>android:searchSuggestThreshold</code></dt> + <dt><a name="searchSuggestThreshold"></a><code>android:searchSuggestThreshold</code></dt> <dd><em>Integer</em>. The minimum number of characters needed to trigger a suggestion look-up. Only guarantees that the system will not query your content provider for anything shorter than the threshold. The default value is 0.</dd> @@ -192,20 +192,20 @@ android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value is following {@code <searchable>} attributes:</p><br/> <dl class="atn-list"> - <dt><code>android:includeInGlobalSearch</code></dt> + <dt><a name="includeInGlobalSearch"></a><code>android:includeInGlobalSearch</code></dt> <dd><em>Boolean</em>. (Required to provide search suggestions in Quick Search Box.) Set to "true" if you want your suggestions to be included in the globally accessible Quick Search Box. The user must still enable your application as a searchable item in the system search settings before your suggestions will appear in Quick Search Box.</dd> - <dt><code>android:searchSettingsDescription</code></dt> + <dt><a name="searchSettingsDescription"></a><code>android:searchSettingsDescription</code></dt> <dd><em>String</em>. Provides a brief description of the search suggestions that you provide to Quick Search Box, which is displayed in the searchable items entry for your application. Your description should concisely describe the content that is searchable. For example, "Artists, albums, and tracks" for a music application, or "Saved notes" for a notepad application.</dd> - <dt><code>android:queryAfterZeroResults</code></dt> + <dt><a name="queryAfterZeroResults"></a><code>android:queryAfterZeroResults</code></dt> <dd><em>Boolean</em>. Set to "true" if you want your content provider to be invoked for supersets of queries that have returned zero results in the past. For example, if your content provider returned zero results for "bo", it should be requiried for "bob". If set to @@ -222,7 +222,7 @@ content provider again). The default value is false.</dd> following {@code <searchable>} attributes:</p><br/> <dl class="atn-list"> - <dt><code>android:voiceSearchMode</code></dt> + <dt><a name="voiceSearchMode"></a><code>android:voiceSearchMode</code></dt> <dd><em>Keyword</em>. (Required to provide voice search capabilities.) Enables voice search, with a specific mode for voice search. (Voice search may not be provided by the device, in which case these flags @@ -252,7 +252,7 @@ then either {@code "launchWebSearch"} or {@code "launchRecognizer"} must also be </table> </dd> - <dt><code>android:voiceLanguageModel</code></dt> + <dt><a name="voiceLanguageModel"></a><code>android:voiceLanguageModel</code></dt> <dd><em>Keyword</em>. The language model that should be used by the voice recognition system. The following values are accepted: <table> @@ -268,20 +268,20 @@ optimized for English. This is the default.</td> available in more languages than "free_form".</td> </tr> </table> - <p>Also see + <p>Also see {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL} for more information.</p></dd> - <dt><code>android:voicePromptText</code></dt> + <dt><a name="voicePromptText"></a><code>android:voicePromptText</code></dt> <dd><em>String</em>. An additional message to display in the voice input dialog.</dd> - <dt><code>android:voiceLanguage</code></dt> + <dt><a name="voiceLanguage"></a><code>android:voiceLanguage</code></dt> <dd><em>String</em>. The spoken language to be expected, expressed as the string value of a constants in {@link java.util.Locale} (such as {@code "de"} for German or {@code "fr"} for French). This is needed only if it is different from the current value of {@link java.util.Locale#getDefault() Locale.getDefault()}.</dd> - <dt><code>android:voiceMaxResults</code></dt> + <dt><a name="voiceMaxResults"></a><code>android:voiceMaxResults</code></dt> <dd><em>Integer</em>. Forces the maximum number of results to return, including the "best" result which is always provided as the {@link android.content.Intent#ACTION_SEARCH} intent's primary @@ -308,7 +308,7 @@ keys are not generally discoverable, so you should not provide them as a core us other three attributes in order to define the search action.</p> <p class="caps">attributes:</p> <dl class="atn-list"> - <dt><code>android:keycode</code></dt> + <dt><a name="keycode"></a><code>android:keycode</code></dt> <dd><em>String</em>. (Required.) A key code from {@link android.view.KeyEvent} that represents the action key you wish to respond to (for example {@code "KEYCODE_CALL"}). This is added to the @@ -318,7 +318,7 @@ android.view.KeyEvent} that represents the action key keys are supported for a search action, as many of them are used for typing, navigation, or system functions.</dd> - <dt><code>android:queryActionMsg</code></dt> + <dt><a name="queryActionMsg"></a><code>android:queryActionMsg</code></dt> <dd><em>String</em>. An action message to be sent if the action key is pressed while the user is entering query text. This is added to the {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that the system @@ -326,17 +326,17 @@ user is entering query text. This is added to the {@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}.</dd> - <dt><code>android:suggestActionMsg</code></dt> + <dt><a name="suggestActionMsg"></a><code>android:suggestActionMsg</code></dt> <dd><em>String</em>. An action message to be sent if the action key is pressed while a suggestion is in focus. This is added to the intent that that the system passes to your searchable activity (using the action you've defined for the suggestion). To examine the string, - use {@link android.content.Intent#getStringExtra + use {@link android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your suggestions support this action key. If not all suggestions can handle the same action key, then you must instead use the following {@code android:suggestActionMsgColumn} attribute.</dd> - <dt><code>android:suggestActionMsgColumn</code></dt> + <dt><a name="suggestActionMsgColumn"></a><code>android:suggestActionMsgColumn</code></dt> <dd><em>String</em>. The name of the column in your content provider that defines the action message for this action key, which is to be sent if the user presses the action key while a suggestion is in focus. This attribute lets you control the diff --git a/docs/html/images/tv/recommend-card.png b/docs/html/images/tv/recommend-card.png Binary files differnew file mode 100644 index 0000000..1cc4311 --- /dev/null +++ b/docs/html/images/tv/recommend-card.png diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 5d73d72..d9a47a2 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -449,7 +449,7 @@ Studio</a>.</p> <ul> <li>Microsoft® Windows® 8/7/Vista/2003 (32 or 64-bit)</li> <li>2 GB RAM minimum, 4 GB RAM recommended</li> -<li>400 MB hard disk space + at least 1 G for Android SDK, emulator system images, and caches</li> +<li>400 MB hard disk space + at least 1 GB for Android SDK, emulator system images, and caches</li> <li>1280 x 800 minimum screen resolution</li> <li>Java Development Kit (JDK) 7 </li> <li>Optional for accelerated emulator: Intel® processor with support for Intel® VT-x, Intel® EM64T diff --git a/docs/html/sdk/installing/create-project.jd b/docs/html/sdk/installing/create-project.jd index a7c12d4..5082537 100644 --- a/docs/html/sdk/installing/create-project.jd +++ b/docs/html/sdk/installing/create-project.jd @@ -1,14 +1,58 @@ -page.title=Creating a Project +page.title=Managing Projects from Android Studio @jd:body + <div id="qv-wrapper"> + <div id="qv"> + <h2>In this document</h2> + + <ol> + <li><a href="#CreatingAProject">Creating an Android Project</a></li> + <ol> + <li><a href="#Step1CreatingAProject">Create a New Project</a> </li> + <li><a href="#Step2SelectFormFactor">Select Form Factors and API Level</a> </li> + <li><a href="#Step3AddActivity">Add an Activity</a> </li> + <li><a href="#Step4ConfigureActivity">Configure Your App</a> </li> + <li><a href="#Step5DevelopYourApp">Develop Your App</a> </li> + </ol> + + <li><a href="#CreatingAModule">Creating an Android Module</a></li> + + <li><a href="#SettingUpLibraryModule">Setting up a Library Module</a></li> + + <li><a href="#ReferencingLibraryModule">Referencing a Library Module</a></li> + + <li><a href="#ReferencingAppEngModule">Setting up an App Eng Module</a></li> + + <li><a href="#ProjectView">Using the Android Project View</a></li> + + </ol> + + </div> + </div> + + +<p>Android Studio provides graphical tools for creating and managing Android projects, which +contain everything that define your Android apps, from app source code to build configurations and +test code. Each project contains one or more different types of modules, such as + application modules, library modules, and test modules.</p> + +<p>This guide explains how to create Android projects and different modules using +<a href="{@docRoot}tools/studio/index.html">Android Studio</a>. +For more information about the Android project structure and module types, read <a href= +"{@docRoot}tools/projects/index.html">Managing Projects Overview</a>.</p> + + + +<h2 id="CreatingAProject">Creating an Android Project</h2> + <p>Android Studio makes it easy to create Android apps for several form factors, such as phone, tablet, TV, Wear, and Google Glass. The <em>New Project</em> wizard lets you choose the form factors for your app and populates the project structure with everything you need to get started.</p> <p>Follow the steps in this section to create a project in Android Studio.</p> -<h2>Step 1: Create a New Project</h2> +<h3 id="Step1CreatingAProject">Step 1: Create a New Project</h2> <p>If you didn't have a project opened, Android Studio shows the Welcome screen. To create a new project, click <strong>New Project</strong>.</p> @@ -22,20 +66,20 @@ of your project.</p> <img src="{@docRoot}images/tools/wizard2.png" alt="" width="500" height="381"> <p class="img-caption"><strong>Figure 1.</strong> Choose a name for your project.</p> -<p>Enter the values for your project and click <strong>Next</strong>.</p> +<p>Enter the values for your project then click <strong>Next</strong>.</p> - -<h2>Step 2: Select Form Factors and API Level</h2> +<h3 id="Step2SelectFormFactor">Step 2: Select Form Factors and API Level</h2> <p>The next window lets you select the form factors supported by your app, such as phone, tablet, -TV, Wear, and Google Glass. For each form factor, you can also select the API -Level that your app requires. To get more information, click <strong>Help me choose</strong>.</p> +TV, Wear, and Google Glass. The selected form factors become the application modules witin the +project. For each form factor, you can also select the API Level for that app. To get more information, +click <strong>Help me choose</strong>.</p> <img src="{@docRoot}images/tools/wizard4.png" alt="" width="750" height="510"> <p class="img-caption"><strong>Figure 2.</strong> Select the API Level.</p> <p>The API Level window shows the distribution of mobile devices running each version of Android, -as shown in Figure 2. Click on an API level to see a list of features introduced in the corresponding +as shown in figure 3. Click on an API level to see a list of features introduced in the corresponding version of Android. This helps you choose the minimum API Level that has all the features that your apps needs, so you can reach as many devices as possible. Then click <strong>OK</strong>.</p> @@ -45,36 +89,39 @@ your apps needs, so you can reach as many devices as possible. Then click <stron <p>Then, on the Form Factors Window, click <strong>Next</strong>.</p> -<h2>Step 3: Add an Activity</h2> +<h3 id="Step3AddActivity">Step 3: Add an Activity</h2> -<p>The next screen lets you select an activity type to add to your app, as shown in Figure 4. -This screen depends on the form factors you selected earlier.</p> +<p>The next screen lets you select an activity type to add to your app, as shown in figure 4. +This screen displays a different set of activities for each of the form factors you selected earlier.</p> <img src="{@docRoot}images/tools/wizard5.png" alt="" width="720" height="504"> <p class="img-caption"><strong>Figure 4.</strong> Add an activity to your app.</p> -<p>Choose an activity type and click <strong>Next</strong>.</p> +<p>Choose an activity type then click <strong>Next</strong>.</p> + + <p class="note"><strong>Note:</strong> If you choose "Add No Activity", click <strong>Finish</strong> + to create the project.</p> -<h2>Step 4: Configure Your Activity</h2> +<h3 id="Step4ConfigureActivity">Step 4: Configure Your Activity</h2> -<p>The next screen lets you configure the activity to add to your app, as shown in Figure 6.</p> +<p>The next screen lets you configure the activity to add to your app, as shown in figure 5.</p> <img src="{@docRoot}images/tools/wizard6.png" alt="" width="450" height="385"> -<p class="img-caption"><strong>Figure 6.</strong> Choose a name for your activity.</p> +<p class="img-caption"><strong>Figure 5.</strong> Choose a name for your activity.</p> <p>Enter the activity name, the layout name, and the activity title. Then click <strong>Finish</strong>.</p> -<h2>Step 5: Develop Your App</h2> +<h3 id="Step5DevelopYourApp">Step 5: Develop Your App</h2> <p>Android Studio creates the default structure for your project and opens the development -environment. If your app supports more than one form factor, Android Studio creates a module for -each of them, as shown in Figure 7.</p> +environment. If your app supports more than one form factor, Android Studio creates a module folder +with complete source files for each of them as shown in figure 6.</p> <img src="{@docRoot}images/tools/wizard7.png" alt="" width="750" height="509"> -<p class="img-caption"><strong>Figure 7.</strong> The default project structure for a mobile app.</p> +<p class="img-caption"><strong>Figure 6.</strong> The default project structure for a mobile app.</p> <p>Now you are ready to develop your app. For more information, see the following links:</p> @@ -84,3 +131,268 @@ each of them, as shown in Figure 7.</p> <li><a href="{@docRoot}tv/">Android TV</a></li> <li><a href="https://developers.google.com/glass/">Google Glass</a></li> </ul> + + + <h2 id="CreatingAModule">Creating an Android Module</h2> + + <p>Android application modules contain the <code>src/main/</code>, <code>AndroidManifest.xml</code>, + <code>build.gradle</code>, build output and other files you need to generate your app's APK files. + Android Studio provides a <em>New Module Wizard</em> that you can use to quickly create a new + Android module (or a module from existing code) based on selected application settings, such as + minimum SDK level and activity template.</p> + + <p>To create a new module, select <strong>File</strong> > <strong>New</strong> > + <strong>Module</strong>. Select the desire module type then click Next to enter the basic module + settings:</p> + + <ul> + <li>Enter an <strong>Application Name</strong>. This name is used as the title of your + application launcher icon when it is installed on a device.</li> + + <li>Enter a <strong>Module Name</strong>. This text is used as the name of the folder where + your Java-based activity files are stored.</li> + + <li>Enter a <strong>Package Name</strong> and <strong>Package Location</strong>. This class + package namespace creates the initial + package structure for your applications code files and is added as the + <a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">{@code package}</a> + attribute in your application's + <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android manifest file</a>. + This manifest value serves as the unique identifier for your application app when you + distribute it to users. The package name must follow the same rules as packages in the Java + programming language.</li> + + <li>Select the <strong>Minimum required SDK</strong>. + This setting indicates the lowest version of the Android platform that your application + supports for the selected form factor. This value sets the + <code>minSdkVersion</code> attribute in the build.gradle file.</li> + + <p class="note"><strong>Note:</strong> You can manually change the minimum and target SDK + for your module at any time: Double-click the module's build.gradle in the Project Explorer, + set the <strong>targetSdkVersion</strong> and <em>targetSdkVersion</em> in the + <em>defaultConfig</em> section.</p> + + + <li>Select a <strong>Target SDK</strong>. This setting indicates the highest version of + Android with which you have tested with your application and sets the + <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code + targetSdkVersion}</a> attribute in your application's' build.gradle file. + + + <li>Select a <strong>Compile With</strong> API version. This setting specifies what version + of the SDK to compile your project against. We strongly recommend using the most recent + version of the API.</li> + + <li>Select a <strong>Language Level</strong> API version. This setting specifies what version + of the SDK to compile your project against. We strongly recommend using the most recent + version of the API.</li> + + <li>Select a <strong>Theme</strong>. This setting specifies which standard Android + <a href="{@docRoot}design/style/themes.html">visual style</a> is applied to your + application. Select activity template. For more information about Android code templates, see + <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>Leave the <strong> + Create activity</strong> option checked so you can start your + application with some essential components. </li> + + <li>Click the check box for the required Support Libraries then click <strong>Next</strong>.</li> + + <li>In the <strong>Configure Launcher Icon</strong> page, create an icon and options, then click + <strong>Next</strong>.</li> + + <li>In the <strong>Create Activity</strong> page, select activity template then click + <strong>Next</strong>. For more information about Android code templates, see + <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>. + </li> + + <li>Review the new module settings then click <strong>Finish</strong>.</li> + + </ul> + + <p>The wizard creates a new Android application module according to the options you have chosen.</p> + + + + <h2 id="SettingUpLibraryModule">Setting up a Library Module</h2> + + <p>A library module is a standard Android module, so you can create a new one in the same way + as you would a new application module, using the New Module wizard and selecting <em>Android + Library</em> as the module type. The created library module will appear in your project view + along with the other modules. </p> + + <p> You can easily change an existing application module to a library module by changing the + plugin assignment in the <strong>build.gradle</strong> file to <em>com.android.libary</em>.</p> + +<pre> +apply plugin: 'com.android.application' + +android {...} +</pre> + +<pre> +apply plugin: 'com.android.library' + +android {...} +</pre> + + + <h3>Adding a dependency on a library module</h3> + + <p>The library dependency can be declared in the module's manifest file or in the + <strong<build.gradle</strong> file. </p> + + <p>A library modules's manifest file must declare all of the shared components that it includes, + just as would a standard Android application. For more information, see the documentation for + <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> + + <p>For example, the <a href= + "{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a> example library + project declares the activity <code>GameActivity</code>:</p> + <pre> +<manifest> + ... + <application> + ... + <activity android:name="GameActivity" /> + ... + </application> +</manifest> +</pre> + + +<p>To add the dependency declaration to the build file, edit the build file for the <code>app</code> +module (<code>app/build.gradle</code>) and add a dependency on the <code>lib</code> module:</p> + +<pre> +... +dependencies { + ... + compile project(":lib") +} +</pre> + +<p>In this example, the <code>lib</code> module can still be built and tested independently, and +the build system creates an AAR package for it that you could reuse in other projects.</p> + +<p class="note"><strong>Note:</strong> The library settings in the <code>app/build.gradle</code> +file will override any shared library resources declared in the manifest file.</p> + + + <h2 id="ReferencingLibraryModule">Referencing a library module</h2> + + <p>If you are developing an application and want to include the shared code or resources from a + library module, you can also do so easily by adding a reference to the library module in the + module's dependency page.</p> + + <p>To add a reference to a library module, follow these steps:</p> + + <ol> + <li>Make sure that both the module library and the application module that depends on it are + in your proejct. If one of the modules is missing, import it into your project.</li> + + <li>In the project view, right-click the dependent module and select + <strong>Open</strong> > <strong>Module Settings</strong>.</li> + + <li>Right-click the plus icon to add a new dependencies. + <p>If you are adding references to multiple libraries, you can set their relative + priority (and merge order) by selecting a library and using the <strong>Up</strong> and + <strong>Down</strong> controls. The tools merge the referenced libraries with your application + starting from lowest priority (bottom of the list) to highest (top of the list). If more than one + library defines the same resource ID, the tools select the resource from the library with higher + priority. The application itself has highest priority and its resources are always used in + preference to identical resource IDs defined in libraries.</p> + </li> + + <li>Use the <strong>Scope</strong> drop-down to select how the dependency will be applied.</li> + + <li>Click <strong>Apply</strong> to create the dependency and <strong>OK</strong> to close the + <strong>Project Structure</strong> window.</li> + </ol> + + <p>Android Studio rebuilds the module, including the contents of the library module the next time + the project or module is built.</p> + + + + <h3>Declaring library components in the manifest file</h3> + + <p>In the manifest file of the application module, you must add declarations of all components + that the application will use that are imported from a library module. For example, you must + declare any <code><activity></code>, <code><service></code>, + <code><receiver></code>, <code><provider></code>, and so on, as well as + <code><permission></code>, <code><uses-library></code>, and similar elements.</p> + + <p>Declarations should reference the library components by their fully-qualified package names, + where appropriate.</p> + + <p>For example, the <a href= + "{@docRoot}resources/samples/TicTacToeMain/AndroidManifest.html">TicTacToeMain</a> example + application declares the library activity <code>GameActivity</code> like this:</p> + <pre> +<manifest> + ... + <application> + ... + <activity android:name="com.example.android.tictactoe.library.GameActivity" /> + ... + </application> +</manifest> +</pre> + + <p>For more information about the manifest file, see the documentation for <a href= + "{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> + + + <h2 id="ProjectView">Using the Android Project View</h2> + + +<p>The Android project view in Android Studio shows a flattened version of your project's structure +that provides quick access to the key source files of Android projects and helps you work with +the new <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>. The +Android project view:</p> + +<ul> +<li>Groups the build files for all modules at the top level of the project hierarchy.</li> +<li>Shows the most important source directories at the top level of the module hierarchy.</li> +<li>Groups all the manifest files for each module.</li> +<li>Shows resource files from all Gradle source sets.</li> +<li>Groups resource files for different locales, orientations, and screen types in a single group +per resource type.</li> +</ul> + +<div style="float:right;margin-left:30px;width:240px"> +<img src="{@docRoot}images/tools/projectview01.png" alt="" width="220" height="264"/> +<p class="img-caption"><strong>Figure 9:</strong> Show the Android project view.</p> +</div> + + +<h2 id="enable-view">Enable and use the Android Project View</h2> + +<p>The Android project view is not yet enabled by default. To show the Android project view, +click <strong>Project</strong> and select <strong>Android</strong>, as shown in figure 9.</p> + +<p>The Android project view shows all the build files at the top level of the project hierarchy +under <strong>Gradle Scripts</strong>. Each project module appears as a folder at the top +level of the project hierarchy and contains these three elements at the top level:</p> + +<ul> +<li><code>java/</code> - Source files for the module.</li> +<li><code>manifests/</code> - Manifest files for the module.</li> +<li><code>res/</code> - Resource files for the module.</li> +</ul> + +<p>Figure 10 shows how the Android project view groups all the instances of the +<code>ic_launcher.png</code> resource for different screen densities under the same element.</p> + +<p class="note"><strong>Note:</strong> The Android project view shows a hierarchy that helps you +work with Android projects by providing a flattened structure that highlights the most commonly +used files while developing Android applications. However, the project structure on disk differs +from this representation.</p> + +<img src="{@docRoot}images/tools/projectview03.png" alt="" + style="margin-top:10px" width="650" height="508"/> +<p class="img-caption"><strong>Figure 10:</strong> The traditional project view (left) and the +Android project view (right).</p> + + + + diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd index 4fe9071..b68b176 100644 --- a/docs/html/sdk/installing/studio-build.jd +++ b/docs/html/sdk/installing/studio-build.jd @@ -98,7 +98,7 @@ To avoid this error, see <h3>Build output</h3> <p>The build generates an APK for each build variant in the <code>app/build</code> folder: -the <code>app/build/apk/</code> directory contains packages named +the <code>app/build/outputs/apk/</code> directory contains packages named <code>app-<flavor>-<buildtype>.apk</code>; for example, <code>app-full-release.apk</code> and <code>app-demo-debug.apk</code>.</p> diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd index 8e7e345..69c188c 100644 --- a/docs/html/sdk/installing/studio-tips.jd +++ b/docs/html/sdk/installing/studio-tips.jd @@ -91,16 +91,11 @@ practices you should consider using when creating Android Studio apps. </p> is based), refer to the <a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA documentation</a>.</p> -<h3>External annotations</h3> -<p>Specify annotations within the code or from an external annotation file. The Android Studio -IDE keeps track of the restrictions and validates compliance, for example setting the data type -of a string as not null.</p> - <h3><em>Alt + Enter</em> key binding</h3> <p>For quick fixes to coding errors, the IntelliJ powered IDE implements the <em>Alt + Enter</em> key binding to fix errors (missing imports, variable assignments, missing references, etc) when -possible, and if not, suggest the most probably solution. </p> +possible, and if not, suggest the most probable solution. </p> <h3><em>Ctrl + D</em> key binding</h3> @@ -169,12 +164,9 @@ various attributes.</p> <p class="note"><strong>Note:</strong> This section lists Android Studio keyboard shortcuts for the default keymap. To change the default keymap on Windows and Linux, go to -<strong>File</strong> > <strong>Settings</strong> > <strong>Keymap</strong>. To change -the default keymap on Mac OS X, go to <strong>Android Studio</strong> > -<strong>Preferences</strong> > <strong>Keymap</strong>.</p> - -<p class="note"><strong>Note:</strong> If you're using Mac OS X, update your keymap to use -the Mac OS X 10.5+ version keymaps under <strong>Android Studio > Preferences > Keymap</strong>.</p> +<strong>File</strong> > <strong>Settings</strong> > <strong>Keymap</strong>. If you're +using Mac OS X, update your keymap to use the Mac OS X 10.5+ version keymaps under +<strong>Android Studio > Preferences > Keymap</strong>.</p> <p class="table-caption"><strong>Table 1.</strong> Programming key commands</p> diff --git a/docs/html/tools/building/configuring-gradle.jd b/docs/html/tools/building/configuring-gradle.jd index 2e15473..5af2096 100644 --- a/docs/html/tools/building/configuring-gradle.jd +++ b/docs/html/tools/building/configuring-gradle.jd @@ -44,7 +44,7 @@ at the module level. For example, the build file for the app module in the <code>BuildSystemExample</code> project looks like this:</p> <pre> -apply plugin: 'android' +apply plugin: 'com.android.application' android { compileSdkVersion 19 @@ -72,7 +72,7 @@ dependencies { } </pre> -<p><code>apply plugin: 'android'</code> applies the Android plugin for Gradle to this build. +<p><code>apply plugin: 'com.android.application'</code> applies the Android plugin for Gradle to this build. This adds Android-specific build tasks to the top-level build tasks and makes the <code>android {...}</code> element available to specify Android-specific build options.</p> diff --git a/docs/html/tools/building/plugin-for-gradle.jd b/docs/html/tools/building/plugin-for-gradle.jd index b479ed8..77cbfda 100644 --- a/docs/html/tools/building/plugin-for-gradle.jd +++ b/docs/html/tools/building/plugin-for-gradle.jd @@ -23,7 +23,7 @@ Building and Running from Android Studio</a></li> <h2>Download</h2> <div class="download-box"> <a href="{@docRoot}shareables/sdk-tools/android-gradle-plugin-dsl.zip" - class="button">Plugin Command Reference</a> + class="button">Plugin Language Reference</a> <p class="filename">android-gradle-plugin-dsl.zip</p> </div> @@ -117,7 +117,7 @@ also has its own build.gradle file for build settings specific to that module.</ <em>repositories</em> and <em>dependencies</em>. This allows different projects to use different Gradle versions. Supported repositories include JCenter, Maven Central, or Ivy. This example declares that the build script uses the JCenter repository and a classpath dependency artifact -that contains the Android plugin for Gradle version 0.14.4. +that contains the Android plugin for Gradle version 1.0.1. </p> <p> <pre> @@ -126,7 +126,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.14.4' + classpath 'com.android.tools.build:gradle:1.0.1' // NOTE: Do not place your application dependencies here: they belong // in the individual module build.gradle files @@ -320,6 +320,9 @@ logic inside Gradle build files instead.</p> <p>You can run the shell scripts to build your project from the command line on your development machine and on other machines where Android Studio is not installed.</p> +<p class="caution"><strong>Caution:</strong> When you create a project, only use the Gradle wrapper +scripts and JAR from a trusted source, such as those generated by Android Studio. /p> + <h2 id="buildVariants"> Build variants</h2> diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd index dc9294b..42240b9 100644 --- a/docs/html/tools/devices/emulator.jd +++ b/docs/html/tools/devices/emulator.jd @@ -294,9 +294,10 @@ with the {@code -gpu on} option enabled: <strong>Run > Edit Configurations...</strong></li> <li>In the left panel of the <strong>Run/Debug Configurations</strong> dialog, select your Android run configuration or create a new configuration.</li> - <li>Under the <strong>Device Target</strong> options, + <li>Under the <strong>Target Device </strong> options, select the AVD you created in the previous procedure.</li> - <li>In the <strong>Additional Command Line Options</strong> field, enter:<br> + <li>In the <strong>Emulator</strong> tab, in the + <strong>Additional command line options</strong> field, enter:<br> {@code -gpu on}</li> <li>Run your Android project using this run configuration.</li> </ol> @@ -421,7 +422,7 @@ AVD: Configurations...</strong></li> <li>In the left panel of the <strong>Run/Debug Configurations</strong> dialog, select your Android run configuration or create a new configuration.</li> - <li>Under the <strong>Device Target</strong> options, select the x86-based AVD you created + <li>Under the <strong>Target Device</strong> options, select the x86-based AVD you created previously.</li> <li>Run your Android project using this run configuration.</li> </ol> @@ -474,7 +475,7 @@ AVD: Configurations...</strong></li> <li>In the left panel of the <strong>Run/Debug Configurations</strong> dialog, select your Android run configuration or create a new configuration.</li> - <li>Under the <strong>Device Target</strong> options, + <li>Under the <strong>Target Device</strong> options, select the x86-based AVD you created previously.</li> <li>Run your Android project using this run configuration.</li> </ol> @@ -513,17 +514,18 @@ AVD and include the KVM options: <p class="note"><strong>Note:</strong> You must provide an x86-based AVD configuration name, otherwise VM acceleration will not be enabled.</p> </li> - <li>If you are running the emulator from Android Studio, run your Android application with an x86-based -AVD and include the KVM options: + <li>If you are running the emulator from Android Studio, run your Android application with an + x86-based AVD and include the KVM options: <ol> <li>In Android Studio, click your Android module folder and then select <strong>Run > Edit Configurations...</strong></li> <li>In the left panel of the <strong>Run/Debug Configurations</strong> dialog, select your Android run configuration or create a new configuration.</li> - <li>Under the <strong>Device Target</strong> options, select the x86-based AVD you created + <li>Under the <strong>Target Device</strong> options, select the x86-based AVD you created previously.</li> - <li>In the <strong>Additional Command Line Options</strong> field, enter: - <pre>-qemu -m 512 -enable-kvm</pre> + <li>In the <strong>Emulator</strong> tab, in the + <strong>Additional command line options</strong> field, enter: + <pre>-qemu -m 512 -enable-kvm</pre> </li> <li>Run your Android project using this run configuration.</li> </ol> diff --git a/docs/html/tools/projects/projects-studio.jd b/docs/html/tools/projects/projects-studio.jd deleted file mode 100644 index 5082537..0000000 --- a/docs/html/tools/projects/projects-studio.jd +++ /dev/null @@ -1,398 +0,0 @@ -page.title=Managing Projects from Android Studio - -@jd:body - - <div id="qv-wrapper"> - <div id="qv"> - <h2>In this document</h2> - - <ol> - <li><a href="#CreatingAProject">Creating an Android Project</a></li> - <ol> - <li><a href="#Step1CreatingAProject">Create a New Project</a> </li> - <li><a href="#Step2SelectFormFactor">Select Form Factors and API Level</a> </li> - <li><a href="#Step3AddActivity">Add an Activity</a> </li> - <li><a href="#Step4ConfigureActivity">Configure Your App</a> </li> - <li><a href="#Step5DevelopYourApp">Develop Your App</a> </li> - </ol> - - <li><a href="#CreatingAModule">Creating an Android Module</a></li> - - <li><a href="#SettingUpLibraryModule">Setting up a Library Module</a></li> - - <li><a href="#ReferencingLibraryModule">Referencing a Library Module</a></li> - - <li><a href="#ReferencingAppEngModule">Setting up an App Eng Module</a></li> - - <li><a href="#ProjectView">Using the Android Project View</a></li> - - </ol> - - </div> - </div> - - -<p>Android Studio provides graphical tools for creating and managing Android projects, which -contain everything that define your Android apps, from app source code to build configurations and -test code. Each project contains one or more different types of modules, such as - application modules, library modules, and test modules.</p> - -<p>This guide explains how to create Android projects and different modules using -<a href="{@docRoot}tools/studio/index.html">Android Studio</a>. -For more information about the Android project structure and module types, read <a href= -"{@docRoot}tools/projects/index.html">Managing Projects Overview</a>.</p> - - - -<h2 id="CreatingAProject">Creating an Android Project</h2> - -<p>Android Studio makes it easy to create Android apps for several form factors, such as phone, -tablet, TV, Wear, and Google Glass. The <em>New Project</em> wizard lets you choose the form factors -for your app and populates the project structure with everything you need to get started.</p> - -<p>Follow the steps in this section to create a project in Android Studio.</p> - -<h3 id="Step1CreatingAProject">Step 1: Create a New Project</h2> - -<p>If you didn't have a project opened, Android Studio shows the Welcome screen. -To create a new project, click <strong>New Project</strong>.</p> - -<p>If you had a project opened, Android Studio shows the development environment. -To create a new project, click <strong>File</strong> > <strong>New Project</strong>.</p> - -<p>The next window lets you configure the name of your app, the package name, and the location -of your project.</p> - -<img src="{@docRoot}images/tools/wizard2.png" alt="" width="500" height="381"> -<p class="img-caption"><strong>Figure 1.</strong> Choose a name for your project.</p> - -<p>Enter the values for your project then click <strong>Next</strong>.</p> - -<h3 id="Step2SelectFormFactor">Step 2: Select Form Factors and API Level</h2> - -<p>The next window lets you select the form factors supported by your app, such as phone, tablet, -TV, Wear, and Google Glass. The selected form factors become the application modules witin the -project. For each form factor, you can also select the API Level for that app. To get more information, -click <strong>Help me choose</strong>.</p> - -<img src="{@docRoot}images/tools/wizard4.png" alt="" width="750" height="510"> -<p class="img-caption"><strong>Figure 2.</strong> Select the API Level.</p> - -<p>The API Level window shows the distribution of mobile devices running each version of Android, -as shown in figure 3. Click on an API level to see a list of features introduced in the corresponding -version of Android. This helps you choose the minimum API Level that has all the features that -your apps needs, so you can reach as many devices as possible. Then click <strong>OK</strong>.</p> - -<img src="{@docRoot}images/tools/wizard3.png" alt="" width="500" height="480"> -<p class="img-caption"><strong>Figure 3.</strong> Choose form factors for your app.</p> - -<p>Then, on the Form Factors Window, click <strong>Next</strong>.</p> - - -<h3 id="Step3AddActivity">Step 3: Add an Activity</h2> - -<p>The next screen lets you select an activity type to add to your app, as shown in figure 4. -This screen displays a different set of activities for each of the form factors you selected earlier.</p> - -<img src="{@docRoot}images/tools/wizard5.png" alt="" width="720" height="504"> -<p class="img-caption"><strong>Figure 4.</strong> Add an activity to your app.</p> - -<p>Choose an activity type then click <strong>Next</strong>.</p> - - <p class="note"><strong>Note:</strong> If you choose "Add No Activity", click <strong>Finish</strong> - to create the project.</p> - - -<h3 id="Step4ConfigureActivity">Step 4: Configure Your Activity</h2> - -<p>The next screen lets you configure the activity to add to your app, as shown in figure 5.</p> - -<img src="{@docRoot}images/tools/wizard6.png" alt="" width="450" height="385"> -<p class="img-caption"><strong>Figure 5.</strong> Choose a name for your activity.</p> - -<p>Enter the activity name, the layout name, and the activity title. Then click -<strong>Finish</strong>.</p> - - -<h3 id="Step5DevelopYourApp">Step 5: Develop Your App</h2> - -<p>Android Studio creates the default structure for your project and opens the development -environment. If your app supports more than one form factor, Android Studio creates a module folder -with complete source files for each of them as shown in figure 6.</p> - -<img src="{@docRoot}images/tools/wizard7.png" alt="" width="750" height="509"> -<p class="img-caption"><strong>Figure 6.</strong> The default project structure for a mobile app.</p> - -<p>Now you are ready to develop your app. For more information, see the following links:</p> - -<ul> -<li><a href="{@docRoot}training/">Training Lessons</a></li> -<li><a href="{@docRoot}training/building-wearables.html">Building Apps for Wearables</a></li> -<li><a href="{@docRoot}tv/">Android TV</a></li> -<li><a href="https://developers.google.com/glass/">Google Glass</a></li> -</ul> - - - <h2 id="CreatingAModule">Creating an Android Module</h2> - - <p>Android application modules contain the <code>src/main/</code>, <code>AndroidManifest.xml</code>, - <code>build.gradle</code>, build output and other files you need to generate your app's APK files. - Android Studio provides a <em>New Module Wizard</em> that you can use to quickly create a new - Android module (or a module from existing code) based on selected application settings, such as - minimum SDK level and activity template.</p> - - <p>To create a new module, select <strong>File</strong> > <strong>New</strong> > - <strong>Module</strong>. Select the desire module type then click Next to enter the basic module - settings:</p> - - <ul> - <li>Enter an <strong>Application Name</strong>. This name is used as the title of your - application launcher icon when it is installed on a device.</li> - - <li>Enter a <strong>Module Name</strong>. This text is used as the name of the folder where - your Java-based activity files are stored.</li> - - <li>Enter a <strong>Package Name</strong> and <strong>Package Location</strong>. This class - package namespace creates the initial - package structure for your applications code files and is added as the - <a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">{@code package}</a> - attribute in your application's - <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android manifest file</a>. - This manifest value serves as the unique identifier for your application app when you - distribute it to users. The package name must follow the same rules as packages in the Java - programming language.</li> - - <li>Select the <strong>Minimum required SDK</strong>. - This setting indicates the lowest version of the Android platform that your application - supports for the selected form factor. This value sets the - <code>minSdkVersion</code> attribute in the build.gradle file.</li> - - <p class="note"><strong>Note:</strong> You can manually change the minimum and target SDK - for your module at any time: Double-click the module's build.gradle in the Project Explorer, - set the <strong>targetSdkVersion</strong> and <em>targetSdkVersion</em> in the - <em>defaultConfig</em> section.</p> - - - <li>Select a <strong>Target SDK</strong>. This setting indicates the highest version of - Android with which you have tested with your application and sets the - <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code - targetSdkVersion}</a> attribute in your application's' build.gradle file. - - - <li>Select a <strong>Compile With</strong> API version. This setting specifies what version - of the SDK to compile your project against. We strongly recommend using the most recent - version of the API.</li> - - <li>Select a <strong>Language Level</strong> API version. This setting specifies what version - of the SDK to compile your project against. We strongly recommend using the most recent - version of the API.</li> - - <li>Select a <strong>Theme</strong>. This setting specifies which standard Android - <a href="{@docRoot}design/style/themes.html">visual style</a> is applied to your - application. Select activity template. For more information about Android code templates, see - <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>Leave the <strong> - Create activity</strong> option checked so you can start your - application with some essential components. </li> - - <li>Click the check box for the required Support Libraries then click <strong>Next</strong>.</li> - - <li>In the <strong>Configure Launcher Icon</strong> page, create an icon and options, then click - <strong>Next</strong>.</li> - - <li>In the <strong>Create Activity</strong> page, select activity template then click - <strong>Next</strong>. For more information about Android code templates, see - <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>. - </li> - - <li>Review the new module settings then click <strong>Finish</strong>.</li> - - </ul> - - <p>The wizard creates a new Android application module according to the options you have chosen.</p> - - - - <h2 id="SettingUpLibraryModule">Setting up a Library Module</h2> - - <p>A library module is a standard Android module, so you can create a new one in the same way - as you would a new application module, using the New Module wizard and selecting <em>Android - Library</em> as the module type. The created library module will appear in your project view - along with the other modules. </p> - - <p> You can easily change an existing application module to a library module by changing the - plugin assignment in the <strong>build.gradle</strong> file to <em>com.android.libary</em>.</p> - -<pre> -apply plugin: 'com.android.application' - -android {...} -</pre> - -<pre> -apply plugin: 'com.android.library' - -android {...} -</pre> - - - <h3>Adding a dependency on a library module</h3> - - <p>The library dependency can be declared in the module's manifest file or in the - <strong<build.gradle</strong> file. </p> - - <p>A library modules's manifest file must declare all of the shared components that it includes, - just as would a standard Android application. For more information, see the documentation for - <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> - - <p>For example, the <a href= - "{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a> example library - project declares the activity <code>GameActivity</code>:</p> - <pre> -<manifest> - ... - <application> - ... - <activity android:name="GameActivity" /> - ... - </application> -</manifest> -</pre> - - -<p>To add the dependency declaration to the build file, edit the build file for the <code>app</code> -module (<code>app/build.gradle</code>) and add a dependency on the <code>lib</code> module:</p> - -<pre> -... -dependencies { - ... - compile project(":lib") -} -</pre> - -<p>In this example, the <code>lib</code> module can still be built and tested independently, and -the build system creates an AAR package for it that you could reuse in other projects.</p> - -<p class="note"><strong>Note:</strong> The library settings in the <code>app/build.gradle</code> -file will override any shared library resources declared in the manifest file.</p> - - - <h2 id="ReferencingLibraryModule">Referencing a library module</h2> - - <p>If you are developing an application and want to include the shared code or resources from a - library module, you can also do so easily by adding a reference to the library module in the - module's dependency page.</p> - - <p>To add a reference to a library module, follow these steps:</p> - - <ol> - <li>Make sure that both the module library and the application module that depends on it are - in your proejct. If one of the modules is missing, import it into your project.</li> - - <li>In the project view, right-click the dependent module and select - <strong>Open</strong> > <strong>Module Settings</strong>.</li> - - <li>Right-click the plus icon to add a new dependencies. - <p>If you are adding references to multiple libraries, you can set their relative - priority (and merge order) by selecting a library and using the <strong>Up</strong> and - <strong>Down</strong> controls. The tools merge the referenced libraries with your application - starting from lowest priority (bottom of the list) to highest (top of the list). If more than one - library defines the same resource ID, the tools select the resource from the library with higher - priority. The application itself has highest priority and its resources are always used in - preference to identical resource IDs defined in libraries.</p> - </li> - - <li>Use the <strong>Scope</strong> drop-down to select how the dependency will be applied.</li> - - <li>Click <strong>Apply</strong> to create the dependency and <strong>OK</strong> to close the - <strong>Project Structure</strong> window.</li> - </ol> - - <p>Android Studio rebuilds the module, including the contents of the library module the next time - the project or module is built.</p> - - - - <h3>Declaring library components in the manifest file</h3> - - <p>In the manifest file of the application module, you must add declarations of all components - that the application will use that are imported from a library module. For example, you must - declare any <code><activity></code>, <code><service></code>, - <code><receiver></code>, <code><provider></code>, and so on, as well as - <code><permission></code>, <code><uses-library></code>, and similar elements.</p> - - <p>Declarations should reference the library components by their fully-qualified package names, - where appropriate.</p> - - <p>For example, the <a href= - "{@docRoot}resources/samples/TicTacToeMain/AndroidManifest.html">TicTacToeMain</a> example - application declares the library activity <code>GameActivity</code> like this:</p> - <pre> -<manifest> - ... - <application> - ... - <activity android:name="com.example.android.tictactoe.library.GameActivity" /> - ... - </application> -</manifest> -</pre> - - <p>For more information about the manifest file, see the documentation for <a href= - "{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> - - - <h2 id="ProjectView">Using the Android Project View</h2> - - -<p>The Android project view in Android Studio shows a flattened version of your project's structure -that provides quick access to the key source files of Android projects and helps you work with -the new <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>. The -Android project view:</p> - -<ul> -<li>Groups the build files for all modules at the top level of the project hierarchy.</li> -<li>Shows the most important source directories at the top level of the module hierarchy.</li> -<li>Groups all the manifest files for each module.</li> -<li>Shows resource files from all Gradle source sets.</li> -<li>Groups resource files for different locales, orientations, and screen types in a single group -per resource type.</li> -</ul> - -<div style="float:right;margin-left:30px;width:240px"> -<img src="{@docRoot}images/tools/projectview01.png" alt="" width="220" height="264"/> -<p class="img-caption"><strong>Figure 9:</strong> Show the Android project view.</p> -</div> - - -<h2 id="enable-view">Enable and use the Android Project View</h2> - -<p>The Android project view is not yet enabled by default. To show the Android project view, -click <strong>Project</strong> and select <strong>Android</strong>, as shown in figure 9.</p> - -<p>The Android project view shows all the build files at the top level of the project hierarchy -under <strong>Gradle Scripts</strong>. Each project module appears as a folder at the top -level of the project hierarchy and contains these three elements at the top level:</p> - -<ul> -<li><code>java/</code> - Source files for the module.</li> -<li><code>manifests/</code> - Manifest files for the module.</li> -<li><code>res/</code> - Resource files for the module.</li> -</ul> - -<p>Figure 10 shows how the Android project view groups all the instances of the -<code>ic_launcher.png</code> resource for different screen densities under the same element.</p> - -<p class="note"><strong>Note:</strong> The Android project view shows a hierarchy that helps you -work with Android projects by providing a flattened structure that highlights the most commonly -used files while developing Android applications. However, the project structure on disk differs -from this representation.</p> - -<img src="{@docRoot}images/tools/projectview03.png" alt="" - style="margin-top:10px" width="650" height="508"/> -<p class="img-caption"><strong>Figure 10:</strong> The traditional project view (left) and the -Android project view (right).</p> - - - - diff --git a/docs/html/tools/support-library/setup.jd b/docs/html/tools/support-library/setup.jd index 845cf76..8112071 100644 --- a/docs/html/tools/support-library/setup.jd +++ b/docs/html/tools/support-library/setup.jd @@ -300,7 +300,7 @@ dependencies { overrides the manifest settings. </p> <pre> -apply plugin: 'android' +apply plugin: 'com.android.application' android { ... diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs index 9437c1b..ab6c739 100644 --- a/docs/html/tools/tools_toc.cs +++ b/docs/html/tools/tools_toc.cs @@ -52,7 +52,7 @@ <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/projects/index.html"><span class="en">Managing Projects</span></a></div> <ul> - <li><a href="<?cs var:toroot ?>tools/projects/projects-studio.html"><span class="en">From Android Studio</span></a></li> + <li><a href="<?cs var:toroot ?>sdk/installing/create-project.html"><span class="en">From Android Studio</span></a></li> <li><a href="<?cs var:toroot ?>tools/projects/projects-cmdline.html"><span class="en">From the Command Line</span></a></li> <li><a href="<?cs var:toroot ?>tools/projects/templates.html"><span class="en">Using Code Templates</span></a></li> </ul> diff --git a/docs/html/tools/workflow/index.jd b/docs/html/tools/workflow/index.jd index 6a114c7..a24a2b0 100644 --- a/docs/html/tools/workflow/index.jd +++ b/docs/html/tools/workflow/index.jd @@ -30,15 +30,15 @@ figure 1. The development steps encompass four development phases, which include <p>During this phase you install and set up your development environment. You also create Android Virtual Devices (AVDs) and connect hardware devices on which you can install your applications.</p> - <p>See <a href="{@docRoot}tools/workflow/devices/index.html">Managing Virtual Devices</a> - and <a href="{@docRoot}tools/workflow/device.html">Using Hardware Devices</a> for more + <p>See <a href="{@docRoot}tools/devices/index.html">Managing Virtual Devices</a> + and <a href="{@docRoot}tools/device.html">Using Hardware Devices</a> for more information. </li> <li><strong>Project Setup and Development</strong> <p>During this phase you set up and develop your Android Studio project and application modules, which contain all of the source code and resource files for your application. For more information, see - <a href="{@docRoot}tools/workflow/projects/index.html">Create an Android project</a>.</p> + <a href="{@docRoot}tools/projects/index.html">Create an Android project</a>.</p> </li> <li><strong>Building, Debugging and Testing</strong> <p>During this phase you build your project into a debuggable <code>.apk</code> package(s) @@ -47,7 +47,7 @@ figure 1. The development steps encompass four development phases, which include that provides flexibility, customized build variants, dependency resolution, and much more. If you're using another IDE, you can build your project using Gradle and install it on a device using <a href="{@docRoot}tools/help/adb.html">adb</a>. For more information, see - <a href="{@docRoot}tools/workflow/building/index.html">Build and run your application</a>.</p> + <a href="{@docRoot}tools/building/index.html">Build and run your application</a>.</p> <p>Next, with Android Studio you debug your application using the <a href="{@docRoot}tools/help/monitor.html">Android Debug Monitor</a> and device log messages (<a href="{@docRoot}tools/help/logcat.html">logact</a>) along with the IntelliJ IDEA intelligent diff --git a/docs/html/training/enterprise/app-compatibility.jd b/docs/html/training/enterprise/app-compatibility.jd new file mode 100644 index 0000000..1ae1ee3 --- /dev/null +++ b/docs/html/training/enterprise/app-compatibility.jd @@ -0,0 +1,274 @@ +page.title=Ensuring Compatibility with Managed Profiles +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#prevent_failed_intents">Prevent Failed Intents</a></li> + <li><a href="#sharing_files">Share Files Across Profiles</a></li> + <li><a href="#testing_apps">Test your App for Compatibility with Managed + Profiles</a></li> +</ol> + +<!-- related docs (NOT javadocs) --> +<h2>Resources</h2> +<ul> + <li><a href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a></li> +</ul> + +</div> +</div> + +<p>The Android platform allows devices to have +<a href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed +profiles</a>. A managed profile is controlled by an administrator, and the +functionality available to it is set separately from the functionality of the +user's primary profile. This approach lets enterprises control the environment +where company-specific apps and data are running on a user's device, while still +letting users use their personal apps and profiles.</p> + +<p>This lesson shows you how to modify your application so it functions +reliably on a device with managed profiles. You don't need to do anything +besides the ordinary app-development best practices. However, some of these best +practices become especially important on devices with managed profiles. This +document highlights the issues you need to be aware of.</p> + +<h2 id="overview">Overview</h2> + +<p>Users often want to use their personal devices in an enterprise setting. This +situation can present enterprises with a dilemma. If the user can use their own +device, the enterprise has to worry that confidential information (like employee +emails and contacts) are on a device the enterprise does not control. </p> + +<p>To address this situation, Android 5.0 (API level 21) allows enterprises to +set up <i>managed profiles</i>. If a device has a managed profile, the profile's +settings are under the control of the enterprise administrator. The +administrator can choose which apps are allowed for that profile, and can +control just what device features are available to the profile.</p> + +<p>If a device has a managed profile, there are implications for apps +running on the device, no matter which profile the app is running under:</p> + +<ul> + +<li>By default, most intents do not cross from one profile to the other. If an +app running on profile fires an intent, there is no handler for the intent on +that profile, and the intent is not allowed to cross to the other profile +due to profile restrictions, the request fails and the app may shut down +unexpectedly.</li> +<li>The profile administrator can limit which system apps are available on the +managed profile. This restriction can also result in there being no handler for +some common intents on the managed profile.</li> +<li>Since the managed and unmanaged profiles have separate storage areas, a +file URI that is valid on one profile is not valid on the other. Any +intent fired on one profile might be handled on the other (depending on profile +settings), so it is not safe to attach file URIs to intents.</li> + +</ul> + +<h2 id="prevent_failed_intents">Prevent Failed Intents</h2> + +<p>On a device with a managed profile, there are restrictions on whether intents +can cross from one profile to another. In most cases, when an intent is fired +off, it is handled on the same profile where it is fired. If there is no handler +for the intent <em>on that profile</em>, the intent is not handled and the app +that fired it may shut down unexpectedly—even if there's a handler for the +intent on the other profile.</p> + +<p>The profile administrator can choose which intents are +allowed to cross from one profile to another. Since the administrator makes +this decision, there's no way for you +to know in advance <em>which</em> intents are allowed to cross this boundary. The +administrator sets this policy, and is free to change it at any time.</p> + +<p>Before your app starts an activity, you should verify that there is a +suitable resolution. You +can verify that there is an acceptable resolution by calling {@link +android.content.Intent#resolveActivity Intent.resolveActivity()}. If there is no +way to resolve the intent, the method returns +<code>null</code>. If the method returns non-null, there is at least one way to +resolve the intent, and it is safe to fire off the intent. In this case, the +intent could be resolvable either +because there is a handler on the current profile, or because the intent is +allowed to cross to a handler on the other profile. (For more information about +resolving intents, see <a +href="{@docRoot}guide/components/intents-common.html">Common Intents</a>.)</p> + +<p>For example, if your app needs to set timers, it would need to check that +there's a valid handler for the {@link +android.provider.AlarmClock#ACTION_SET_TIMER} intent. If the app cannot resolve +the intent, it should take an appropriate action (such as showing an error +message).</p> + +<pre>public void startTimer(String message, int seconds) { + + // Build the "set timer" intent + Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER) + .putExtra(AlarmClock.EXTRA_MESSAGE, message) + .putExtra(AlarmClock.EXTRA_LENGTH, seconds) + .putExtra(AlarmClock.EXTRA_SKIP_UI, true); + + // Check if there's a handler for the intent + <strong>if (timerIntent.resolveActivity(getPackageManager()) == null)</strong> { + + // Can't resolve the intent! Fail this operation cleanly + // (perhaps by showing an error message) + + } else { + // Intent resolves, it's safe to fire it off + startActivity(timerIntent); + + } +} +</pre> + +<h2 id="sharing_files">Share Files Across Profiles</h2> + +<p>Sometimes an app needs to provide other apps with access to its own files. +For example, an image gallery app might want to share its images with image +editors. There are two ways you would ordinarily share a file: with a <em>file +URI</em> or a <em>content URI</em>.</p> + +<p>A file URI begins with the <code>file:</code> prefix, followed by the +absolute path of the file on the device's storage. However, because the +managed profile and the personal profile use separate storage areas, a file URI +that is valid on one profile is not valid on the other. This situation +means that if you +attach a file URI to an intent, and the intent is handled on the other profile, +the handler is not able to access the file.</p> + +<p>Instead, you should share files with <em>content URIs</em>. Content URIs +identify the file in a more secure, shareable fashion. The content URI contains +the file path, but also the authority that provides the file, and an ID number +identifying the file. You can generate a content ID for any file by using a +{@link android.support.v4.content.FileProvider}. You can then share that content +ID with other apps (even on the other profile). The recipient can use the +content ID to get access to the actual file.</p> + +<p>For example, here's how you would get the content URI for a specific file +URI:</p> + +<pre>// Open File object from its file URI +File fileToShare = new File(<em>fileUriToShare</em>); + +Uri contentUriToShare = FileProvider.getUriForFile(getContext(), + <em>"com.example.myapp.fileprovider"</em>, fileToShare);</pre> + +<p>When you call the {@link +android.support.v4.content.FileProvider#getUriForFile getUriForFile()} method, +you must include the file provider's authority (in this example, +<code>"com.example.myapp.fileprovider"</code>), which is specified in the +<a href="{@docRoot}guide/topics/manifest/provider-element.html"><code><provider></code></a> +element of your app manifest. +For more information about sharing files with content URIs, see +<a href="{@docRoot}training/secure-file-sharing/index.html">Sharing +Files</a>.</p> + +<h2 id="testing_apps">Test your App for Compatibility with Managed Profiles</h2> + +<p>You should test your app in a managed-profile environment to +catch problems that would cause your app to fail on a device with +managed profiles. In particular, testing on a managed-profile device is a good +way to make sure that your app handles intents properly: not firing intents that +can't be handled, not attaching URIs that don't work cross-profile, and so +on.</p> + +<p>We have provided a sample app, <a +href="{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>, +which you can use to set up a managed profile on an Android device that runs +Android 5.0 (API level 21) and higher. This app offers you a simple way to test +your app in a managed-profile environment. You can also use this app to +configure the managed profile as follows:</p> + +<ul> + + <li>Specify which default apps are available on the managed + profile</li> + + <li>Configure which intents are allowed to cross from one profile to + the other</li> + +</ul> + +<p>If you manually install an app over a USB cable to a device which has a +managed profile, the app is installed on both the managed and the unmanaged +profile. Once you have installed the app, you can test the app under the +following conditions:</p> + +<ul> + + <li>If an intent would ordinarily be handled by a default app (for example, + the camera app), try disabling that default app on the managed profile, and + verify that the app handles this appropriately.</li> + + <li>If you fire an intent expecting it to be handled by some other app, try +enabling and disabling that intent's permission to cross from one profile to +another. Verify that the app behaves properly under both circumstances. If the +intent is not allowed to cross between profiles, verify the app's behavior both +when there is a suitable handler on the app's profile, and when there is not. +For example, if your app fires a map-related intent, try each of the following +scenarios: + + <ul> + +<li>The device allows map intents to cross from one profile to the other, and +there is a suitable handler on the other profile (the profile the app is not +running on)</li> + +<li>The device does not allow map intents to cross between profiles, but there +is a suitable handler on the app's profile</li> + +<li>The device does not allow map intents to cross between profiles, and there +is no suitable handler for map intents on the device's profile</li> + + </ul> + </li> + +<li>If you attach content to an intent, verify that the intent behaves properly +both when it is handled on the app's profile, and when it crosses between +profiles.</li> + +</ul> + +<h3 id="testing_tips">Testing on managed profiles: Tips and tricks</h3> + +<p>There are a few tricks that you may find helpful in testing on a +managed-profile device.</p> + +<ul> + +<li>As noted, when you side-load an app on a managed profile device, it is +installed on both profiles. If you wish, you can delete the app from one profile +and leave it on the other.</li> + +<li>Most of the activity manager commands available in the <a +href="{@docRoot}tools/help/adb.html">Android Debug Bridge</a> (adb) shell +support the <code>--user</code> flag, which lets you specify which user to run +as. By specifying a user, you can choose whether to run as the unmanaged or +managed profile. For +more information, see <a href="{@docRoot}tools/help/adb.html#am">Android Debug +Bridge: Using activity manager (am)</a>.</li> + +<li>To find the active users on a device, use the adb package manager's +<code>list users</code> command. The first number in the output string is the +user ID, which you can use with the <code>--user</code> flag. For more +information, see <a href="{@docRoot}tools/help/adb.html#pm">Android Debug +Bridge: Using package manager (pm)</a>.</li> + +</ul> + +<p>For example, to find the users on a device, you would run this command:</p> + +<pre class="no-pretty-print">$ <strong>adb shell pm list users</strong> +UserInfo{0:Drew:13} running +UserInfo{10:Work profile:30} running</pre> + +<p>In this case, the unmanaged profile ("Drew") has the user ID 0, and the +managed profile has the user ID 10. To run an app in the work profile, you +would use a command like this:</p> + +<pre class="no-pretty-print">$ adb shell am start --user 10 \ +-n "<em>com.example.myapp/com.example.myapp.testactivity</em>" \ +-a android.intent.action.MAIN -c android.intent.category.LAUNCHER</pre> diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd index 2926f71..0ac68cc 100644 --- a/docs/html/training/enterprise/index.jd +++ b/docs/html/training/enterprise/index.jd @@ -47,4 +47,12 @@ for the enterprise.</p> Policies</a></b></dt> <dd>In this lesson, you will learn how to create a security-aware application that manages access to its content by enforcing device management policies</dd> + + <dt><b><a href="app-compatibility.html">Ensuring Compatibility with Managed Profiles</a></b></dt> + + <dd>In this lesson, you will learn the best practices to follow to ensure + that your app functions properly on devices that use <a + href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed + profiles</a></dd> + </dl> diff --git a/docs/html/training/location/receive-location-updates.jd b/docs/html/training/location/receive-location-updates.jd index e6e8c51..208dc17 100644 --- a/docs/html/training/location/receive-location-updates.jd +++ b/docs/html/training/location/receive-location-updates.jd @@ -1,612 +1,417 @@ page.title=Receiving Location Updates trainingnavtop=true @jd:body + <div id="tb-wrapper"> -<div id="tb"> - -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#Permissions">Request Location Permission</a></li> - <li><a href="#PlayServices">Check for Google Play Services</a></li> - <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li> - <li><a href="#UpdateParameters">Specify Update Parameters</a></li> - <li><a href="#StartUpdates">Start Location Updates</a></li> - <li><a href="#StopUpdates">Stop Location Updates</a></li> -</ol> - -<h2>You should also read</h2> -<ul> + <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="#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> + <li><a href="#save-state">Save the State of the Activity</a></li> + </ol> + + <h2>You should also read</h2> + <ul> <li> - <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> + <a href="{@docRoot}google/play-services/setup.html">Setting up Google Play + Services</a> </li> <li> - <a href="retrieve-current.html">Retrieving the Current Location</a> + <a href="retrieve-current.html">Getting the Last Known Location</a> </li> - </ul> + </ul> -<h2>Try it out</h2> + <h2>Try it out</h2> -<div class="download-box"> - <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample</a> - <p class="filename">LocationUpdates.zip</p> + <ul> + <li> + <a href="https://github.com/googlesamples/android-play-location/tree/master/LocationUpdates" class="external-link">LocationUpdates</a> + </li> + </ul> + </div> </div> -</div> -</div> +<p>If your app can continuously track location, it can deliver more relevant + information to the user. For example, if your app helps the user find their + way while walking or driving, or if your app tracks the location of assets, it + needs to get the location of the device at regular intervals. As well as the + geographical location (latitude and longitude), you may want to give the user + further information such as the bearing (horizontal direction of travel), + altitude, or velocity of the device. This information, and more, is available + in the {@link android.location.Location} object that your app can retrieve + from the + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused + location provider</a>.</p> + +<p>While you can get a device's location with + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>, + as illustrated in the lesson on + <a href="retrieve-current.html">Getting the Last Known Location</a>, + a more direct approach is to request periodic updates from the fused location + provider. In response, the API updates your app periodically with the best + available location, based on the currently-available location providers such + as WiFi and GPS (Global Positioning System). The accuracy of the location is + determined by the providers, the location permissions you've requested, and + the options you set in the location request.</p> + +<p>This lesson shows you how to request regular updates about a device's + location using the + <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> + +<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 + periodic location updates. The lesson on + <a href="retrieve-current.html">Getting the Last Known Location</a> shows you + how to get the last known location by calling + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>. + The snippets in the following sections assume that your app has already + retrieved the last known location and stored it as a + {@link android.location.Location} object in the global variable + {@code mCurrentLocation}.</p> + +<p>Apps that use location services must request location permissions. In this + lesson you require fine location detection, so that your app can get as + precise a location as possible from the available location providers. Request + this permission with the + {@code uses-permission} element in your app manifest, as shown in the + following example:</p> -<p> - If your app does navigation or tracking, you probably want to get the user's - location at regular intervals. While you can do this with -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">LocationClient.getLastLocation()</a></code>, - a more direct approach is to request periodic updates from Location Services. In - response, Location Services automatically updates your app with the best available location, - based on the currently-available location providers such as WiFi and GPS. -</p> -<p> - To get periodic location updates from Location Services, you send a request using a location - client. Depending on the form of the request, Location Services either invokes a callback - method and passes in a {@link android.location.Location} object, or issues an - {@link android.content.Intent} that contains the location in its extended data. The accuracy and - frequency of the updates are affected by the location permissions you've requested and the - parameters you pass to Location Services with the request. -</p> -<!-- Request permission --> -<h2 id="Permissions">Specify App Permissions</h2> -<p> - Apps that use Location Services must request location permissions. Android has two location - permissions, {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} - and {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. The - permission you choose affects the accuracy of the location updates you receive. - For example, If you request only coarse location permission, Location Services obfuscates the - updated location to an accuracy that's roughly equivalent to a city block. -</p> -<p> - Requesting {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} implies - a request for {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}. -</p> -<p> - For example, to add the coarse location permission to your manifest, insert the following as a - child element of - the -<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> - element: -</p> <pre> -<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> +<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_FINE_LOCATION"/> +</manifest> </pre> -<!-- Check for Google Play services --> -<h2 id="PlayServices">Check for Google Play Services</h2> -<p> - Location Services is part of the Google Play services APK. Since it's hard to anticipate the - state of the user's device, you should always check that the APK is installed before you attempt - to connect to Location Services. To check that the APK is installed, call -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>, - which returns one of the - integer result codes listed in the API reference documentation. If you encounter an error, - call -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code> - to retrieve localized dialog that prompts users to take the correct action, then display - the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the - user to correct the problem, in which case Google Play services may send a result back to your - activity. To handle this result, override the method - {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} - -</p> -<p class="note"> - <strong>Note:</strong> To make your app compatible with - platform version 1.6 and later, the activity that displays the - {@link android.support.v4.app.DialogFragment} must subclass - {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using - {@link android.support.v4.app.FragmentActivity} also allows you to call - {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager - getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}. -</p> -<p> - Since you usually need to check for Google Play services in more than one place in your code, - define a method that encapsulates the check, then call the method before each connection - attempt. The following snippet contains all of the code required to check for Google - Play services: -</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="{@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> -public class MainActivity extends FragmentActivity { - ... - // Global constants - /* - * Define a request code to send to Google Play services - * This code is returned in Activity.onActivityResult - */ - private final static int - CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; - ... - // Define a DialogFragment that displays the error dialog - public static class ErrorDialogFragment extends DialogFragment { - // Global field to contain the error dialog - private Dialog mDialog; - // Default constructor. Sets the dialog field to null - public ErrorDialogFragment() { - super(); - mDialog = null; - } - // Set the dialog to display - public void setDialog(Dialog dialog) { - mDialog = dialog; - } - // Return a Dialog to the DialogFragment. - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return mDialog; - } - } - ... - /* - * Handle results returned to the FragmentActivity - * by Google Play services - */ - @Override - protected void onActivityResult( - int requestCode, int resultCode, Intent data) { - // Decide what to do based on the original request code - switch (requestCode) { - ... - case CONNECTION_FAILURE_RESOLUTION_REQUEST : - /* - * If the result code is Activity.RESULT_OK, try - * to connect again - */ - switch (resultCode) { - case Activity.RESULT_OK : - /* - * Try the request again - */ - ... - break; - } - ... - } - ... - } - ... - private boolean servicesConnected() { - // Check that Google Play services is available - int resultCode = - GooglePlayServicesUtil. - isGooglePlayServicesAvailable(this); - // If Google Play services is available - if (ConnectionResult.SUCCESS == resultCode) { - // In debug mode, log the status - Log.d("Location Updates", - "Google Play services is available."); - // Continue - return true; - // Google Play services was not available for some reason - } else { - // Get the error code - int errorCode = connectionResult.getErrorCode(); - // Get the error dialog from Google Play services - Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog( - errorCode, - this, - CONNECTION_FAILURE_RESOLUTION_REQUEST); - // If Google Play services can provide an error dialog - if (errorDialog != null) { - // Create a new DialogFragment for the error dialog - ErrorDialogFragment errorFragment = - new ErrorDialogFragment(); - // Set the dialog in the DialogFragment - errorFragment.setDialog(errorDialog); - // Show the error dialog in the DialogFragment - errorFragment.show( - getSupportFragmentManager(), - "Location Updates"); - } - } - } - ... +protected void createLocationRequest() { + LocationRequest mLocationRequest = new LocationRequest(); + mLocationRequest.setInterval(10000); + mLocationRequest.setFastestInterval(5000); + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } </pre> -<p> - Snippets in the following sections call this method to verify that Google Play services is - available. -</p> -<!-- - Define Location Services Callbacks - --> -<h2 id="DefineCallbacks">Define Location Services Callbacks</h2> -<p> - Before you request location updates, you must first implement the interfaces that Location - Services uses to communicate connection status to your app: -</p> -<dl> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code> - </dt> - <dd> - Specifies methods that Location Services calls when a location client is connected or - disconnected. - </dd> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code> - </dt> - <dd> - Specifies a method that Location Services calls if an error occurs while attempting to - connect the location client. This method uses the previously-defined {@code showErrorDialog} - method to display an error dialog that attempts to fix the problem using Google Play - services. - </dd> -</dl> -<p> - The following snippet shows how to specify the interfaces and define the methods: -</p> + +<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 + <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> + callback provided by Google API Client, which is called when the client is + ready.</p> + +<p>Depending on the form of the request, the fused location provider either + invokes the + <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener.onLocationChanged()}</a> + callback method and passes it a {@link android.location.Location} object, or + issues a + <a href="{@docRoot}reference/android/app/PendingIntent.html">{@code PendingIntent}</a> + that contains the location in its extended data. The accuracy and frequency of + the updates are affected by the location permissions you've requested and the + options you set in the location request object.</p> + +<p>This lesson shows you how to get the update using the + <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a> + callback approach. Call + <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>, + passing it your instance of the + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>, + the + <a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">{@code LocationRequest}</a> + object, + and a <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>. + Define a {@code startLocationUpdates()} method, called from the + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a> + callback, as shown in the following code sample:</p> + <pre> -public class MainActivity extends FragmentActivity implements - GooglePlayServicesClient.ConnectionCallbacks, - GooglePlayServicesClient.OnConnectionFailedListener { +@Override +public void onConnected(Bundle connectionHint) { ... - /* - * Called by Location Services when the request to connect the - * client finishes successfully. At this point, you can - * request the current location or start periodic updates - */ - @Override - public void onConnected(Bundle dataBundle) { - // Display the connection status - Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); + if (mRequestingLocationUpdates) { + startLocationUpdates(); } - ... - /* - * Called by Location Services if the connection to the - * location client drops because of an error. - */ - @Override - public void onDisconnected() { - // Display the connection status - Toast.makeText(this, "Disconnected. Please re-connect.", - Toast.LENGTH_SHORT).show(); - } - ... - /* - * Called by Location Services if the attempt to - * Location Services fails. - */ - @Override - public void onConnectionFailed(ConnectionResult connectionResult) { - /* - * Google Play services can resolve some errors it detects. - * If the error has a resolution, try sending an Intent to - * start a Google Play services activity that can resolve - * error. - */ - if (connectionResult.hasResolution()) { - try { - // Start an Activity that tries to resolve the error - connectionResult.startResolutionForResult( - this, - CONNECTION_FAILURE_RESOLUTION_REQUEST); - /* - * Thrown if Google Play services canceled the original - * PendingIntent - */ - } catch (IntentSender.SendIntentException e) { - // Log the error - e.printStackTrace(); - } - } else { - /* - * If no resolution is available, display a dialog to the - * user with the error. - */ - showErrorDialog(connectionResult.getErrorCode()); - } - } - ... +} + +protected void startLocationUpdates() { + LocationServices.FusedLocationApi.requestLocationUpdates( + mGoogleApiClient, mLocationRequest, this); } </pre> -<h3>Define the location update callback</h3> -<p> - Location Services sends location updates to your app either as an {@link android.content.Intent} - or as an argument passed to a callback method you define. This lesson shows you how to get the - update using a callback method, because that pattern works best for most use cases. If you want - to receive updates in the form of an {@link android.content.Intent}, read the lesson - <a href="activity-recognition.html">Recognizing the User's Current Activity</a>, which - presents a similar pattern. -</p> -<p> - The callback method that Location Services invokes to send a location update to your app is - specified in the -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">LocationListener</a></code> - interface, in the method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">onLocationChanged()</a></code>. - The incoming argument is a {@link android.location.Location} object containing the location's - latitude and longitude. The following snippet shows how to specify the interface and define - the method: -</p> + +<p>Notice that the above code snippet refers to a boolean flag, + {@code mRequestingLocationUpdates}, used to track whether the user has + turned location updates on or off. For more about retaining the value of this + flag across instances of the activity, see + <a href="#save-state">Save the State of the Activity</a>. + +<h2 id="callback">Define the Location Update Callback</h2> + +<p>The fused location provider invokes the + <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html#onLocationChanged(android.location.Location)">{@code LocationListener.onLocationChanged()}</a> + callback method. The incoming argument is a {@link android.location.Location} + object containing the location's latitude and longitude. The following snippet + shows how to implement the + <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a> + interface and define the method, then get the timestamp of the location update + and display the latitude, longitude and timestamp on your app's user + interface:</p> + <pre> -public class MainActivity extends FragmentActivity implements - GooglePlayServicesClient.ConnectionCallbacks, - GooglePlayServicesClient.OnConnectionFailedListener, - LocationListener { +public class MainActivity extends ActionBarActivity implements + ConnectionCallbacks, OnConnectionFailedListener, LocationListener { ... - // Define the callback method that receives location updates @Override public void onLocationChanged(Location location) { - // Report to the UI that the location was updated - String msg = "Updated Location: " + - Double.toString(location.getLatitude()) + "," + - Double.toString(location.getLongitude()); - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + mCurrentLocation = location; + mLastUpdateTime = DateFormat.getTimeInstance().format(new Date()); + updateUI(); + } + + private void updateUI() { + mLatitudeTextView.setText(String.valueOf(mCurrentLocation.getLatitude())); + mLongitudeTextView.setText(String.valueOf(mCurrentLocation.getLongitude())); + mLastUpdateTimeTextView.setText(mLastUpdateTime); } - ... } </pre> -<p> - Now that you have the callbacks prepared, you can set up the request for location updates. - The first step is to specify the parameters that control the updates. -</p> -<!-- Specify update parameters --> -<h2 id="UpdateParameters">Specify Update Parameters</h2> -<p> - Location Services allows you to control the interval between updates and the location accuracy - you want, by setting the values in a -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html">LocationRequest</a></code> - object and then sending this object as part of your request to start updates. -</p> -<p> - First, set the following interval parameters: -</p> -<dl> - <dt> - Update interval - </dt> - <dd> - Set by -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>. - This method sets the rate in milliseconds at which your app prefers to receive location - updates. If no other apps are receiving updates from Location Services, your app will - receive updates at this rate. - </dd> - <dt> - Fastest update interval - </dt> - <dd> - Set by -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>. - This method sets the <b>fastest</b> 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. Location Services sends out updates at the fastest rate that any - app requested by calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>. - If this rate is faster than your app can handle, you may encounter problems with UI flicker - or data overflow. To prevent this, call -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code> - to set an upper limit to the update rate. - <p> - Calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code> - also helps to save power. When you request a preferred update rate by calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>, - and a maximum rate by calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">LocationRequest.setFastestInterval()</a></code>, - then your app gets the same update rate as the fastest rate in the system. If other - apps have requested a faster rate, you get the benefit of a faster rate. If no other - apps have a faster rate request outstanding, your app receives updates at the rate you specified - with -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">LocationRequest.setInterval()</a></code>. - </p> - </dd> -</dl> -<p> - Next, set the accuracy parameter. In a foreground app, you need constant location updates with - high accuracy, so use the setting -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#PRIORITY_HIGH_ACCURACY">LocationRequest.PRIORITY_HIGH_ACCURACY</a></code>. -</p> -<p> - The following snippet shows how to set the update interval and accuracy in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}: -</p> + +<h2 id="stop-updates">Stop Location Updates</h2> + +<p>Consider whether you want to stop the location updates when the activity is + no longer in focus, such as when the user switches to another app or to a + different activity in the same app. This can be handy to reduce power + consumption, provided the app doesn't need to collect information even when + it's running in the background. This section shows how you can stop the + updates in the activity's + {@link android.app.Activity#onPause onPause()} method.</p> + +<p>To stop location updates, call + <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)">{@code removeLocationUpdates()}</a>, + passing it your instance of the + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a> + object and a + <a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code LocationListener}</a>, + as shown in the following code sample:</p> + <pre> -public class MainActivity extends FragmentActivity implements - GooglePlayServicesClient.ConnectionCallbacks, - GooglePlayServicesClient.OnConnectionFailedListener, - LocationListener { - ... - // Global constants - ... - // Milliseconds per second - private static final int MILLISECONDS_PER_SECOND = 1000; - // Update frequency in seconds - public static final int UPDATE_INTERVAL_IN_SECONDS = 5; - // Update frequency in milliseconds - private static final long UPDATE_INTERVAL = - MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS; - // The fastest update frequency, in seconds - private static final int FASTEST_INTERVAL_IN_SECONDS = 1; - // A fast frequency ceiling in milliseconds - private static final long FASTEST_INTERVAL = - MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS; - ... - // Define an object that holds accuracy and frequency parameters - LocationRequest mLocationRequest; - ... - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // Create the LocationRequest object - mLocationRequest = LocationRequest.create(); - // Use high accuracy - mLocationRequest.setPriority( - LocationRequest.PRIORITY_HIGH_ACCURACY); - // Set the update interval to 5 seconds - mLocationRequest.setInterval(UPDATE_INTERVAL); - // Set the fastest update interval to 1 second - mLocationRequest.setFastestInterval(FASTEST_INTERVAL); - ... - } - ... +@Override +protected void onPause() { + super.onPause(); + stopLocationUpdates(); +} + +protected void stopLocationUpdates() { + LocationServices.FusedLocationApi.removeLocationUpdates( + mGoogleApiClient, this); } </pre> -<p class="note"> - <strong>Note:</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 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> -<!-- Start Location Updates --> -<h2 id="StartUpdates">Start Location Updates</h2> -<p> - To send the request for location updates, create a location client in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}, then connect it and make - the request by calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">requestLocationUpdates()</a></code>. - Since your client must be connected for your app to receive updates, you should - connect the client in - {@link android.support.v4.app.FragmentActivity#onStart onStart()}. This ensures that you always - have a valid, connected client while your app is visible. Since you need a connection before you - can request updates, make the update request in -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">ConnectionCallbacks.onConnected()</a></code> -</p> -<p> - Remember that the user may want to turn off location updates for various reasons. You should - provide a way for the user to do this, and you should ensure that you don't start updates in - {@link android.support.v4.app.FragmentActivity#onStart onStart()} if updates were previously - turned off. To track the user's preference, store it in your app's - {@link android.content.SharedPreferences} in - {@link android.support.v4.app.FragmentActivity#onPause onPause()} and retrieve it in - {@link android.support.v4.app.FragmentActivity#onResume onResume()}. -</p> -<p> - The following snippet shows how to set up the client in - {@link android.support.v4.app.FragmentActivity#onCreate onCreate()}, and how to connect it - and request updates in {@link android.support.v4.app.FragmentActivity#onStart onStart()}: -</p> + +<p>Use a boolean, {@code mRequestingLocationUpdates}, to track + whether location updates are currently turned on. In the activity's + {@link android.app.Activity#onResume onResume()} method, check + whether location updates are currently active, and activate them if not:</p> + <pre> -public class MainActivity extends FragmentActivity implements - GooglePlayServicesClient.ConnectionCallbacks, - GooglePlayServicesClient.OnConnectionFailedListener, - LocationListener { - ... - // Global variables - ... - LocationClient mLocationClient; - boolean mUpdatesRequested; - ... - @Override - protected void onCreate(Bundle savedInstanceState) { - ... - // Open the shared preferences - mPrefs = getSharedPreferences("SharedPreferences", - Context.MODE_PRIVATE); - // Get a SharedPreferences editor - mEditor = mPrefs.edit(); - /* - * Create a new location client, using the enclosing class to - * handle callbacks. - */ - mLocationClient = new LocationClient(this, this, this); - // Start with updates turned off - mUpdatesRequested = false; - ... - } - ... - @Override - protected void onPause() { - // Save the current setting for updates - mEditor.putBoolean("KEY_UPDATES_ON", mUpdatesRequested); - mEditor.commit(); - super.onPause(); - } - ... - @Override - protected void onStart() { - ... - mLocationClient.connect(); +@Override +public void onResume() { + super.onResume(); + if (mGoogleApiClient.isConnected() && !mRequestingLocationUpdates) { + startLocationUpdates(); } - ... - @Override - protected void onResume() { - /* - * Get any previous setting for location updates - * Gets "false" if an error occurs - */ - if (mPrefs.contains("KEY_UPDATES_ON")) { - mUpdatesRequested = - mPrefs.getBoolean("KEY_UPDATES_ON", false); - - // Otherwise, turn off location updates - } else { - mEditor.putBoolean("KEY_UPDATES_ON", false); - mEditor.commit(); - } - } - ... - /* - * Called by Location Services when the request to connect the - * client finishes successfully. At this point, you can - * request the current location or start periodic updates - */ - @Override - public void onConnected(Bundle dataBundle) { - // Display the connection status - Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show(); - // If already requested, start periodic updates - if (mUpdatesRequested) { - mLocationClient.requestLocationUpdates(mLocationRequest, this); - } - } - ... } </pre> -<p> - For more information about saving preferences, read -<a href="{@docRoot}training/basics/data-storage/shared-preferences.html">Saving Key-Value Sets</a>. -</p> -<!-- - Stop Location Updates - --> -<h2 id="StopUpdates">Stop Location Updates</h2> -<p> - To stop location updates, save the state of the update flag in - {@link android.support.v4.app.FragmentActivity#onPause onPause()}, and stop updates in - {@link android.support.v4.app.FragmentActivity#onStop onStop()} by calling -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#removeLocationUpdates(com.google.android.gms.location.LocationListener)">removeLocationUpdates(LocationListener)</a></code>. - For example: -</p> + +<h2 id="save-state">Save the State of the Activity</h2> + +<p>A change to the device's configuration, such as a change in screen + orientation or language, can cause the current activity to be destroyed. Your + app must therefore store any information it needs to recreate the activity. + One way to do this is via an instance state stored in a + {@link android.os.Bundle} object.</p> + +<p>The following code sample shows how to use the activity's + <a href="{@docRoot}reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)">{@code onSaveInstanceState()}</a> + callback to save the instance state:</p> + <pre> -public class MainActivity extends FragmentActivity implements - GooglePlayServicesClient.ConnectionCallbacks, - GooglePlayServicesClient.OnConnectionFailedListener, - LocationListener { +public void onSaveInstanceState(Bundle savedInstanceState) { + savedInstanceState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, + mRequestingLocationUpdates); + savedInstanceState.putParcelable(LOCATION_KEY, mCurrentLocation); + savedInstanceState.putString(LAST_UPDATED_TIME_STRING_KEY, mLastUpdateTime); + super.onSaveInstanceState(savedInstanceState); +} +</pre> + +<p>Define an {@code updateValuesFromBundle()} method to restore + the saved values from the previous instance of the activity, if they're + available. Call the method from the activity's + {@link android.app.Activity#onCreate onCreate()} method, as shown in the + following code sample:</p> + +<pre> +@Override +public void onCreate(Bundle savedInstanceState) { ... - /* - * Called when the Activity is no longer visible at all. - * Stop updates and disconnect. - */ - @Override - protected void onStop() { - // If the client is connected - if (mLocationClient.isConnected()) { - /* - * Remove location updates for a listener. - * The current Activity is the listener, so - * the argument is "this". - */ - removeLocationUpdates(this); + updateValuesFromBundle(savedInstanceState); +} + +private void updateValuesFromBundle(Bundle savedInstanceState) { + if (savedInstanceState != null) { + // Update the value of mRequestingLocationUpdates from the Bundle, and + // make sure that the Start Updates and Stop Updates buttons are + // correctly enabled or disabled. + if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { + mRequestingLocationUpdates = savedInstanceState.getBoolean( + REQUESTING_LOCATION_UPDATES_KEY); + setButtonsEnabledState(); + } + + // Update the value of mCurrentLocation from the Bundle and update the + // UI to show the correct latitude and longitude. + if (savedInstanceState.keySet().contains(LOCATION_KEY)) { + // Since LOCATION_KEY was found in the Bundle, we can be sure that + // mCurrentLocationis not null. + mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY); + } + + // Update the value of mLastUpdateTime from the Bundle and update the UI. + if (savedInstanceState.keySet().contains(LAST_UPDATED_TIME_STRING_KEY)) { + mLastUpdateTime = savedInstanceState.getString( + LAST_UPDATED_TIME_STRING_KEY); } - /* - * After disconnect() is called, the client is - * considered "dead". - */ - mLocationClient.disconnect(); - super.onStop(); + updateUI(); } - ... } </pre> -<p> - You now have the basic structure of an app that requests and receives periodic location updates. - You can combine the features described in this lesson with the geofencing, activity recognition, - or reverse geocoding features described in other lessons in this class. -</p> -<p> - The next lesson, <a href="display-address.html">Displaying a Location Address</a>, shows you how - to use the current location to display the current street address. -</p> + +<p>For more about saving instance state, see the + <a href="{@docRoot}reference/android/app/Activity.html#ConfigurationChanges">Android + Activity</a> class reference.</p> + +<p class="note"><strong>Note:</strong> For a more persistent storage, you can + store the user's preferences in your app's + {@link android.content.SharedPreferences}. Set the shared preference in + your activity's {@link android.app.Activity#onPause onPause()} method, and + retrieve the preference in {@link android.app.Activity#onResume onResume()}. + For more information about saving preferences, read + <a href="{@docRoot}training/basics/data-storage/shared-preferences.html">Saving + Key-Value Sets</a>.</p> + +<p>The next lesson, + <a href="display-address.html">Displaying a Location Address</a>, shows + you how to display the street address for a given location.</p> diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd index fd21e3d..820a004 100644 --- a/docs/html/training/material/drawables.jd +++ b/docs/html/training/material/drawables.jd @@ -83,6 +83,16 @@ class.</p> <h2 id="VectorDrawables">Create Vector Drawables</h2> +<!-- video box --> +<a class="notice-developers-video" + href="https://www.youtube.com/watch?v=wlFVIIstKmA" + style="margin-top:18px"> +<div> + <h3>Video</h3> + <p>Android Vector Graphics</p> +</div> +</a> + <p>In Android 5.0 (API Level 21) and above, you can define vector drawables, which scale without losing definition. You need only one asset file for a vector image, as opposed to an asset file for each screen density in the case of bitmap images. To create a vector image, you define the details diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 2489b91..00eca7c 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -891,25 +891,30 @@ include the action bar on devices running Android 2.1 or higher." <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/tv/start/index.html" + ja-lang="TV アプリのビルド" description="How to start building TV apps or extend your existing app to run on TV devices."> Building TV Apps</a> </div> <ul> <li> - <a href="<?cs var:toroot ?>training/tv/start/start.html"> + <a href="<?cs var:toroot ?>training/tv/start/start.html" + ja-lang="TV アプリのビルドを開始する"> Getting Started with TV Apps</a> </li> <li> - <a href="<?cs var:toroot ?>training/tv/start/hardware.html"> + <a href="<?cs var:toroot ?>training/tv/start/hardware.html" + ja-lang="TV ハードウェアを処理する"> Handling TV Hardware</a> </li> <li> - <a href="<?cs var:toroot ?>training/tv/start/layouts.html"> + <a href="<?cs var:toroot ?>training/tv/start/layouts.html" + ja-lang="TV 向けレイアウトをビルドする"> Building TV Layouts</a> </li> <li> - <a href="<?cs var:toroot ?>training/tv/start/navigation.html"> + <a href="<?cs var:toroot ?>training/tv/start/navigation.html" + ja-lang="TV 用のナビゲーションを作成する"> Creating TV Navigation</a> </li> </ul> @@ -918,20 +923,24 @@ include the action bar on devices running Android 2.1 or higher." <li class="nav-section"> <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/tv/playback/index.html" + ja-lang="TV 再生アプリのビルド" description="How to build apps that provide media catalogs and play content."> Building TV Playback Apps</a> </div> <ul> <li> - <a href="<?cs var:toroot ?>training/tv/playback/browse.html"> + <a href="<?cs var:toroot ?>training/tv/playback/browse.html" + ja-lang="カタログ ブラウザを作成する"> Creating a Catalog Browser</a> </li> <li> - <a href="<?cs var:toroot ?>training/tv/playback/details.html"> + <a href="<?cs var:toroot ?>training/tv/playback/details.html" + ja-lang="詳細ビューをビルドする"> Building a Details View</a> </li> <li> - <a href="<?cs var:toroot ?>training/tv/playback/now-playing.html"> + <a href="<?cs var:toroot ?>training/tv/playback/now-playing.html" + ja-lang="再生中カードを表示する"> Displaying a Now Playing Card</a> </li> </ul> @@ -949,6 +958,9 @@ include the action bar on devices running Android 2.1 or higher." Recommending TV Content</a> </li> <li> + <a href="<?cs var:toroot ?>training/tv/discovery/searchable.html"> + Making TV Apps Searchable</a> + <li> <a href="<?cs var:toroot ?>training/tv/discovery/in-app-search.html"> Searching within TV Apps</a> </li> @@ -1713,6 +1725,10 @@ results." Enhancing Security with Device Management Policies </a> </li> + <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html"> + Ensuring Compatibility with Managed Profiles + </a> + </li> </ul> </li> </ul> diff --git a/docs/html/training/tv/discovery/recommendations.jd b/docs/html/training/tv/discovery/recommendations.jd index 0f6d256..d348c14 100644 --- a/docs/html/training/tv/discovery/recommendations.jd +++ b/docs/html/training/tv/discovery/recommendations.jd @@ -14,6 +14,11 @@ trainingnavtop=true <li><a href="#build">Build Recommendations</a></li> <li><a href="#run-service">Run Recommendations Service</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> @@ -25,7 +30,7 @@ trainingnavtop=true <p> The Android framework assists with minimum-input interaction by providing a recommendations row - on the home screen. Content recommendations appear as the first row of the TV launch screen after + on the home screen. Content recommendations appear as the first row of the TV home screen after the first use of the device. Contributing recommendations from your app's content catalog can help bring users back to your app. </p> @@ -37,7 +42,9 @@ trainingnavtop=true <p> This lesson teaches you how to create recommendations and provide them to the Android framework - so your app content can be easily discovered and enjoyed by users. + so users can easily discover and enjoy your app content. This discussion describes some code from + the <a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android + Leanback sample app</a>. </p> @@ -46,7 +53,7 @@ trainingnavtop=true <p> Content recommendations are created with background processing. In order for your application to contribute to recommendations, create a service that periodically adds listings from your - app's catalog to the system list of recommendations. + app's catalog to the system's list of recommendations. </p> <p> @@ -54,26 +61,50 @@ trainingnavtop=true create a recommendation service for your application: </p> + +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/UpdateRecommendationsService.java" target="_blank"> + UpdateRecommendationsService.java</a> +</p> <pre> -public class RecommendationsService extends IntentService { +public class UpdateRecommendationsService extends IntentService { + private static final String TAG = "UpdateRecommendationsService"; private static final int MAX_RECOMMENDATIONS = 3; - public RecommendationsService() { + public UpdateRecommendationsService() { super("RecommendationService"); } @Override protected void onHandleIntent(Intent intent) { - MovieDatabase database = MovieDatabase.instance(getApplicationContext()); - List<Movie> recommendations = database.recommendations(); + Log.d(TAG, "Updating recommendation cards"); + HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList(); + if (recommendations == null) return; int count = 0; try { - for (Movie movie : recommendations) { - // build the individual content recommendations - buildRecommendation(getApplicationContext(), movie); - + RecommendationBuilder builder = new RecommendationBuilder() + .setContext(getApplicationContext()) + .setSmallIcon(R.drawable.videos_by_google_icon); + + for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) { + for (Movie movie : entry.getValue()) { + Log.d(TAG, "Recommendation - " + movie.getTitle()); + + builder.setBackground(movie.getCardImageUrl()) + .setId(count + 1) + .setPriority(MAX_RECOMMENDATIONS - count) + .setTitle(movie.getTitle()) + .setDescription(getString(R.string.popular_header)) + .setImage(movie.getCardImageUrl()) + .setIntent(buildPendingIntent(movie)) + .build(); + + if (++count >= MAX_RECOMMENDATIONS) { + break; + } + } if (++count >= MAX_RECOMMENDATIONS) { break; } @@ -82,6 +113,21 @@ public class RecommendationsService extends IntentService { Log.e(TAG, "Unable to update recommendation", e); } } + + private PendingIntent buildPendingIntent(Movie movie) { + Intent detailsIntent = new Intent(this, DetailsActivity.class); + detailsIntent.putExtra("Movie", movie); + + TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); + stackBuilder.addParentStack(DetailsActivity.class); + stackBuilder.addNextIntent(detailsIntent); + // Ensure a unique PendingIntents, otherwise all recommendations end up with the same + // PendingIntent + detailsIntent.setAction(Long.toString(movie.getId())); + + PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + return intent; + } } </pre> @@ -90,125 +136,165 @@ public class RecommendationsService extends IntentService { app manifest. The following code snippet illustrates how to declare this class as a service: </p> +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank"> + AndroidManifest.xml</a> +</p> <pre> <manifest ... > <application ... > ... - <service android:name=".RecommendationsService" - android:enabled="true" android:exported="true"/> + <service + android:name="com.example.android.tvleanback.UpdateRecommendationsService" + android:enabled="true" /> </application> </manifest> </pre> +<h3 id="refreshing">Refreshing Recommendations</h3> + +<p>Base your recommendations on user behavior and data such as play lists, wish lists, and associated +content. When refreshing recommendations, don't just remove and repost them, because doing so causes +the recommendations to appear at the end of the recommendations row. Once a content item, such as a +movie, has been played, <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Removing"> +remove it</a> from the recommendations.</p> <h2 id="build">Build Recommendations</h2> <p> - Once your recommendation server starts running, it must create recommendations and pass them to + Once your recommendation service starts running, it must create recommendations and pass them to the Android framework. The framework receives the recommendations as {@link android.app.Notification} objects that use a specific template and are marked with a specific category. </p> -<p> - The following code example demonstrates how to get an instance of the {@link - android.app.NotificationManager}, build a recommendation, and post it to the manager: -</p> +<h3 id="setting-ui">Setting the Values</h3> -<pre> -public class RecommendationsService extends IntentService { +<p>To set the UI element values for the recommendation card, you create a builder class that follows +the builder pattern described as follows. First, you set the values of the recommendation card +elements.</p> +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/RecommendationBuilder.java" target="_blank"> + RecommendationBuilder.java</a> +</p> +<pre> +public class RecommendationBuilder { ... - public Notification buildRecommendation(Context context, Movie movie) - throws IOException { + public RecommendationBuilder setTitle(String title) { + mTitle = title; + return this; + } + + public RecommendationBuilder setDescription(String description) { + mDescription = description; + return this; + } - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); + public RecommendationBuilder setImage(String uri) { + mImageUri = uri; + return this; } - Bundle extras = new Bundle(); - if (mBackgroundUri != movie.getBackgroundUri()) { - extras.putString(EXTRA_BACKGROUND_IMAGE_URL, movie.getBackgroundUri()); + public RecommendationBuilder setBackground(String uri) { + mBackgroundUri = uri; + return this; } +... +</pre> + +<h3 id="create-notification">Creating the Notification</h3> + +<p> + Once you've set the values, you then build the notification, assigning the values from the builder + class to the notification, and calling {@link android.support.v4.app.NotificationCompat.Builder#build() + NotificationCompat.Builder.build()}. +</p> + +<p> + Also, be sure to call + {@link android.support.v4.app.NotificationCompat.Builder#setLocalOnly(boolean) setLocalOnly()} + so the {@link android.support.v4.app.NotificationCompat.BigPictureStyle} notification won't show up + on other devices. +</p> + +<p> + The following code example demonstrates how to build a recommendation, and post it to the manager. +</p> + +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/RecommendationBuilder.java" target="_blank"> + RecommendationBuilder.java</a> +</p> +<pre> +public class RecommendationBuilder { + ... + + public Notification build() throws IOException { + ... - // build the recommendation as a Notification object Notification notification = new NotificationCompat.BigPictureStyle( - new NotificationCompat.Builder(context) - .setContentTitle(movie.getTitle()) - .setContentText(movie.getDescription()) - .setContentInfo(APP_NAME) - .setGroup("ActionMovies") - .setSortKey("0.8") - .setPriority(movie.getPriority()) - .setColor(#FFFF2020) - .setCategory("recommendation") - .setLargeIcon(movie.getImage()) - .setSmallIcon(movie.getSmallIcon()) - .setContentIntent(buildPendingIntent(movie.getId())) + new NotificationCompat.Builder(mContext) + .setContentTitle(mTitle) + .setContentText(mDescription) + .setPriority(mPriority) + .setLocalOnly(true) + .setOngoing(true) + .setColor(mContext.getResources().getColor(R.color.fastlane_background)) + .setCategory(Notification.CATEGORY_RECOMMENDATION) + .setLargeIcon(image) + .setSmallIcon(mSmallIcon) + .setContentIntent(mIntent) .setExtras(extras)) .build(); - // post the recommendation to the NotificationManager - mNotificationManager.notify(movie.getId(), notification); + mNotificationManager.notify(mId, notification); mNotificationManager = null; return notification; } - - private PendingIntent buildPendingIntent(long id) { - Intent detailsIntent = new Intent(this, DetailsActivity.class); - detailsIntent.putExtra("id", id); - - TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); - stackBuilder.addParentStack(DetailsActivity.class); - stackBuilder.addNextIntent(detailsIntent); - // Ensure each PendingIntent is unique - detailsIntent.setAction(Long.toString(id)); - - PendingIntent intent = stackBuilder.getPendingIntent( - 0, PendingIntent.FLAG_UPDATE_CURRENT); - return intent; - } } </pre> - -<h3 id="run-service">Run Recommendations Service</h3> +<h2 id="run-service">Run Recommendations Service</h3> <p> Your app's recommendation service must run periodically in order to create current recommendations. To run your service, create a class that runs a timer and invokes it at regular intervals. The following code example extends the {@link android.content.BroadcastReceiver} class to start periodic execution of a recommendation service - every 12 hours: + every half hour: </p> +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/BootupActivity.java" target="_blank"> + BootupActivity.java</a> +</p> <pre> -public class BootupReceiver extends BroadcastReceiver { +public class BootupActivity extends BroadcastReceiver { private static final String TAG = "BootupActivity"; private static final long INITIAL_DELAY = 5000; @Override public void onReceive(Context context, Intent intent) { + Log.d(TAG, "BootupActivity initiated"); if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) { scheduleRecommendationUpdate(context); } } private void scheduleRecommendationUpdate(Context context) { - AlarmManager alarmManager = (AlarmManager)context.getSystemService( - Context.ALARM_SERVICE); - Intent recommendationIntent = new Intent(context, - UpdateRecommendationsService.class); - PendingIntent alarmIntent = PendingIntent.getService(context, 0, - recommendationIntent, 0); + Log.d(TAG, "Scheduling recommendations update"); + + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class); + PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0); alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, INITIAL_DELAY, - AlarmManager.INTERVAL_HALF_DAY, + AlarmManager.INTERVAL_HALF_HOUR, alarmIntent); } } @@ -221,10 +307,15 @@ public class BootupReceiver extends BroadcastReceiver { following sample code demonstrates how to add this configuration to the manifest: </p> +<p class="code-caption"> + <a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank"> + AndroidManifest.xml</a> +</p> <pre> <manifest ... > <application ... > - <receiver android:name=".BootupReceiver" android:enabled="true" + <receiver android:name="com.example.android.tvleanback.BootupActivity" + android:enabled="true" android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> @@ -234,7 +325,7 @@ public class BootupReceiver extends BroadcastReceiver { </manifest> </pre> -<p class="important"> +<p class="note"> <strong>Important:</strong> Receiving a boot completed notification requires that your app requests the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. For more information, see {@link android.content.Intent#ACTION_BOOT_COMPLETED}. diff --git a/docs/html/training/tv/discovery/searchable.jd b/docs/html/training/tv/discovery/searchable.jd new file mode 100644 index 0000000..5d3b9e3 --- /dev/null +++ b/docs/html/training/tv/discovery/searchable.jd @@ -0,0 +1,383 @@ +page.title=Making TV Apps Searchable +page.tags="search","searchable" + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + <h2>This lesson teaches you to</h2> + <ol> + <li><a href="#columns">Identify Columns</a></li> + <li><a href="#provide">Provide Search Suggestion Data</a></li> + <li><a href="#suggestions">Handle Search Suggestions</a></li> + <li><a href="#terms">Handle Search Terms</a></li> + <li><a href="#details">Deep Link to Your App in the Details Screen</a></li> + </ol> + <h2>You should also read</h2> + <ul> + <li><a href="{@docRoot}guide/topics/search/index.html">Search</a></li> + <li><a href="{@docRoot}training/search/index.html">Adding Search Functionality</a></li> + </ul> + <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>Android TV uses the Android <a href="{@docRoot}guide/topics/search/index.html">search interface</a> +to retrieve content data from installed apps and deliver search results to the user. Your app's +content data can be included with these results, to give the user instant access to the content in +your app.</p> + +<p>Your app must provide Android TV with the data fields from which it generates suggested search +results as the user enters characters in the search dialog. To do that, your app must implement a +<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> that serves +up the suggestions along with a <a href="{@docRoot}guide/topics/search/searchable-config.html"> +{@code searchable.xml}</a> configuration file that describes the content +provider and other vital information for Android TV. You also need an activity that handles the +intent that fires when the user selects a suggested search result. All of this is described in +more detail in <a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html">Adding Custom +Suggestions</a>. Here are described the main points for Android TV apps.</p> + +<p>This lesson builds on your knowledge of using search in Android to show you how to make your app +searchable in Android TV. Be sure you are familiar with the concepts explained in the +<a href="{@docRoot}guide/topics/search/index.html">Search API guide</a> before following this lesson. +See also the training <a href="{@docRoot}training/search/index.html">Adding Search Functionality</a>.</p> + +<p>This discussion describes some code from the +<a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android Leanback sample app</a>, +available on GitHub.</p> + +<h2 id="columns">Identify Columns</h2> + +<p>The {@link android.app.SearchManager} describes the data fields it expects by representing them as +columns of an SQLite database. Regardless of your data's format, you must map your data fields to +these columns, usually in the class that accessess your content data. For information about building +a class that maps your existing data to the required fields, see +<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#SuggestionTable"> +Building a suggestion table</a>.</p> + +<p>The {@link android.app.SearchManager} class includes several columns for Android TV. Some of the +more important columns are described below.</p> + +<table> +<tr> + <th>Value</th> + <th>Description</th> +</tr><tr> + <td>{@code SUGGEST_COLUMN_TEXT_1}</td> + <td>The name of your content <strong>(required)</strong></td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_TEXT_2}</td> + <td>A text description of your content</td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_RESULT_CARD_IMAGE}</td> + <td>An image/poster/cover for your content</td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_CONTENT_TYPE}</td> + <td>The MIME type of your media <strong>(required)</strong></td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_VIDEO_WIDTH}</td> + <td>The resolution width of your media</td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_VIDEO_HEIGHT}</td> + <td>The resolution height of your media</td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_PRODUCTION_YEAR}</td> + <td>The production year of your content <strong>(required)</strong></td> +</tr><tr> + <td>{@code SUGGEST_COLUMN_DURATION}</td> + <td>The duration in milliseconds of your media</td> +</tr> +</table> + +<p>The search framework requires the following columns:</p> +<ul> + <li>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</li> + <li>{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}</li> + <li>{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR}</li> +</ul> + +<p>When the values of these columns for your content match the values for the same content from other +providers found by Google servers, the system provides a +<a href="{@docRoot}training/app-indexing/deep-linking.html">deep link</a> to your app in the details +view for the content, along with links to the apps of other providers. This is discussed more in +<a href="#details">Display Content in the Details Screen</a>, below.</p> + +<p>Your application's database class might define the columns as follows:</p> + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoDatabase.java#L41" target="_blank"> +VideoDatabase.java</a></p> +<pre> +public class VideoDatabase { + //The columns we'll include in the video database table + public static final String KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1; + public static final String KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2; + public static final String KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE; + public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE; + public static final String KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE; + public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH; + public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT; + public static final String KEY_AUDIO_CHANNEL_CONFIG = + SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG; + public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE; + public static final String KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE; + public static final String KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE; + public static final String KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE; + public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR; + public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION; + public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION; +... +</pre> + +<p>When you build the map from the {@link android.app.SearchManager} columns to your data fields, you +must also specify the {@link android.provider.BaseColumns#_ID} to give each row a unique ID.</p> + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoDatabase.java#L83" target="_blank"> +VideoDatabase.java</a></p> +<pre> +... + private static HashMap<String, String> buildColumnMap() { + HashMap<String, String> map = new HashMap<String, String>(); + map.put(KEY_NAME, KEY_NAME); + map.put(KEY_DESCRIPTION, KEY_DESCRIPTION); + map.put(KEY_ICON, KEY_ICON); + map.put(KEY_DATA_TYPE, KEY_DATA_TYPE); + map.put(KEY_IS_LIVE, KEY_IS_LIVE); + map.put(KEY_VIDEO_WIDTH, KEY_VIDEO_WIDTH); + map.put(KEY_VIDEO_HEIGHT, KEY_VIDEO_HEIGHT); + map.put(KEY_AUDIO_CHANNEL_CONFIG, KEY_AUDIO_CHANNEL_CONFIG); + map.put(KEY_PURCHASE_PRICE, KEY_PURCHASE_PRICE); + map.put(KEY_RENTAL_PRICE, KEY_RENTAL_PRICE); + map.put(KEY_RATING_STYLE, KEY_RATING_STYLE); + map.put(KEY_RATING_SCORE, KEY_RATING_SCORE); + map.put(KEY_PRODUCTION_YEAR, KEY_PRODUCTION_YEAR); + map.put(KEY_COLUMN_DURATION, KEY_COLUMN_DURATION); + map.put(KEY_ACTION, KEY_ACTION); + map.put(BaseColumns._ID, "rowid AS " + + BaseColumns._ID); + map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); + map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " + + SearchManager.SUGGEST_COLUMN_SHORTCUT_ID); + return map; + } +... +</pre> + +<p>In the example above, notice the mapping to the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} +field. This is the portion of the URI that points to the content unique to the data in this row — +that is, the last part of the URI describing where the content is stored. The first part of the URI, +when it is common to all of the rows in the table, is set in the +<a href="{@docRoot}guide/topics/search/searchable-config.html"> {@code searchable.xml}</a> file as the +<a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentData"> +{@code android:searchSuggestIntentData}</a> attribute, as described in +<a href="#suggestions">Handle Search Suggestions</a>, below. + +<p>If the first part of the URI is different for each row in the +table, you map that value with the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} field. +When the user selects this content, the intent that fires provides the intent data from the +combination of the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} +and either the {@code android:searchSuggestIntentData} attribute or the +{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} field value.</p> + +<h2 id="provide">Provide Search Suggestion Data</h2> + +<p>Implement a <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> +to return search term suggestions to the Android TV search dialog. The system queries your content +provider for suggestions by calling the {@link android.content.ContentProvider#query(android.net.Uri, +java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()} method each time +a letter is typed. In your implementation of {@link android.content.ContentProvider#query(android.net.Uri, +java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()}, your content +provider searches your suggestion data and returns a {@link android.database.Cursor} that points to +the rows you have designated for suggestions.</p> + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/java/com/example/android/tvleanback/VideoContentProvider.java" target="_blank"> +VideoContentProvider.java</a></p> +<pre> +@Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + // Use the UriMatcher to see what kind of query we have and format the db query accordingly + switch (URI_MATCHER.match(uri)) { + case SEARCH_SUGGEST: + Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri); + if (selectionArgs == null) { + throw new IllegalArgumentException( + "selectionArgs must be provided for the Uri: " + uri); + } + return getSuggestions(selectionArgs[0]); + default: + throw new IllegalArgumentException("Unknown Uri: " + uri); + } + } + + private Cursor getSuggestions(String query) { + query = query.toLowerCase(); + String[] columns = new String[]{ + BaseColumns._ID, + VideoDatabase.KEY_NAME, + VideoDatabase.KEY_DESCRIPTION, + VideoDatabase.KEY_ICON, + VideoDatabase.KEY_DATA_TYPE, + VideoDatabase.KEY_IS_LIVE, + VideoDatabase.KEY_VIDEO_WIDTH, + VideoDatabase.KEY_VIDEO_HEIGHT, + VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG, + VideoDatabase.KEY_PURCHASE_PRICE, + VideoDatabase.KEY_RENTAL_PRICE, + VideoDatabase.KEY_RATING_STYLE, + VideoDatabase.KEY_RATING_SCORE, + VideoDatabase.KEY_PRODUCTION_YEAR, + VideoDatabase.KEY_COLUMN_DURATION, + VideoDatabase.KEY_ACTION, + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID + }; + return mVideoDatabase.getWordMatch(query, columns); + } +... +</pre> + +<p>In your manifest file, the content provider receives special treatment. Rather than getting +tagged as an activity, it is described as a +<a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>}</a>. The +provider includes the {@code android:searchSuggestAuthority} attribute to tell the system the +namespace of your content provider. Also, you must set its {@code android:exported} attribute to +{@code "true"} so that the Android global search can use the results returned from it.</p> + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank"> +AndroidManifest.xml</a></p> +<pre> +<provider android:name="com.example.android.tvleanback.VideoContentProvider" + android:authorities="com.example.android.tvleanback" + android:exported="true" /> +</pre> + +<h2 id="suggestions">Handle Search Suggestions</h2> + +<p>Your app must include a <a href="{@docRoot}guide/topics/search/searchable-config.html"> +{@code res/xml/searchable.xml}</a> file to configure the search suggestions settings. It inlcudes +the <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestAuthority"> +{@code android:searchSuggestAuthority}</a> attribute to tell the system the namespace of your +content provider. This must match the string value you specify in the +<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code android:authorities}</a> +attribute of the <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>} +</a> element in your {@code AndroidManifest.xml} file.</p> + +The <a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file +must also include the <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentAction"> +{@code android:searchSuggestIntentAction}</a> with the value {@code "android.intent.action.VIEW"} +to define the intent action for providing a custom suggestion. This is different from the intent +action for providing a search term, explained below. See also, +<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#IntentAction">Declaring the +intent action</a> for other ways to declare the intent action for suggestions.</p> + +<p>Along with the intent action, your app must provide the intent data, which you specify with the +<a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentData"> +{@code android:searchSuggestIntentData}</a> attribute. This is the first part of the URI that points +to the content. It describes the portion of the URI common to all rows in the mapping table for that +content. The portion of the URI that is unique to each row is established with the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} field, +as described above in <a href="#columns">Identify Columns</a>. See also, +<a href="{@docRoot}guide/topics/search/adding-custom-suggestions.html#IntentData"> +Declaring the intent data</a> for other ways to declare the intent data for suggestions.</p> + +<p>Also, note the {@code android:searchSuggestSelection=" ?"} attribute which specifies the value passed +as the {@code selection} parameter of the {@link android.content.ContentProvider#query(android.net.Uri, +java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) query()} method where the +question mark ({@code ?}) value is replaced with the query text.</p> + +<p>Finally, you must also include the <a href="{@docRoot}guide/topics/search/searchable-config.html#includeInGlobalSearch"> +{@code android:includeInGlobalSearch}</a> attribute with the value {@code "true"}. Here is an example +<a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> +file:</p> + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/res/xml/searchable.xml" target="_blank"> +Searchable.xml</a></p> +<pre> +<searchable xmlns:android="http://schemas.android.com/apk/res/android" + android:label="@string/search_label" + android:hint="@string/search_hint" + android:searchSettingsDescription="@string/settings_description" + android:searchSuggestAuthority="com.example.android.tvleanback" + android:searchSuggestIntentAction="android.intent.action.VIEW" + android:searchSuggestIntentData="content://com.example.android.tvleanback/video_database_leanback" + android:searchSuggestSelection=" ?" + android:searchSuggestThreshold="1" + android:includeInGlobalSearch="true" + > +</searchable> +</pre> + +<h2 id="terms">Handle Search Terms</h2> + +<p>As soon as the search dialog has a word which matches the value in one of your app's columns +(described in <a href="#identifying">Identifying Columns</a>, above), the system fires the +{@link android.content.Intent#ACTION_SEARCH} intent. The activity in your app which handles that +intent searches the repository for columns with the given word in their values, and returns a list +of content items with those columns. In your {@code AndroidManifest.xml} file, you designate the +activity which handles the {@link android.content.Intent#ACTION_SEARCH} intent like this: + +<p class="code-caption"><a href="https://github.com/googlesamples/androidtv-Leanback/blob/master/app/src/main/AndroidManifest.xml" target="_blank"> +AndroidManifest.xml</a></p> +<pre> +... + <activity + android:name="com.example.android.tvleanback.DetailsActivity" + android:exported="true"> + + <!-- Receives the search request. --> + <intent-filter> + <action android:name="android.intent.action.SEARCH" /> + <!-- No category needed, because the Intent will specify this class component --> + </intent-filter> + + <!-- Points to searchable meta data. --> + <meta-data android:name="android.app.searchable" + android:resource="@xml/searchable" /> + </activity> +... + <!-- Provides search suggestions for keywords against video meta data. --> + <provider android:name="com.example.android.tvleanback.VideoContentProvider" + android:authorities="com.example.android.tvleanback" + android:exported="true" /> +... +</pre> + +<p>The activity must also describe the searchable configuration with a reference to the +<a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file. +To <a href="{@docRoot}guide/topics/search/search-dialog.html">use the global search dialog</a>, +the manifest must describe which activity should receive search queries. The manifest must also +describe the <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code <provider>} +</a>element, exactly as it is described in the <a href="{@docRoot}guide/topics/search/searchable-config.html"> +{@code searchable.xml}</a> file.</p> + +<h2 id="details">Deep Link to Your App in the Details Screen</h2> + +<p>If you have set up the search configuration as described in <a href="#suggestions">Handle Search +Suggestions</a> and mapped the {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}, +{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}, and +{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR} fields as described in +<a href="#columns">Identify Columns</a>, a <a href="{@docRoot}training/app-indexing/deep-linking.html"> +deep link</a> to your content appears in the details screen that launches when the user selects a +search result.</p> + +<p>When the user selects the link for your app, identified by the "Available On" button in the +details screen, the system launches the activity which handles the {@link android.content.Intent#ACTION_VIEW} +(set as <a href="{@docRoot}guide/topics/search/searchable-config.html#searchSuggestIntentAction"> +{@code android:searchSuggestIntentAction}</a> with the value {@code "android.intent.action.VIEW"} in +the <a href="{@docRoot}guide/topics/search/searchable-config.html">{@code searchable.xml}</a> file).</p> + +<p>You can also set up a custom intent to launch your activity, and this is demonstrated in the +<a class="external-link" href="https://github.com/googlesamples/androidtv-Leanback">Android Leanback +sample app</a>. Note that the sample app launches its own <code>LeanbackDetailsFragment</code> to +show the details for the selected media, but you should launch the activity that plays the media +immediately to save the user another click or two.</p> + + + + + + diff --git a/docs/html/training/wearables/ui/lists.jd b/docs/html/training/wearables/ui/lists.jd index 1d6e8ed..20f8bbd 100644 --- a/docs/html/training/wearables/ui/lists.jd +++ b/docs/html/training/wearables/ui/lists.jd @@ -82,20 +82,21 @@ the list is displayed properly on both round and square devices:</p> <p>In many cases, each list item consists of an icon and a description. The <em>Notifications</em> sample from the Android SDK implements a custom layout that extends {@link android.widget.LinearLayout} to incorporate these two elements inside each list item. -This layout also implements the methods in the <code>WearableListView.Item</code> interface -to animate the item's icon and fade the text in response to events from +This layout also implements the methods in the +<code>WearableListView.OnCenterProximityListener</code> interface +to change the color of the item's icon and fade the text in response to events from <code>WearableListView</code> as the user scrolls through the list.</p> <pre> public class WearableListItemLayout extends LinearLayout - implements WearableListView.Item { + implements WearableListView.OnCenterProximityListener { + + private ImageView mCircle; + private TextView mName; private final float mFadedTextAlpha; private final int mFadedCircleColor; private final int mChosenCircleColor; - private ImageView mCircle; - private float mScale; - private TextView mName; public WearableListItemLayout(Context context) { this(context, null); @@ -108,6 +109,7 @@ public class WearableListItemLayout extends LinearLayout public WearableListItemLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mFadedTextAlpha = getResources() .getInteger(R.integer.action_text_faded_alpha) / 100f; mFadedCircleColor = getResources().getColor(R.color.grey); @@ -124,46 +126,27 @@ public class WearableListItemLayout extends LinearLayout mName = (TextView) findViewById(R.id.name); } - // Provide scaling values for WearableListView animations @Override - public float getProximityMinValue() { - return 1f; - } - - @Override - public float getProximityMaxValue() { - return 1.6f; - } - - @Override - public float getCurrentProximityValue() { - return mScale; - } - - // Scale the icon for WearableListView animations - @Override - public void setScalingAnimatorValue(float scale) { - mScale = scale; - mCircle.setScaleX(scale); - mCircle.setScaleY(scale); - } - - // Change color of the icon, remove fading from the text - @Override - public void onScaleUpStart() { + public void onCenterPosition(boolean animate) { mName.setAlpha(1f); ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor); } - // Change the color of the icon, fade the text @Override - public void onScaleDownStart() { + public void onNonCenterPosition(boolean animate) { ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor); mName.setAlpha(mFadedTextAlpha); } } </pre> +<p>You can also create animator objects to enlarge the icon of the center item in the list. You can +use the <code>onCenterPosition()</code> and <code>onNonCenterPosition()</code> callback methods +in the <code>WearableListView.OnCenterProximityListener</code> interface to manage your +animators. For more information about animators, see +<a href="{@docRoot}guide/topics/graphics/prop-animation.html#object-animator">Animating with +ObjectAnimator</a>.</p> + <h2 id="layout-def">Create a Layout Definition for Items</h2> |
