处理TV硬件部分
最后更新于:2022-04-01 01:42:26
> 编写:[awong1900](https://github.com/awong1900) - 原文:[http://developer.android.com/training/tv/start/hardware.html](http://developer.android.com/training/tv/start/hardware.html)
TV硬件和其他安卓设备有实质性的不同。TV不包含一些其他安卓设备具备的硬件特性,如触摸屏,摄像头,和GPS。TV也完全依赖于其他辅助硬件设备。为了让用户与TV应用交互,他们必须使用遥控器或者游戏手柄。当您创建TV应用时,必须小心的考虑到TV硬件的限制和操作要求。
本节课程讨论如何检查应用是不是运行在TV上,怎样去处理不支持的硬件特性,和讨论处理TV设备控制器的要求。
### TV设备的检测
如果你创建的应用同时支持TV设备和其他设备,你可能需要检测应用当前运行在哪种设备上,并调整应用的执行。例如,如果你有一个应用通过[Intent](http://developer.android.com/reference/android/content/Intent.html)启动,你的应用应该检查设备特性然后决定是应该启动TV导向的[activity](# "An activity represents a single screen with a user interface.")还是手机的[activity](# "An activity represents a single screen with a user interface.")。
检查应用是否运行在TV设备上,推荐的方式是用[UiModeManager.getCurrentModeType()](http://developer.android.com/reference/android/app/UiModeManager.html#getCurrentModeType())方法检测设备是否运行在TV模式。下面的示例代码展示了如何检查你的应用是否运行在TV设备上:
~~~
public static final String TAG = "DeviceTypeRuntimeCheck";
UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
Log.d(TAG, "Running on a TV Device")
} else {
Log.d(TAG, "Running on a non-TV Device")
}
~~~
### 处理不支持的硬件特性
基于设计和应用的功能,你可能需要在某些硬件特性不可用的情况下工作。这节讨论哪些硬件特性对于TV是典型不可用的,如何去检测缺少的硬件特性,并且建议替代方法去用这些特性。
### 不支持的TV硬件特性
TV有不同于其他设备的用途,因此它们没有一些其他安卓设备通常有的硬件特性。由于这个原因,TV设备的安卓系统不支持以下特性:
| 硬件 | 安卓特性描述 |
|-----|-----|
| 触屏 | `android.hardware.touchscreen` |
| 触屏模拟器 | `android.hardware.faketouch` |
| 电话 | `android.hardware.telephony` |
| 摄像头 | `android.hardware.camera` |
| 蓝牙 | `android.hardware.bluetooth` |
| 近场通讯(NFC) | `android.hardware.nfc` |
| GPS | `android.hardware.location.gps` |
| 麦克风 **[1]** | `android.hardware.microphone` |
| 传感器 | `android.hardware.sensor` |
> **[1]** 一些TV控制器有麦克风,但不是这里描述的麦克风硬件特性。控制器麦克风是完全被支持的。
查看[Features Reference](http://developer.android.com/guide/topics/manifest/uses-feature-element.html#features-reference)获得完全的特性列表,子特性,和他们的描述。
### 声明TV硬件需求
安卓应用能通过在manifest中定义硬件特性需求来确保应用不能被安装在不提供这些特性的设备上。如果你正在扩展应用到TV上,仔细地审查你的manifest的硬件特性需求,它有可能阻止应用安装到TV设备上。
即使你的应用使用了TV上不存在的硬件特性(如触屏或者摄像头),应用也可以在没有那些特性的情况下工作,需要修改应用的manifest来表明这些特性不是必须的。接下来的manifest代码片段示范了如何声明在TV设备中不可用的硬件特性,尽管你的应用在非TV设备上可能会用上这些特性。
~~~
<uses-feature android:name="android.hardware.touchscreen"
android:required="false"></uses>
<uses-feature android:name="android.hardware.faketouch"
android:required="false"></uses>
<uses-feature android:name="android.hardware.telephony"
android:required="false"></uses>
<uses-feature android:name="android.hardware.camera"
android:required="false"></uses>
<uses-feature android:name="android.hardware.bluetooth"
android:required="false"></uses>
<uses-feature android:name="android.hardware.nfc"
android:required="false"></uses>
<uses-feature android:name="android.hardware.gps"
android:required="false"></uses>
<uses-feature android:name="android.hardware.microphone"
android:required="false"></uses>
<uses-feature android:name="android.hardware.sensor"
android:required="false"></uses>
~~~
> **Note**:一些特性有子特性,如`android.hardware.camera.front`,参考:[Feature Reference](http://developer.android.com/guide/topics/manifest/uses-feature-element.html#features-reference)。确保应用中任何子特性也标记为`required="false"`。
所有想用在TV设备上的应用必须声明触屏特性不被需要,在[创建TV应用的第一步](http://developer.android.com/training/tv/start/start.html#no-touchscreen)有描述。如果你的应用使用了一个或更多的上面列表上的特性,改变manifest特性的`android:required`属性为`false`。
> **Caution**:表明一个硬件特性是必须的,设置它的值为`true`可以阻止应用在TV设备上安装或者出现在安卓TV的主屏幕launcher上。
一旦你决定了应用的硬件特性选项,你必须检查在运行时那些特性的可用性,然后调整你的应用的行为。下一节讨论如何检查硬件特性和改变应用行为的建议处理。
更多关于filter和在manifest里声明特性,参考:[uses-feature](http://developer.android.com/guide/topics/manifest/uses-feature-element.html)。
### 声明权限会隐含硬件特性
一些[uses-permission](http://developer.android.com/guide/topics/manifest/uses-permission-element.html) manifest声明隐含了硬件特性。这些行为意味着在应用中请求一些权限能导致应用不能安装和使用在TV设备上。下面普通的权限请求包含了一个隐式的硬件特性需求:
| 权限 | 隐式的硬件需求 |
|-----|-----|
| [RECORD_AUDIO]() | `android.hardware.microphone` |
| [CAMERA]() | `android.hardware.camera`_and_`android.hardware.camera.autofocus` |
| [ACCESS_COARSE_LOCATION]() | `android.hardware.location`_and_`android.hardware.location.network` |
| [ACCESS_FINE_LOCATION]() | `android.hardware.location`_and_`android.hardware.location.gps` |
包含隐式硬件特性需求的完整权限需求列表,参考:[uses-feature](http://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions-features)。如果你的应用请求了上面列表上的特性的任何一个,在manifest中设置它的隐式硬件特性为不需要(`android:required="false"`)。
### 检查硬件特性
在应用运行时,Android framework能告诉你硬件特性是否可用。用[hasSystemFeature(String)](http://developer.android.com/reference/android/content/pm/PackageManager.html#hasSystemFeature(java.lang.String))方法在运行时检查特定的特性。这个方法只需要一个字符串参数,即想检查的特性名字。
接下来的示例代码展示了如何在陨石检测硬件特性的可用性:
~~~
// Check if the telephony hardware feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.telephony")) {
Log.d("HardwareFeatureTest", "Device can make phone calls");
}
// Check if android.hardware.touchscreen feature is available.
if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) {
Log.d("HardwareFeatureTest", "Device has a touch screen.");
}
~~~
### 触屏
因为大部分的TV没有触摸屏,在TV设备上,安卓不支持触屏交互。此外,用触屏交互和坐在离显示器3米外观看是相互矛盾的。
在TV设备中,你应该设计应用交互模式支持遥控器上的方向键(D-pad)操作。更多关于正确地支持TV友好的控制器操作的信息,参考[Creating TV Navigation](http://developer.android.com/training/tv/start/navigation.html)。
### 摄像头
尽管TV通常没有摄像头,但是你仍然可以提供拍照相关的TV应用,如果应用有拍照,查看和编辑图片功能,在TV上可以关闭拍照功能但仍可以允许用户查看甚至编辑图片。如果你决定在TV上使用摄像相关的应用,在manifest里添加接下来的特性声明:
~~~
<uses-feature android:name="android.hardware.camera" android:required="false" ></uses>
~~~
如果在缺少摄像头情况下运行你的应用,在你的应用中添加代码去检测是否摄像头特性可用,并且调整应用的操作。接下来的示例代码展示了如何检测一个摄像头的存在:
~~~
// 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.");
}
~~~
### GPS
TV是固定的室内设备,并且没有内置的全球定位系统(GPS)接收器。如果你的应用使用定位信息,你仍可以允许用户搜索位置,或者用固定位置提供商代替,如在TV设置中设置邮政编码。
~~~
// Request a static location from the location manager
LocationManager locationManager = (LocationManager) this.getSystemService(
Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation("static");
// Attempt to get postal or zip code from the static location object
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);
}
~~~
### 处理控制器
TV设备需要辅助硬件设备与应用交互,如一个基本形式的遥控器或者游戏手柄。这意味着你的应用必须支持D-pad(十字方向键)输入。它也意味着你的应用可能需要处理手柄掉线和更多类型的手柄输入。
### D-pad必须的按键
默认的TV设备控制器是D-pad。通常,你可以用遥控器的上,下,左,右,选择,返回,和Home键操作应用。如果你的应用是一个游戏而需要游戏手柄额外的控制,你的应用也应该尝试允许用D-pad操作。这种情况下,你的应用也应该警告用户需要手柄,并且允许他们用D-pad优雅的退出游戏。更多关于在TV设备如理D-pad的操作,参考[Creating TV Navigation](http://developer.android.com/training/tv/start/navigation.html)。
### 处理手柄掉线
TV的手柄通常是蓝牙设备,它为了省电而定期的休眠并且与TV设备断开连接。这意味着如果不处理这些重连事件,应用可能被中断或者重新开始。这些事件可以发生在下面任何情景中:
- 当在看几分钟的视频,D-Pad或者游戏手柄进入了睡眠模式,从TV设备上断开连接并且随后重新连接。
- 在玩游戏时,新玩家用不是当前连接的游戏手柄加入游戏。
- 在玩游戏时,一个玩家离开游戏并且断开游戏手柄。
任何TV应用[activity](# "An activity represents a single screen with a user interface.")受制于断开连接和重连事件,这些必须在manifest中配置为处理重连事件。。接下来的示例代码展示了如何打开一个[activity](# "An activity represents a single screen with a user interface.")去处理配置改变,包括键盘或者操作设备连接,断开连接,或者重新连接:
~~~
<activity
android:name="com.example.android.TvActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|navigation"
android:theme="@style/Theme.Leanback">
<intent-filter>
<action android:name="android.intent.action.MAIN" ></action>
<category android:name="android.intent.category.LEANBACK_LAUNCHER" ></category>
</intent-filter>
...
</activity>
~~~
这个配置改变允许应用通过重连事件继续运行,比较而言Android framework强制重启应用会导致一个不好的用户体验。
### 处理D-pad变种输入
TV设备用户可能有超过一种类型的控制器来操纵TV。例如,一个用户可能有基本D-pad控制器和一个游戏控制器。游戏控制器用于D-pad功能的按键代码可能和物理十字键提供的不相同。
你的应用应该要处理游戏控制器D-pad的变种输入,因此用户不需要通过物理开关控制器去操作你的应用。更多信息关于处理这些变种输入,参考[Handling Controller Actions](http://developer.android.com/training/tv/start/hardware.html)。
[下一节: 创建TV布局](#)