> 編寫:[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布局](#)
- 序言
- Android入門基礎:從這里開始
- 建立第一個App
- 創建Android項目
- 執行Android程序
- 建立簡單的用戶界面
- 啟動其他的Activity
- 添加ActionBar
- 建立ActionBar
- 添加Action按鈕
- 自定義ActionBar的風格
- ActionBar的覆蓋層疊
- 兼容不同的設備
- 適配不同的語言
- 適配不同的屏幕
- 適配不同的系統版本
- 管理Activity的生命周期
- 啟動與銷毀Activity
- 暫停與恢復Activity
- 停止與重啟Activity
- 重新創建Activity
- 使用Fragment建立動態的UI
- 創建一個Fragment
- 建立靈活動態的UI
- Fragments之間的交互
- 數據保存
- 保存到Preference
- 保存到文件
- 保存到數據庫
- 與其他應用的交互
- Intent的發送
- 接收Activity返回的結果
- Intent過濾
- Android分享操作
- 分享簡單的數據
- 給其他App發送簡單的數據
- 接收從其他App返回的數據
- 給ActionBar增加分享功能
- 分享文件
- 建立文件分享
- 分享文件
- 請求分享一個文件
- 獲取文件信息
- 使用NFC分享文件
- 發送文件給其他設備
- 接收其他設備的文件
- Android多媒體
- 管理音頻播放
- 控制音量與音頻播放
- 管理音頻焦點
- 兼容音頻輸出設備
- 拍照
- 簡單的拍照
- 簡單的錄像
- 控制相機硬件
- 打印
- 打印照片
- 打印HTML文檔
- 打印自定義文檔
- Android圖像與動畫
- 高效顯示Bitmap
- 高效加載大圖
- 非UI線程處理Bitmap
- 緩存Bitmap
- 管理Bitmap的內存
- 在UI上顯示Bitmap
- 使用OpenGL ES顯示圖像
- 建立OpenGL ES的環境
- 定義Shapes
- 繪制Shapes
- 運用投影與相機視圖
- 添加移動
- 響應觸摸事件
- 添加動畫
- View間漸變
- 使用ViewPager實現屏幕側滑
- 展示卡片翻轉動畫
- 縮放View
- 布局變更動畫
- Android網絡連接與云服務
- 無線連接設備
- 使得網絡服務可發現
- 使用WiFi建立P2P連接
- 使用WiFi P2P服務
- 執行網絡操作
- 連接到網絡
- 管理網絡
- 解析XML數據
- 高效下載
- 為網絡訪問更加高效而優化下載
- 最小化更新操作的影響
- 避免下載多余的數據
- 根據網絡類型改變下載模式
- 云同步
- 使用備份API
- 使用Google Cloud Messaging
- 解決云同步的保存沖突
- 使用Sync Adapter傳輸數據
- 創建Stub授權器
- 創建Stub Content Provider
- 創建Sync Adpater
- 執行Sync Adpater
- 使用Volley執行網絡數據傳輸
- 發送簡單的網絡請求
- 建立請求隊列
- 創建標準的網絡請求
- 實現自定義的網絡請求
- Android聯系人與位置信息
- Android聯系人信息
- 獲取聯系人列表
- 獲取聯系人詳情
- 使用Intents修改聯系人信息
- 顯示聯系人頭像
- Android位置信息
- 獲取最后可知位置
- 獲取位置更新
- 顯示位置地址
- 創建和監視地理圍欄
- Android可穿戴應用
- 賦予Notification可穿戴特性
- 創建Notification
- 在Notifcation中接收語音輸入
- 為Notification添加顯示頁面
- 以Stack的方式顯示Notifications
- 創建可穿戴的應用
- 創建并運行可穿戴應用
- 創建自定義的布局
- 添加語音功能
- 打包可穿戴應用
- 通過藍牙進行調試
- 創建自定義的UI
- 定義Layouts
- 創建Cards
- 創建Lists
- 創建2D-Picker
- 創建確認界面
- 退出全屏的Activity
- 發送并同步數據
- 訪問可穿戴數據層
- 同步數據單元
- 傳輸資源
- 發送與接收消息
- 處理數據層的事件
- Android TV應用
- 創建TV應用
- 創建TV應用的第一步
- 處理TV硬件部分
- 創建TV的布局文件
- 創建TV的導航欄
- 創建TV播放應用
- 創建目錄瀏覽器
- 提供一個Card視圖
- 創建詳情頁
- 顯示正在播放卡片
- 幫助用戶在TV上探索內容
- TV上的推薦內容
- 使得TV App能夠被搜索
- 使用TV應用進行搜索
- 創建TV游戲應用
- 創建TV直播應用
- TV Apps Checklist
- Android企業級應用
- Ensuring Compatibility with Managed Profiles
- Implementing App Restrictions
- Building a Work Policy Controller
- Android交互設計
- 設計高效的導航
- 規劃屏幕界面與他們之間的關系
- 為多種大小的屏幕進行規劃
- 提供向下和橫向導航
- 提供向上和歷史導航
- 綜合:設計樣例 App
- 實現高效的導航
- 使用Tabs創建Swipe視圖
- 創建抽屜導航
- 提供向上的導航
- 提供向后的導航
- 實現向下的導航
- 通知提示用戶
- 建立Notification
- 當啟動Activity時保留導航
- 更新Notification
- 使用BigView風格
- 顯示Notification進度
- 增加搜索功能
- 建立搜索界面
- 保存并搜索數據
- 保持向下兼容
- 使得你的App內容可被Google搜索
- 為App內容開啟深度鏈接
- 為索引指定App內容
- Android界面設計
- 為多屏幕設計
- 兼容不同的屏幕大小
- 兼容不同的屏幕密度
- 實現可適應的UI
- 創建自定義View
- 創建自定義的View類
- 實現自定義View的繪制
- 使得View可交互
- 優化自定義View
- 創建向后兼容的UI
- 抽象新的APIs
- 代理至新的APIs
- 使用舊的APIs實現新API的效果
- 使用版本敏感的組件
- 實現輔助功能
- 開發輔助程序
- 開發輔助服務
- 管理系統UI
- 淡化系統Bar
- 隱藏系統Bar
- 隱藏導航Bar
- 全屏沉浸式應用
- 響應UI可見性的變化
- 創建使用Material Design的應用
- 開始使用Material Design
- 使用Material的主題
- 創建Lists與Cards
- 定義Shadows與Clipping視圖
- 使用Drawables
- 自定義動畫
- 維護兼容性
- Android用戶輸入
- 使用觸摸手勢
- 檢測常用的手勢
- 跟蹤手勢移動
- Scroll手勢動畫
- 處理多觸摸手勢
- 拖拽與縮放
- 管理ViewGroup中的觸摸事件
- 處理鍵盤輸入
- 指定輸入法類型
- 處理輸入法可見性
- 兼容鍵盤導航
- 處理按鍵動作
- 兼容游戲控制器
- 處理控制器輸入動作
- 支持不同的Android系統版本
- 支持多個控制器
- Android后臺任務
- 在IntentService中執行后臺任務
- 創建IntentService
- 發送工作任務到IntentService
- 報告后臺任務執行狀態
- 使用CursorLoader在后臺加載數據
- 使用CursorLoader執行查詢任務
- 處理查詢的結果
- 管理設備的喚醒狀態
- 保持設備的喚醒
- 制定重復定時的任務
- Android性能優化
- 管理應用的內存
- 代碼性能優化建議
- 提升Layout的性能
- 優化layout的層級
- 使用include標簽重用layouts
- 按需加載視圖
- 使得ListView滑動順暢
- 優化電池壽命
- 監測電量與充電狀態
- 判斷與監測Docking狀態
- 判斷與監測網絡連接狀態
- 根據需要操作Broadcast接受者
- 多線程操作
- 在一個線程中執行一段特定的代碼
- 為多線程創建線程池
- 啟動與停止線程池中的線程
- 與UI線程通信
- 避免出現程序無響應ANR
- JNI使用指南
- 優化多核處理器(SMP)下的Android程序
- Android安全與隱私
- Security Tips
- 使用HTTPS與SSL
- 為防止SSL漏洞而更新Security
- 使用設備管理條例增強安全性
- Android測試程序
- 測試你的Activity
- 建立測試環境
- 創建與執行測試用例
- 測試UI組件
- 創建單元測試
- 創建功能測試
- 術語表