Merge "Creating new "Optimizing for TV" training." into ics-mr1

This commit is contained in:
Megha Joshi
2012-04-03 16:08:29 -07:00
committed by Android (Google) Code Review
7 changed files with 680 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@@ -278,6 +278,26 @@ class="new">&nbsp;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">&nbsp;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">

View 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>

View 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>
&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}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>

View 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>
&lt;EditText android:id="@+id/LastNameField" android:nextFocusDown="@+id/FirstNameField"\&gt;
</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>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;
&lt;item android:state_pressed="true"
android:drawable="@drawable/button_pressed" /&gt; &lt;!-- pressed --&gt;
&lt;item android:state_focused="true"
android:drawable="@drawable/button_focused" /&gt; &lt;!-- focused --&gt;
&lt;item android:state_hovered="true"
android:drawable="@drawable/button_focused" /&gt; &lt;!-- hovered --&gt;
&lt;item android:drawable="@drawable/button_normal" /&gt; &lt;!-- default --&gt;
&lt;/selector&gt;
</pre>
<p>
This layout XML applies the above state list drawable to a {@link android.widget.Button}:
</p>
<pre>
&lt;Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:background="@drawable/button" /&gt;
</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>
&lt;LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
&gt;
&lt;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"/&gt;
&lt;fragment
android:id="@+id/continents"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_marginLeft="10dip"
android:layout_weight="0.2"/&gt;
&lt;fragment
android:id="@+id/places"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_marginLeft="10dip"
android:layout_weight="0.6"/&gt;
&lt;/LinearLayout&gt;
</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>

View 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>
&lt;uses-feature android:name="android.hardware.touchscreen" android:required="false"/&gt;
</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>