Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd74a901 authored by Joe Fernandez's avatar Joe Fernandez Committed by Android Git Automerger
Browse files

am d86a2f5b: docs: Android TV App Dev Basic Training

* commit 'd86a2f5b':
  docs: Android TV App Dev Basic Training
parents f5afb4d6 d86a2f5b
Loading
Loading
Loading
Loading
+0 −183
Original line number Diff line number Diff line
page.title=Hardware Features on TV
page.tags="unsupported"

@jd:body

<div id="qv-wrapper">
<div id="qv">
  <h2>In this document</h2>
  <ol>
    <li><a href="#unsupported-features">Unsupported Hardware Features</a></li>
    <li><a href="#workaround-features">Handling Unsupported Features</a></li>
    <li><a href="#check-features">Checking Available Features</a>
      <ol>
        <li><a href="#no-touchscreen">Touch screen</a></li>
        <li><a href="#no-camera">Camera</a></li>
        <li><a href="#no-gps">GPS</a></li>
      </ol>

    </li>
  </ol>
</div>
</div>

<p>TVs do not have some of the hardware features found on other Android devices.
Touch screens, cameras, and GPS receivers are some of the most commonly used hardware features
which are typically not available on a TV. When you build an app for TV, you must carefully
consider if your app can handle not having these features and, if necessary, work around them.</p>

<p>This guide discusses the hardware features not available on TV devices and shows you how to
work around those limitations in your app. For more information on filtering and declaring
features in the manifest, see the
<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">uses-feature</a> guide.</p>


<h2 id="unsupported-features">Unsupported Hardware Features</h2>

<p>TVs have a different purpose from other devices, and so they do not 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>


<h2 id="check-features">Checking Available Features</h2>

<p>To check if a feature is available at runtime, call {@link
  android.content.pm.PackageManager#hasSystemFeature(String)}. This method takes a single string
  argument that specifies the feature you want to check. For example, to check for a touch screen,
  use {@link android.content.pm.PackageManager#hasSystemFeature(String)} with the argument
  {@link android.content.pm.PackageManager#FEATURE_TOUCHSCREEN}.</p>

<p>The following code example demonstrates how to detect the availability of a hardware features
  at runtime:</p>

<pre>
// Check if the telephony hardware 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 telephony but "+
            "do have a touch screen.");
} else {
    Log.d("TV Test", "Running on a TV!");
}
</pre>

<p class="note">
  <strong>Note:</strong> You can also use the {@link android.app.UiModeManager#getCurrentModeType
  UiModeManager.getCurrentModeType()} method to detect the current platform type. For TV devices,
  this method returns a value of {@link android.content.res.Configuration#UI_MODE_TYPE_TELEVISION
  Configuration.UI_MODE_TYPE_TELEVISION}.
</p>


<h2 id="workaround-features">Handling Unsupported Features</h2>

<p>Depending on the design and functionality of your app, you may be able to work around certain
  hardware features being unavailable. This section discusses how to work around specific hardware
  features.</p>


<h3 id="no-touchscreen">Touch screen</h3>

<p>Android doesn't support touch screen interaction for TV devices, since most TVs don't have touch
  screens, and using a touch screen is not consistent with a viewing environment where the user is
  seated 10 feet away from the display.</p>

<p>On TV devices, you should work around this limitation by supporting navigation using a directional
  pad (D-pad) on TV remote control. For more information on properly supporting navigation using
  TV-friendly controls, see <a href="{@docRoot}preview/tv/ui/navigation.html">Navigation for
  TV</a>.</p>

<p>You can explicitly declare if your application requires (or does not require) a touch screen
  by including the following entry in your manifest:</p>

<pre>
&lt;uses-feature android:name="android.hardware.touchscreen"
        android:required="false"/&gt;
</pre>


<h3 id="no-camera">Camera</h3>

<p>Although a TV typically does not 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. If you decide that you want to enable your camera-related application to work on a
  TV device without a camera, you can add an attribute to your app manifest declaring that
  a camera is not required by your app:</p>

<pre>
&lt;uses-feature android:name="android.hardware.camera" android:required="false" /&gt;
</pre>

<p>If you enable your application to run without a camera, you should add code to your application
that detects if the camera feature is available and makes adjustments to the operation of your app.
The following code example demonstrates how to detect the presence of a camera:</p>

<pre>
// Check if the camera hardware feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.camera")) {
    Log.d("Camera test", "Camera available!");
} else {
    Log.d("Camera test", "No camera available. View and edit features only.");
}
</pre>


