Merge "Creating new "Optimizing for TV" training." into ics-mr1
This commit is contained in:
BIN
docs/html/images/training/cool-places.png
Executable file
BIN
docs/html/images/training/cool-places.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/html/images/training/panoramio-grid.png
Executable file
BIN
docs/html/images/training/panoramio-grid.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
@@ -278,6 +278,26 @@ class="new"> new!</span></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toggle-list">
|
||||
<div><a href="<?cs var:toroot ?>training/tv/index.html">
|
||||
<span class="en">Designing for TV<span class="new"> new!</span></span>
|
||||
</a>
|
||||
</div>
|
||||
<ul>
|
||||
<li><a href="<?cs var:toroot ?>training/tv/optimizing-layouts-tv.html">
|
||||
<span class="en">Optimizing Layouts for TV</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/tv/optimizing-navigation-tv.html">
|
||||
<span class="en">Optimizing Navigation for TV</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/tv/unsupported-features-tv.html">
|
||||
<span class="en">Handling Features Not Supported on TV</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="toggle-list">
|
||||
|
||||
52
docs/html/training/tv/index.jd
Normal file
52
docs/html/training/tv/index.jd
Normal file
@@ -0,0 +1,52 @@
|
||||
page.title=Designing for TV
|
||||
|
||||
trainingnavtop=true
|
||||
startpage=true
|
||||
next.title=Optimizing layouts for TV
|
||||
next.link=optimizing-layouts-tv.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
|
||||
<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
|
||||
<h2>Dependencies and prerequisites</h2>
|
||||
<ul>
|
||||
<li>Android 2.0 (API Level 5) or higher</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
Smart TVs powered by Android bring your favorite Android apps to the best screen in your house.
|
||||
Thousands of apps in the Google Play Store are already optimized for TVs. This class shows how
|
||||
you can optimize your Android app for TVs, including how to build a layout that
|
||||
works great when the user is ten feet away and navigating with a remote control.
|
||||
</p>
|
||||
|
||||
<h2>Lessons</h2>
|
||||
|
||||
<dl>
|
||||
<dt><b><a href="optimizing-layouts-tv.html">Optimizing Layouts for TV</a></b></dt>
|
||||
<dd>Shows you how to optimize app layouts for TV screens, which have some unique characteristics such as:
|
||||
<ul>
|
||||
<li>permanent "landscape" mode</li>
|
||||
<li>high-resolution displays</li>
|
||||
<li>"10 foot UI" environment.</li>
|
||||
</ul>
|
||||
</dd>
|
||||
|
||||
<dt><b><a href="optimizing-navigation-tv.html">Optimizing Navigation for TV</a></b></dt>
|
||||
<dd>Shows you how to design navigation for TVs, including:
|
||||
<ul>
|
||||
<li>handling D-pad navigation</li>
|
||||
<li>providing navigational feedback</li>
|
||||
<li>providing easily-accessible controls on the screen.</li>
|
||||
</ul>
|
||||
</dd>
|
||||
|
||||
<dt><b><a href="unsupported-features-tv.html">Handling features not supported on TV</a></b></dt>
|
||||
<dd>Lists the hardware features that are usually not available on TVs. This lesson also shows you how to
|
||||
provide alternatives for missing features or check for missing features and disable code at run time.</dd>
|
||||
</dl>
|
||||
246
docs/html/training/tv/optimizing-layouts-tv.jd
Normal file
246
docs/html/training/tv/optimizing-layouts-tv.jd
Normal file
@@ -0,0 +1,246 @@
|
||||
page.title=Optimizing Layouts for TV
|
||||
parent.title=Designing for TV
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
next.title=Optimizing Navigation for TV
|
||||
next.link=optimizing-navigation-tv.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li>
|
||||
<li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li>
|
||||
<li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li>
|
||||
<li><a href="#HandleLargeBitmaps">Handle Large Bitmaps in Your Application</a></li>
|
||||
</ol>
|
||||
|
||||
<h2>You should also read</h2>
|
||||
<ul>
|
||||
<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When your application is running on a television set, you should assume that the user is sitting about
|
||||
ten feet away from the screen. This user environment is referred to as the
|
||||
<a href="http://en.wikipedia.org/wiki/10-foot_user_interface">10-foot UI</a>. To provide your
|
||||
users with a usable and enjoyable experience, you should style and lay out your UI accordingly..
|
||||
</p>
|
||||
<p>
|
||||
This lesson shows you how to optimize layouts for TV by:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Providing appropriate layout resources for landscape mode.</li>
|
||||
<li>Ensuring that text and controls are large enough to be visible from a distance.</li>
|
||||
<li>Providing high resolution bitmaps and icons for HD TV screens.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="DesignLandscapeLayouts">Design Landscape Layouts</h2>
|
||||
|
||||
<p>
|
||||
TV screens are always in landscape orientation. Follow these tips to build landscape layouts optimized for TV screens:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Put on-screen navigational controls on the left or right side of the screen and save the
|
||||
vertical space for content.</li>
|
||||
<li>Create UIs that are divided into sections, by using <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>
|
||||
and use view groups like {@link android.widget.GridView} instead
|
||||
of {@link android.widget.ListView} to make better use of the
|
||||
horizontal screen space.</li>
|
||||
<li>Use view groups such as {@link android.widget.RelativeLayout}
|
||||
or {@link android.widget.LinearLayout} to arrange views.
|
||||
This allows the Android system to adjust the position of the views to the size, alignment,
|
||||
aspect ratio, and pixel density of the TV screen.</li>
|
||||
<li>Add sufficient margins between layout controls to avoid a cluttered UI.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For example, the following layout is optimized for TV:
|
||||
</p>
|
||||
|
||||
<img src="{@docRoot}images/training/panoramio-grid.png" />
|
||||
|
||||
<p>
|
||||
In this layout, the controls are on the lefthand side. The UI is displayed within a
|
||||
{@link android.widget.GridView}, which is well-suited to landscape orientation.
|
||||
In this layout both GridView and Fragment have the width and height set
|
||||
dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime.
|
||||
The layout file for this UI is {@code res/layout-land-large/photogrid_tv.xml}.
|
||||
(This layout file is placed in {@code layout-land-large} because TVs have large screens with landscape orientation. For details refer to
|
||||
<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.)</p>
|
||||
|
||||
res/layout-land-large/photogrid_tv.xml
|
||||
<pre>
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
|
||||
<fragment
|
||||
android:id="@+id/leftsidecontrols"
|
||||
android:layout_width="0dip"
|
||||
android:layout_marginLeft="5dip"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<GridView
|
||||
android:id="@+id/gridview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To set up action bar items on the left side of the screen, you can also include the <a
|
||||
href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary">
|
||||
Left navigation bar library</a> in your application to set up action items on the left side
|
||||
of the screen, instead of creating a custom Fragment to add controls:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
When you have an activity in which the content scrolls vertically, always use a left navigation bar;
|
||||
otherwise, your users have to scroll to the top of the content to switch between the content view and
|
||||
the ActionBar. Look at the
|
||||
<a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo">
|
||||
Left navigation bar sample app</a> to see how to simple it is to include the left navigation bar in your app.
|
||||
</p>
|
||||
|
||||
<h2 id="MakeTextControlsEasyToSee">Make Text and Controls Easy to See</h2>
|
||||
<p>
|
||||
The text and controls in a TV application's UI should be easily visible and navigable from a distance.
|
||||
Follow these tips to make them easier to see from a distance :
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Break text into small chunks that users can quickly scan.</li>
|
||||
<li>Use light text on a dark background. This style is easier to read on a TV.</li>
|
||||
<li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes. Use simple sans-serif
|
||||
fonts and use anti-aliasing to increase readability.</li>
|
||||
<li>Use Android's standard font sizes:
|
||||
<pre>
|
||||
<TextView
|
||||
android:id="@+id/atext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
</pre></li>
|
||||
<li>Ensure that all your view widgets are large enough to be clearly visible to someone sitting 10 feet away
|
||||
from the screen (this distance is greater for very large screens). The best way to do this is to use
|
||||
layout-relative sizing rather than absolute sizing, and density-independent pixel units instead of absolute
|
||||
pixel units. For example, to set the width of a widget, use wrap_content instead of a pixel measurement,
|
||||
and to set the margin for a widget, use dip instead of px values.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
||||
<h2 id="DesignForLargeScreens">Design for High-Density Large Screens</h2>
|
||||
|
||||
<p>
|
||||
The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then
|
||||
allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels)
|
||||
does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades
|
||||
UI quality).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To get the best scaling results for images, provide them as <a href="{@docRoot}guide/developing/tools/draw9patch.html">
|
||||
9-patch image</a> elements if possible.
|
||||
If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This
|
||||
is not a good experience for the user. Instead, use high-quality images.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html">
|
||||
Designing for multiple screens</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2>
|
||||
|
||||
<p>
|
||||
The Android system has a limited amount of memory, so downloading and storing high-resolution images can often
|
||||
cause out-of-memory errors in your app. To avoid this, follow these tips:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Load images only when they're displayed on the screen. For example, when displaying multiple images in
|
||||
a {@link android.widget.GridView} or
|
||||
{@link android.widget.Gallery}, only load an image when
|
||||
{@link android.widget.Adapter#getView(int, View, ViewGroup) getView()}
|
||||
is called on the View's {@link android.widget.Adapter}.
|
||||
</li>
|
||||
<li>Call {@link android.graphics.Bitmap#recycle()} on
|
||||
{@link android.graphics.Bitmap} views that are no longer needed.
|
||||
</li>
|
||||
<li>Use {@link java.lang.ref.WeakReference} for storing references
|
||||
to {@link android.graphics.Bitmap} objects in a in-memory
|
||||
<a href="{@link java.util.Collection}.</li>
|
||||
<li>If you fetch images from the network, use {@link android.os.AsyncTask}
|
||||
to fetch them and store them on the SD card for faster access.
|
||||
Never do network transactions on the application's UI thread.
|
||||
</li>
|
||||
<li>Scale down really large images to a more appropriate size as you download them; otherwise, downloading the image
|
||||
itself may cause an "Out of Memory" exception. Here is sample code that scales down images while downloading:
|
||||
|
||||
<pre>
|
||||
// Get the source image's dimensions
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
// This does not download the actual image, just downloads headers.
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
|
||||
// The actual width of the image.
|
||||
int srcWidth = options.outWidth;
|
||||
// The actual height of the image.
|
||||
int srcHeight = options.outHeight;
|
||||
|
||||
// Only scale if the source is bigger than the width of the destination view.
|
||||
if(desiredWidth > srcWidth)
|
||||
desiredWidth = srcWidth;
|
||||
|
||||
// Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2.
|
||||
int inSampleSize = 1;
|
||||
while(srcWidth / 2 > desiredWidth){
|
||||
srcWidth /= 2;
|
||||
srcHeight /= 2;
|
||||
inSampleSize *= 2;
|
||||
}
|
||||
|
||||
float desiredScale = (float) desiredWidth / srcWidth;
|
||||
|
||||
// Decode with inSampleSize
|
||||
options.inJustDecodeBounds = false;
|
||||
options.inDither = false;
|
||||
options.inSampleSize = inSampleSize;
|
||||
options.inScaled = false;
|
||||
// Ensures the image stays as a 32-bit ARGB_8888 image.
|
||||
// This preserves image quality.
|
||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
|
||||
Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
|
||||
|
||||
// Resize
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(desiredScale, desiredScale);
|
||||
Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0,
|
||||
sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
|
||||
sampledSrcBitmap = null;
|
||||
|
||||
// Save
|
||||
FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE);
|
||||
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
|
||||
scaledBitmap = null;
|
||||
</pre>
|
||||
</li> </ul>
|
||||
206
docs/html/training/tv/optimizing-navigation-tv.jd
Normal file
206
docs/html/training/tv/optimizing-navigation-tv.jd
Normal file
@@ -0,0 +1,206 @@
|
||||
page.title=Optimizing Navigation for TV
|
||||
parent.title=Designing for TV
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
previous.title=Optimizing Layouts for TV
|
||||
previous.link=optimizing-layouts-tv.html
|
||||
next.title=Handling features not supported on TV
|
||||
next.link=unsupported-features-tv.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#HandleDpadNavigation">Handle D-pad Navigation</a></li>
|
||||
<li><a href="#HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</a></li>
|
||||
<li><a href="#DesignForEasyNavigation">Design for Easy Navigation</a></li>
|
||||
</ol>
|
||||
|
||||
<h2>You should also read</h2>
|
||||
<ul>
|
||||
<li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
An important aspect of the user experience when operating a TV is the direct human interface: a remote control.
|
||||
As you optimize your Android application for TVs, you should pay special attention to how the user actually navigates
|
||||
around your application when using a remote control instead of a touchscreen.
|
||||
</p>
|
||||
<p>
|
||||
This lesson shows you how to optimize navigation for TV by:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Ensuring all layout controls are D-pad navigable.</li>
|
||||
<li>Providing highly obvious feedback for UI navigation.</li>
|
||||
<li>Placing layout controls for easy access.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="HandleDpadNavigation">Handle D-pad Navigation</h2>
|
||||
|
||||
<p>
|
||||
On a TV, users navigate with controls on a TV remote, using either a D-pad or arrow keys.
|
||||
This limits movement to up, down, left, and right.
|
||||
To build a great TV-optimized app, you must provide a navigation scheme in which the user can
|
||||
quickly learn how to navigate your app using the remote.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When you design navigation for D-pad, follow these guidelines:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Ensure that the D-pad can navigate to all the visible controls on the screen.</li>
|
||||
<li>For scrolling lists with focus, D-pad up/down keys scroll the list and Enter key selects an item in the list. Ensure that users can
|
||||
select an element in the list and that the list still scrolls when an element is selected.</li>
|
||||
<li>Ensure that movement between controls is straightforward and predictable.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Android usually handles navigation order between layout elements automatically, so you don't need to do anything extra. If the screen layout
|
||||
makes navigation difficult, or if you want users to move through the layout in a specific way, you can set up explicit navigation for your
|
||||
controls.
|
||||
For example, for an {@code android.widget.EditText}, to define the next control to receive focus, use:
|
||||
<pre>
|
||||
<EditText android:id="@+id/LastNameField" android:nextFocusDown="@+id/FirstNameField"\>
|
||||
</pre>
|
||||
The following table lists all of the available navigation attributes:
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Function</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{@link android.R.attr#nextFocusDown}</td>
|
||||
<td>Defines the next view to receive focus when the user navigates down.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{@link android.R.attr#nextFocusLeft}</td>
|
||||
<td>Defines the next view to receive focus when the user navigates left.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{@link android.R.attr#nextFocusRight}</td>
|
||||
<td>Defines the next view to receive focus when the user navigates right.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{@link android.R.attr#nextFocusUp}</td>
|
||||
<td>Defines the next view to receive focus when the user navigates up.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
To use one of these explicit navigation attributes, set the value to the ID (android:id value) of another widget in the layout. You should set
|
||||
up the navigation order as a loop, so that the last control directs focus back to the first one.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note: You should only use these attributes to modify the navigation order if the default order that the system applies does not work well.
|
||||
</p>
|
||||
|
||||
<h2 id="HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</h2>
|
||||
|
||||
<p>
|
||||
Use appropriate color highlights for all navigable and selectable elements in the UI. This makes it easy for users to know whether the control
|
||||
is currently focused or selected when they navigate with a D-pad. Also, use uniform highlight scheme across your application.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Android provides <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">Drawable State List Resources</a> to implement highlights
|
||||
for selected and focused controls. For example:
|
||||
</p>
|
||||
|
||||
res/drawable/button.xml:
|
||||
<pre>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/button_pressed" /> <!-- pressed -->
|
||||
<item android:state_focused="true"
|
||||
android:drawable="@drawable/button_focused" /> <!-- focused -->
|
||||
<item android:state_hovered="true"
|
||||
android:drawable="@drawable/button_focused" /> <!-- hovered -->
|
||||
<item android:drawable="@drawable/button_normal" /> <!-- default -->
|
||||
</selector>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This layout XML applies the above state list drawable to a {@link android.widget.Button}:
|
||||
</p>
|
||||
<pre>
|
||||
<Button
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:background="@drawable/button" />
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Provide sufficient padding within the focusable and selectable controls so that the highlights around them are clearly visible.
|
||||
</p>
|
||||
|
||||
<h2 id="DesignForEasyNavigation">Design for Easy Navigation</h2>
|
||||
|
||||
<p>
|
||||
Users should be able to navigate to any UI control with a couple of D-pad clicks. Navigation should be easy and intuitive to
|
||||
understand. For any non-intuitive actions, provide users with written help, using a dialog triggered by a help button or action bar icon.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Predict the next screen that the user will want to navigate to and provide one click navigation to it. If the current screen UI is very sparse,
|
||||
consider making it a multi pane screen. Use fragments for making multi-pane screens. For example, consider the multi-pane UI below with continent names
|
||||
on the left and list of cool places in each continent on the right.
|
||||
</p>
|
||||
|
||||
<img src="{@docRoot}images/training/cool-places.png" alt="" />
|
||||
|
||||
<p>
|
||||
The above UI consists of three Fragments - <code>left_side_action_controls</code>, <code>continents</code> and
|
||||
<code>places</code> - as shown in its layout
|
||||
xml file below. Such multi-pane UIs make D-pad navigation easier and make good use of the horizontal screen space for
|
||||
TVs.
|
||||
</p>
|
||||
res/layout/cool_places.xml
|
||||
<pre>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<fragment
|
||||
android:id="@+id/left_side_action_controls"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_weight="0.2"/>
|
||||
<fragment
|
||||
android:id="@+id/continents"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_weight="0.2"/>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/places"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_weight="0.6"/>
|
||||
|
||||
</LinearLayout>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Also, notice in the UI layout above action controls are on the left hand side of a vertically scrolling list to make
|
||||
them easily accessible using D-pad.
|
||||
In general, for layouts with horizontally scrolling components, place action controls on left or right hand side and
|
||||
vice versa for vertically scrolling components.
|
||||
</p>
|
||||
|
||||
156
docs/html/training/tv/unsupported-features-tv.jd
Normal file
156
docs/html/training/tv/unsupported-features-tv.jd
Normal file
@@ -0,0 +1,156 @@
|
||||
page.title=Handling Features Not Supported on TV
|
||||
parent.title=Designing for TV
|
||||
parent.link=index.html
|
||||
|
||||
trainingnavtop=true
|
||||
previous.title=Optimizing Navigation for TV
|
||||
previous.link=optimizing-navigation-tv.html
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</a></li>
|
||||
<li><a href="#CheckAvailableFeatures">Check for Available Features at Runtime</a></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
TVs are much different from other Android-powered devices:
|
||||
</p>
|
||||
<ul>
|
||||
<li>They're not mobile.</li>
|
||||
<li>Out of habit, people use them for watching media with little or no interaction.</li>
|
||||
<li>People interact with them from a distance.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Because TVs have a different purpose from other devices, they usually don't have hardware features
|
||||
that other Android-powered devices often have. For this reason, the Android system does not
|
||||
support the following features for a TV device:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Hardware</th>
|
||||
<th>Android feature descriptor</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Camera</td>
|
||||
<td>android.hardware.camera</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GPS</td>
|
||||
<td>android.hardware.location.gps</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microphone</td>
|
||||
<td>android.hardware.microphone</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Near Field Communications (NFC)</td>
|
||||
<td>android.hardware.nfc</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Telephony</td>
|
||||
<td>android.hardware.telephony</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Touchscreen</td>
|
||||
<td>android.hardware.touchscreen</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This lesson shows you how to work around features that are not available on TV by:
|
||||
<ul>
|
||||
<li>Providing work arounds for some non-supported features.</li>
|
||||
<li>Checking for available features at runtime and conditionally activating/deactivating certain code
|
||||
paths based on availability of those features.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</h2>
|
||||
|
||||
<p>
|
||||
Android doesn't support touchscreen interaction for TV devices, most TVs don't have touch screens,
|
||||
and interacting with a TV using a touchscreen is not consistent with the 10 foot environment. For
|
||||
these reasons, users interact with Android-powered TVs using a remote. In consideration of this,
|
||||
ensure that every control in your app can be accessed with the D-pad. Refer back to the previous two lessons
|
||||
<a href="{@docRoot}training/tv/optimizing-layouts-tv">Optimizing Layouts for TV</a> and
|
||||
<a href="{@docRoot}training/tv/optimizing-navigation-tv">Optimize Navigation for TV</a> for more details
|
||||
on this topic. The Android system assumes that a device has a touchscreen, so if you want your application
|
||||
to run on a TV, you must <strong>explicitly</strong> disable the touchscreen requirement in your manifest file:
|
||||
<pre>
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Although a TV doesn't have a camera, you can still provide a photography-related application on a TV.
|
||||
For example, if you have an app that takes, views and edits photos, you can disable its picture-taking
|
||||
functionality for TVs and still allow users to view and even edit photos. The next section talks about how to
|
||||
deactivate or activate specific functions in the application based on runtime device type detection.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Because TVs are stationary, indoor devices, they don't have built-in GPS. If your application uses location
|
||||
information, allow users to search for a location or use a "static" location provider to get
|
||||
a location from the zip code configured during the TV setup.
|
||||
<pre>
|
||||
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
|
||||
Location location = locationManager.getLastKnownLocation("static");
|
||||
Geocoder geocoder = new Geocoder(this);
|
||||
Address address = null;
|
||||
|
||||
try {
|
||||
address = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1).get(0);
|
||||
Log.d("Zip code", address.getPostalCode());
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Geocoder error", e);
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
TVs usually don't support microphones, but if you have an application that uses voice control,
|
||||
you can create a mobile device app that takes voice input and then acts as a remote control for a TV.
|
||||
</p>
|
||||
|
||||
<h2 id="CheckAvailableFeatures">Check for Available Features at Runtime</h2>
|
||||
|
||||
<p>
|
||||
To check if a feature is available at runtime, call
|
||||
{@link android.content.pm.PackageManager#hasSystemFeature(String)}.
|
||||
This method takes a single argument : a string corresponding to the
|
||||
feature you want to check. For example, to check for touchscreen, use
|
||||
{@link android.content.pm.PackageManager#hasSystemFeature(String)} with the argument
|
||||
{@link android.content.pm.PackageManager#FEATURE_TOUCHSCREEN}.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following code snippet demonstrates how to detect device type at runtime based on supported features:
|
||||
|
||||
<pre>
|
||||
// Check if android.hardware.telephony feature is available.
|
||||
if (getPackageManager().hasSystemFeature("android.hardware.telephony")) {
|
||||
Log.d("Mobile Test", "Running on phone");
|
||||
// Check if android.hardware.touchscreen feature is available.
|
||||
} else if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) {
|
||||
Log.d("Tablet Test", "Running on devices that don't support telphony but have a touchscreen.");
|
||||
} else {
|
||||
Log.d("TV Test", "Running on a TV!");
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is just one example of using runtime checks to deactivate app functionality that depends on features
|
||||
that aren't available on TVs.
|
||||
</p>
|
||||
Reference in New Issue
Block a user