<h3 id="no-gps">GPS</h3>

<p>TVs are stationary, indoor devices, and do not have built-in global positioning system (GPS)
  receivers. If your application uses location information, you can still allow users to search
  for a location, or use a static location provider such as a zip code configured during the
  TV device setup.</p>

<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>
+42 −23
Original line number Diff line number Diff line
@@ -839,6 +839,48 @@ include the action bar on devices running Android 2.1 or higher."

  <!-- End Building for wearables -->

  <!-- Start: Building for TV -->
  <li class="nav-section">
    <div class="nav-section-header">
      <a href="<?cs var:toroot ?>training/tv/index.html">
      <span class="small">Building Apps for</span><br/>
              TV
      </a>
    </div>
    <ul>

      <li class="nav-section">
        <div class="nav-section-header">
          <a href="<?cs var:toroot ?>training/tv/start/index.html"
             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">
              Getting Started with TV Apps</a>
          </li>
          <li>
            <a href="<?cs var:toroot ?>training/tv/start/hardware.html">
              Handling TV Hardware</a>
          </li>
          <li>
            <a href="<?cs var:toroot ?>training/tv/start/layouts.html">
              Building TV Layouts</a>
          </li>
          <li>
            <a href="<?cs var:toroot ?>training/tv/start/navigation.html">
              Creating TV Navigation</a>
          </li>
        </ul>
      </li>

    </ul>
  </li>
  <!-- End: Building for TV -->


  <li class="nav-section">
    <div class="nav-section-header">
      <a href="<?cs var:toroot ?>training/best-ux.html">
@@ -1045,29 +1087,6 @@ results."
        </ul>
      </li>

      <li class="nav-section">
        <div class="nav-section-header"><a href="<?cs var:toroot ?>training/tv/index.html"
             description=
             "How to optimize your app's user interface and user input for
             the &quot;ten foot experience&quot; of a TV screen."
            >Designing for TV</a>
        </div>
        <ul>
          <li><a href="<?cs var:toroot ?>training/tv/optimizing-layouts-tv.html">
            Optimizing Layouts for TV
          </a>
          </li>
          <li><a href="<?cs var:toroot ?>training/tv/optimizing-navigation-tv.html">
            Optimizing Navigation for TV
          </a>
          </li>
          <li><a href="<?cs var:toroot ?>training/tv/unsupported-features-tv.html">
            Handling Features Not Supported on TV
          </a>
          </li>
        </ul>
      </li>

      <li class="nav-section">
        <div class="nav-section-header">
          <a href="<?cs var:toroot ?>training/custom-views/index.html"
+3 −54
Original line number Diff line number Diff line
page.title=Designing for TV
page.tags="input","screens"

trainingnavtop=true
startpage=true
page.title=Building Apps for TV
page.trainingcourse=true

@jd:body

<div id="tb-wrapper">
<div id="tb">

<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
<h2>Dependencies and prerequisites</h2>
<ul>
  <li>Android 2.0 (API Level 5) or higher</li>
</ul>

</div>
</div>

<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=zsRnRLh-O34">
<div>
    <h3>Video</h3>
    <p>DevBytes: Design for Large Displays - Part 1</p>
</div>
</a>

<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> 
<p>These classes teach you how to build apps for TV devices.</p>
 No newline at end of file
+0 −246
Original line number Diff line number Diff line
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">Design to Handle Large Bitmaps</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/components/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>
&lt;RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" &gt;

    &lt;fragment
        android:id="@+id/leftsidecontrols"
        android:layout_width="0dip"
        android:layout_marginLeft="5dip"
        android:layout_height="match_parent" /&gt;

    &lt;GridView        
        android:id="@+id/gridview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" /&gt;

&lt;/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>
  &lt;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"/&gt;
  </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}tools/help/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 an in-memory 
      {@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>
 No newline at end of file
+0 −206

File deleted.

Preview size limit exceeded, changes collapsed.

Loading