aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Partner Docs <noreply@android.com>2017-09-01 04:14:51 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-09-01 04:14:51 +0000
commit9cbc304db3123a41fee75af09603d9016fb66587 (patch)
tree267ce24faebe92e33b56bb542fd75dc2c7c30af8
parent7035fd91926c209c7bca71f359730aed76b20e7c (diff)
parent6fcef5f72c8b2ea92f472b6335bc86408da97b33 (diff)
downloadsource.android.com-9cbc304db3123a41fee75af09603d9016fb66587.tar.gz
Merge "Docs: Changes to source.android.com"
am: 6fcef5f72c Change-Id: I3455cadd8428dfc81975287e73c65b0068255121
-rw-r--r--en/compatibility/cts/usb-audio.html2
-rw-r--r--en/compatibility/index.html5
-rw-r--r--en/devices/_toc-interfaces.yaml6
-rw-r--r--en/devices/_toc-tech.yaml2
-rw-r--r--en/devices/architecture/index.html10
-rw-r--r--en/devices/audio/debugging.html5
-rw-r--r--en/devices/bluetooth/ble_advertising.html258
-rw-r--r--en/devices/bluetooth/services.html463
-rw-r--r--en/devices/camera/camera3_requests_methods.html2
-rw-r--r--en/devices/input/migration-guide.html3
-rw-r--r--en/devices/tech/admin/testing-setup.html62
-rw-r--r--en/devices/tech/config/filesystem.html390
-rw-r--r--en/devices/tech/dalvik/images/jit-arch.pngbin31349 -> 19327 bytes
-rw-r--r--en/devices/tech/dalvik/images/jit-daemon.pngbin53542 -> 21919 bytes
-rw-r--r--en/devices/tech/dalvik/images/jit-profile-comp.pngbin41397 -> 18648 bytes
-rw-r--r--en/devices/tech/dalvik/images/jit-workflow.pngbin104054 -> 60140 bytes
-rw-r--r--en/devices/tech/dalvik/jit-compiler.html177
-rw-r--r--en/devices/tech/debug/index.html7
-rw-r--r--en/devices/tech/perf/low-ram.html2
-rw-r--r--en/security/bulletin/2017-08-01.html16
-rw-r--r--en/source/build-numbers.html2
-rw-r--r--en/source/devices.html2
-rw-r--r--en/source/report-bugs.html2
-rw-r--r--en/source/running.html307
-rw-r--r--en/source/site-updates.html29
-rw-r--r--zh-cn/devices/accessories/aoa.html128
-rw-r--r--zh-cn/devices/accessories/aoa2.html219
-rw-r--r--zh-cn/devices/accessories/headset/usb-headset-spec.html162
-rw-r--r--zh-cn/devices/accessories/protocol.html37
-rw-r--r--zh-cn/devices/architecture/hal.html92
-rw-r--r--zh-cn/devices/architecture/index.html50
-rw-r--r--zh-cn/devices/architecture/treble.html46
-rw-r--r--zh-cn/devices/audio/latency_design.html186
-rw-r--r--zh-cn/devices/audio/midi_test.html221
-rw-r--r--zh-cn/devices/audio/terminology.html27
-rw-r--r--zh-cn/devices/audio/tv.html283
-rw-r--r--zh-cn/devices/automotive/index.html62
-rw-r--r--zh-cn/devices/automotive/properties.html162
-rw-r--r--zh-cn/devices/camera/camera3_3Amodes.html487
-rw-r--r--zh-cn/devices/camera/camera3_crop_reprocess.html67
-rw-r--r--zh-cn/devices/graphics/arch-sv-glsv.html110
-rw-r--r--zh-cn/devices/graphics/architecture.html56
-rw-r--r--zh-cn/devices/graphics/automate-tests.html102
-rw-r--r--zh-cn/devices/graphics/implement-vdisplays.html51
-rw-r--r--zh-cn/devices/graphics/port-tests.html138
-rw-r--r--zh-cn/devices/graphics/run-tests.html259
-rw-r--r--zh-cn/devices/graphics/test-groups.html49
-rw-r--r--zh-cn/devices/index.html137
-rw-r--r--zh-cn/devices/input/diagnostics.html465
-rw-r--r--zh-cn/devices/input/keyboard-devices.html6305
-rw-r--r--zh-cn/devices/media/index.html84
-rw-r--r--zh-cn/devices/sensors/batching.html128
-rw-r--r--zh-cn/devices/sensors/sensor-types.html492
-rw-r--r--zh-cn/devices/sensors/versioning.html125
-rw-r--r--zh-cn/devices/storage/index.html48
-rw-r--r--zh-cn/devices/tech/dalvik/dex-format.html33
-rw-r--r--zh-cn/devices/tech/debug/gdb.html8
-rw-r--r--zh-cn/devices/tech/debug/index.html86
-rw-r--r--zh-cn/devices/tech/ota/device_code.html163
-rw-r--r--zh-cn/devices/tech/power/mgmt.html24
-rw-r--r--zh-cn/devices/tv/index.html425
-rw-r--r--zh-cn/devices/tv/reference-tv-app.html154
62 files changed, 12846 insertions, 577 deletions
diff --git a/en/compatibility/cts/usb-audio.html b/en/compatibility/cts/usb-audio.html
index 6c8ca5b2..b81a8909 100644
--- a/en/compatibility/cts/usb-audio.html
+++ b/en/compatibility/cts/usb-audio.html
@@ -76,8 +76,6 @@ USB</a></li>
<p class="note"><strong>Note:</strong> This list is preliminary and subject to change.</p>
-<p>Google USB headset</p>
-
<table>
<tr>
<td width="50%">A USB headset
diff --git a/en/compatibility/index.html b/en/compatibility/index.html
index e6bc9959..d053a587 100644
--- a/en/compatibility/index.html
+++ b/en/compatibility/index.html
@@ -30,9 +30,10 @@ innovative apps.</p>
Android platform and provides tools for OEMs to ensure developer applications
run on a variety of devices.</li>
<li>The Android SDK provides built-in tools for developers to clearly state the
-device features required by their applications.
+device features required by their applications.</li>
<li>Google Play shows applications only to those devices that can properly run
-those applications.</li></li>
+those applications.</li>
+</ul>
<h2 id="why-build-compatible-android-devices">Why build compatible Android
devices?</h2>
diff --git a/en/devices/_toc-interfaces.yaml b/en/devices/_toc-interfaces.yaml
index 78759ac0..6c13a21c 100644
--- a/en/devices/_toc-interfaces.yaml
+++ b/en/devices/_toc-interfaces.yaml
@@ -205,6 +205,10 @@ toc:
section:
- title: Overview
path: /devices/bluetooth
+ - title: Services
+ path: /devices/bluetooth/services
+ - title: BLE Advertising
+ path: /devices/bluetooth/ble_advertising
- title: Verifying and Debugging
path: /devices/bluetooth/verifying_debugging
- title: HCI Requirements
@@ -303,8 +307,6 @@ toc:
path: /devices/input/keyboard-devices
- title: Touch Devices
path: /devices/input/touch-devices
- - title: Diagnostics
- path: /devices/input/diagnostics
- title: Getevent
path: /devices/input/getevent
- title: Validate Keymaps
diff --git a/en/devices/_toc-tech.yaml b/en/devices/_toc-tech.yaml
index acbcf334..14c55a38 100644
--- a/en/devices/_toc-tech.yaml
+++ b/en/devices/_toc-tech.yaml
@@ -205,8 +205,6 @@ toc:
path: /devices/tech/power/device
- title: Power Values
path: /devices/tech/power/values
- - title: Battery Use
- path: /devices/tech/power/batterystats
- title: Settings Menu
section:
- title: Overview
diff --git a/en/devices/architecture/index.html b/en/devices/architecture/index.html
index a4a415e3..38f494a7 100644
--- a/en/devices/architecture/index.html
+++ b/en/devices/architecture/index.html
@@ -65,10 +65,12 @@ loaded by the Android system at the appropriate time. For details, see
<h2 id="Linux-kernel">Linux kernel</h2>
<p>Developing your device drivers is similar to developing a typical Linux
device driver. Android uses a version of the Linux kernel with a few special
-additions such as wake locks (a memory management system that is more aggressive
-in preserving memory), the Binder IPC driver, and other features important for a
-mobile embedded platform. These additions are primarily for system functionality
-and do not affect driver development.</p>
+additions such as Low Memory Killer (a memory management system that is more
+aggressive in preserving memory), wake locks (a
+<a href="https://developer.android.com/reference/android/os/PowerManager.html">
+<code>PowerManager</code></a> system service), the Binder IPC driver, and
+other features important for a mobile embedded platform. These additions are
+primarily for system functionality and do not affect driver development.</p>
<p>You can use any version of the kernel as long as it supports the required
features (such as the binder driver). However, we recommend using the latest
diff --git a/en/devices/audio/debugging.html b/en/devices/audio/debugging.html
index 67e23d03..c2b7cd73 100644
--- a/en/devices/audio/debugging.html
+++ b/en/devices/audio/debugging.html
@@ -121,12 +121,13 @@ but you can get similar results using "4."
<ol>
<li>Run your audio test.</li>
<li><code class="devsite-terminal">adb shell dumpsys media.audio_flinger</code></li>
-<li>Look for a line in dumpsys output such as this:<br />
+<li>Look for a line in <code>dumpsys</code> output such as this:<br />
<code>tee copied to /data/misc/media/20131010101147_2.wav</code>
<br />This is a PCM .wav file.
</li>
<li>Then <code>adb pull</code> any <code>/data/misc/media/*.wav</code> files of interest;
-note that track-specific dump filenames do not appear in the dumpsys output,
+ note that track-specific dump filenames do not appear in the
+ <code>dumpsys</code> output,
but are still saved to <code>/data/misc/media</code> upon track closure.
</li>
<li>Review the dump files for privacy concerns before sharing with others.</li>
diff --git a/en/devices/bluetooth/ble_advertising.html b/en/devices/bluetooth/ble_advertising.html
new file mode 100644
index 00000000..6fc93f8c
--- /dev/null
+++ b/en/devices/bluetooth/ble_advertising.html
@@ -0,0 +1,258 @@
+<html devsite>
+ <head>
+ <title>Bluetooth Low Energy Advertising</title>
+ <meta name="project_path" value="/_project.yaml" />
+ <meta name="book_path" value="/_book.yaml" />
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <p>
+ Bluetooth Low Energy (BLE) conserves power by remaining in sleep mode
+ most of the time. It wakes up only to make advertisements and short
+ connections, so advertisements affect both power consumption and
+ data transfer bandwidth.
+ </p>
+
+ <h2 id="bluetooth-5-advertising-extension">Bluetooth 5 advertising extension</h2>
+
+ <p>
+ Android 8.0 supports Bluetooth 5, which provides broadcasting
+ improvements and flexible data advertisement for BLE. Bluetooth 5 supports BLE Physical Layers (PHYs) that retain the
+ reduced power consumption of Bluetooth 4.2 and let users choose
+ increased bandwidth or range. More information can be found in the
+ <a href="https://www.bluetooth.com/specifications/adopted-specifications">
+ Bluetooth 5 Core Specifications</a>.
+ </p>
+
+ <h3 id="implementation">Implementation</h3>
+
+ <p>
+ New Bluetooth 5 features are automatically available for devices
+ running Android 8.0 with compatible Bluetooth controllers. Use these
+ <code><a href="https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html">
+ BluetoothAdapter</a></code>
+ methods to check if a device supports Bluetooth 5 features:
+ </p>
+
+ <ul>
+ <li><code>isLe2MPhySupported()</code></li>
+ <li><code>isLeCodedPhySupported()</code></li>
+ <li><code>isLeExtendedAdvertisingSupported()</code></li>
+ <li><code>isLePeriodicAdvertisingSupported()</code></li>
+ </ul>
+
+ <p>
+ To disable the advertising features, work with the Bluetooth chip
+ vendor to disable chip-set support.
+ </p>
+
+ <p>
+ The Bluetooth PHYs are exclusive of one another, and the behavior of
+ each PHY is predefined by the Bluetooth SIG. By default, Android 8.0
+ uses Bluetooth LE 1M PHY, from Bluetooth 4.2. The
+ <code><a href="https://developer.android.com/reference/android/bluetooth/le/package-summary.html">
+ android.bluetooth.le</a></code>
+ package exposes the Bluetooth 5 advertising features through these
+ APIs:
+ </p>
+
+ <ul>
+ <li><code>AdvertisingSet</code></li>
+ <li><code>AdvertisingSetCallback</code></li>
+ <li><code>AdvertisingSetParameters</code></li>
+ <li><code>PeriodicAdvertisingParameters</code></li>
+ </ul>
+
+ <p>
+ Create an <code><a href="https://developer.android.com/reference/android/bluetooth/le/AdvertisingSet.html">
+ AdvertisingSet</a></code>
+ to modify Bluetooth advertisement settings by using the <code><a
+ href="https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html#startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters,
+ android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData,
+ android.bluetooth.le.PeriodicAdvertisingParameters,
+ android.bluetooth.le.AdvertiseData,
+ android.bluetooth.le.AdvertisingSetCallback)">
+ startAdvertisingSet()</a></code> method in <code><a
+ href="https://developer.android.com/reference/android/bluetooth/le/BluetoothLeAdvertiser.html">
+ android.bluetooth.le.BluetoothLeAdvertiser</a></code>. Even if
+ support for Bluetooth 5 or its advertising features is disabled, the
+ API features can also apply to LE 1M PHY.
+ </p>
+
+ <h4 id="examples">Examples</h4>
+
+ <p>
+ This example app uses Bluetooth LE 1M PHY for advertising:
+ </p>
+
+<pre class="prettyprint">
+ // Start legacy advertising. Works for devices with 5.x controllers,
+ and devices that support multi-advertising.
+
+ void example1() {
+ BluetoothLeAdvertiser advertiser =
+ BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
+
+ AdvertisingSetParameters parameters = (new AdvertisingSetParameters.Builder())
+ .setLegacyMode(true) // True by default, but set here as a reminder.
+ .setConnectable(true)
+ .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
+ .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
+ .build();
+
+ AdvertiseData data = (new AdvertiseData.Builder()).setIncludeDeviceName(true).build();
+
+ AdvertisingSetCallback callback = new AdvertisingSetCallback() {
+ &#64;Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
+ Log.i(LOG_TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
+ + status);
+ currentAdvertisingSet = advertisingSet;
+ }
+
+ &#64;Override
+ public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ Log.i(LOG_TAG, "onAdvertisingDataSet() :status:" + status);
+ }
+
+ &#64;Override
+ public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
+ Log.i(LOG_TAG, "onScanResponseDataSet(): status:" + status);
+ }
+
+ &#64;Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ Log.i(LOG_TAG, "onAdvertisingSetStopped():");
+ }
+ };
+
+ advertiser.startAdvertisingSet(parameters, data, null, null, null, callback);
+
+ // After onAdvertisingSetStarted callback is called, you can modify the
+ // advertising data and scan response data:
+ currentAdvertisingSet.setAdvertisingData(new AdvertiseData.Builder().
+ setIncludeDeviceName(true).setIncludeTxPowerLevel(true).build());
+ // Wait for onAdvertisingDataSet callback...
+ currentAdvertisingSet.setScanResponseData(new
+ AdvertiseData.Builder().addServiceUuid(new ParcelUuid(UUID.randomUUID())).build());
+ // Wait for onScanResponseDataSet callback...
+
+ // When done with the advertising:
+ advertiser.stopAdvertisingSet(callback);
+}</pre>
+
+ <p>
+ This example app uses the BLE 2M PHY for advertising. The app first
+ checks that the device supports the features being used. If the
+ advertising features are supported, then the app configures BLE 2M
+ PHY as the primary PHY. While 2M PHY is active, advertisement does
+ not support Bluetooth 4.x controllers, so <code>setLegacyMode</code>
+ is set to <code>false</code>. This example modifies parameters while
+ advertising and also pauses the advertisement.
+ </p>
+
+<pre class="prettyprint">void example2() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothLeAdvertiser advertiser =
+ BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
+
+ // Check if all features are supported
+ if (!adapter.isLe2MPhySupported()) {
+ Log.e(LOG_TAG, "2M PHY not supported!");
+ return;
+ }
+ if (!adapter.isLeExtendedAdvertisingSupported()) {
+ Log.e(LOG_TAG, "LE Extended Advertising not supported!");
+ return;
+ }
+
+ int maxDataLength = adapter.getLeMaximumAdvertisingDataLength();
+
+ AdvertisingSetParameters.Builder parameters = (new AdvertisingSetParameters.Builder())
+ .setLegacyMode(false)
+ .setInterval(AdvertisingSetParameters.INTERVAL_HIGH)
+ .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MEDIUM)
+ .setPrimaryPhy(BluetoothDevice.PHY_LE_2M)
+ .setSecondaryPhy(BluetoothDevice.PHY_LE_2M);
+
+ AdvertiseData data = (new AdvertiseData.Builder()).addServiceData(new
+ ParcelUuid(UUID.randomUUID()),
+ "You should be able to fit large amounts of data up to maxDataLength. This goes
+ up to 1650 bytes. For legacy advertising this would not
+ work".getBytes()).build();
+
+ AdvertisingSetCallback callback = new AdvertisingSetCallback() {
+ &#64;Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
+ Log.i(LOG_TAG, "onAdvertisingSetStarted(): txPower:" + txPower + " , status: "
+ + status);
+ currentAdvertisingSet = advertisingSet;
+ }
+
+ &#64;Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ Log.i(LOG_TAG, "onAdvertisingSetStopped():");
+ }
+ };
+
+ advertiser.startAdvertisingSet(parameters.build(), data, null, null, null, callback);
+
+ // After the set starts, you can modify the data and parameters of currentAdvertisingSet.
+ currentAdvertisingSet.setAdvertisingData((new
+ AdvertiseData.Builder()).addServiceData(new ParcelUuid(UUID.randomUUID()),
+ "Without disabling the advertiser first, you can set the data, if new data is
+ less than 251 bytes long.".getBytes()).build());
+
+ // Wait for onAdvertisingDataSet callback...
+
+ // Can also stop and restart the advertising
+ currentAdvertisingSet.enableAdvertising(false, 0, 0);
+ // Wait for onAdvertisingEnabled callback...
+ currentAdvertisingSet.enableAdvertising(true, 0, 0);
+ // Wait for onAdvertisingEnabled callback...
+
+ // Or modify the parameters - i.e. lower the tx power
+ currentAdvertisingSet.enableAdvertising(false, 0, 0);
+ // Wait for onAdvertisingEnabled callback...
+ currentAdvertisingSet.setAdvertisingParameters(parameters.setTxPowerLevel
+ (AdvertisingSetParameters.TX_POWER_LOW).build());
+ // Wait for onAdvertisingParametersUpdated callback...
+ currentAdvertisingSet.enableAdvertising(true, 0, 0);
+ // Wait for onAdvertisingEnabled callback...
+
+ // When done with the advertising:
+ advertiser.stopAdvertisingSet(callback);
+}</pre>
+
+ <h3 id="verification">Verification</h3>
+
+ <p> Run applicable <a
+ href="https://www.bluetooth.com/develop-with-bluetooth/test-tools">
+ Bluetooth product tests</a> to verify device compatibility with
+ Bluetooth 5.
+ </p>
+
+ <p>
+ AOSP contains the Android Comms Test Suite (ACTS), which includes
+ tests for Bluetooth 5. The ACTS tests for Bluetooth 5 can be found
+ in <code><a
+ href="https://android.googlesource.com/platform/tools/test/connectivity/+/master/acts/tests/google/ble/bt5/">
+ tools/test/connectivity/acts/tests/google/ble/bt5</a></code>.
+ </p>
+ </body>
+</html>
diff --git a/en/devices/bluetooth/services.html b/en/devices/bluetooth/services.html
new file mode 100644
index 00000000..59a76ca2
--- /dev/null
+++ b/en/devices/bluetooth/services.html
@@ -0,0 +1,463 @@
+<html devsite>
+ <head>
+ <title>Bluetooth Services</title>
+ <meta name="project_path" value="/_project.yaml" />
+ <meta name="book_path" value="/_book.yaml" />
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+ <p>
+ Over Bluetooth, devices can transmit data that can be used for
+ interactive services such as audio, messaging, and telephony. The
+ Bluetooth profiles used for different services can be found in
+ <code><a href="https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware">
+ hardware/libhardware/include/hardware/</a></code>.
+ </p>
+
+ <h2 id="audio">Audio</h2>
+
+ <aside class="note"><strong>Note</strong>: Currently only
+ Classic Bluetooth supports any type of audio streaming.
+ </aside>
+
+ <p>
+ A Bluetooth connection lets users stream audio on Bluetooth-enabled
+ devices. For most audio use cases, the Android device is the source,
+ and the rendering device, such as a speaker or a headset, is the sink.
+ </p>
+
+ <h3 id="absolute-volume-control">Absolute volume control</h3>
+
+ <p>
+ In Android 6.0 and later, the Android Bluetooth stack lets a
+ source set an absolute volume, giving users accurate control over
+ audio volume. The source device sends un-attenuated audio and volume
+ information to the sink. The sink then amplifies the audio according
+ to the volume information, so users hear accurate playback volume.
+ </p>
+
+ <p>
+ The source device can also register volume notifications. When
+ volume changes are made with controls on the sink, the sink sends a
+ notification to the source. This lets the source accurately display
+ volume information on a user interface.
+ </p>
+
+ <p>
+ Absolute volume control is on by default. To disable absolute
+ volume control, users can go to <strong>Settings</strong> &gt;
+ <strong>System</strong> &gt; <strong>Developer options</strong>
+ and select the toggle for <strong>Disable absolute volume</strong>.
+ </p>
+
+ <h3 id="advanced-audio-codecs">Advanced audio codecs</h3>
+
+ <p>
+ In Android 8.0, devices that use the Advanced Audio Distribution
+ Profile (A2DP) can support additional audio codecs. The Bluetooth
+ stack supports audio codec negotiation for when devices connect to
+ a remote audio sink. This negotiation selects the best codec
+ supported by both the sender and the sink to provide high-quality
+ audio. After selection, all audio is routed through the selected
+ encoder and then sent to the sink.
+ </p>
+
+ <h4 id="implementation">Implementation</h4>
+
+ <p>
+ Devices running Android 8.0 that support A2DP automatically
+ gain the additional codec support. Device manufacturers may need
+ to obtain separate licenses and binary blobs for some
+ proprietary audio codecs. In addition to SBC, Android 8.0
+ supports the following codecs:
+ </p>
+
+ <ul>
+ <li>AAC</li>
+ <li>aptX</li>
+ <li>aptX HD</li>
+ <li>LDAC</li>
+ </ul>
+
+ <p>
+ Device manufacturers can choose which codecs their devices
+ attempt to use first. Set the codec priorities by changing the
+ following values in <code><a href="https://android.googlesource.com/platform/packages/apps/Bluetooth/+/master/res/values/config.xml">
+ res/values/config.xml</a></code>:
+ </p>
+
+<pre class="prettyprint">
+ &lt;!-- Configuring priorities of A2DP source codecs. Larger value means
+ higher priority. Value -1 means the codec is disabled.
+ Value 0 is reserved and should not be used here. Enabled codecs
+ should have priorities in the interval [1, 999999], and each
+ priority value should be unique. --&gt;
+ &lt;integer name="a2dp_source_codec_priority_sbc"&gt;1001&lt;/integer&gt;
+ &lt;integer name="a2dp_source_codec_priority_aac"&gt;2001&lt;/integer&gt;
+ &lt;integer name="a2dp_source_codec_priority_aptx"&gt;3001&lt;/integer&gt;
+ &lt;integer name="a2dp_source_codec_priority_aptx_hd"&gt;4001&lt;/integer&gt;
+ &lt;integer name="a2dp_source_codec_priority_ldac"&gt;5001&lt;/integer&gt;
+ </pre>
+
+ <h4 id="ldac-certification">LDAC certification</h4>
+
+ <p>
+ The Android Open Source Project includes Sony's LDAC codec, so a
+ separate license or blob is not needed for it. To integrate the
+ LDAC codec into your device, register with Sony and follow the
+ <a href="https://www.sony.net/Products/LDAC/aosp/">
+ LDAC certification process</a>.
+ </p>
+
+ <p>
+ The LDAC certification website has documentation about LDAC,
+ such as specification and operation handbooks. The LDAC site also
+ provides validation and interoperability tests for mobile and
+ tablet devices. Send passing test results to Sony to complete LDAC
+ certification.
+ </p>
+
+ <h4 id="ui-features">UI features</h4>
+
+ <p>
+ Along with additional codec support, Android 8.0 provides a
+ user-facing setting to disable high-definition (HD) Bluetooth
+ audio codecs.
+ </p>
+
+ <ol>
+ <li>Navigate to <strong>Settings</strong> &gt;
+ <strong>Connected devices</strong> &gt;
+ <strong>Bluetooth</strong>.</li>
+ <li>Tap on the gear icon next to the sink you want to disable codecs for.</li>
+ <li>Uncheck the <strong>HD Audio</strong> checkbox.</li>
+ </ol>
+
+ <p>
+ Device manufacturers that customize Settings should implement a
+ way for users to disable HD codecs.
+ </p>
+
+ <h2 id="messaging">Messaging</h2>
+
+ <p>
+ Messaging over Bluetooth lets users read, browse, and compose SMS
+ messages from a remote device. This capability is often used when
+ connecting a phone to an in-vehicle infotainment system.
+ </p>
+
+ <aside class="note"><strong>Note</strong>: Bluetooth messaging services
+ currently only support SMS. Email and instant messages are not
+ supported.
+ </aside>
+
+ <h2 id="telephony">Telephony</h2>
+
+ <p>
+ Bluetooth telephony services lets users stream calls and sync
+ contacts from a phone to another Bluetooth device. These features are
+ often used for hands-free calls when driving.
+ </p>
+
+ <p>
+ In Android 8.0, Bluetooth supports in-band ringtone. When a phone
+ connected over Bluetooth receives an incoming call, the ringtone will
+ play on the sink. Enable in-band ringtone in <strong>Settings</strong>
+ &gt; <strong>System</strong> &gt; <strong>Developer options</strong> by
+ selecting the toggle for <strong>Enable in-band ringing</strong>.
+ </p>
+
+ <h2>Bluetooth features</h2>
+ <p> To implement the Bluetooth services, the Bluetooth stack supports a
+ variety of profiles and features.
+ </p>
+
+ <h3 id="bluetooth-profiles">Bluetooth profiles</h3>
+
+ <p>
+ These profiles are available for Bluetooth:
+ </p>
+
+ <table>
+ <tr>
+ <th colspan="2" >Feature</th>
+ <th colspan="5" >Android version</th>
+ </tr>
+ <tr>
+ <th>Name</th>
+ <th>Description</th>
+ <th>6.0</th>
+ <th>7.0</th>
+ <th>7.1</th>
+ <th>7.1.2</th>
+ <th>8.0</th>
+ </tr>
+ <tr>
+ <td><strong>SAP</strong></td>
+ <td>SIM Access Profile</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ </tr>
+ <tr>
+ <td><strong>MAP</strong></td>
+ <td>Message Access Profile for SMS</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>OPP</strong></td>
+ <td>Object Push Profile</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>OBEX over L2CAP</strong></td>
+ <td>OBject EXchange over Logical Link Control and Adaptation
+ Protocol</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>HFP Audio Gateway</strong></td>
+ <td>Hands-Free Profile</td>
+ <td>1.6</td>
+ <td>1.6</td>
+ <td>1.7</td>
+ <td>1.7</td>
+ <td>1.7</td>
+ </tr>
+ <tr>
+ <td><strong>HSP</strong></td>
+ <td>Headset Profile</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>A2DP</strong></td>
+ <td>Advanced Audio Distribution Profile</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>AVRCP</strong></td>
+ <td>Audio/Video Remote Control Profile</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.4</td>
+ </tr>
+ <tr>
+ <td><strong>HID</strong></td>
+ <td>Human Interface Device Profile</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ </tr>
+ <tr>
+ <td><strong>PBAP</strong></td>
+ <td>Phone Book Access Profile</td>
+ <td>1.1.1</td>
+ <td>1.1.1</td>
+ <td>1.1.1</td>
+ <td>1.1.1</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>HDP</strong></td>
+ <td>Health Device Profile</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ <td>1.1</td>
+ </tr>
+ <tr>
+ <td><strong>SPP</strong></td>
+ <td>Serial Port Profile</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ <td>1.2</td>
+ </tr>
+ <tr>
+ <td><strong>PAN / BNEP</strong></td>
+ <td>Personal Area Networking Profile / Bluetooth Network
+ Encapsulation Protocol</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ <td>1.0</td>
+ </tr>
+ <tr>
+ <td><strong>DIP</strong></td>
+ <td>Device ID Profile</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ <td>1.3</td>
+ </tr>
+ <tr>
+ <td><strong>HOGP 1.0</strong></td>
+ <td>HID over GATT</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>HD Audio</strong><sup id="fnref1"><a href="#fn1"
+ rel="footnote">1</a></sup></td>
+ <td>See "Advanced audio codecs" above</td>
+ <td>No</td>
+ <td>No</td>
+ <td>No</td>
+ <td>No</td>
+ <td>Yes</td>
+ </tr>
+ </table>
+
+ <p>
+ <sup id="fn1">1</sup> Implementing HD Audio depends on device
+ capabilities, both on the source and the sink.
+ </p>
+
+ <h3 id="bluetooth-low-energy-features">Bluetooth Low Energy features</h3>
+
+ <p>
+ These features are available for BLE:
+ </p>
+
+ <table>
+ <tr>
+ <th>Feature</th>
+ <th colspan="5" >Android version</th>
+ </tr>
+ <tr>
+ <th>Name</th>
+ <th>6.0</th>
+ <th>7.0</th>
+ <th>7.1</th>
+ <th>7.1.2</th>
+ <th>8.0</th>
+ </tr>
+ <tr>
+ <td><strong>BR/EDR secure connections</strong></td>
+ <td>4.1</td>
+ <td>4.1</td>
+ <td>4.1</td>
+ <td>4.1</td>
+ <td>5.0</td>
+ </tr>
+ <tr>
+ <td><strong>LE Privacy</strong></td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>5.0</td>
+ </tr>
+ <tr>
+ <td><strong>LE secure connections</strong></td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>5.0</td>
+ </tr>
+ <tr>
+ <td><strong>Data Packet Extensions</strong></td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>4.2</td>
+ <td>5.0</td>
+ </tr>
+ <tr>
+ <td><strong>32-bit UUIDs</strong></td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>Dual Mode LE Central/Peripheral</strong></td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>LE Peripheral Mode</strong></td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>Google HCI Requirements</strong></td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ <td>Yes</td>
+ </tr>
+ <tr>
+ <td><strong>LE Connection-Oriented Channels</strong></td>
+ <td>No</td>
+ <td>No</td>
+ <td>No</td>
+ <td>No</td>
+ <td>Yes<sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ <sup id="fn2">2</sup> Implementing LE Connection-Oriented Channels
+ depends on device capabilities, both on the source and the sink.
+ </p>
+ </body>
+</html>
diff --git a/en/devices/camera/camera3_requests_methods.html b/en/devices/camera/camera3_requests_methods.html
index edd4dfe5..6fd429d4 100644
--- a/en/devices/camera/camera3_requests_methods.html
+++ b/en/devices/camera/camera3_requests_methods.html
@@ -85,7 +85,7 @@ returned by the HAL through the <code>process_capture_result()</code> call. This
<h3 id="dump">dump</h3>
<p>Print out debugging state for the camera device. This will be called by the
framework when the camera service is asked for a debug dump, which happens when
- using the dumpsys tool, or when capturing a bugreport. The passed-in file
+ using the <code>dumpsys</code> tool, or when capturing a bugreport. The passed-in file
descriptor can be used to write debugging text using <code>dprintf()</code> or <code>write()</code>. The
text should be in ASCII encoding only.</p>
<h3 id="flush">flush</h3>
diff --git a/en/devices/input/migration-guide.html b/en/devices/input/migration-guide.html
index 6f50f004..9ca346b8 100644
--- a/en/devices/input/migration-guide.html
+++ b/en/devices/input/migration-guide.html
@@ -45,7 +45,8 @@ function input devices. These files should simple contain a line to set
the keyboard type to <code>SPECIAL_FUNCTION</code>.</p>
<p>A good way to ensure that all built-in input devices are appropriately configured
is to run <a
- href="https://developer.android.com/studio/command-line/dumpsys.html">Dumpsys</a>
+ href="https://developer.android.com/studio/command-line/dumpsys.html">
+ <code>dumpsys</code></a>
and look for devices that are inappropriately using <code>Generic.kcm</code>.</p>
<h2 id="migrating-to-android-honeycomb-32">Migrating to Android Honeycomb 3.2</h2>
<p>In Honeycomb 3.2, we added support for joysticks and extended the key layout file
diff --git a/en/devices/tech/admin/testing-setup.html b/en/devices/tech/admin/testing-setup.html
index dc89c1a4..131ade86 100644
--- a/en/devices/tech/admin/testing-setup.html
+++ b/en/devices/tech/admin/testing-setup.html
@@ -27,45 +27,39 @@
following essential elements:</p>
<ul>
- <li>Profile owner (as described in
- <a href="https://developer.android.com/training/enterprise/app-compatibility.html">Ensuring
- Compatibility with Managed Profiles</a>)</li>
- <li>Device owner</li>
- </ul>
+<li>Profile owner (as described in
+<a href="https://developer.android.com/training/enterprise/app-compatibility.html" class="external">Ensuring
+Compatibility with Managed Profiles</a>)</li>
+<li>Device owner</li>
+</ul>
<p>For a complete list of requirements, see
<a href="/devices/tech/admin/implement.html">Implementing Device
-Administration</a>.</p>
-
-<p>To test device administration features, device owners can use the TestDPC
-application (described below); consider also working directly with other
-enterprise mobility management (EMM) providers.</p>
+Administration</a>. To test device administration features, device owners can
+use the TestDPC application described below.</p>
<h2 id=set_up_the_device_owner_for_testing>Set up device owner for testing</h2>
<p>Use the following instructions to set up a device owner testing environment.</p>
<ol>
- <li>Set up the device:
- <ol>
- <li style="list-style-type: lower-alpha">Factory reset the target device.</li>
- <li style="list-style-type: lower-alpha">Ensure you do not add any user accounts
- (e.g. those used to log into online services) to the device.
- This can be checked in <em>Settings->Accounts</em>.</li>
- </ol></li>
- <li>Set up the testing application using one of the following methods:
+<li>Factory reset the target device.</li>
+<li>Ensure the device does not contain any user accounts (e.g. those used to log
+into online services). To verify, check <em>Settings > Accounts</em>.</li>
+<li>Set up the testing application using one of the following methods:
<ul>
- <li><a href="https://play.google.com/store/apps/details?id=com.afwsamples.testdpc&hl=en">Download
+ <li><a href="https://play.google.com/store/apps/details?id=com.afwsamples.testdpc&hl=en" class="external">Download
the TestDPC application</a> (available from Google Play).</li>
- <li><a href="https://github.com/googlesamples/android-testdpc/">Build
+ <li><a href="https://github.com/googlesamples/android-testdpc/" class="external">Build
the TestDPC application</a> (available from github.com).</li>
</ul>
- </li>
- <li>Set the TestDPC app as the device owner using the following command:<br>
+</li>
+<li>Set the TestDPC app as the device owner using the following command:
<pre class="devsite-terminal devsite-click-to-copy">
adb shell dpm set-device-owner "com.afwsamples.testdpc/.DeviceAdminReceiver"
</pre>
- </li>
- <li>Go through device owner setup on the device (encrypt, select Wi-Fi, etc.)</li>
+</li>
+<li>Go through device owner setup on the device (encrypt, select Wi-Fi, etc.).
+</li>
</ol>
<h2 id=verify_the_device_owner_was_correctly_setup>Verify device owner setup</h2>
@@ -80,22 +74,22 @@ the Android for Work (AfW) Test Harness. For details, see
Provisioning</a>.</p>
<h2 id="troubleshooting">Bug reports and logs</h2>
-<p>In Android 7.0, device owner Device Policy Client (DPCs) can get bug reports
-and view logs for enterprise processes on a managed device.</p>
-
-<p>To trigger a bug report (i.e., the equivalent data collected by <code>adb
-bugreport</code> containing dumpsys, dumpstate, and logcat data), use
-<code>DevicePolicyController.requestBugReport</code>. After the bug report is
-collected, the user is prompted to give consent to send the bug report data.
-Results are received by
+<p>As of Android 7.0, device owner Device Policy Client (DPCs) can get bug
+reports and view logs for enterprise processes on a managed device.</p>
+
+<p>To trigger a bug report (i.e., the equivalent data collected by
+<code>adb bugreport</code> containing <code>dumpsys</code>, dumpstate, and
+logcat data), use <code>DevicePolicyController.requestBugReport</code>. After
+the bug report is collected, the user is prompted to give consent to send the
+bug report data. Results are received by
<code>DeviceAdminReceiver.onBugreport[Failed|Shared|SharingDeclined]</code>. For
details on bug report contents, see
-<a href="/source/read-bug-reports.html">Reading Bug Reports</a>.
+<a href="/source/read-bug-reports.html">Reading Bug Reports</a>.</p>
<p>In addition, device owner DPCs can also collect logs related to actions a
user has taken on a managed device. Enterprise process logging is required for
all devices that report device_admin and enabled by a new log security buffer
-readable only by the system server (i.e., <code>adb logcat -b security</code>
+readable only by the system server (i.e., <code>$ adb logcat -b security</code>
cannot read the buffer). ActivityManager service and Keyguard components log the
following events to the security buffer:</p>
diff --git a/en/devices/tech/config/filesystem.html b/en/devices/tech/config/filesystem.html
index 98a72baa..c1bf33d5 100644
--- a/en/devices/tech/config/filesystem.html
+++ b/en/devices/tech/config/filesystem.html
@@ -21,31 +21,306 @@
limitations under the License.
-->
+<p>When adding file system objects and services to the build, such items
+frequently need separate unique IDs, known as Android IDs (AIDs). Currently,
+many resources such as files and services use core, Android-defined AIDs
+unnecessarily; in many cases you can use OEM-defined AIDs instead.</p>
-<p>Earlier versions of Android used a system configuration file that was
-not extensible, preventing device manufacturers from adding named binaries to
-specify Discretionary Access Controls (DAC) of ownership, access mode, or
-executable capabilities. This limitation occurred as a result of support for
-Linux kernels 3.14 and higher in which wake lock is enabled via the
-<code>CAP_SUSPEND_BLOCK</code> capability; partner-supplied GPS daemons were
-required to hold this wake lock (and thus have this capability set in the file
-system).</p>
-
-<p>As of Android 6.0, <code>fs_config</code> and associated structure definitions
-(<code>system/core/include/private/android_filesystem_config.h</code>) are now
-located in <code>system/core/libcutils/fs_config.c</code> where they can be
-updated or overridden by binary files installed in
-<code>/system/etc/fs_config_dirs</code> and
-<code>/system/etc/fs_config_files</code>. For clarity, Android uses separate
-matching and parsing rules for directories and files (which can use additional
-glob expressions) and handles directories and files in two different tables.
-Structure definitions in <code>system/core/libcutils/fs_config.c</code> not only
-allow runtime reading of directories and files, but the host may use the same
-files during build time to construct filesystem images as
+<p>In earlier versions of Android, extending the AIDs mechanism used a
+device-specific <code>android_filesystem_config.h</code> file to specify the
+filesystem capabilities and/or custom OEM AIDs. However, this system was
+unintuitive as it did not support using nice names for OEM AIDs, requiring you
+to specify the raw numeric for user and group fields without a way to associate
+a friendly name with the numeric AID.</p>
+
+<p>Android 8.0 and higher includes a new AIDs mechanism for extending filesystem
+capabilities. This new method has support for the following:</p>
+<ul>
+<li>Multiple source locations for configuration files (enables extensible build
+configurations).</li>
+<li>Build-time sanity checking of OEM AID values.</li>
+<li>Generation of a custom OEM AID header that can be used in source files as
+needed.</li>
+<li>Association of a friendly name with the actual OEM AID value. Supports
+non-numeric string arguments for user and group, i.e. "foo" instead of
+"2901".</li>
+</ul>
+
+<p>Additional improvements include the removal of the <code>android_ids[]</code>
+array from <code>system/core/include/private/android_filesystem_config.h</code>.
+This array now exists in Bionic as a fully private generated array, with
+accessors via <code>getpwnam()</code> and <code>getgrnam()</code>. (This has the
+side effect of producing stable binaries as core AIDs are modified.) For tooling
+and a README file with more details, refer to
+<code>build/make/tools/fs_config</code>.</p>
+
+<aside class="note"><strong>Note:</strong> While you can still use the
+<a href="#older">filesystem override method from previous Android releases</a>,
+you cannot use it simultaneously with the new AIDs mechanism. Using the new
+mechanism whenever possible is recommended.</aside>
+
+<h2 id="adding-android-ids-aids">Adding Android IDs (AIDs)</h2>
+<p>Android 8.0 removes the <code>android_ids[]</code> array from the Android
+Open Source Project (AOSP). All AID-friendly names are instead generated from
+the <code>system/core/include/private/android_filesystem_config.h</code> header
+file when generating the Bionic <code>android_ids[]</code> array. Any
+<code>define</code> matching <code>AID_*</code> is picked up by the tooling and
+<strong>*</strong> becomes the lowercase name.</p>
+
+<p>For example, in <code>private/android_filesystem_config.h</code>:</p>
+
+<pre class="prettyprint">#define AID_SYSTEM 1000</pre>
+
+<p>Becomes:</p>
+<ul>
+<li>Friendly name: system</li>
+<li>uid: 1000</li>
+<li>gid: 1000</li>
+</ul>
+
+<p>To add a new AOSP core AID, simply add the <code>#define</code> to the
+<code>android_filesystem_config.h</code> header file. The AID will be generated
+at build and made available to interfaces that use user and group arguments. The
+tooling validates the new AID is not within the APP or OEM ranges; it also
+respects changes to those ranges and should automatically reconfigure on changes
+or new OEM-reserved ranges.</p>
+
+<h2 id="configuring-aids">Configuring AIDs</h2>
+<p>
+To enable the new AIDs mechanism, set <code>TARGET_FS_CONFIG_GEN</code> in the
+<code>BoardConfig.mk</code> file. This variable holds a list of configuration
+files, enabling you to append files as needed.</p>
+
+<aside class="caution"><strong>Caution:</strong> Don't use
+<code>TARGET_FS_CONFIG_GEN</code> with the
+older <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> method from older Android
+releases! You will get an error.</aside>
+
+<p>By convention, configuration files use the name <code>config.fs</code>, but
+in practice you can use any name. <code>config.fs</code> files are in the
+<a href="https://docs.python.org/2/library/configparser.html" class="external">Python
+ConfigParser ini format</a> and include a caps section (for configuring file
+system capabilities) and an AIDs section (for configuring OEM-specific AIDs).
+</p>
+
+<h3 id="configuring-the-caps-section">Configuring the caps section</h3>
+<p>The caps section supports setting
+<a href="http://man7.org/linux/man-pages/man7/capabilities.7.html" class="external">file
+system capabilities</a> on filesystem objects within the build (the filesystem
+itself must also support this functionality).</p>
+
+<p>Because running a stable service as root in Android causes a
+<a href="/compatibility/cts/index.html">Compatibility Test Suite (CTS)</a>
+failure, previous requirements for retaining a capability while running a
+process or service involved setting up capabilities then using
+<code>setuid</code>/<code>setgid</code> to a proper AID to run. With caps, you
+can skip these requirements and have the kernel do it for you. When control is
+handed to <code>main()</code>, your process already has the capabilities it
+needs so your service can use a non-root user and group (this is the preferred
+way for starting privileged services).</p>
+
+<p>The caps section uses the following syntax:</p>
+<table>
+ <tr>
+ <th>Section</th>
+ <th>Value</th>
+ <th>Definition</th>
+ </tr>
+ <tr>
+ <td><code>[path]</code></td>
+ <td></td>
+ <td>The filesystem path to configure. A path ending in / is considered a dir,
+ else it's a file.
+ <br><br>It is an error to specify multiple sections with the same
+ <code>[path]</code> in different files. In Python versions <= 3.2, the same
+ file may contain sections that override the previous section; in Python 3.2,
+ it's set to strict mode.</td>
+ </tr>
+ <tr>
+ <td><code>mode</code></td>
+ <td>Octal file mode</td>
+ <td>A valid octal file mode of at least 3 digits. If 3 is specified, it is
+ prefixed with a 0, else mode is used as is.</td>
+ </tr>
+ <tr>
+ <td><code>user</code></td>
+ <td>AID_&lt;user&gt;</td>
+ <td>Either the C <code>define</code> for a valid AID or the friendly name
+ (e.g. both <code>AID_RADIO</code> and <code>radio</code> are acceptable). To
+ define a custom AID, see <a href="#configuring-the-aid-section">Configuring
+ the AID section</a>.</td>
+ </tr>
+ <tr>
+ <td><code>group</code></td>
+ <td>AID_&lt;group&gt;</td>
+ <td>Same as user.</td>
+ </tr>
+ <tr>
+ <td><code>caps</code></td>
+ <td>cap*</td>
+ <td>The name as declared in
+ <code>system/core/include/private/android_filesystem_capability.h</code>
+ without the leading <code>CAP_</code>. Mixed case allowed. Caps can also be
+ the raw:
+ <ul>
+ <li>binary (0b0101)</li>
+ <li>octal (0455)</li>
+ <li>int (42)</li>
+ <li>hex (0xFF)</li>
+ </ul>
+ Separate multiple caps using whitespaces.</td>
+ </tr>
+</table>
+
+<p>For a usage example, see <a href="#using-file-system-capabilities">Using file
+system capabilities</a>.</p>
+
+<h3 id="configuring-the-aid-section">Configuring the AID section</h3>
+<p>The AID section contains OEM-specific AIDs and uses the following syntax:</p>
+
+<table>
+ <tr>
+ <th>Section</th>
+ <th>Value</th>
+ <th>Definition</th>
+ </tr>
+ <tr>
+ <td><code>[AID_&lt;name&gt;]</code></td>
+ <td></td>
+ <td>The <code>&lt;name&gt;</code> can contain characters in the set
+ uppercase, numbers, and underscores. The lowercase version is used as the
+ friendly name. The generated header file for code inclusion uses the exact
+ <code>AID_&lt;name&gt;</code>.
+ <br><br>It is an error to specify multiple sections with the same
+ <code>AID_&lt;name&gt;</code> (case insensitive with the same constraints as
+ <code>[path]</code>).</td>
+ </tr>
+ <tr>
+ <td><code>value</code></td>
+ <td>&lt;number&gt;</td>
+ <td>A valid C style number string (hex, octal, binary and decimal).
+ <br><br>It is an error to specify multiple sections with the same value option
+ <strong>or</strong> to specify a value that is outside of the inclusive OEM
+ ranges (defined in
+ <code>system/core/include/private/android_filesystem_config.h</code>):
+ <ul>
+ <li>AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)</li>
+ <li>AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)</li>
+ </ul>
+ </td>
+ </tr>
+</table>
+
+<p>For usage examples, see <a href="#defining-an-oem-specific-aid">Defining an
+OEM-specific AID</a> and <a href="#using-an-oem-specific-aid">Using an
+OEM-specific AID</a>.</p>
+
+<h2 id="usage-examples">Usage examples</h2>
+<p>The following examples detail how to define and use an OEM-specific AID and
+how to enable filesystem capabilities.</p>
+
+<h3 id="defining-an-oem-specific-aid">Defining an OEM-specific AID</h3>
+<p>To define an OEM-specific AID, create a <code>config.fs</code> file and set
+the AID value. For example, in <code>device/x/y/config.fs</code>, set the
+following:</p>
+
+<pre class="prettyprint">
+[AID_FOO]
+value: 2900
+</pre>
+
+<p>After creating the file, set the <code>TARGET_FS_CONFIG_GEN</code> variable
+and point to it in <code>BoardConfig.mk</code>. For example, in
+<code>device/x/y/BoardConfig.mk</code>, set the following:</p>
+
+<pre class="prettyprint">TARGET_FS_CONFIG_GEN += device/x/y/config.fs</pre>
+
+<p>Your custom AID can now be consumed by the system at large on a new build.
+</p>
+
+<h3 id="using-an-oem-specific-aid">Using an OEM-specific AID</h3>
+<p>To access the <code>#define</code> value of your AID via C or C++ code, use
+the autogenerated header file by adding to your module's <code>Android.mk</code>
+and including the empty faux library. For example, in <code>Android.mk</code>,
+add the following:</p>
+
+<pre class="prettyprint"> LOCAL_STATIC_LIBRARIES := liboemaids</pre>
+<p>In your C code, <code>#include "generated_oem_aid.h"</code> and start using
+the declared identifiers. For example, in <code>my_file.c</code>, add the
+following: </p>
+
+<pre class="prettyprint">
+#include "generated_oem_aid.h"
+
+…
+
+If (ipc->uid == AID_FOO) {
+ // Do something
+...
+</pre>
+
+<p>In Android 8.0, you must continue to use <code>oem_####</code> with
+<code>getpwnam</code> and similar functions, as well in places that handle
+lookups via <code>getpwnam</code> (such as init scripts). For example, in
+<code>some/init.rc</code>, use the following:</p>
+
+<pre class="prettyprint">
+service foo /vendor/bin/foo_service
+ user: oem_2900
+ group: oem_2900
+</pre>
+
+<h3 id="using-file-system-capabilities">Using file system capabilities</h3>
+<p>To enable filesystem capabilities, create a caps section in the
+<code>config.fs</code> file. For example, in <code>device/x/y/config.fs</code>,
+add the following section:</p>
+
+<pre class="prettyprint">
+[system/bin/foo_service]
+mode: 0555
+user: AID_FOO
+group: AID_SYSTEM
+caps: SYS_ADMIN | SYS_NICE
+</pre>
+
+<aside class="note"><strong>Note:</strong> The nice names <code>foo</code> and
+<code>system</code> could be used here as well.</aside>
+
+<p>After creating the file, set the <code>TARGET_FS_CONFIG_GEN</code> to point
+to it in <code>BoardConfig.mk</code>. For example, in
+<code>device/x/y/BoardConfig.mk</code>, set the following:</p>
+
+<pre class="prettyprint">TARGET_FS_CONFIG_GEN += device/x/y/config.fs</pre>
+
+<p>When service <code>foo</code> is executed, it starts with capabilities
+<code>CAP_SYS_ADMIN</code> and <code>CAP_SYS_NICE</code> without
+<code>setuid</code> and <code>setgid</code> calls. In addition, the
+<code>foo</code> service's SELinux policy no longer needs <code>setuid</code>
+and <code>setgid</code>, so these capabilities can be removed from the SELinux
+policy for <code>foo</code>.</p>
+
+<h2 id="older">Configuring overrides (Android 6.x-7.x)</h2>
+
+<p>Android 6.0 relocated <code>fs_config</code> and associated structure
+definitions
+(<code>system/core/include/private/android_filesystem_config.h</code>) to
+<code>system/core/libcutils/fs_config.c</code> where they could be updated or
+overridden by binary files installed in <code>/system/etc/fs_config_dirs</code>
+and <code>/system/etc/fs_config_files</code>. Using separate matching and
+parsing rules for directories and files (which could use additional glob
+expressions) enabled Android to handle directories and files in two different
+tables. Structure definitions in <code>system/core/libcutils/fs_config.c</code>
+not only allowed runtime reading of directories and files, but the host could
+use the same files during build time to construct filesystem images as
<code>${OUT}/system/etc/fs_config_dirs</code> and
<code>${OUT}/system/etc/fs_config_files</code>.</p>
-<h2 id=gen-files>Generating override files</h2>
+<p>While the override method of extending the filesystem has been superseded by
+the modular config system introduced in Android 8.0, you can still use the old
+method if desired. The following sections detail how to generate and include
+override files and configure the filesystem.</p>
+
+<h3 id=older-generate>Generating override files</h3>
<p>You can generate the aligned binary files
<code>/system/etc/fs_config_dirs</code> and
@@ -69,27 +344,23 @@ following structure initializations for directory and file symbols:</p>
<p>When not using <code>android_device_dirs[]</code> and
<code>android_device_files[]</code>, you can define
<code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS</code> and <code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES</code> (see the
-<a href="#example">example</a> below).</p>
-
-<p>You can also specify the
-override file using <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> in the board
+<a href="#older-example">example</a> below). You can also specify the override file
+using <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> in the board
configuration, with an enforced basename of
-<code>android_filesystem_config.h</code>.
-
-<h2 id=include-files>Including files</h2>
-
-<p><code>PRODUCT_PACKAGES</code> must include <code>fs_config_dirs</code>
-and/or <code>fs_config_files</code> to install them to
-<code>/system/etc/fs_config_dirs</code> and
-<code>/system/etc/fs_config_files</code>, respectively.</p>
+<code>android_filesystem_config.h</code>.</p>
-<p>The build system searches for custom <code>android_filesystem_config.h</code>
-in <code>$(TARGET_DEVICE_DIR)</code>, where <code>BoardConfig.mk</code> exists.
+<h3 id=older-include>Including override files</h3>
+<p>To include files, ensure that <code>PRODUCT_PACKAGES</code> includes
+<code>fs_config_dirs</code> and/or <code>fs_config_files</code> so it can
+install them to <code>/system/etc/fs_config_dirs</code> and
+<code>/system/etc/fs_config_files</code>, respectively. The build system
+searches for custom <code>android_filesystem_config.h</code> in
+<code>$(TARGET_DEVICE_DIR)</code>, where <code>BoardConfig.mk</code> exists.
If this file exists elsewhere, set board config variable
<code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> to point to that location.</p>
-<h2 id=configuring>Configuring</h2>
-<p>To configure the file system in Android 6.0 and higher:</p>
+<h3 id=older-configure>Configuring the filesystem</h3>
+<p>To configure the filesystem in Android 6.0 and higher:</p>
<ol>
<li>Create the <code>$(TARGET_DEVICE_DIR)/android_filesystem_config.h</code>
@@ -99,28 +370,7 @@ file.</li>
<code>$(TARGET_DEVICE_DIR)/device.mk</code>).</li>
</ol>
-<h2 id=migration-concerns>Migration concerns</h2>
-<p>Migrating system configurations from Android 5.0 and earlier can be
-disruptive. When planning such a migration, keep in mind that Android 6.0:</p>
-<ul>
-<li>Removes some includes, structures, and inline definitions.</li>
-<li>Requires a reference to <code>libcutils</code> instead of running directly
-from <code>system/core/include/private/android_filesystem_config.h</code>.
-Device manufacturer private executables that depend on
-<code>system/code/include/private_filesystem_config.h</code> for the file or
-directory structures or <code>fs_config</code> must add <code>libcutils</code>
-library dependencies.</li>
-<li>Requires device manufacturer private branch copies of the
-<code>system/core/include/private/android_filesystem_config.h</code> with extra
-content on existing targets to move to
-<code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code>.
-</li>
-<li>As Android reserves the right to apply SELinux Mandatory Access Controls (MAC)
-to configuration files on the target system, implementations that include
-custom target executables using <code>fs_config()</code> must ensure access.</li>
-</ul>
-
-<h2 id=example>Example</h2>
+<h3 id=older-example>Override example</h3>
<p>This example shows a patch for overriding the <code>system/bin/glgps</code>
daemon to add wake lock support in the
@@ -201,7 +451,27 @@ index 0c71d21..235c1a7 100644
ifeq ($(USE_SVELTE_KERNEL), true)
</pre>
-
+<h3 id=older-migration>Migrating filesystems from earlier releases</h3>
+<p>When migrating filesystems from Android 5.x and earlier, keep in mind that
+Android 6.x:</p>
+<ul>
+<li>Removes some includes, structures, and inline definitions.</li>
+<li>Requires a reference to <code>libcutils</code> instead of running directly
+from <code>system/core/include/private/android_filesystem_config.h</code>.
+Device manufacturer private executables that depend on
+<code>system/code/include/private_filesystem_config.h</code> for the file or
+directory structures or <code>fs_config</code> must add <code>libcutils</code>
+library dependencies.</li>
+<li>Requires device manufacturer private branch copies of the
+<code>system/core/include/private/android_filesystem_config.h</code> with extra
+content on existing targets to move to
+<code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code>.
+</li>
+<li>As Android reserves the right to apply SELinux Mandatory Access Controls
+(MAC) to configuration files on the target system, implementations that include
+custom target executables using <code>fs_config()</code> must ensure access.
+</li>
+</ul>
</body>
</html>
diff --git a/en/devices/tech/dalvik/images/jit-arch.png b/en/devices/tech/dalvik/images/jit-arch.png
index 6e2960eb..b34acb32 100644
--- a/en/devices/tech/dalvik/images/jit-arch.png
+++ b/en/devices/tech/dalvik/images/jit-arch.png
Binary files differ
diff --git a/en/devices/tech/dalvik/images/jit-daemon.png b/en/devices/tech/dalvik/images/jit-daemon.png
index ae46d594..6a801120 100644
--- a/en/devices/tech/dalvik/images/jit-daemon.png
+++ b/en/devices/tech/dalvik/images/jit-daemon.png
Binary files differ
diff --git a/en/devices/tech/dalvik/images/jit-profile-comp.png b/en/devices/tech/dalvik/images/jit-profile-comp.png
index 47fad635..f9dca0ab 100644
--- a/en/devices/tech/dalvik/images/jit-profile-comp.png
+++ b/en/devices/tech/dalvik/images/jit-profile-comp.png
Binary files differ
diff --git a/en/devices/tech/dalvik/images/jit-workflow.png b/en/devices/tech/dalvik/images/jit-workflow.png
index 282c5d9b..e9a5d732 100644
--- a/en/devices/tech/dalvik/images/jit-workflow.png
+++ b/en/devices/tech/dalvik/images/jit-workflow.png
Binary files differ
diff --git a/en/devices/tech/dalvik/jit-compiler.html b/en/devices/tech/dalvik/jit-compiler.html
index 74ac6de0..c105fd06 100644
--- a/en/devices/tech/dalvik/jit-compiler.html
+++ b/en/devices/tech/dalvik/jit-compiler.html
@@ -24,112 +24,97 @@
<p>
-Android 7.0 adds a just-in-time (JIT) compiler with code profiling to Android
-runtime (ART) that constantly improves the performance of Android apps as they
-run. The JIT compiler complements ART's current ahead-of-time (AOT) compiler and
-improves runtime performance, saves storage space, and speeds app updates and
-system updates.
+Android runtime (ART) includes a just-in-time (JIT) compiler with code profiling
+that continually improves the performance of Android applications as they run.
+The JIT compiler complements ART's current ahead-of-time (AOT) compiler and
+improves runtime performance, saves storage space, and speeds application and
+system updates. It also improves upon the AOT compiler by avoiding system
+slowdown during automatic application updates or recompilation of applications
+during over-the-air (OTA) updates.
</p>
<p>
-The JIT compiler also improves upon the AOT compiler by avoiding system slowdown
-during automatic application updates or recompilation of applications during
-OTAs. This feature should require minimal device integration on the part of
-manufacturers.
+Although JIT and AOT use the same compiler with a similar set of optimizations,
+the generated code might not be identical. JIT makes use of runtime type
+information, can do better inlining, and makes on stack replacement (OSR)
+compilation possible, all of which generates slightly different code.
</p>
-<p>
-JIT and AOT use the same compiler with an almost identical set of optimizations.
-The generated code might not be the same but it depends. JIT makes uses of
-runtime type information and can do better inlining. Also, with JIT we sometimes
-do OSR compilation (on stack replacement) which will again generate a bit
-different code.
-</p>
+<h2 id="architectural-overview">JIT architecture</h2>
-<h2 id="architectural-overview">Architectural Overview</h2>
-
-<img src="/devices/tech/dalvik/images/jit-arch.png" alt="JIT architecture" width="633" id="JIT-architecture" />
-<p class="img-caption">
- <strong>Figure 1.</strong> JIT architecture - how it works
-</p>
+<img src="./images/jit-arch.png" alt="JIT architecture"/>
+<figcaption><strong>Figure 1.</strong> JIT architecture.</figcaption>
-<h2 id="flow">Flow</h2>
+<h2 id="flow">JIT compilation</h2>
-<p>
-JIT compilation works in this manner:
-</p>
+<p>JIT compilation involves the following activities:</p>
+<img src="./images/jit-profile-comp.png" alt="Profile-guided comp"/>
+<figcaption><strong>Figure 2.</strong> Profile-guided compilation.</figcaption>
<ol>
-<li>The user runs the app, which then triggers ART to load the .dex file.
-<li>If the .oat file (the AOT binary for the .dex file) is available, ART uses
-them directly. Note that .oat files are generated regularly. However, that does
-not imply they contain compiled code (AOT binary).
-<li>If no .oat file is available, ART runs through either JIT or an interpreter
-to execute the .dex file. ART will always use the .oat files if available.
-Otherwise, it will use the APK and extract it in memory to get to the .dex
-incurring a big memory overhead (equal to the size of the dex files).
+<li>The user runs the app, which then triggers ART to load the <code>.dex</code>
+file.
+ <ul>
+ <li>If the <code>.oat</code> file (the AOT binary for the <code>.dex</code>
+ file) is available, ART uses it directly. Although <code>.oat</code> files are
+ generated regularly, they don't always contain compiled code (AOT binary).</li>
+ <li>If no <code>.oat</code> file is available, ART runs through JIT or an
+ interpreter to execute the <code>.dex</code> file.</li>
+ ART always uses the <code>.oat</code> files if available. Otherwise, it uses
+ the APK and extracts it in memory to get to the <code>.dex</code>; this incurs
+ a big memory overhead that is equal to the size of the dex files.</li>
+</ul>
+</li>
<li>JIT is enabled for any application that is not compiled according to the
-"speed" compilation filter (which says, compile as much as you can from the
-app).
-<li>The JIT profile data is dumped to a file in a system directory. Only the
-application has access to the directory.
-<li>The AOT compilation (dex2oat) daemon parses that file to drive its
-compilation.</li>
+<code>speed</code> compilation filter (which says "compile as much as you can
+from the app").</li>
+<li>The JIT profile data is dumped to a file in a system directory that only
+the application can access.</li>
+<li>The AOT compilation (<code>dex2oat</code>) daemon parses that file to drive
+its compilation.
+<br>
+<br>
+<img src="./images/jit-daemon.png" alt="JIT daemon"/>
+<figcaption><strong>Figure 3.</strong> JIT daemon activities.</figcaption>
+</li>
</ol>
-<img src="/devices/tech/dalvik/images/jit-profile-comp.png" alt="Profile-guided comp" width="452" id="JIT-profile-comp" />
-<p class="img-caption">
- <strong>Figure 2.</strong> Profile-guided compilation
-</p>
-
-<img src="/devices/tech/dalvik/images/jit-daemon.png" alt="JIT daemon" width="718" id="JIT-daemon" />
-<p class="img-caption">
- <strong>Figure 3.</strong> How the daemon works
-</p>
-
<p>
-The Google Play service is an example used by other apps. These application tend
-to behave more like shared libraries.
+The Google Play service is an example used by other applications that behave
+similar to shared libraries.
</p>
-<h2 id="jit-workflow">JIT Workflow</h2>
-<p>
-See the following high-level overview of how JIT works in the next diagram.
-</p>
+<h2 id="jit-workflow">JIT workflow</h2>
-<img src="/devices/tech/dalvik/images/jit-workflow.png" alt="JIT architecture" width="707" id="JIT-workflow" />
-<p class="img-caption">
- <strong>Figure 4.</strong> JIT data flow
-</p>
-
-<p>
-This means:
-</p>
+<img src=./images/jit-workflow.png" alt="JIT architecture"/>
+<figcaption><strong>Figure 4.</strong> JIT data flow.</figcaption>
<ul>
<li>Profiling information is stored in the code cache and subjected to garbage
collection under memory pressure.
-<li>As a result, there’s no guarantee the snapshot taken when the application is
-in the background will contain the complete data (i.e. everything that was
-JITed).
-<li>There is no attempt to make sure we record everything as that will impact
-runtime performance.
-<li>Methods can be in three different states: <ul>
- <li>interpreted (dex code)
- <li>JIT compiled
- <li>AOT compiled
-<li>If both, JIT and AOT code exists (e.g. due to repeated de-optimizations),
-the JITed code will be preferred.
-<li>The memory requirement to run JIT without impacting foreground app
-performance depends upon the app in question. Large apps will require more
-memory than small apps. In general, big apps stabilize around 4 MB.</li></ul>
+ <ul>
+ <li>There is no guarantee a snapshot taken when the application was in the
+ background will contain complete data (i.e., everything that was JITed).</li>
+ <li>There is no attempt to ensure everything is recorded (as this can impact
+ runtime performance).</li>
+ </ul>
</li>
+<li>Methods can be in three different states:
+ <ul>
+ <li>interpreted (dex code)</li>
+ <li>JIT compiled</li>
+ <li>AOT compiled</li>
+ </ul>
+ If both JIT and AOT code exists (e.g. due to repeated de-optimizations),
+ the JITed code is preferred.
+</li>
+<li>The memory requirement to run JIT without impacting foreground app
+performance depends upon the app in question. Large apps require more memory
+than small apps. In general, large apps stabilize around 4 MB.</li>
</ul>
-<h2 id="tuning">Useful tips</h2>
-
-<h3 id="turn-on-jit-logging">Turn on JIT logging</h3>
-
+<h2 id="turn-on-jit-logging">Turning on JIT logging</h2>
+<p>To turn on JIT logging, run the following commands:</p>
<pre class="devsite-click-to-copy">
<code class="devsite-terminal">adb root</code>
<code class="devsite-terminal">adb shell stop</code>
@@ -137,8 +122,8 @@ memory than small apps. In general, big apps stabilize around 4 MB.</li></ul>
<code class="devsite-terminal">adb shell start</code>
</pre>
-<h3 id="disable-jit-and-run-applications-in-interpreter">Disable JIT</h3>
-
+<h2 id="disable-jit-and-run-applications-in-interpreter">Disabling JIT</h2>
+<p>To disable JIT, run the following commands:</p>
<pre class="devsite-click-to-copy">
<code class="devsite-terminal">adb root</code>
<code class="devsite-terminal">adb shell stop</code>
@@ -146,13 +131,14 @@ memory than small apps. In general, big apps stabilize around 4 MB.</li></ul>
<code class="devsite-terminal">adb shell start</code>
</pre>
-<h3 id="force-compilation-of-a-specific-package">Force compilation of a specific
-package</h3>
+<h2 id="force-compilation-of-a-specific-package">Forcing compilation</h2>
-<p>
-Check <code>$ adb shell cmd package compile</code> for usage. A few common use cases:
-</p>
+<p>To force compilation, run the following:</p>
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell cmd package compile
+</pre>
+<p>Common use cases for force compiling a specific package:</p>
<ul>
<li>Profile-based:
<pre class="devsite-terminal devsite-click-to-copy">
@@ -166,9 +152,7 @@ adb shell cmd package compile -m speed -f my-package
</li>
</ul>
-<h3 id="force-compilation-of-all-packages">Force compilation of all
-packages</h3>
-
+<p>Common use cases for force compiling all packages:</p>
<ul>
<li>Profile-based:
<pre class="devsite-terminal devsite-click-to-copy">
@@ -182,16 +166,15 @@ adb shell cmd package compile -m speed -f -a
</li>
</ul>
-<h3 id="clear-profile-data-and-remove-compiled-code">Clear profile data and
-remove compiled code</h3>
-
+<h2 id="clear-profile-data-and-remove-compiled-code">Clearing profile data</h2>
+<p>To clear profile data and remove compiled code, run the following:</p>
<ul>
-<li>One package:
+<li>For one package:
<pre class="devsite-terminal devsite-click-to-copy">
adb shell cmd package compile --reset my-package
</pre>
</li>
-<li>All packages
+<li>For all packages:
<pre class="devsite-terminal devsite-click-to-copy">
adb shell cmd package compile --reset -a
</pre>
diff --git a/en/devices/tech/debug/index.html b/en/devices/tech/debug/index.html
index 307c4585..702b7a14 100644
--- a/en/devices/tech/debug/index.html
+++ b/en/devices/tech/debug/index.html
@@ -36,9 +36,10 @@ it was necessary to truncate the name to fit. In Android O and later, this
limit is much greater and should require no truncation.</p>
<p>This page covers use of <code>debuggerd</code>, a daemon process for
-collecting error information after applications crash. Other pages in this
-section explore system services with
-<a href="https://developer.android.com/studio/command-line/dumpsys.html">Dumpsys</a>, viewing
+collecting error information after applications crash. Other pages explore system services with
+<a
+ href="https://developer.android.com/studio/command-line/dumpsys.html">
+ <code>dumpsys</code></a>, viewing
<a href="/devices/tech/debug/native-memory.html">native memory</a>,
<a href="https://developer.android.com/studio/command-line/dumpsys.html#network">network</a>, and
<a href="https://developer.android.com/studio/command-line/dumpsys.html#procstats">RAM</a> usage, using
diff --git a/en/devices/tech/perf/low-ram.html b/en/devices/tech/perf/low-ram.html
index d1ca5b5e..4b9f67e7 100644
--- a/en/devices/tech/perf/low-ram.html
+++ b/en/devices/tech/perf/low-ram.html
@@ -71,7 +71,7 @@ when running on low memory devices and choose to disable large-RAM features.
<h3 id="opt-track">Memory tracking</h3>
<p>
New memtrack HAL to track graphics memory allocations, additional information
-in dumpsys meminfo, clarified summaries in meminfo (for example reported free
+in <code>dumpsys</code> meminfo, clarified summaries in meminfo (for example reported free
RAM includes RAM of cached processes, so that OEMs don't try to optimize the
wrong thing).
</p>
diff --git a/en/security/bulletin/2017-08-01.html b/en/security/bulletin/2017-08-01.html
index 00acb55c..bf8571bd 100644
--- a/en/security/bulletin/2017-08-01.html
+++ b/en/security/bulletin/2017-08-01.html
@@ -20,7 +20,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<p><em>Published August 7, 2017 | Updated August 14, 2017</em></p>
+<p><em>Published August 7, 2017 | Updated August 23, 2017</em></p>
<p>The Android Security Bulletin contains details of security vulnerabilities
affecting Android devices. Security patch levels of August 05, 2017 or later
@@ -357,6 +357,13 @@ privileged process.</p>
<td>4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2</td>
</tr>
<tr>
+ <td>CVE-2017-0805</td>
+ <td><a href="https://android.googlesource.com/platform/frameworks/av/+/77e075ddd6d8cae33832add5225ee8f8c77908f0">A-37237701</a></td>
+ <td>EoP</td>
+ <td>High</td>
+ <td>4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2</td>
+ </tr>
+ <tr>
<td>CVE-2017-0738</td>
<td><a href="https://android.googlesource.com/platform/frameworks/av/+/1d919d737b374b98b900c08c9d0c82fe250feb08">A-37563371</a>
[<a href="https://android.googlesource.com/platform/hardware/qcom/audio/+/234848dd6756c5d636f5a103e51636d60932983c">2</a>]</td>
@@ -786,7 +793,7 @@ href="https://twitter.com/jiych_guru">@jiych_guru</a>)</td>
of TrendMicro</td>
</tr>
<tr>
- <td>CVE-2017-0732</td>
+ <td>CVE-2017-0732, CVE-2017-0805</td>
<td>Timothy Becker of CSS Inc.</td>
</tr>
<tr>
@@ -974,6 +981,11 @@ site</a>.</p>
<td>August 14, 2017</td>
<td>Bulletin revised to add CVE-2017-0687.</td>
</tr>
+ <tr>
+ <td>1.2</td>
+ <td>August 23, 2017</td>
+ <td>Bulletin revised to add CVE-2017-0805.</td>
+ </tr>
</table>
</body>
</html>
diff --git a/en/source/build-numbers.html b/en/source/build-numbers.html
index 26d30d9c..84de44f4 100644
--- a/en/source/build-numbers.html
+++ b/en/source/build-numbers.html
@@ -41,7 +41,7 @@ API levels and NDK releases provided for convenience:</p>
<tbody>
<tr>
<td>Oreo</td>
-<td>8.0</td>
+<td>8.0.0</td>
<td>API level 26</td>
</tr>
<tr>
diff --git a/en/source/devices.html b/en/source/devices.html
index 53efcf40..27b24018 100644
--- a/en/source/devices.html
+++ b/en/source/devices.html
@@ -133,7 +133,7 @@ HiKey960 user guide).</li>
<pre class="devsite-click-to-copy">
<code class="devsite-terminal">git clone <a href="https://android.googlesource.com/kernel/hikey-linaro">https://android.googlesource.com/kernel/hikey-linaro</a></code>
<code class="devsite-terminal">cd hikey-linaro</code>
-<code class="devsite-terminal">git checkout -b android-hikey-linaro-4.4 origin/android-hikey-linaro-4.4</code>
+<code class="devsite-terminal">git checkout -b android-hikey-linaro-4.9 origin/android-hikey-linaro-4.9</code>
<code class="devsite-terminal">make ARCH=arm64 hikey960_defconfig</code>
<code class="devsite-terminal">make ARCH=arm64 CROSS_COMPILE=aarch64-linux-android- -j24</code>
</pre>
diff --git a/en/source/report-bugs.html b/en/source/report-bugs.html
index 7635e0a3..848a50d9 100644
--- a/en/source/report-bugs.html
+++ b/en/source/report-bugs.html
@@ -109,7 +109,7 @@ open issues, only closed issues or issues that have been made public.
<tr>
<td>Security</td>
<td><a href="/security/overview/updates-resources#report-issues">Android Security details</a></td>
- <td><a href="https://issuetracker.google.com/issues/new?component=190951">
+ <td><a href="https://www.google.com/appserve/security-bugs/m2/new">
<i class="material-icons">bug_report</i></a></td>
</tr>
<tr>
diff --git a/en/source/running.html b/en/source/running.html
index 4a67565f..486fa9c1 100644
--- a/en/source/running.html
+++ b/en/source/running.html
@@ -23,149 +23,149 @@
-<p>This page provides details for running builds on specific devices and is
-designed to complement the information in
-<a href="/source/building.html">Building the System</a>.</p>
+<p>This page provides details for running builds on specific devices and
+complements the information in <a href="/source/building.html">Building the
+System</a>.</p>
<h2 id="building-fastboot-and-adb">Building fastboot and adb</h2>
-<p>If you don't already have fastboot and adb, you can build them with the
-regular build system. Use the instructions in
+<p>If you don't already have <code>fastboot</code> and <code>adb</code>, you can
+build them with the regular build system. Use the instructions in
<a href="/source/building.html">Building a System</a> and replace the
main <code>make</code> command with:</p>
-<pre class="devsite-terminal devsite-click-to-copy">
-make fastboot adb
-</pre>
+<pre class="devsite-click-to-copy devsite-terminal">make fastboot adb</pre>
<h2 id="booting-into-fastboot-mode">Booting into fastboot mode</h2>
-<p><em>Fastboot</em> is a bootloader mode in which you can flash a device.
+<p><code>Fastboot</code> is a bootloader mode in which you can flash a device.
During a cold boot of a device, use the following key combinations to boot into
-fastboot mode:</p>
+<code>fastboot</code> mode:</p>
<table>
<thead>
<tr>
-<th>Codename</th>
<th>Device</th>
+<th>Code name</th>
<th>Keys</th>
</tr>
</thead>
<tbody>
<tr>
-<td>marlin</td><td>Pixel XL</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>Pixel XL</td>
+<td>marlin</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>sailfish</td>
<td>Pixel</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>sailfish</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
<td>hikey</td>
<td>hikey</td>
-<td>Link pins 1 - 2 and 5 - 6 of J15</td>
+<td>Link pins 1 - 2 and 5 - 6 of J15.</td>
</tr>
<tr>
-<td>angler</td>
<td>Nexus 6P</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>angler</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>bullhead</td>
<td>Nexus 5X</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>bullhead</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>shamu</td>
<td>Nexus 6</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>shamu</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>fugu</td>
<td>Nexus Player</td>
-<td>Press and hold <em>Power</em></td>
+<td>fugu</td>
+<td>Press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>volantis</td>
<td>Nexus 9</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>volantis</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>hammerhead</td>
<td>Nexus 5</td>
+<td>hammerhead</td>
<td>Press and hold both <em>Volume Up</em> and <em>Volume Down</em>, then press
-and hold <em>Power</em></td>
+and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>flo</td>
<td>Nexus 7</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>flo</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>deb</td>
<td>Nexus 7 3G</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>deb</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>manta</td>
<td>Nexus 10</td>
+<td>manta</td>
<td>Press and hold both <em>Volume Up</em> and <em>Volume Down</em>, then press
-and hold <em>Power</em></td>
+and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>mako</td>
<td>Nexus 4</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>mako</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>grouper</td>
<td>Nexus 7 (2012)</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>grouper</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>tilapia</td>
<td>Nexus 7 3G (2012)</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>tilapia</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>phantasm</td>
<td>Nexus Q</td>
-<td>Power the device, cover it with one hand after the LEDs light up and until
-they turn red</td>
+<td>phantasm</td>
+<td>Power the device then cover it with one hand after the LEDs light up and
+until they turn red.</td>
</tr>
<tr>
-<td>maguro</td>
<td>Galaxy Nexus GSM</td>
+<td>maguro</td>
<td>Press and hold both <em>Volume Up</em> and <em>Volume Down</em>, then press
-and hold <em>Power</em></td>
+and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>toro</td>
<td>Galaxy Nexus (Verizon)</td>
+<td>toro</td>
<td>Press and hold both <em>Volume Up</em> and <em>Volume Down</em>, then press
-and hold <em>Power</em></td>
+and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>toroplus</td>
<td>Galaxy Nexus (Sprint)</td>
+<td>toroplus</td>
<td>Press and hold both <em>Volume Up</em> and <em>Volume Down</em>, then press
-and hold <em>Power</em></td>
+and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>wingray</td>
<td>Motorola Xoom</td>
-<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em></td>
+<td>wingray</td>
+<td>Press and hold <em>Volume Down</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>crespo</td>
<td>Nexus S</td>
-<td>Press and hold <em>Volume Up</em>, then press and hold <em>Power</em></td>
+<td>crespo</td>
+<td>Press and hold <em>Volume Up</em>, then press and hold <em>Power</em>.</td>
</tr>
<tr>
-<td>crespo4g</td>
<td>Nexus SG</td>
-<td>Press and hold <em>Volume Up</em>, then press and hold <em>Power</em></td>
+<td>crespo4g</td>
+<td>Press and hold <em>Volume Up</em>, then press and hold <em>Power</em>.</td>
</tr>
</tbody>
</table>
+
<p>You can also use the command <code>adb reboot bootloader</code> to reboot
from Android directly into the bootloader with no key combinations.</p>
@@ -187,61 +187,54 @@ Nexus 9) have factory reset protection and require a multi-step process to
unlock the bootloader.</p>
<ol>
- <li>Enable OEM unlocking on the device:
- <ol style="list-style-type:lower-alpha">
- <li>In Settings, tap <strong>About phone</strong>, then tap <strong>Build number</strong> seven (7) times.</li>
- <li>When you see the message "You are a developer", tap the back button.</li>
- <li>Tap <strong>Developer options</strong> and enable <strong>OEM unlocking</strong> and <strong>USB debugging</strong>. (If OEM unlocking is disabled, connect to the Internet so the device can check in at least once. If it remains disabled, your device may be SIM locked by your carrier and the bootloader cannot be unlocked.)</li>
- </ol>
+<li>To enable OEM unlocking on the device:
+ <ol>
+ <li>In Settings, tap <strong>About phone</strong>, then tap <strong>Build
+ number</strong> seven (7) times.</li>
+ <li>When you see the message "You are a developer", tap the back button.</li>
+ <li>Tap <strong>Developer options</strong> and enable
+ <strong>OEM unlocking</strong> and <strong>USB debugging</strong>. (If OEM
+ unlocking is disabled, connect to the Internet so the device can check in at
+ least once. If it remains disabled, your device may be SIM locked by your
+ carrier and the bootloader cannot be unlocked.)</li>
+ </ol>
+</li>
+<li>Reboot into the bootloader and use <code>fastboot</code> to unlock it.
+ <ul>
+ <li>For new devices (2015 and later):
+ <pre class="devsite-click-to-copy devsite-terminal">fastboot flashing unlock</pre>
</li>
- <li>Reboot into the bootloader and use fastboot to unlock it.
- <ul>
- <li>For new devices (2015 and later):
-<pre class="devsite-terminal devsite-click-to-copy">
-fastboot flashing unlock
-</pre>
- </li>
- <li>For older devices (2014 and earlier):
-<pre class="devsite-terminal devsite-click-to-copy">
-fastboot oem unlock
-</pre>
- </li>
- </ul>
- You must confirm the unlock onscreen.
+ <li>For older devices (2014 and earlier):
+ <pre class="devsite-click-to-copy devsite-terminal">fastboot oem unlock</pre>
</li>
+ </ul>
+</li>
+<li>Confirm the unlock onscreen.</li>
</ol>
-<p class="note"><strong>Note:</strong> On Nexus 10, after unlocking the
+<aside class="note"><strong>Note:</strong> On Nexus 10, after unlocking the
bootloader, the internal storage remains unformatted. You can format the device
-using <code>fastboot format cache</code> followed by <code>fastboot format userdata</code></p>
+using <code>fastboot format cache</code> followed by
+<code>fastboot format userdata</code>.</aside>
<h3 id="relocking-the-bootloader">Re-locking the bootloader</h3>
<p>To re-lock the bootloader:</p>
<ul>
- <li>For new devices (2015 and later):
-<pre class="devsite-terminal devsite-click-to-copy">
-fastboot flashing lock
-</pre>
- </li>
- <li>For older devices (2014 and earlier):
-<pre class="devsite-terminal devsite-click-to-copy">
-fastboot oem lock
-</pre>
- </li>
+<li>For new devices (2015 and later):
+<pre class="devsite-click-to-copy devsite-terminal">fastboot flashing lock</pre>
+</li>
+<li>For older devices (2014 and earlier):
+<pre class="devsite-click-to-copy devsite-terminal">fastboot oem lock</pre>
+</li>
</ul>
-<p class="note"><strong>Note</strong>: Re-locking the bootloading on a Motorola
-Xoom erases user data (including the shared USB data).</p>
+<aside class="note"><strong>Note</strong>: Re-locking the bootloading on a
+Motorola Xoom erases user data (including the shared USB data).</aside>
<h2 id="flash-unlock">Using Flash Unlock</h2>
-
-<p>Android 7.0 includes a new system API, <code>getFlashLockState()</code>, to
-transmit bootloader state, as well as the following system API that returns the
-bootloader’s lock status on compliant devices:</p>
-
-<pre>
-PersistentDataBlockManager.getFlashLockState()
-</pre>
+<p>The <code>getFlashLockState()</code> system API transmits the bootloader
+state and the <code>PersistentDataBlockManager.getFlashLockState()</code> system
+API returns the bootloader’s lock status on compliant devices.</p>
<table>
<tr>
@@ -249,62 +242,55 @@ PersistentDataBlockManager.getFlashLockState()
<th>Conditions</th>
</tr>
<tr>
-<td><code>FLASH_LOCK_UNKNOWN</code>
-</td>
-<td><p>Returned only by devices upgrading to Android 7.0 that have not supported
-bootloader changes required to get the flash lock status if they support
-flashing lock/unlock capability.</p>
-<p>New Android 7.0 devices must be in either <code>FLASH_LOCK_LOCKED</code> or
-<code>FLASH_LOCK_UNLOCKED</code> state. If a device is upgrading to Android 7.0
-and does not support flashing unlock/lock capability, it should simply return
-<code>FLASH_LOCK_LOCKED</code> state.</p>
+<td><code>FLASH_LOCK_UNKNOWN</code></td>
+<td>Returned only by devices upgrading to Android 7.x or higher that did not
+previously support the bootloader changes required to get the flash lock
+status if they supported flashing lock/unlock capability.<br>
+<ul>
+<li>New devices running Android 7.x or higher must be in either
+<code>FLASH_LOCK_LOCKED</code> or <code>FLASH_LOCK_UNLOCKED</code> state.</li>
+<li>Devices upgrading to Android 7.x or higher that do not support flashing
+unlock/lock capability should return <code>FLASH_LOCK_LOCKED</code> state.</li>
+</ul>
</td>
</tr>
<tr>
-<td><code>FLASH_LOCK_LOCKED</code>
-</td>
+<td><code>FLASH_LOCK_LOCKED</code></td>
<td>Should be returned by any device that does not support flashing
lock/unlock (i.e. the device is always locked), or any device that does support
-flashing lock/unlock and is in the locked state.
-</td>
+flashing lock/unlock and is in the locked state.</td>
</tr>
<tr>
-<td><code>FLASH_LOCK_UNLOCKED</code>
-</td>
-<td>Returned by any device that supports flashing lock/unlock and is
-currently in the unlocked state.
-</td>
+<td><code>FLASH_LOCK_UNLOCKED</code></td>
+<td>Returned by any device that supports flashing lock/unlock and is currently
+in the unlocked state.</td>
</tr>
</table>
-<h3 id="examples-and-source">Examples and source</h3>
-
-<p>AOSP contains a reference implementation that returns a value based on the
-<code>ro.boot.flash.locked</code> boot property. The code lives in the following
-directories:</p>
-
-<pre>
-frameworks/base/services/core/java/com/android/server/PersistentDataBlockService.java
-frameworks/base/core/java/android/service/persistentdata/PersistentDataBlockManager.java
-</pre>
-
-<h3 id="validation">Validation</h3>
<p>Manufacturers should test the values returned by devices with locked and
-unlocked bootloaders.</p>
+unlocked bootloaders. For an example, the Android Open Source Project (AOSP)
+contains a reference implementation that returns a value based on the
+<code>ro.boot.flash.locked</code> boot property. Example code is located in the
+following directories:</p>
+
+<ul>
+<li><code>frameworks/base/services/core/java/com/android/server/PersistentDataBlockService.java</code></li>
+<li><code>frameworks/base/core/java/android/service/persistentdata/PersistentDataBlockManager.java</code></li>
+</ul>
<h2 id="selecting-device-build">Selecting a device build</h2>
-<p>The recommended builds for devices are available from the lunch menu,
-accessed when running the <code>lunch</code> command with no arguments. You can
-download factory images and binaries for Nexus devices from
+<p>The recommended builds for devices are available from the <code>lunch</code>
+menu, accessed when running the <code>lunch</code> command with no arguments.
+You can download factory images and binaries for Nexus devices from
developers.google.com:</p>
<ul>
-<li><a href="https://developers.google.com/android/nexus/blobs-preview">Preview
+<li><a href="https://developers.google.com/android/nexus/blobs-preview" class="external">Preview
binaries (blobs)</a></li>
-<li><a href="https://developers.google.com/android/nexus/images">Factory images
-for released devices</a></li>
-<li><a href="https://developers.google.com/android/nexus/drivers">Support
+<li><a href="https://developers.google.com/android/nexus/images" class="external">Factory
+images for released devices</a></li>
+<li><a href="https://developers.google.com/android/nexus/drivers" class="external">Support
binaries (drivers) for release devices</a></li>
</ul>
@@ -430,8 +416,8 @@ requirements</a>.</p>
</tbody>
</table>
-<p class="note"><b>Note</b>: Do not use Android 4.1.1 on a Nexus 7 originally
-sold with Android 4.1.2 or newer.</p>
+<aside class="note"><strong>Note</strong>: Do not use Android 4.1.1 on a Nexus
+7 originally sold with Android 4.1.2 or newer.</aside>
<h2 id="flashing-a-device">Flashing a device</h2>
@@ -441,40 +427,31 @@ writes the boot, recovery, and system partitions together, then reboots the
system. Flashing also erases all user data, similarly to <code>fastboot oem
unlock</code>.</p>
-<p>Place the device in fastboot mode either manually by holding the appropriate
-key combination at boot, or from the shell with:</p>
-
-<pre class="devsite-terminal devsite-click-to-copy">
-adb reboot bootloader
-</pre>
-
-<p>After the device is in fastboot mode, run:</p>
-
-<pre class="devsite-terminal devsite-click-to-copy">
-fastboot flashall -w
-</pre>
-
-<p>The <code>-w</code> option wipes the <code>/data</code> partition on the
+<p>To flash a device:</p>
+<ol>
+<li>Place the device in <code>fastboot</code> mode by holding the appropriate
+key combination at boot or using the following command:
+<pre class="devsite-click-to-copy devsite-terminal">adb reboot bootloader</pre></li>
+<li>After the device is in fastboot mode, run:
+<pre class="devsite-click-to-copy devsite-terminal">fastboot flashall -w</pre>
+The <code>-w</code> option wipes the <code>/data</code> partition on the
device; this is useful for your first time flashing a particular device but is
-otherwise unnecessary.</p>
-
-<p class="note"><strong>Note</strong>: Filesystems created via fastboot on
-Motorola Xoom do not function optimally. We recommend re-creating filesystems
-through recovery, using: <code>$ adb reboot recovery</code>. While in recovery,
-open the menu (press Power + Volume Up), wipe the cache partition, then wipe
-data.</p>
+otherwise unnecessary.</li>
+</ol>
+<aside class="note"><strong>Note</strong>: Filesystems created via
+<code>fastboot</code> on Motorola Xoom do not function optimally. We recommend
+re-creating filesystems through recovery using <code>$ adb reboot
+recovery</code>. While in recovery, open the menu (press Power + Volume Up),
+wipe the cache partition, then wipe data.</aside>
<h2 id="restoring-devices-to-factory-state">Restoring devices to factory
state</h2>
-<p>Factory images for Nexus 5, Nexus 10, Nexus 4, Nexus Q, Nexus 7, Galaxy Nexus
-(GSM/HSPA+ "yakju" and "takju", and CDMA/LTE "mysid" and "mysidspr"), Nexus S,
-and Nexus S 4G are available from
-<a href="https://developers.google.com/android/nexus/images">Google's factory
-image</a> page.</p>
-
-<p>Factory images for the Motorola Xoom are distributed directly by Motorola.</p>
+<p>Factory images for Google devices are available from
+<a href="https://developers.google.com/android/nexus/images" class="external">Factory
+Images for Nexus and Pixel Devices</a>. Factory images for the Motorola Xoom are
+distributed directly by Motorola.</p>
</body>
</html>
diff --git a/en/source/site-updates.html b/en/source/site-updates.html
index 656301c5..402eb8b3 100644
--- a/en/source/site-updates.html
+++ b/en/source/site-updates.html
@@ -153,21 +153,36 @@ href="/devices/bluetooth/index.html">Bluetooth
overview</a>.
</p>
-<h4>Verifying and Debugging Bluetooth</h4>
+<h4>Verifying and debugging Bluetooth</h4>
<p>
A new page about how to verify and debug the native Bluetooth stack. See this page at
<a href="/devices/bluetooth/verifying_debugging.html">Verifying and Debugging</a>.
</p>
-<!--
+<h4>Bluetooth services</h4>
+<p>
+Bluetooth provides a variety of features that enable core services between devices,
+such as audio streaming, phone calls, and messaging. For more information about the Android
+Bluetooth services, see <a href="/devices/bluetooth/services.html">
+Bluetooth Services</a>.
+</p>
+
+<h4>BLE advertising</h4>
+<p>
+Bluetooth 5 supports different modes of data advertisements for Bluetooth Low Energy,
+including higher bandwidth or increased range. For more information, see
+<a href="/devices/bluetooth/ble_advertising.html">
+Bluetooth Low Energy Advertising</a>.
+</p>
+
+
<h4>Bluetooth support for audio codecs</h4>
<p>
The Android 8.0 release includes support for Bluetooth high-definition audio
codecs. For more information, see <a
-href="/devices/bluetooth/audio-codecs.html">Bluetooth
-Support for Audio Codecs in Android 8.0</a>.
+href="/devices/bluetooth/services.html#advanced-audio-codecs">Advanced audio codecs</a>.
</p>
--->
+
<h3 id="camera">Camera</h3>
@@ -426,11 +441,11 @@ href="https://groups.google.com/forum/#!forum/android-llvm">android-llvm</a>
public group to get help and take part in development.
</p>
-<h3 id="drm">DRM</h3>
+<h3 id="drm-kms">DRM / KMS</h3>
<h4>DRM/KMS in Linux Kernel Version 4.9</h4>
<p>
-The Digital Rights Management (DRM)/Kernel Mode Setting (KMS) framework used by
+The Direct Rendering Manager (DRM)/Kernel Mode Setting (KMS) framework used by
Android is developed and maintained by Linux kernel developers in the Linux
kernel. Android merges down from the Linux kernel. By merging down from our
common kernel, device manufacturers gain the DRM/KMS framework automatically.
diff --git a/zh-cn/devices/accessories/aoa.html b/zh-cn/devices/accessories/aoa.html
new file mode 100644
index 00000000..98eb6e09
--- /dev/null
+++ b/zh-cn/devices/accessories/aoa.html
@@ -0,0 +1,128 @@
+<html devsite><head>
+ <title>Android 开放配件协议 1.0</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android USB 配件必须遵循 Android 开放配件 (AOA) 协议,该协议规定了配件如何检测 Android 设备并与其建立通信。配件应执行以下步骤:</p>
+
+<ol>
+<li>等待设备连接并对其进行检测。</li>
+<li>确定设备是否支持配件模式。</li>
+<li>尝试以配件模式启动设备(如需要)。</li>
+<li>如果设备支持 AOA,则与该设备建立通信。</li>
+</ol>
+
+<p>以下部分介绍了如何执行上述步骤。</p>
+
+<p class="note"><strong>注意</strong>:要开发能通过 USB 连接到 Android 设备的新配件,请使用 <a href="aoa2.html">AOAv2</a>。</p>
+
+<h2 id="wait-for-and-detect-connected-devices">等待设备连接并对其进行检测</h2>
+
+<p>配件应该不间断地检查是否连接了 Android 设备。设备成功连接后,配件应该确定设备是否支持配件模式。</p>
+
+<h2 id="determine-accessory-mode-support">确定是否支持配件模式</h2>
+
+<p>当 Android 设备成功连接后,它可能处于以下三种状态之一:
+</p>
+
+<ul>
+<li>支持 Android 配件模式,并且已处于配件模式。</li>
+<li>支持 Android 配件模式,但是未处于配件模式。</li>
+<li>不支持 Android 配件模式。</li>
+</ul>
+
+<p>在初次连接时,配件应该检查所连接设备的 USB 设备描述符的供应商 ID 和产品 ID。供应商 ID 应与 Google 的 ID (<code>0x18D1</code>) 相符。如果设备已经处于配件模式,则产品 ID 应为 <code>0x2D00</code> 或 <code>0x2D01</code>,配件可以使用自己的通信协议通过批量传输端点<a href="#establish-communication-with-the-device">与设备建立通信</a>(不需要以配件模式启动设备)。</p>
+
+<p class="note"><strong>注意</strong>:<code>0x2D00</code> 是为支持配件模式的 Android 设备预留的产品 ID。<code>0x2D01</code> 则是为同时支持配件模式和 Android 调试桥 (ADB) 协议的设备预留的产品 ID,这类设备提供了第二个接口(具有两个批量端点,用于 ADB 通信)。如果您在计算机上模拟配件,则可以使用这些端点来调试配件应用。一般来说,不要使用该接口,除非配件在设备上实现了到 ADB 的直通通信。
+</p>
+
+<p>如果发现 USB 设备描述符中的供应商 ID 或产品 ID 与期望值不符,则配件无法确定设备是否支持 Android 配件模式。配件应尝试以配件模式启动设备(详见下文)以确定设备是否支持配件模式。</p>
+
+<h2 id="attempt-to-start-in-accessory-mode">尝试以配件模式启动</h2>
+
+<p>如果供应商 ID 和产品 ID 与处于配件模式下的 Android 设备不对应,则配件无法辨别未处于配件模式下的设备是否支持配件模式。发生这种情况是因为支持配件模式(但未处于配件模式下)的设备首先报告的是设备制造商的供应商 ID 和产品 ID,而不是 AOA<em></em> 供应商 ID 和产品 ID<em></em>。</p>
+
+<p>配件应尝试以配件模式启动设备,以确定设备是否支持该模式:</p>
+
+<ol>
+ <li>发送 51 控制请求(“获取协议”)以确定设备是否支持 Android 配件协议。如果设备支持协议,则返回一个非零数字,代表所支持的协议版本。该控制请求为端点 0 上的请求,具有以下特征:
+
+<pre class="devsite-click-to-copy">
+requestType: USB_DIR_IN | USB_TYPE_VENDOR
+request: 51
+value: 0
+index: 0
+data: protocol version number (16 bits little endian sent from the
+ device to the accessory)
+</pre>
+ </li>
+
+ <li>如果设备返回所支持的协议版本,则向设备发送含标识字符串信息的控制请求。该信息让设备可以确定适合配件的应用(如果没有适合配件的应用,则向用户呈现一个网址)。该控制请求为端点 0 上的请求(适用每个字符串 ID),具有以下特征:
+
+<pre class="devsite-click-to-copy">
+requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+request: 52
+value: 0
+index: string ID
+data zero terminated UTF8 string sent from accessory to device
+</pre>
+
+ <p>支持以下字符串 ID,并且每个字符串的最大值为 256 个字节(必须以零结束,以 <code>\0</code> 结尾)。</p>
+
+<pre class="devsite-click-to-copy">
+manufacturer name: 0
+model name: 1
+description: 2
+version: 3
+URI: 4
+serial number: 5
+</pre>
+ </li>
+
+ <li>发送控制请求,要求设备以配件模式启动。该控制请求为端点 0 上的请求,具有以下特征:
+
+<pre class="devsite-click-to-copy">
+requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+request: 53
+value: 0
+index: 0
+data: none
+</pre>
+ </li>
+</ol>
+
+<p>完成这些步骤后,配件应等待所连接的 USB 设备在配件模式下将其自身重新接入总线,然后重新枚举所连接的设备。该算法通过检查供应商 ID 和产品 ID 来<a href="#determine-accessory-mode-support">确定设备是否支持配件模式</a>,如果设备成功切换到配件模式,那么供应商 ID 和产品 ID 应该是正确的(例如,与 Google 的供应商 ID 和产品 ID 而不是设备制造商的 ID 相对应)。如果 ID 正确,配件则进而<a href="#establish-communication-with-the-device">与设备建立通信</a>。</p>
+
+<p class="note"><strong>注意</strong>:AOA 当前不支持同时进行 AOA 连接和 MTP 连接。要从 AOA 切换到 MTP,配件必须首先与 USB 设备断开连接(断开物理连接或以电气等效的方式断开),然后使用 MTP 重新连接 USB 设备。</p>
+
+<p>如果有任意步骤失败,配件则确定设备不支持 Android 配件模式,并等待下一个设备连接。</p>
+
+<h2 id="establish-communication-with-the-device">与设备建立通信</h2>
+
+<p>如果配件检测到配件模式下的 Android 设备,则配件可以查询设备接口和端点描述符,以获取用于与设备进行通信的批量端点。</p>
+
+<p>接口和批量端点的数量取决于产品 ID。具有以下产品 ID 的 Android 设备所具备的接口情况:</p>
+
+<ul>
+<li><code>0x2D00</code> 有一个接口,该接口有两个批量端点,用于输入和输出通信。</li>
+<li><code>0x2D01</code> 有两个接口,每个接口有两个批量端点,用于输入和输出通信。第一个接口处理标准通信,第二个接口则处理 ADB 通信。要使用接口,请找到第一个批量输入和输出端点,使用 <code>SET_CONFIGURATION</code> (<code>0x09</code>) 设备请求将设备配置的值设为 1,然后使用端点进行通信。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/accessories/aoa2.html b/zh-cn/devices/accessories/aoa2.html
new file mode 100644
index 00000000..70d44160
--- /dev/null
+++ b/zh-cn/devices/accessories/aoa2.html
@@ -0,0 +1,219 @@
+<html devsite><head>
+ <title>Android 开放配件协议 2.0</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>本文介绍了 Android 开放配件 (AOA) 协议自初始版本以来的变化,并对 <a href="aoa.html">AOA 1.0 文档</a>进行补充。AOAv2 增加了以下功能:</p>
+
+<ul>
+<li>音频输出(从 Android 设备到配件)。</li>
+<li>支持配件充当 Android 设备的一个或多个人机接口设备 (HID)。</li>
+</ul>
+
+<p>提供给 Android 应用开发者的 Android SDK API 保持不变。
+</p>
+
+<h2 id="detecting-android-open-accessory-20-support">检测 AOAv2 支持</h2>
+
+<p>要确定连接的 Android 设备是否支持配件和支持的协议版本,该配件必须发送 <code>getProtocol()</code> 命令并检查结果。仅支持 AOAv1 功能的 Android 设备必须返回 <code>1</code> 作为协议版本;支持 AOAv2 的额外功能的设备必须返回 <code>2</code> 作为协议版本。AOAv2 向后兼容 AOAv1,因此基于原始配件协议设计的配件将可以兼容更高版本的 Android 设备。</p>
+
+<p>以下示例来自配件开发工具包 2011 <a href="http://developer.android.com/tools/adk/adk2.html#src-download">源代码</a> (<code>&lt;adk-src&gt;/adk1/board/AndroidAccessory/AndroidAccessory.cpp</code>) 库,该示例演示了此协议的检查过程:</p>
+
+<pre class="devsite-click-to-copy">
+bool AndroidAccessory::switchDevice(byte addr)
+{
+ int protocol = getProtocol(addr);
+ if (protocol &gt;= 1) {
+ Serial.print("device supports protocol 1 or higher\n");
+ } else {
+ Serial.print("could not read device protocol version\n");
+ return false;
+ }
+
+ sendString(addr, ACCESSORY_STRING_MANUFACTURER, manufacturer);
+ sendString(addr, ACCESSORY_STRING_MODEL, model);
+ sendString(addr, ACCESSORY_STRING_DESCRIPTION, description);
+ sendString(addr, ACCESSORY_STRING_VERSION, version);
+ sendString(addr, ACCESSORY_STRING_URI, uri);
+ sendString(addr, ACCESSORY_STRING_SERIAL, serial);
+
+ usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR |
+ USB_SETUP_RECIPIENT_DEVICE, ACCESSORY_START, 0, 0, 0, 0, NULL);
+ return true;
+}
+</pre>
+
+<p>AOAv2 包含了新的 USB 产品 ID,以用于配件模式下每种可能的 USB 接口组合。</p>
+
+<table id="AOA-version-comparison">
+<tbody>
+
+<tr>
+<th>版本</th>
+<th>产品 ID</th>
+<th>通信</th>
+<th>说明</th>
+</tr>
+
+<tr>
+<td rowspan="2">AOAv1</td>
+<td><code>0x2D00</code></td>
+<td>配件</td>
+<td>提供两个批量端点,用于与 Android 应用通信。</td>
+</tr>
+
+<tr>
+<td><code>0x2D01</code></td>
+<td>配件 + adb</td>
+<td>在配件开发过程中用于调试。仅当用户在 Android 设备设置中启用了“USB 调试”<em></em>时才可用。</td>
+</tr>
+
+<tr>
+<td rowspan="4">AOAv2</td>
+<td><code>0x2D02</code></td>
+<td>音频</td>
+<td>将音频从 Android 设备流式传输至配件。</td>
+</tr>
+
+<tr>
+<td><code>0x2D03</code></td>
+<td>音频 + adb</td>
+<td></td>
+</tr>
+
+<tr>
+<td><code>0x2D04</code></td>
+<td>配件 + 音频</td>
+<td></td>
+</tr>
+
+<tr>
+<td><code>0x2D05</code></td>
+<td>配件 + 音频 + adb</td>
+<td></td>
+</tr>
+
+</tbody>
+</table>
+
+<p>AOAv1 中使用的产品 ID(<code>0x2D00</code> 和 <code>0x2D01</code>)在 AOAv2 中仍然受支持。</p>
+
+<h2 id="audio-support">音频支持</h2>
+
+<p>AOAv2 支持通过标准的 USB 音频类接口,将音频从 Android 设备输出到配件。该音频类接口支持比特率为 44100 Khz 的 2 声道 16 位 PCM 音频(未来可能会添加其他音频模式)。</p>
+
+<p>如需启用音频支持,配件必须发送新的 USB 控制请求:
+</p>
+
+<pre class="devsite-click-to-copy">
+**SET_AUDIO_MODE**
+requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+request: 58
+value: 0 for no audio (default),
+ 1 for 2 channel, 16-bit PCM at 44100 KHz
+index: 0
+data none
+</pre>
+
+<p>此命令必须在发送用于进入配件模式的 <code>ACCESSORY_START</code> 命令之前发送。<em></em></p>
+
+<h2 id="hid-support">HID 支持功能</h2>
+
+<p>AOAv2 允许配件在 Android 设备上注册一个或多个 USB HID 设备。这种方式反转了典型 USB HID 设备(如 USB 鼠标和键盘)的通信方向。通常情况下,HID 设备是连接到 USB 主机(即个人计算机)的外围设备,但在 AOA 中,USB 主机可以充当 USB 外围设备的一个或多个输入设备。</p>
+
+<p>HID 支持功能是标准 HID 事件的代理;该实现不会对事件内容或类型做出假设,而是直接将其传递给输入系统,从而使 AOAv2 配件能够充当任何 HID 设备(如鼠标、键盘、游戏控制器等)。您可以利用 HID 支持功能来提供基本功能(如媒体扩充基座上的播放/暂停按钮),也可提供高级功能(如带有鼠标和完整 QWERTY 键盘的扩展坞)。</p>
+
+<p>AOAv2 增加了新的 USB 控制请求,允许配件充当 Android 设备的一个或多个 HID 输入设备。HID 支持功能完全由端点 0 上的控制请求处理,因而不需要新的 USB 接口。这四个新控制请求为:</p>
+
+<ul>
+<li><strong>ACCESSORY_REGISTER_HID</strong> 向 Android 设备注册新的 HID 设备。配件提供 ID,以供其他三个调用用来识别该 HID 设备。在 USB 断开连接或配件发送 <code>ACCESSORY_UNREGISTER_HID</code> 以取消注册 HID 设备前,此 ID 将一直有效。</li>
+<li><strong>ACCESSORY_UNREGISTER_HID</strong> 取消注册之前通过 <code>ACCESSORY_REGISTER_HID</code> 注册的 HID 设备。</li>
+<li><strong>ACCESSORY_SET_HID_REPORT_DESC</strong> 将 HID 设备的报告描述符发送至 Android 设备。该请求用于描述 HID 设备的功能,且必须在向 Android 设备报告任何 HID 事件之前发送。如果报告描述符大于端点 0 的最大数据包大小,则会发送多个 <code>ACCESSORY_SET_HID_REPORT_DESC</code> 命令来传输整个描述符。</li>
+<li><strong>ACCESSORY_SEND_HID_EVENT</strong> 将配件中的输入事件发送至 Android 设备。</li>
+</ul>
+
+<p>新控制请求的代码定义如下:</p>
+
+<pre class="devsite-click-to-copy">
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID_DEVICE
+ * value: Accessory assigned ID for the HID device
+ * index: total length of the HID report descriptor
+ * data none
+ */
+#define ACCESSORY_REGISTER_HID 54
+
+/* Control request for unregistering a HID device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_UNREGISTER_HID 55
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_HID_REPORT_DESC
+ * value: Accessory assigned ID for the HID device
+ * index: offset of data in descriptor
+ * (needed when HID descriptor is too big for one packet)
+ * data the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+
+/* Control request for sending HID events.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_HID_EVENT
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT 57
+</pre>
+
+<h2 id="interoperability-with-aoa-10-features">与 AOAv1 的互操作性</h2>
+
+<p>原始协议 (<a href="aoa.html">AOAv1</a>) 支持 Android 应用通过 USB 直接与 USB 主机(配件)通信。AOAv2 在提供此支持的基础上增加了新的功能,使配件本身就能与 Android 操作系统(特别是音频和输入系统)通信。除了原有的功能集外,AOAv2 还可以构建使用新的音频和 HID 支持功能的配件。在保留已有功能的同时,让您畅享新功能。</p>
+
+<h2 id="connecting-aoa-20-without-an-android-app">在不使用 Android 应用的情况下连接 AOAv2</h2>
+
+<p>您可以设计这样一种配件,它可以使用音频和 HID 支持功能,但不与 Android 设备上的应用通信,例如音频基座。对于这些配件,用户无需接收对话框提示(告知他们发现了新连接的配件并请他们将配件与可与之通信的 Android 应用关联)。</p>
+
+<p>如需在配件连接后阻止系统显示此类对话框,配件可选择不将制造商和型号名称发送至 Android 设备。当这些字符串未提供给 Android 设备时:</p>
+
+<ul>
+<li>系统不会尝试查找可与配件通信的应用。</li>
+<li>当设备进入配件模式后,配件 USB 接口不会出现在 Android 设备的 USB 配置中。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/accessories/headset/usb-headset-spec.html b/zh-cn/devices/accessories/headset/usb-headset-spec.html
new file mode 100644
index 00000000..44e357f3
--- /dev/null
+++ b/zh-cn/devices/accessories/headset/usb-headset-spec.html
@@ -0,0 +1,162 @@
+<html devsite><head>
+ <title>USB 耳机:配件规格</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>
+本文档详细说明了 USB 耳机上各个按钮的行为,以使其在整个 Android 生态系统中保持一致。设备制造商还应参考 <a href="/devices/audio/usb.html">USB 数字音频</a>页面,以了解有关在 Android 设备上实现 USB 的更多信息;以及参考 <a href="http://source.android.com/compatibility/android-cdd.html">Android 兼容性定义文档 (CDD)</a>,以了解与 Android 设备相关的要求。
+</p>
+<p>此外,本文档还介绍了面向配件制造商的 <a href="plug-headset-spec.html">3.5 毫米耳机</a>规格和面向设备制造商的 <a href="jack-headset-spec.html">3.5 毫米耳机插孔</a>规格。
+</p>
+<p>
+本文档给出的是最低要求,我们鼓励配件制造商在满足这些要求的基础上添加新的功能。
+</p>
+<h2 id="control-function-mapping">控件-功能映射</h2>
+<table>
+ <tbody><tr>
+ <th>控件功能</th>
+ <th>配件支持</th>
+ <th>说明</th>
+ </tr>
+ <tr>
+ <td>A</td>
+ <td>必需</td>
+ <td>播放/暂停(短按)、启动语音命令(长按)、下一曲(按两下)</td>
+ </tr>
+ <tr>
+ <td>B</td>
+ <td>可选</td>
+ <td>调高音量</td>
+ </tr>
+ <tr>
+ <td>C</td>
+ <td>可选</td>
+ <td>调低音量</td>
+ </tr>
+ <tr>
+ <td>D</td>
+ <td>可选</td>
+ <td>启动语音命令</td>
+ </tr>
+</tbody></table>
+<p>
+<strong>按钮功能分配如下:</strong>
+</p>
+<ul>
+ <li>所有单按钮耳机都必须实现功能 A。</li>
+ <li>多按钮耳机必须按照以下模式实现相关功能:
+ <ul>
+ <li>2 项功能:A 和 D</li>
+ <li>3 项功能:A、B、C</li>
+ <li>4 项功能:A、B、C、D</li>
+ </ul>
+ </li>
+</ul>
+<p class="note">
+<strong>注意</strong>:不允许按键锁定。最终用户每次按键时都必须生成相应的“按下”和“释放”按键事件,与最终用户的操作相匹配。换句话说,功能 A 到功能 D 所对应的按键一律不能被“锁定”,也不能用作切换开关(在这种情况下,当生成“按下”按键事件后,第二次按下按键时才会生成“释放”按键事件)。
+</p>
+<h2 id="software-mapping">软件映射</h2>
+<p>
+兼容的 USB 耳机需要支持耳机按钮的以下软件映射。以下软件映射需要设备支持。
+</p>
+
+<table>
+ <tbody><tr>
+ <th>功能</th>
+ <th>映射</th>
+ <th>环境</th>
+ <th>行为</th>
+ </tr>
+ <tr>
+ <td rowspan="6">A</td>
+ <td rowspan="6"><strong>HID 用途页</strong>:0x0C<br />
+ <strong>HID 用途</strong>:0x0CD<br />
+ <strong>内核按键</strong>:<code>KEY_PLAYPAUSE</code><br />
+ <strong>Android 按键</strong>:<code>KEYCODE_MEDIA_PLAY_PAUSE</code></td>
+ <td rowspan="2">媒体播放</td>
+ <td><strong>输入</strong>:短按<br />
+ <strong>输出</strong>:播放或暂停</td>
+ </tr>
+ <tr>
+ <td><strong>输入</strong>:长按<br />
+ <strong>输出</strong>:启动语音命令<br />
+ <strong>发送</strong>:<code>android.intent.action.VOICE_SEARCH_HANDS_FREE</code></td>
+ </tr>
+ <tr>
+ <td rowspan="2">来电</td>
+ <td><strong>输入</strong>:短按<br />
+ <strong>输出</strong>:接听来电</td>
+ </tr>
+ <tr>
+ <td><strong>输入</strong>:长按<br />
+ <strong>输出</strong>:拒绝来电</td>
+ </tr>
+ <tr>
+ <td rowspan="2">当前通话</td>
+ <td><strong>输入</strong>:短按<br />
+ <strong>输出</strong>:结束通话</td>
+ </tr>
+ <tr>
+ <td><strong>输入</strong>:长按<br />
+ <strong>输出</strong>:将麦克风设为静音或取消静音</td>
+ </tr>
+ <tr>
+ <td>B</td>
+ <td><strong>HID 用途页</strong>:0x0C<br />
+ <strong>HID 用途</strong>:0x0E9<br />
+ <strong>内核按键</strong>:<code>KEY_VOLUMEUP</code><br />
+ <strong>Android 按键</strong>:<code>VOLUME_UP</code></td>
+ <td>媒体播放、当前通话</td>
+ <td><strong>输入</strong>:短按或长按<br />
+ <strong>输出</strong>:调高系统或耳机的音量</td>
+ </tr>
+ <tr>
+ <td>C</td>
+ <td><strong>HID 用途页</strong>:0x0C<br />
+ <strong>HID 用途</strong>:0x0EA<br />
+ <strong>内核按键</strong>:<code>KEY_VOLUMEDOWN</code><br />
+ <strong>Android 按键</strong>:<code>VOLUME_DOWN</code></td>
+ <td>媒体播放、当前通话</td>
+ <td><strong>输入</strong>:短按或长按<br />
+ <strong>输出</strong>:调低系统或耳机的音量</td>
+ </tr>
+ <tr>
+ <td>D</td>
+ <td><strong>HID 用途页</strong>:0x0C<br />
+ <strong>HID 用途</strong>:0x0CF<br />
+ <strong>内核按键</strong>:<code>KEY_VOICECOMMAND</code><br />
+ <strong>Android 按键</strong>:<code>KEYCODE_VOICE_ASSIST</code></td>
+ <td>所有。可在任何情况下触发。</td>
+ <td><strong>输入</strong>:短按或长按<br />
+ <strong>输出</strong>:启动语音命令</td>
+ </tr>
+</tbody></table>
+
+<p class="note">按键映射应在 HID 应用集合中声明。对于不带麦克风的配件,请使用耳机(用途页:消费者 (0x0C),用途:耳机 (0x05))。对于带有麦克风的配件,请使用耳麦(用途页:电话 (0x0B),用途:耳麦 (0x05))。</p>
+
+<h2 id="mechanical">机械</h2>
+<p>
+配件制造商必须遵循 <a href="http://www.usb.org/">USB.org</a> 规定的对 USB 连接器的要求。
+</p>
+<p>
+设备制造商必须遵循 Android CDD 的 <a href="/compatibility/android-cdd.html#7_7_usb">USB 部分</a>中的要求。
+</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/accessories/protocol.html b/zh-cn/devices/accessories/protocol.html
new file mode 100644
index 00000000..fb7202cc
--- /dev/null
+++ b/zh-cn/devices/accessories/protocol.html
@@ -0,0 +1,37 @@
+<html devsite><head>
+ <title>Android 开放配件 (AOA)</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android 开放配件 (AOA) 支持功能可让外部 USB 硬件(Android USB 配件)与处于配件模式下的 Android 设备进行交互。<em></em>当某台 Android 设备处于配件模式时,所连接的配件会充当 USB 主机(为总线供电并列举设备),而 Android 设备则充当 USB 配件。
+</p>
+
+<p>Android USB 配件专门用于和 Android 设备相连。这些配件遵循 AOA 要求,从而能够检测到支持配件模式的 Android 设备,并且必须提供 500 毫安(电压为 5 伏)的充电电流。之前发布的部分 Android 设备只能充当 USB 设备,无法发起与外部 USB 设备的连接。AOA 支持功能打破了这一局限,让您能够构建可以与各种 Android 设备建立连接并与其进行交互的配件。
+</p>
+
+<p class="note"><strong>注意</strong>:配件模式取决于设备硬件;部分设备可能不支持配件模式。您可以在相应应用的 Android 清单中使用 <code>&lt;uses-feature&gt;</code> 元素来滤出支持配件模式的设备。有关详情,请参阅 <a href="http://developer.android.com/guide/topics/connectivity/usb/accessory.html#manifest">USB 配件</a>开发者指南。</p>
+
+<p>AOA 有以下两个版本,分别支持不同通信类型:</p>
+<ul>
+<li><strong>AOAv1</strong>。支持通用配件通信和 adb 调试。适用于 Android 3.1(API 级别 12)及更高版本,也可以在 Android 2.3.4(API 级别 10)及更高版本中通过<a href="https://developers.google.com/android/add-ons/google-apis/">附加库</a>来实现。</li>
+<li><strong>AOAv2</strong>。支持音频流式传输和人机接口设备 (HID) 功能。适用于 Android 4.1(API 级别 16)。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/architecture/hal.html b/zh-cn/devices/architecture/hal.html
new file mode 100644
index 00000000..4b3f199e
--- /dev/null
+++ b/zh-cn/devices/architecture/hal.html
@@ -0,0 +1,92 @@
+<html devsite><head>
+ <title>硬件抽象层 (HAL)</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>HAL 可定义一个标准接口以供硬件供应商实现,这可让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。HAL 实现会被封装成模块,并由 Android 系统适时地加载。</p>
+
+<img src="../images/ape_fwk_hal.png"/>
+
+<p class="img-caption"><strong>图 1.</strong> HAL 组件</p>
+
+<p>您必须为您的产品所提供的特定硬件实现相应的 HAL(和驱动程序)。HAL 实现通常会内置在共享库模块(<code>.so</code> 文件)中,但 Android 并不要求 HAL 实现与设备驱动程序之间进行标准交互,因此您可以视情况采取适当的做法。不过,要使 Android 系统能够与您的硬件正确互动,您<strong>必须</strong>遵守各个特定于硬件的 HAL 接口中定义的合同。</p>
+
+<p>为了保证 HAL 具有可预测的结构,每个特定于硬件的 HAL 接口都要具有 <code>hardware/libhardware/include/hardware/hardware.h</code> 中定义的属性。这类接口可让 Android 系统以一致的方式加载 HAL 模块的正确版本。HAL 接口包含两个组件:模块和设备。
+</p>
+
+<h2 id="hal-module">HAL 模块</h2>
+<p>模块表示被封装且存储为共享库 (<code>.so file</code>) 的 HAL 实现。<code>hardware/libhardware/include/hardware/hardware.h</code> 标头文件会定义一个表示模块的结构体 (<code>hw_module_t</code>),其中包含模块的版本、名称和作者等元数据。Android 会根据这些元数据来找到并正确加载 HAL 模块。</p>
+
+<p>另外,<code>hw_module_t</code> 结构体还包含指向另一个结构体 <code>hw_module_methods_t</code> 的指针,后面这个结构体会包含一个指向相应模块的 open 函数的指针。此 open 函数用于与相关硬件(此 HAL 是其抽象形式)建立通信。每个特定于硬件的 HAL 通常都会使用附加信息为该特定硬件扩展通用的 <code>hw_module_t</code> 结构体。例如,在相机 HAL 中,<code>camera_module_t</code> 结构体会包含一个 <code>hw_module_t</code> 结构体以及其他特定于相机的函数指针:</p>
+
+<pre class="devsite-click-to-copy">
+typedef struct camera_module {
+ hw_module_t common;
+ int (*get_number_of_cameras)(void);
+ int (*get_camera_info)(int camera_id, struct camera_info *info);
+} camera_module_t;
+</pre>
+
+<p>实现 HAL 并创建模块结构体时,您必须将其命名为 <code>HAL_MODULE_INFO_SYM</code>。以下是 Nexus 9 音频 HAL 的示例:</p>
+
+<pre class="devsite-click-to-copy">
+struct audio_module HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "NVIDIA Tegra Audio HAL",
+ .author = "The Android Open Source Project",
+ .methods = &amp;hal_module_methods,
+ },
+};
+</pre>
+
+<h2 id="hal-device">HAL 设备</h2>
+<p>设备是产品硬件的抽象表示。例如,一个音频模块可能包含主音频设备、USB 音频设备或蓝牙 A2DP 音频设备。</p>
+
+<p>设备由 <code>hw_device_t</code> 结构体表示。与模块类似,每类设备都定义了一个通用 <code>hw_device_t</code> 的详细版本,其中包含指向硬件特定功能的函数指针。例如,<code>audio_hw_device_t</code> 结构体类型会包含指向音频设备操作的函数指针:</p>
+
+<pre class="devsite-click-to-copy">
+struct audio_hw_device {
+ struct hw_device_t common;
+
+ /**
+ * used by audio flinger to enumerate what devices are supported by
+ * each audio_hw_device implementation.
+ *
+ * Return value is a bitmask of 1 or more values of audio_devices_t
+ */
+ uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
+ ...
+};
+typedef struct audio_hw_device audio_hw_device_t;
+</pre>
+
+<p>除了这些标准属性之外,每个特定于硬件的 HAL 接口都可以定义更多的自有功能和要求。有关详情,请参阅 <a href="/reference/hal/">HAL 参考文档</a>以及各 HAL 的单独说明。</p>
+
+<h2 id="hal-building">编译 HAL 模块</h2>
+<p>HAL 实现会内置在模块 (<code>.so</code>) 文件中,并由 Android 适时地动态链接。您可以为每个 HAL 实现创建 <code>Android.mk</code> 文件并指向源文件,从而编译模块。一般来说,您的共享库必须以特定格式命名,以方便找到并正确加载。各模块的命名方案略有不同,但它们都遵循以下通用模式:<code>&lt;module_type&gt;.&lt;device_name&gt;</code>。
+</p>
+
+<p>要详细了解如何为每个 HAL 设置模块编译,请参阅本网站“移植”部分中特定于 HAL 的文档。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/architecture/index.html b/zh-cn/devices/architecture/index.html
new file mode 100644
index 00000000..749c90d8
--- /dev/null
+++ b/zh-cn/devices/architecture/index.html
@@ -0,0 +1,50 @@
+<html devsite><head>
+ <title>架构</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>
+Android 系统架构包含以下组件:
+</p>
+
+<img src="../images/ape_fwk_all.png"/>
+
+<p class="img-caption"><strong>图 1.</strong> Android 系统架构</p>
+
+<h2 id="application-framework">应用框架</h2>
+
+<p>应用框架最常被应用开发者使用。如果您是硬件开发者,则应该了解开发者 API,因为很多此类 API 都会直接映射到底层 HAL 接口,并可提供与实现驱动程序相关的实用信息。</p>
+
+<h2 id="binder-ipc">Binder IPC</h2>
+<p>Binder 进程间通信 (IPC) 机制允许应用框架跨越进程边界并调用 Android 系统服务代码,从而使得高级框架 API 能与 Android 系统服务进行交互。在应用框架级别,开发者无法看到此类通信的过程,但一切都会“按部就班地运行”。</p>
+
+<h2 id="system-services">系统服务</h2>
+<p>系统服务是集中的模块化组件,例如窗口管理器、搜索服务或通知管理器。应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。Android 包含两组服务:“系统”(诸如窗口管理器和通知管理器之类的服务)和“媒体”(与播放和录制媒体相关的服务)。<em></em><em></em></p>
+
+<h2 id="hal">硬件抽象层 (HAL)</h2>
+<p>硬件抽象层 (HAL) 会定义一个标准接口来供硬件供应商实现,从而能让 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或更改更高级别的系统。HAL 实现会被封装成模块,并会由 Android 系统适时地加载。有关详情,请参阅<a href="/devices/architecture/hal.html">硬件抽象层 (HAL)</a> 一文。
+</p>
+
+<h2 id="Linux-kernel">Linux 内核</h2>
+<p>开发设备驱动程序与开发典型的 Linux 设备驱动程序类似。Android 使用的 Linux 内核版本包含一些特殊的补充功能,例如:唤醒锁(这是一种内存管理系统,可更主动地保护内存)、Binder IPC 驱动程序以及对移动嵌入式平台非常重要的其他功能。这些补充功能主要用于增强系统功能,不会影响驱动程序开发。</p>
+
+<p>您可以使用任意版本的内核,只要它支持所需功能(如 Binder 驱动程序)。不过,我们建议您使用 Android 内核的最新版本。有关详情,请参阅<a href="/source/building-kernels.html">编译内核</a>一文。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/architecture/treble.html b/zh-cn/devices/architecture/treble.html
new file mode 100644
index 00000000..e4c2c3a9
--- /dev/null
+++ b/zh-cn/devices/architecture/treble.html
@@ -0,0 +1,46 @@
+<html devsite><head>
+ <title>Treble</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>即将推出的 Android O 版本新增了 Project Treble,这是 Android 操作系统框架对架构进行的一项重大改变,旨在让制造商以更低的成本更轻松、更快速地将设备更新到新版 Android 系统。</p>
+
+<h2 id="about-treble">Android 更新</h2>
+<p>Project Treble 通过新的供应商接口将供应商实现(由芯片制造商编写的设备专属底层软件)与 Android 操作系统框架分开。</p>
+
+<p>Android 7.x 及更早版本中没有正式的供应商接口,因此设备制造商必须更新大量 Android 代码才能将设备更新到新版 Android 系统:</p>
+
+<img src="images/treble_blog_before.png"/>
+
+<p class="img-caption"><strong>图 1.</strong> Treble 推出前的 Android 更新环境</p>
+
+<p>Treble 提供了一个稳定的新供应商接口,供设备制造商访问 Android 代码中特定于硬件的部分,这样一来,设备制造商只需更新 Android 操作系统框架,即可跳过芯片制造商直接提供新的 Android 版本:</p>
+
+<img src="images/treble_blog_after.png"/>
+
+<p class="img-caption"><strong>图 2.</strong> Treble 推出后的 Android 更新环境</p>
+
+<h2 id="testing-treble">对 Treble 进行测试</h2>
+<p>为了确保供应商实现的前向兼容性,可以使用供应商测试套件 (VTS) 对新的供应商接口进行验证,该套件类似于<a href="/compatibility/cts/">兼容性测试套件 (CTS)</a>。已经发布的 VTS 可以自动执行 HAL 和操作系统内核测试,即便是 Treble 推出前的环境也适用;有关详细信息,请参阅<a href="/devices/tech/test_infra/tradefed/fundamentals/vts">使用 VTS 进行系统测试</a>一文。</p>
+
+<h2 id="launching-treble">即将推出</h2>
+<p>Project Treble 即将登陆搭载 Android O 及后续版本的所有新设备,不过,这种新的架构已经在 Pixel 手机的 O 开发者预览版中投入使用。在发布 Android O 时,我们将提供完整详情(届时请访问 <a href="https://source.android.com/">source.android.com</a>)。在过渡期间,如需详细了解 Treble,请参阅 <a href="https://android-developers.googleblog.com/2017/05/here-comes-treble-modular-base-for.html">Android 开发者博客</a>。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/audio/latency_design.html b/zh-cn/devices/audio/latency_design.html
new file mode 100644
index 00000000..6e52d3bd
--- /dev/null
+++ b/zh-cn/devices/audio/latency_design.html
@@ -0,0 +1,186 @@
+<html devsite><head>
+ <title>专为缩短延迟时间进行设计</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>
+Android 4.1 版本更改了内部框架,缩短了音频输出路径的<a href="http://en.wikipedia.org/wiki/Low_latency">延迟时间</a>。该版本还对公开客户端 API 或 HAL API 进行了细微更改。本文档介绍了初始设计,此设计也在不断发展。充分了解这一设计应该有助于设备的原始设备制造商 (OEM) 和 SoC 供应商在其特定设备和芯片组上正确地实施此设计。本文不适用于应用开发者。
+</p>
+
+<h2 id="trackCreation">创建音轨</h2>
+
+<p>
+客户端可以选择性地在 AudioTrack C++ 构造函数或 <code>AudioTrack::set()</code> 的 <code>audio_output_flags_t</code> 参数中设置位 <code>AUDIO_OUTPUT_FLAG_FAST</code>。目前能执行此操作的客户端仅包括:
+</p>
+
+<ul>
+<li>基于 <a href="https://developer.android.com/ndk/guides/audio/opensl/index.html">OpenSL ES</a> 或 <a href="https://developer.android.com/ndk/guides/audio/aaudio/aaudio.html">AAudio</a> 的 Android 原生音频</li>
+<li><a href="http://developer.android.com/reference/android/media/SoundPool.html">android.media.SoundPool</a></li>
+<li><a href="http://developer.android.com/reference/android/media/ToneGenerator.html">android.media.ToneGenerator</a></li>
+</ul>
+
+<p>
+AudioTrack C++ 实现会审核 <code>AUDIO_OUTPUT_FLAG_FAST</code> 请求,并且可以选择性地拒绝客户端级别的请求。如果它决定传递该请求,则会使用 <code>IAudioTrack</code> 工厂方法 <code>IAudioFlinger::createTrack()</code> 的 <code>track_flags_t</code> 参数的 <code>TRACK_FAST</code> 位来实现。
+</p>
+
+<p>
+AudioFlinger 音频服务器会审核 <code>TRACK_FAST</code> 请求,并且可以选择性地拒绝服务器级别的请求。它通过共享存储器控制块的位 <code>CBLK_FAST</code> 通知客户端是否已接受该请求。
+</p>
+
+<p>
+影响决定的因素包括:
+</p>
+
+<ul>
+<li>此输出的快速混音器线程分布(见下文)</li>
+<li>音轨采样率</li>
+<li>为音轨执行回调处理程序的客户端线程分布</li>
+<li>音轨缓冲区的大小</li>
+<li>可用的快速音轨槽(见下文)</li>
+</ul>
+
+<p>
+如果客户端的请求被接受,则称为“快速音轨”,否则称为“常规音轨”。
+</p>
+
+<h2 id="mixerThreads">混音器线程</h2>
+
+<p>
+AudioFlinger 在创建常规混音器线程时,会决定是否也要创建快速混音器线程。常规混音器和快速混音器都不与特定的音轨相关联,而是与一组音轨相关联。一直都会存在一个常规混音器线程。快速混音器线程(如果存在)的运行优先级低于常规混音器线程并在其控制下运行。
+</p>
+
+<h3 id="fastMixer">快速混音器</h3>
+
+<h4>功能</h4>
+
+<p>
+快速混音器线程具备以下功能:
+</p>
+
+<ul>
+<li>对常规混音器的子混音和最多 7 个客户端快速音轨进行混音</li>
+<li>每条音轨的衰减</li>
+</ul>
+
+<p>
+删减的功能:
+</p>
+
+<ul>
+<li>每条音轨的采样率转换</li>
+<li>每条音轨的效果</li>
+<li>每次混音的效果</li>
+</ul>
+
+<h4>周期</h4>
+
+<p>
+快速混音器按周期运行,推荐周期为 2 到 3 毫秒 (ms),但如果有调度稳定性需求,则可采用略久的 5 毫秒为周期。之所以选择这个数字,是为了确保在考虑完整的缓冲区流水线的情况下,总延迟时间大约为 10 毫秒。可以采用更小的值,但这样可能导致功耗增加以及出现异常,具体取决于 CPU 调度的可预测性。也可以采用更大的值(最高 20 毫秒),但这样会导致总延迟时间降级,因此应避免采用。
+</p>
+
+<h4>调度</h4>
+
+<p>
+快速混音器以较高的 <code>SCHED_FIFO</code> 优先级运行。它只需要很短的 CPU 时间,但必须经常运行并且具有低调度抖动。
+<a href="http://en.wikipedia.org/wiki/Jitter">抖动</a>表示周期时间的变化:它是实际周期时间与预计周期时间之间的差值。运行太迟会因欠载而导致异常。运行过早则会因从快速音轨中提取数据时音轨尚未提供数据而导致异常。
+</p>
+
+<h4>屏蔽</h4>
+
+<p>
+在理想情况下,除了在 HAL <code>write()</code> 时,快速混音器线程不会屏蔽。快速混音器内的其他屏蔽事件将被视为错误。尤其要避免互斥情况。相反,应使用<a href="http://en.wikipedia.org/wiki/Non-blocking_algorithm">非屏蔽算法</a>(也称为无锁算法)。有关此主题的更多信息,请参阅<a href="avoiding_pi.html">避免优先级反转</a>。
+</p>
+
+<h4>与其他组件的关系</h4>
+
+<p>
+快速混音器几乎不与客户端直接交互。尤其是,快速混音器看不到 Binder 级别的操作,但它确实会访问客户端的共享存储器控制块。
+</p>
+
+<p>
+快速混音器通过状态队列接收来自常规混音器的命令。
+</p>
+
+<p>
+除了提取音轨数据,快速混音器通过常规混音器与客户端进行交互。
+</p>
+
+<p>
+快速混音器的主接收器是音频 HAL。
+</p>
+
+<h3 id="normalMixer">常规混音器</h3>
+
+<h4>功能</h4>
+
+<p>
+已启用所有功能:
+</p>
+
+<ul>
+<li>最多 32 条音轨</li>
+<li>每条音轨的衰减</li>
+<li>每条音轨的采样率转换</li>
+<li>效果处理</li>
+</ul>
+
+<h4>周期</h4>
+
+<p>
+该周期被计算为快速混音器周期(大于等于 20 毫秒)的第一个整数倍数。
+</p>
+
+<h4>调度</h4>
+
+<p>
+常规混音器以较高的 <code>SCHED_OTHER</code> 优先级运行。
+</p>
+
+<h4>屏蔽</h4>
+
+<p>
+允许常规混音器屏蔽,并且通常在各种互斥体以及屏蔽管中发生屏蔽,以写入其子混音。
+</p>
+
+<h4>与其他组件的关系</h4>
+
+<p>
+常规混音器与外界广泛互动,包括 Binder 线程、音频策略管理器、快速混音器线程和客户端音轨。
+</p>
+
+<p>
+常规混音器的接收器是快速混音器音轨 0 的屏蔽管。
+</p>
+
+<h2 id="flags">标记</h2>
+
+<p>
+<code>AUDIO_OUTPUT_FLAG_FAST</code> 位是一个提示。无法保证满足要求。
+</p>
+
+<p>
+<code>AUDIO_OUTPUT_FLAG_FAST</code> 是一个客户端级别的概念。它不会出现在服务器中。
+</p>
+
+<p>
+<code>TRACK_FAST</code> 是一个客户端到服务器的概念。
+</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/audio/midi_test.html b/zh-cn/devices/audio/midi_test.html
new file mode 100644
index 00000000..9fa84daf
--- /dev/null
+++ b/zh-cn/devices/audio/midi_test.html
@@ -0,0 +1,221 @@
+<html devsite><head>
+ <title>MIDI 测试程序</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>以下测试可用于验证 Android 设备上的 MIDI 功能。成功执行这些测试是<a href="midi.html#claim-feature">声明 MIDI 功能</a>的先决条件。
+</p>
+
+<h2 id="preparation">准备</h2>
+
+<h3 id="hardware">硬件</h3>
+
+<p>
+测试需要使用以下硬件。
+</p>
+
+<ul>
+ <li>配备 USB 连接器的 MIDI 键盘,例如 <a href="http://www.akaipro.com/product/lpk25">Akai LPK25</a></li>
+ <li>配备低功耗蓝牙 (BLE) 的 MIDI 键盘,例如 <a href="http://miselu.com/">Miselu C.24</a></li>
+ <li>USB 数据线</li>
+ <li>可将 USB-A 母头转换为 micro-USB 或 USB-C 公头的 USB On-The-Go (OTG) 适配器</li>
+ <li>运行 Android 6.0 Marshmallow 或更高版本的 Android 设备</li>
+ <li>可选:桌面设备</li>
+</ul>
+
+<h3 id="apps">应用</h3>
+
+<p>
+该测试程序涉及多个应用。您可以通过点击下表中的链接获取 GitHub 项目 <a href="https://github.com/philburk/android-midisuite">android-midisuite</a> 应用的源代码或通过 Google Play<em></em>™ 安装应用。
+</p>
+
+<table>
+<tbody><tr>
+ <th>源代码</th>
+ <th>Google Play™</th>
+ <th>说明</th>
+</tr>
+<tr>
+ <td><a href="https://github.com/philburk/android-midisuite/tree/master/MidiScope">MidiScope</a> 或 <a href="https://github.com/googlesamples/android-MidiScope">MidiScope</a></td>
+ <td><a href="https://play.google.com/store/apps/details?id=com.mobileer.example.midiscope">MIDI Scope</a></td>
+ <td>在屏幕上显示 MIDI 信息</td>
+</tr>
+<tr>
+ <td><a href="https://github.com/philburk/android-midisuite/tree/master/MidiKeyboard">MidiKeyboard</a></td>
+ <td><a href="https://play.google.com/store/apps/details?id=com.mobileer.midikeyboard">MIDI Keyboard</a></td>
+ <td>在按屏幕上的音乐键盘时发送 MIDI 信息</td>
+</tr>
+<tr>
+ <td><a href="https://github.com/philburk/android-midisuite/tree/master/MidiSynthExample">MidiSynthExample</a> 或<br /><a href="https://github.com/googlesamples/android-MidiSynth">MidiSynth</a></td>
+ <td><a href="https://play.google.com/store/apps/details?id=com.mobileer.midisynthexample">MIDI Synth Ex</a></td>
+ <td>采用锯齿波振荡器的简易 MIDI 合成器</td>
+</tr>
+<tr>
+ <td><a href="https://github.com/philburk/android-midisuite/tree/master/MidiBtlePairing">MidiBtlePairing</a></td>
+ <td><a href="https://play.google.com/store/apps/details?id=com.mobileer.example.midibtlepairing">MIDI BLE Connect</a></td>
+ <td>将 Android 设备与 BLE 外围设备配对使用</td>
+</tr>
+<tr>
+ <td><a href="https://github.com/philburk/android-midisuite/tree/master/MidiTools">MidiTools</a></td>
+ <td></td>
+ <td>上述应用的库依赖项</td>
+</tr>
+</tbody></table>
+
+<p>
+如果您选择从源代码开始编译,而不是通过 Google Play<em></em>™ 进行安装,请先使用附带的 <em></em>Android.mk 编译应用。然后使用 <a href="http://developer.android.com/tools/help/adb.html">Android 调试桥</a> (ADB) 安装该应用。例如,要安装 <em></em>MidiScope 应用,请按以下步骤操作:</p>
+
+<ol>
+ <li>使用安装了 ADB 的工作站。</li>
+ <li>使用 USB 数据线将工作站连接到 Android 设备。</li>
+ <li>您可能需要在 Android 设备上允许 USB 连接;请参阅 <a href="midi.html#usb-peripheral">USB 外设模式</a>。</li>
+ <li>在工作站上,输入以下内容:</li>
+</ol>
+
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">cd <var>THIS_FOLDER</var></code>
+<code class="devsite-terminal">adb install -r MidiScope.apk</code>
+</pre>
+
+<h2 id="virtual_synth_tests">虚拟合成器测试</h2>
+
+<p>请注意,MIDI 输入端口只能建立一个连接。因此,如果另一个应用已经连接到输入端口,则该端口将不可用。如果您无法连接到输入端口,请尝试关闭其他应用。</p>
+
+<p>所需的硬件:受测 Android 设备 </p>
+
+<h3 id="simple_connection">简易连接</h3>
+
+<p>所需的应用:MidiKeyboard、MidiSynthExample<em></em><em></em></p>
+
+<p>这部分是测试设备枚举、虚拟设备、端口连接和消息发送等功能。</p>
+
+<ol>
+ <li>将 Android 设备上的音量调节至大约一半的位置。</li>
+ <li>将手机切换为横屏模式。</li>
+ <li>启动 MidiKeyboard 应用。<em></em></li>
+ <li>从下拉菜单中选择 <strong>SynthExample</strong>。</li>
+ <li>弹奏琴键。您应该能听到 SynthExample 应用中播放的音符。<em></em></li>
+ <li>按<strong>返回</strong>按钮退出应用后,端口将关闭。</li>
+</ol>
+
+<h2 id="host_mode">USB 测试:主机模式</h2>
+
+<p>所需的硬件:USB MIDI 键盘、USB 数据线、OTG 适配器</p>
+
+<p>这些测试需要重复进行几次。我们发现,如果将设备插入和拔下数次,某些原型设备上会出现 USB 协议栈严重崩溃。</p>
+
+<h3 id="keyboard_already_plugged_in">键盘已插入</h3>
+
+<p>所需的应用:MidiSynthExample 或 MidiScope<em></em><em></em></p>
+
+<p>这部分是在主机模式下测试 USB MIDI。</p>
+
+<ol>
+ <li>将 Android 设备上的音量调节至大约一半的位置。</li>
+ <li>使用 OTG 适配器连接 USB 键盘。</li>
+ <li>启动 SynthExample 应用或 MidiScope 应用。<em></em><em></em></li>
+ <li>从菜单中选择 USB 键盘。将显示键盘的品牌信息。</li>
+ <li>在键盘上弹奏音符。如果运行 SynthExample,您应该能在手机上听到播放的音符。<em></em>如果运行 MidiScope,屏幕上将显示 NoteOn 和 NoteOff 消息。<em></em><em></em><em></em></li>
+ <li>拔下键盘。<em></em><em></em>“合成器的发送器”菜单应该会显示“- - - - -”。</li>
+ <li>按<strong>返回</strong>按钮退出应用。</li>
+</ol>
+
+<h3 id="hot_plug_usb_keyboard">热插拔 USB 键盘</h3>
+
+<p>所需的应用:MidiSynthExample 或 MidiScope<em></em><em></em></p>
+
+<p>这部分是在主机模式下测试 USB MIDI。</p>
+
+<ol>
+ <li>将 Android 设备上的音量调节至大约一半的位置。</li>
+ <li>确保没有插入任何 USB MIDI 键盘。</li>
+ <li>启动 SynthExample 应用。<em></em></li>
+ <li>在中间位置,找到“合成器的发送器”旁边的菜单。<em></em>应该不会列出 USB 键盘。</li>
+ <li>使用 OTG 适配器连接 USB 键盘。</li>
+ <li>在中间位置,选择“合成器的发送器”旁边的 USB 键盘。<em></em>将显示键盘的品牌信息。</li>
+ <li>在键盘上弹奏音符。您应该能在手机上听到播放的音符。</li>
+ <li><em></em>在中间位置,选择“合成器的发送器”旁边的 <strong>- - - - -</strong>。</li>
+ <li>在键盘上弹奏音符。您应该不会听到任何声音。</li>
+ <li>在中间位置,选择“合成器的发送器”旁边的 USB 键盘。<em></em>将显示键盘的品牌信息。</li>
+ <li>在键盘上弹奏音符。您应该能在手机上听到播放的音符。</li>
+ <li>拔下合成器。<em></em><em></em>“合成器的发送器”菜单应该会显示“- - - - -”。</li>
+ <li>按<strong>返回</strong>按钮退出应用。</li>
+</ol>
+
+<h2 id="peripheral_mode">USB 测试:外围设备模式</h2>
+
+<p>所需的硬件:USB 数据线、OTG 适配器</p>
+
+<h3 id="android_to_android">Android 设备到 Android 设备</h3>
+
+<p>所需的应用:受测 Android 设备上的 MidiKeyboard,另一台 Android 设备上的 MidiScope。<em></em><em></em></p>
+
+<p>将 Android 设备用作另一台 Android 设备的外围设备控制器。为了帮助测试该模式,请使用另一台在主机模式下运行的 Android 设备。请注意,您可以修改测试,以便与运行数字音频工作站 (DAW) 软件(如 workGarageBand)的台式机配合使用。</p>
+
+<ol>
+ <li>将 USB 数据线连接到受测 Android 设备(Android 设备 <strong>A</strong>)。</li>
+ <li>使用 OTG 适配器将数据线的另一端连接到另一台 Android 设备 <strong>B</strong>(在主机模式下运行)。</li>
+ <li>在 Android 设备 A 上执行以下操作:
+ <ol>
+ <li>用手指从屏幕顶部向下滑动。</li>
+ <li>选择<strong>正在通过 USB 充电</strong>图标。</li>
+ <li>选择 <strong>MIDI</strong>。</li>
+ <li>启动 MidiKeyboard 应用。<em></em></li>
+ <li>从顶部的“按键接收器”菜单中选择 <strong>Android USB 外设端口</strong>。<em></em></li>
+ </ol>
+ </li>
+ <li>在 Android 设备 B 上执行以下操作:
+ <ol>
+ <li>启动 MidiScope 应用。<em></em></li>
+ <li>选择另一台 Android 设备作为源设备。</li>
+ </ol>
+ </li>
+ <li>在 Android 设备 A 上执行以下操作:
+ <ol>
+ <li>在键盘上弹奏音符,并在 Android 设备 B 上查找 NoteOn 和 NoteOff。<em></em><em></em></li>
+ </ol>
+ </li>
+ </ol>
+
+<h2 id="bluetooth_le_test">BLE 测试</h2>
+
+<p>所需的硬件:支持 BLE 的 MIDI 键盘</p>
+
+<h3 id="basic_pairing_and_playing">基本配对和弹奏</h3>
+
+<p>所需的应用:MidiBtlePairing、MidiSynthExample<em></em><em></em></p>
+
+<p>这部分是测试通过 BLE 连接到 Android 设备的键盘。</p>
+
+<ol>
+ <li>重新启动 Android 设备。</li>
+ <li>开启 BLE 键盘。<br />
+ (按下靠近背面的按钮,开启 Miselu C.24 键盘,从而使其弹开。在配对模式下,C.24 上的电源按钮闪烁蓝光。)</li>
+ <li>启动 MidiBtlePairing 应用。<em></em>该应用具有 MIDI + BTLE<em></em> 图标。</li>
+ <li>按<strong>蓝牙扫描</strong>按钮。</li>
+ <li>选择所需的 BLE 外围设备。</li>
+ <li>应用应该返回到主页面,您应该会看到列出的外围设备。如果您使用的是 C.24,那么您会发现 C.24 上的指示灯变绿,表明已配对成功。</li>
+ <li>按<strong>主屏幕</strong>按钮(而非<strong>返回</strong>按钮)退出应用。</li>
+ <li>启动 SynthExample 应用。</li>
+ <li>从菜单中选择 BLE 键盘作为发送器。</li>
+ <li>在 BLE 键盘上弹奏琴键后,您能够在 Android 设备上听到播放的音符。</li>
+</ol>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/audio/terminology.html b/zh-cn/devices/audio/terminology.html
index 18640bdb..010bbc7c 100644
--- a/zh-cn/devices/audio/terminology.html
+++ b/zh-cn/devices/audio/terminology.html
@@ -69,7 +69,7 @@
<dt>DSD</dt>
<dd>
-直接数字流。基于<a href="http://en.wikipedia.org/wiki/Pulse-density_modulation">脉冲密度调制</a>的专有音频编码技术。脉冲编码调制 (PCM) 可将波形编码为多位的个体音频样本序列,而 DSD 可以非常高的采样率将波形编码为位数序列(不涉及样本这一概念)。PCM 和 DSD 均代表按独立序列划分的多个声道。由于我们很难将传统的数字信号处理 (DSP) 算法应用于 DSD,因此 DSD 更适用于内容分发,而不是作为内在体现对象进行处理。DSD 可用于<a href="http://en.wikipedia.org/wiki/Super_Audio_CD">超音频 CD (SACD)</a>,以及针对 USB 的 DoP (DSD over PCM)。如需了解详情,请参阅<a href="http://en.wikipedia.org/wiki/Direct_Stream_Digital">直接数字流</a>。
+直接数字流。基于<a href="http://en.wikipedia.org/wiki/Pulse-density_modulation">脉冲密度调制</a>的专有音频编码技术。脉冲编码调制 (PCM) 可将波形编码为多位的个体音频样本序列,而 DSD 可以非常高的采样率将波形编码为位数序列(不涉及样本这一概念)。PCM 和 DSD 均代表按独立序列划分的多个声道。由于我们很难将传统的数字信号处理 (DSP) 算法应用于 DSD,因此 DSD 更适用于内容分发,而不是作为内在体现对象进行处理。DSD 可用于<a href="http://en.wikipedia.org/wiki/Super_Audio_CD">超音频 CD (SACD)</a> 以及针对 USB 的 DoP (DSD over PCM)。如需了解详情,请参阅<a href="http://en.wikipedia.org/wiki/Direct_Stream_Digital">直接数字流</a>。
</dd>
<dt>闪避</dt>
@@ -243,11 +243,21 @@
<a href="https://en.wikipedia.org/wiki/Dongle">外接小配件</a>是一种小工具,特指可直接插入到其他设备上的小工具。
</dd>
-<dt>HDMI</dt>
+<dt>FireWire</dt>
+<dd>
+参阅 IEEE 1394。
+</dd>
+
+<dt>HDMI 端口</dt>
<dd>
高清晰度多媒体接口,用于传输音频和视频数据。移动设备上会使用微型 HDMI(D 型)或 MHL 连接器。
</dd>
+<dt>IEEE 1394</dt>
+<dd>
+<a href="https://en.wikipedia.org/wiki/IEEE_1394">IEEE 1394</a>(也称为 FireWire)是一种用于实时低延迟应用(如音频)的串行总线。
+</dd>
+
<dt>Intel HDA</dt>
<dd>
Intel 高清晰度音频(请不要与泛指的“高清晰度音频”或“高解析度音频”混淆);<em></em><em></em>一种前面板连接器规范。如需了解详情,请参阅 <a href="http://en.wikipedia.org/wiki/Intel_High_Definition_Audio">Intel 高清晰度音频</a>。
@@ -290,7 +300,8 @@ Sony/Philips 数字接口格式,用于未压缩的 PCM 音频的互连。如
<dt>TOSLINK</dt>
<dd>
-<a href="https://en.wikipedia.org/wiki/TOSLINK">TOSLINK</a> 是一种配合 S/PDIF 使用的光纤音频数据线。<em></em></dd>
+<a href="https://en.wikipedia.org/wiki/TOSLINK">TOSLINK</a> 是一种配合 S/PDIF<em></em> 使用的光纤音频数据线。
+</dd>
<dt>USB</dt>
<dd>
@@ -317,7 +328,7 @@ Sony/Philips 数字接口格式,用于未压缩的 PCM 音频的互连。如
</ul>
<p>
-在 <a href="http://www.alsa-project.org/main/index.php/ASoC">ALSA 系统芯片 (ASoC)</a> 中,以上统称为<a href="https://www.kernel.org/doc/Documentation/sound/alsa/soc/DAI.txt">数字音频接口</a> (DAI)。
+在 <a href="http://www.alsa-project.org/main/index.php/ASoC">ALSA 系统芯片 (ASoC)</a> 中,以上统称为<a href="https://www.kernel.org/doc/Documentation/sound/soc/dai.rst">数字音频接口</a> (DAI)。
</p>
<h3 id="signalTerms">音频信号路径</h3>
@@ -415,7 +426,7 @@ Android 专用术语包括仅在 Android 音频框架中使用的术语,以及
<dt>ALSA</dt>
<dd>
-高级 Linux 声音体系。Linux 的音频框架,对其他系统也有影响。要了解通用定义,请参阅 <a href="http://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture">ALSA</a>。在 Android 中,ALSA 指的是内核音频框架和驱动程序,而不是用户模式 API。另请参阅“tinyalsa”。<em></em>
+高级 Linux 声音体系。Linux 的音频框架,对其他系统也有影响。要了解通用定义,请参阅 <a href="http://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture">ALSA</a>。在 Android 中,ALSA 指的是内核音频框架和驱动程序,而不是用户模式 API。另请参阅“tinyalsa”<em></em>。
</dd>
<dt>音频设备</dt>
@@ -435,7 +446,7 @@ Android 声音服务器实现用例。AudioFlinger 在 mediaserver 进程中运
<dt>音频焦点</dt>
<dd>
-跨多个独立应用管理音频互动的 API 集。如需了解详情,请参阅<a href="http://developer.android.com/training/managing-audio/audio-focus.html">管理音频焦点</a>以及与焦点相关的方法和 <a href="http://developer.android.com/reference/android/media/AudioManager.html">android.media.AudioManager</a> 的常量。
+跨多个独立应用管理音频互动的 API 集。如需了解详情,请参阅<a href="http://developer.android.com/training/managing-audio/audio-focus.html">管理音频焦点</a>以及与焦点相关的方法和 <a href="http://developer.android.com/reference/android/media/AudioManager.html">android.media.AudioManager</a>。
</dd>
<dt>AudioMixer</dt>
@@ -555,7 +566,7 @@ AudioFlinger 中的模块,负责同步线程之间的状态。NBAIO 用于传
<dt>音频流类型</dt>
<dd>
-表示音频输出使用情形的枚举。音频政策的实现使用音频流类型以及其他参数来确定音量和路由决策。要查看音频流类型的列表,请参阅 <a href="http://developer.android.com/reference/android/media/AudioManager.html">android.media.AudioManager</a>。
+表示音频输出使用情形的枚举。音频政策的实现使用音频流类型以及其他参数来确定音量和路由决策。要查看音频流类型的列表,请参阅 <a href="http://developer.android.com/reference/android/media/AudioManager.html">android.mediaAudioManager</a>。
</dd>
<dt>tee sink</dt>
@@ -570,7 +581,7 @@ ALSA 内核之上具有 BSD 许可的小型用户模式 API。建议用于实现
<dt>ToneGenerator</dt>
<dd>
-比 AudioTrack 级别更高的客户端 API,用于播放双音多频 (DTMF) 信号。如需了解详情,请参阅<a href="http://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling">双音多频信号</a>和 <a href="http://developer.android.com/reference/android/media/ToneGenerator.html">android.media.ToneGenerator</a> 中的 API 定义。
+比 AudioTrack 级别更高的客户端 API,用于播放双音多频 (DTMF) 信号。如需了解详情,请参阅<a href="http://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling">双音多频信号</a>和 <a href="http://developer.android.com/reference/android/media/ToneGenerator.html">android.mediaToneGenerator</a> 中的 API 定义。
</dd>
<dt>音轨</dt>
diff --git a/zh-cn/devices/audio/tv.html b/zh-cn/devices/audio/tv.html
new file mode 100644
index 00000000..225f7ec1
--- /dev/null
+++ b/zh-cn/devices/audio/tv.html
@@ -0,0 +1,283 @@
+<html devsite><head>
+ <title>TV 音频</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>TV 输入框架 (TIF) 管理器与音频路由 API 配合使用,可支持灵活的音频路径更改。当系统芯片 (SoC) 实现 TV 硬件抽象层 (HAL) 时,每个 TV 输入源(HDMI IN、调谐器等)均提供 <code>TvInputHardwareInfo</code>,用于为音频类型和地址指定 AudioPort 信息。</p>
+
+<ul>
+<li><b>物理</b>音频输入/输出设备具有相应的 AudioPort。</li>
+<li><b>软件</b>音频输出/输入流表示为 AudioMixPort(AudioPort 的子类)。</li>
+</ul>
+
+<p>然后,TIF 将 AudioPort 信息用于音频路由 API。</p>
+
+<p><img src="images/ape_audio_tv_tif.png" alt="Android TV 输入框架 (TIF)"/></p>
+<p class="img-caption"><strong>图 1.</strong> TV 输入框架 (TIF)</p>
+
+<h2 id="requirements">要求</h2>
+
+<p>SoC 必须通过以下音频路由 API 支持功能来实现音频 HAL:</p>
+
+<table>
+<tbody>
+<tr>
+<th>音频端口</th>
+<td>
+<ul>
+<li>TV 音频输入端口具有相应的音频源端口实现。</li>
+<li>TV 音频输出端口具有相应的音频接收器端口实现。</li>
+<li>可在任意 TV 输入音频端口和任意 TV 输出音频端口之间创建音频通路。</li>
+</ul>
+</td>
+</tr>
+<tr>
+<th>默认输入</th>
+<td>AudioRecord(使用默认输入源创建)必须在 Android TV 上采集“虚拟 Null 输入源”,以获取 AUDIO_DEVICE_IN_DEFAULT。<i></i></td>
+</tr>
+<tr>
+<th>设备环回</th>
+<td>需要支持 AUDIO_DEVICE_IN_LOOPBACK 输入,这是所有 TV 输出(11 Khz、16bit 单声道或 48 Khz、16bit 单声道)的所有音频输出的完整组合。仅用于音频采集。
+</td>
+</tr>
+</tbody>
+</table>
+
+<h2 id="audioDevices">TV 音频设备</h2>
+
+<p>Android 支持使用以下设备处理 TV 音频输入/输出。</p>
+
+<h4><code>system/media/audio/include/system/audio.h</code></h4>
+
+<p class="note"><strong>注意</strong>:在 Android 5.1 及更早版本中,此文件的路径为:<code>system/core/include/system/audio.h</code></p>
+
+<pre class="devsite-click-to-copy">
+/* output devices */
+AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400,
+AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL,
+/* HDMI Audio Return Channel */
+AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000,
+/* S/PDIF out */
+AUDIO_DEVICE_OUT_SPDIF = 0x80000,
+/* input devices */
+AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
+AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL,
+/* TV tuner input */
+AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000,
+/* S/PDIF in */
+AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000,
+AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000,
+</pre>
+
+<h2 id="halExtension">音频 HAL 扩展</h2>
+
+<p>音频路由 API 的音频 HAL 扩展定义如下:</p>
+
+<h4><code>system/media/audio/include/system/audio.h</code></h4>
+
+<p class="note"><strong>注意</strong>:在 Android 5.1 及更早版本中,此文件的路径为:<code>system/core/include/system/audio.h</code></p>
+
+<pre class="devsite-click-to-copy">
+/* audio port configuration structure used to specify a particular configuration of an audio port */
+struct audio_port_config {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int config_mask; /* e.g AUDIO_PORT_CONFIG_ALL */
+ unsigned int sample_rate; /* sampling rate in Hz */
+ audio_channel_mask_t channel_mask; /* channel mask if applicable */
+ audio_format_t format; /* format if applicable */
+ struct audio_gain_config gain; /* gain to apply if applicable */
+ union {
+ struct audio_port_config_device_ext device; /* device specific info */
+ struct audio_port_config_mix_ext mix; /* mix specific info */
+ struct audio_port_config_session_ext session; /* session specific info */
+ } ext;
+};
+struct audio_port {
+ audio_port_handle_t id; /* port unique ID */
+ audio_port_role_t role; /* sink or source */
+ audio_port_type_t type; /* device, mix ... */
+ unsigned int num_sample_rates; /* number of sampling rates in following array */
+ unsigned int sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+ unsigned int num_channel_masks; /* number of channel masks in following array */
+ audio_channel_mask_t channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+ unsigned int num_formats; /* number of formats in following array */
+ audio_format_t formats[AUDIO_PORT_MAX_FORMATS];
+ unsigned int num_gains; /* number of gains in following array */
+ struct audio_gain gains[AUDIO_PORT_MAX_GAINS];
+ struct audio_port_config active_config; /* current audio port configuration */
+ union {
+ struct audio_port_device_ext device;
+ struct audio_port_mix_ext mix;
+ struct audio_port_session_ext session;
+ } ext;
+};
+</pre>
+
+<h4><code>hardware/libhardware/include/hardware/audio.h</code></h4>
+
+<pre class="devsite-click-to-copy">
+struct audio_hw_device {
+ :
+ /**
+ * Routing control
+ */
+
+ /* Creates an audio patch between several source and sink ports.
+ * The handle is allocated by the HAL and should be unique for this
+ * audio HAL module. */
+ int (*create_audio_patch)(struct audio_hw_device *dev,
+ unsigned int num_sources,
+ const struct audio_port_config *sources,
+ unsigned int num_sinks,
+ const struct audio_port_config *sinks,
+ audio_patch_handle_t *handle);
+
+ /* Release an audio patch */
+ int (*release_audio_patch)(struct audio_hw_device *dev,
+ audio_patch_handle_t handle);
+
+ /* Fills the list of supported attributes for a given audio port.
+ * As input, "port" contains the information (type, role, address etc...)
+ * needed by the HAL to identify the port.
+ * As output, "port" contains possible attributes (sampling rates, formats,
+ * channel masks, gain controllers...) for this port.
+ */
+ int (*get_audio_port)(struct audio_hw_device *dev,
+ struct audio_port *port);
+
+ /* Set audio port configuration */
+ int (*set_audio_port_config)(struct audio_hw_device *dev,
+ const struct audio_port_config *config);
+</pre>
+
+<h2 id="testing">测试 DEVICE_IN_LOOPBACK</h2>
+
+<p>要测试用于 TV 监控的 DEVICE_IN_LOOPBACK,请使用以下测试代码。运行测试后,采集到的音频将保存到 <code>/sdcard/record_loopback.raw</code> 中,您可以使用 <code><a href="https://en.wikipedia.org/wiki/FFmpeg">FFmpeg</a></code> 来收听。</p>
+
+<pre class="devsite-click-to-copy">
+&lt;uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" /&gt;
+&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
+
+ AudioRecord mRecorder;
+ Handler mHandler = new Handler();
+ int mMinBufferSize = AudioRecord.getMinBufferSize(RECORD_SAMPLING_RATE,
+ AudioFormat.CHANNEL_IN_MONO,
+ AudioFormat.ENCODING_PCM_16BIT);;
+ static final int RECORD_SAMPLING_RATE = 48000;
+ public void doCapture() {
+ mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, RECORD_SAMPLING_RATE,
+ AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mMinBufferSize * 10);
+ AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ ArrayList&lt;AudioPort&gt; audioPorts = new ArrayList&lt;AudioPort&gt;();
+ am.listAudioPorts(audioPorts);
+ AudioPortConfig srcPortConfig = null;
+ AudioPortConfig sinkPortConfig = null;
+ for (AudioPort audioPort : audioPorts) {
+ if (srcPortConfig == null
+ &amp;&amp; audioPort.role() == AudioPort.ROLE_SOURCE
+ &amp;&amp; audioPort instanceof AudioDevicePort) {
+ AudioDevicePort audioDevicePort = (AudioDevicePort) audioPort;
+ if (audioDevicePort.type() == AudioManager.DEVICE_IN_LOOPBACK) {
+ srcPortConfig = audioPort.buildConfig(48000, AudioFormat.CHANNEL_IN_DEFAULT,
+ AudioFormat.ENCODING_DEFAULT, null);
+ Log.d(LOG_TAG, "Found loopback audio source port : " + audioPort);
+ }
+ }
+ else if (sinkPortConfig == null
+ &amp;&amp; audioPort.role() == AudioPort.ROLE_SINK
+ &amp;&amp; audioPort instanceof AudioMixPort) {
+ sinkPortConfig = audioPort.buildConfig(48000, AudioFormat.CHANNEL_OUT_DEFAULT,
+ AudioFormat.ENCODING_DEFAULT, null);
+ Log.d(LOG_TAG, "Found recorder audio mix port : " + audioPort);
+ }
+ }
+ if (srcPortConfig != null &amp;&amp; sinkPortConfig != null) {
+ AudioPatch[] patches = new AudioPatch[] { null };
+ int status = am.createAudioPatch(
+ patches,
+ new AudioPortConfig[] { srcPortConfig },
+ new AudioPortConfig[] { sinkPortConfig });
+ Log.d(LOG_TAG, "Result of createAudioPatch(): " + status);
+ }
+ mRecorder.startRecording();
+ processAudioData();
+ mRecorder.stop();
+ mRecorder.release();
+ }
+ private void processAudioData() {
+ OutputStream rawFileStream = null;
+ byte data[] = new byte[mMinBufferSize];
+ try {
+ rawFileStream = new BufferedOutputStream(
+ new FileOutputStream(new File("/sdcard/record_loopback.raw")));
+ } catch (FileNotFoundException e) {
+ Log.d(LOG_TAG, "Can't open file.", e);
+ }
+ long startTimeMs = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTimeMs &lt; 5000) {
+ int nbytes = mRecorder.read(data, 0, mMinBufferSize);
+ if (nbytes &lt;= 0) {
+ continue;
+ }
+ try {
+ rawFileStream.write(data);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Error on writing raw file.", e);
+ }
+ }
+ try {
+ rawFileStream.close();
+ } catch (IOException e) {
+ }
+ Log.d(LOG_TAG, "Exit audio recording.");
+ }
+</pre>
+
+<p>在 <code>/sdcard/record_loopback.raw</code> 中找到采集到的音频文件,并使用 <code>FFmpeg</code> 来收听:</p>
+
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb pull /sdcard/record_loopback.raw</code>
+<code class="devsite-terminal">ffmpeg -f s16le -ar 48k -ac 1 -i record_loopback.raw record_loopback.wav</code>
+<code class="devsite-terminal">ffplay record_loopback.wav</code>
+</pre>
+
+<h2 id="useCases">用例</h2>
+
+<p>本节包括 TV 音频的常见用例。</p>
+
+<h3 id="tvSpeaker">带有扬声器输出的 TV 调谐器</h3>
+
+<p>当 TV 调谐器进入活动状态时,音频路由 API 会在调谐器和默认输出(例如扬声器)之间创建一个音频通路。调谐器输出无需解码,但最终音频输出会与软件 output_stream 混合。</p>
+
+<img src="images/ape_audio_tv_tuner.png" alt="Android TV 调谐器音频通路"/>
+<p class="img-caption">
+<strong>图 2.</strong> 带有扬声器输出的 TV 调谐器的音频通路。</p>
+
+<h3 id="hdmiOut">直播 TV 期间的 HDMI OUT</h3>
+
+<p>用户正在观看直播 TV,随后切换到 HDMI 音频输出 (Intent.ACTION_HDMI_AUDIO_PLUG)。所有 output_stream 的输出设备均更改到 HDMI_OUT 端口,而 TIF 管理器将现有调谐器音频通路的接收器端口更改为 HDMI_OUT 端口。</p>
+
+<img src="images/ape_audio_tv_hdmi_tuner.png" alt="Android TV HDMI-OUT 音频通路"/>
+<p class="img-caption">
+<strong>图 3.</strong> 来自直播 TV 的 HDMI OUT 音频通路。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/automotive/index.html b/zh-cn/devices/automotive/index.html
new file mode 100644
index 00000000..7d550cf0
--- /dev/null
+++ b/zh-cn/devices/automotive/index.html
@@ -0,0 +1,62 @@
+<html devsite><head>
+ <title>汽车</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<img style="float: right; margin: 0px 15px 15px 15px;" src="../images/ape_fwk_hal_vehicle.png" alt="Android 车载 HAL 图标"/>
+
+<p>借助各种总线拓扑,很多汽车子系统都可以实现互连以及与车载信息娱乐 (IVI) 系统的连接。根据制造商不同,所提供的确切总线类型和协议也有很大差异(甚至同一品牌的不同车型之间也是如此);示例包括控制器区域网络 (CAN) 总线、本地互联网络 (LIN) 总线、媒体导向系统传输 (MOST) 总线以及汽车级以太网和 TCP/IP 网络(例如 BroadR-Reach)。
+</p>
+<p>Android Automotive 的硬件抽象层 (HAL) 为 Android 框架提供了一致的接口(无需考虑物理传输层)。此车载 HAL 是用于开发 Android Automotive 实现的接口。</p>
+<p>系统集成人员可以将特定于功能的平台 HAL 接口(如 HVAC)与特定于技术的网络接口(如 CAN 总线)连接,以实现车载 HAL 模块。典型的实现可能包括运行专有实时操作系统 (RTOS) 的专用微控制器单元(MCU,用于 CAN 总线访问或类似操作),该微控制器单元可通过串行链路连接到运行 Android Automotive 的 CPU。除了专用的 MCU,您还可以将总线访问作为虚拟 CPU 来实现。只要实现符合车载 HAL 的接口要求,每个合作伙伴都可以选择适合硬件的架构。</p>
+
+<h2 id="arch">架构</h2>
+<p>车载 HAL 是汽车与车辆网络服务之间的接口定义:</p>
+
+<img src="../images/vehicle_hal_arch.png" alt="Android 车载 HAL 架构"/>
+<p class="img-caption"><strong>图 1</strong>. 车载 HAL 与 Android Automotive 架构</p>
+
+<ul>
+<li><strong>Car API</strong>:包含 CarHvacManager、CarSensorManager 和 CarCameraManager 等 API。如需详细了解受支持的 API,请参阅 <code>/platform/packages/services/Car/car-lib</code>。</li>
+<li><strong>CarService</strong>:位于 <code>/platform/packages/services/Car/</code>。</li>
+<li><strong>VehicleNetworkService</strong>:通过内置安全机制来控制车载 HAL。仅限系统组件使用(第三方应用等非系统组件应使用汽车 API)。原始设备制造商 (OEM) 可以通过 <code>vns_policy.xml</code> 和 <code>vendor_vns_policy.xml</code> 控制访问权限。位于 <code>/platform/packages/services/Car/vehicle_network_service/</code>;要查看用于访问车辆网络的库,请参阅 <code>/platform/packages/services/Car/libvehiclenetwork/</code>。</li>
+<li><strong>车载 HAL</strong>:定义 OEM 可以实现的车辆属性的接口。包含属性元数据(例如,车辆属性是否为 int 以及允许使用哪些更改模式)。位于 <code>hardware/libhardware/include/hardware/vehicle.h</code>。要了解基本参考实现的相关信息,请参阅 <code>hardware/libhardware/modules/vehicle/</code>。</li>
+</ul>
+<p>有关更多详情,请参阅<a href="/devices/automotive/properties.html">车辆属性</a>。
+
+</p><h2 id="security">安全性</h2>
+<p>车载 HAL 支持 3 个级别的数据访问安全性:</p>
+<ul>
+<li>仅限系统(由 <code>vns_policy.xml</code> 控制)</li>
+<li>允许拥有权限的应用进行访问(通过汽车服务)</li>
+<li>无需任何权限即可访问(通过汽车服务)</li>
+</ul>
+<p>仅允许部分系统组件直接访问车辆属性,而车辆网络服务是把关程序。大多数应用都需要通过汽车服务的额外把关(例如,只有系统应用可以控制 HVAC,因为系统权限只能授予系统应用)。</p>
+
+<h2 id="validation">验证</h2>
+<p>AOSP 包含开发过程中使用的以下测试资源:</p>
+<ul>
+<li><code>hardware/libhardware/tests/vehicle/vehicle-hal-tool.c</code><br />
+加载车载 HAL 并执行简单操作的命令行原生工具。它有助于系统在开发的早期阶段启动并运行。</li>
+<li><code>packages/services/Car/tests/carservice_test/</code><br />包含使用模拟车载 HAL 属性进行的汽车服务测试。每个属性的预期行为都会在测试中实现,这是了解预期行为的绝佳起点。</li>
+<li><code>hardware/libhardware/modules/vehicle/</code><br />基本参考实现。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/automotive/properties.html b/zh-cn/devices/automotive/properties.html
new file mode 100644
index 00000000..7480ba8d
--- /dev/null
+++ b/zh-cn/devices/automotive/properties.html
@@ -0,0 +1,162 @@
+<html devsite><head>
+ <title>车辆属性</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>车载 HAL 接口会定义原始设备制造商 (OEM) 可以实现的属性,并会包含属性元数据(例如,属性是否为 int 以及允许使用哪些更改模式)。车载 HAL 接口是以对属性(特定功能的抽象表示)的访问(读取、写入、订阅)为基础。</p>
+
+<h2 id="interfaces">HAL 接口</h2>
+<p>车载 HAL 使用以下接口:</p>
+<ul>
+<li><code>vehicle_prop_config_t const *(*list_properties)(..., int*
+num_properties)</code>
+<br />列出车载 HAL 所支持的所有属性的配置。车辆网络服务只会使用受支持的属性。
+</li>
+<li><code>(*get)(..., vehicle_prop_value_t *data)</code>
+<br />读取属性的当前值。对于区域属性,每个区域都可能具有不同的值。</li>
+<li><code>(*set)(..., const vehicle_prop_value_t *data)</code>
+<br />为属性写入相应值。写入的结果是按属性进行定义。</li>
+<li><code>(*subscribe)(..., int32_t prop, float sample_rate, int32_t
+zones)</code>
+<ul>
+<li>开始监视属性值的变化。对于区域属性,订阅适用于请求的区域。“zones = 0”用于请求所有受支持的区域。
+</li>
+<li>车载 HAL 应该在属性值发生变化时(即 on-change 类型)或按一定间隔(即 continuous 类型)调用单独的回调。</li>
+</ul></li>
+<li><code>(*release_memory_from_get)(struct vehicle_hw_device* device,
+vehicle_prop_value_t *data)</code>
+<br />释放从 get 调用分配的内存。</li>
+</ul>
+
+<p>车载 HAL 使用以下回调接口:</p>
+<ul>
+<li><code>(*vehicle_event_callback_fn)(const vehicle_prop_value_t
+*event_data)</code>
+<br />通知车辆属性值的变化。应只针对已订阅属性执行。</li>
+<li><code>(*vehicle_error_callback_fn)(int32_t error_code, int32_t property,
+int32_t operation)</code>
+<br />返回全局车载 HAL 级错误或每个属性的错误。全局错误会导致 HAL 重新启动,这可能导致包括应用在内的其他组件重新启动。</li>
+</ul>
+
+<h2 id="properties">车辆属性</h2>
+<p>属性可以是只读、只写(用于将信息传递到车载 HAL 一级),也可以是能够读取和写入(对大多数属性而言支持读写是可选的)。每个属性都由 int32 键唯一标识,且具有预定义的类型 (<code>value_type</code>):</p>
+
+<ul>
+<li><code>INT32</code>(和数组)、<code>INT64</code>、<code>BOOLEAN</code>、<code>FLOAT</code>(和数组)、字符串、字节。</li>
+<li>区域类型除了值之外还有区域。</li>
+</ul>
+
+<h2 id-="zone_type">区域类型</h2>
+<p>车载 HAL 定义了 3 种区域类型:</p>
+<ul>
+<li><code>vehicle_zone</code>
+<br />基于排的区域。</li>
+<li><code>vehicle_seat</code>
+<br />基于座位的区域。</li>
+<li><code>vehicle_window</code>
+<br />基于窗户的区域。</li>
+</ul>
+<p>每个区域属性都应使用预定义的区域类型。如有必要,您可以为每个属性都使用自定义区域类型(有关详情,请参阅<a href="#prop_custom">处理自定义属性</a>一节)。</p>
+
+<h2 id="prop_config">配置属性</h2>
+<p>请使用 <code>vehicle_prop_config_t</code> 为每个属性提供配置信息。具体信息包括:</p>
+<ul>
+<li><code>access</code>(r、w、rw)</li>
+<li><code>change_mode</code>(表示监视属性的方式:on-change 模式还是 continuous 模式)</li>
+<li><code>min_value</code>(int32、float、int64)、<code>max_value</code>(int32、float、int64)</li>
+<li><code>min_sample_rate</code>、<code>max_sample_rate</code></li>
+<li><code>permission_model</code></li>
+<li><code>prop</code>(属性 ID、int)</li>
+<li><code>value_type</code></li>
+<li><code>zone_flags</code>(将受支持的区域表示为位标记)</li>
+</ul>
+<p>此外,某些属性具有表示功能的具体配置标记。</p>
+
+<h2 id="zone_prop">处理区域属性</h2>
+<p>区域属性相当于多个属性的集合,其中每个子属性都可由指定的区域值访问。</p>
+<ul>
+<li>区域属性的 <code>get</code> 调用请求中始终包含区域,因此,只应返回所请求区域的当前值。</li>
+<li>区域属性的 <code>set</code> 调用请求中始终包含区域,因此,只应更改所请求的区域。</li>
+<li><code>subscribe</code> 调用包含所有已订阅区域的标记。不应报告来自未订阅区域的事件。</li>
+</ul>
+
+<h3 id="get">get 调用</h3>
+<p>在初始化期间,由于尚未收到匹配的车辆网络消息,因此属性的值可能不可用。在这种情况下,<code>get</code> 调用应该返回 <code>-EAGAIN</code>。某些属性(如 HVAC)具有单独的电源开/关属性。关机时这种属性的 <code>get</code> 调用应返回特殊值 <code>(VEHICLE_INT_OUT_OF_RANGE_OFF/VEHICLE_FLOAT_OUT_OF_RANGE_OFF)</code>,而不是返回错误。</p>
+<p>此外,某些属性(如 HVAC 温度)可以用某个值来表示其处于最大功率模式,而不是特定的温度值。在这种情况下,请使用特殊值表示这种状态。</p>
+<ul>
+<li>VEHICLE_INT_OUT_OF_RANGE_MAX/MIN</li>
+<li>VEHICLE_FLOAT_OUT_OF_RANGE_MAX/MIN</li>
+</ul>
+
+<p>示例:获取 HVAC 温度</p>
+<img src="../images/vehicle_hvac_get.png" alt="车载 HAL 获取 HVAC 的示例"/>
+<p class="img-caption"><strong>图 1</strong>. 获取 HVAC 温度(CS = CarService、VNS = VehicleNetworkService、VHAL = 车载 HAL)</p>
+
+<h3 id="set">set 调用</h3>
+<p><code>set</code> 调用属于异步操作,涉及进行所请求更改之后的事件通知。在典型的操作中,<code>set</code> 调用会导致在车辆网络中发出更改请求。拥有该属性的电子控制单元 (ECU) 执行更改后,更新后的值会通过车辆网络返回,而车载 HAL 会将更新后的值作为事件发送给车辆网络服务 (VNS)。</p>
+<p>某些 <code>set</code> 调用可能要求准备好初始数据,而这些数据在初始化期间可能尚未提供。在这种情况下,<code>set</code> 调用应该返回 <code>-EAGAIN</code>。某些具有单独的电源开/关的属性应在电源关闭且无法设置时返回 <code>-ESHUTDOWN</code>。</p>
+<p>在 <code>set</code> 生效之前,<code>get</code> 不一定会返回所设置的值。不过,例外的是更改模式为 <code>VEHICLE_PROP_CHANGE_MODE_ON_SET.</code> 的属性。此类属性仅在被 Android 之外的外部组件(如 <code>VEHICLE_PROPERTY_UNIX_TIME</code> 等时钟属性)设置时才会通知更改。</p>
+
+<p>示例:设置 HVAC 温度</p>
+<img src="../images/vehicle_hvac_set.png" alt="车载 HAL 设置 HVAC 的示例"/>
+<p class="img-caption"><strong>图 2</strong>. 设置 HVAC 温度(CD = CarService、VNS = VehicleNetworkService、VHAL = 车载 HAL)</p>
+
+<h2 id="prop_custom">处理自定义属性</h2>
+<p>为了满足合作伙伴的特定需求,车载 HAL 允许使用仅限于系统应用的自定义属性。在使用自定义属性时,请遵循以下指南:</p>
+<ul>
+<li>键应该处于 [<code>VEHICLE_PROPERTY_CUSTOM_START,
+VEHICLE_PROPERTY_CUSTOM_END</code>] 范围内。其他范围已预留下来以供将来扩展;使用这些范围可能会导致在将来的 Android 版本中出现冲突。</li>
+<li>仅使用定义的 <code>value_type</code>。BYTES 类型允许传递原始数据,因此,在大多数情况下这就足够了。通过自定义属性频繁发送大数据可能会减缓整个车辆网络的访问速度,因此,在添加大量需要 HAL 处理的数据时要小心谨慎。</li>
+<li>将访问策略添加到 <code>vendor_vns_policy.xml</code>(否则所有访问都会被拒)。</li>
+<li>通过 <code>VendorExtensionManager</code>(适用于 Java 组件)或 Vehicle Network Service API(适用于原生代码)访问。请勿修改其他汽车 API,因为这样做可能会在将来导致兼容性问题。</li>
+</ul>
+
+<h2 id="prop_hvac">处理 HVAC 属性</h2>
+<p>您可以通过设置与 HVAC 相关的属性,来使用车载 HAL 控制 HVAC。大多数 HVAC 属性都是区域属性,但也有一些非区域(全局)属性。定义的示例属性包括:</p>
+<ul>
+<li><code>VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET</code>
+<br />按区域设置温度。</li>
+<li><code>VEHICLE_PROPERTY_HVAC_RECIRC_ON</code>
+<br />按区域控制再循环。</li>
+</ul>
+<p>有关 HVAC 属性的完整列表,请在 <code>vehicle.h</code> 中搜索 <code>VEHICLE_PROPERTY_HVAC_*</code>。</p>
+
+<h2 id="prop_sensor">处理传感器属性</h2>
+<p>车载 HAL 传感器属性表示实际的传感器数据或策略信息,如驾驶状况。某些传感器信息(如驾驶状况和日间/夜间模式)不限制任何应用的访问,因为这些数据是构建安全车载应用所必需的。还有一些传感器信息(如车辆速度)更为敏感,需要用户可以管理的特定权限。</p>
+<p>支持的传感器属性包括:</p>
+<ul>
+<li><code>DRIVING_STATUS</code>
+<br />应该支持。表示在当前驾驶状态下允许的操作。此信息用于在驾驶过程中屏蔽不安全的应用。</li>
+<li><code>NIGHT_MODE</code>
+<br />应该支持。确定日间/夜间显示模式。</li>
+<li><code>GEAR_SELECTION/CURRENT_GEAR</code>
+<br />驾驶员选择的挡位与实际挡位。</li>
+<li><code>VEHICLE_SPEED</code>
+<br />车速。受权限保护。</li>
+<li><code>ODOMETER</code>
+<br />当前里程表读数。受权限保护。
+</li>
+<li><code>FUEL_LEVEL</code>
+<br />当前油位 (%)。</li>
+<li><code>FUEL_LEVEL_LOW</code>
+<br />油位是否较低(布尔值)。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/camera/camera3_3Amodes.html b/zh-cn/devices/camera/camera3_3Amodes.html
new file mode 100644
index 00000000..91b2a746
--- /dev/null
+++ b/zh-cn/devices/camera/camera3_3Amodes.html
@@ -0,0 +1,487 @@
+<html devsite><head>
+ <title>3A 模式和状态转换</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>虽然实际的 3A 算法取决于 HAL 实现,但高级状态机的说明由 HAL 接口定义,以支持 HAL 设备和框架就 3A 的当前状态进行通信并触发 3A 事件。</p>
+<p>当设备开启时,所有单独的 3A 状态都必须为 STATE_INACTIVE。流配置不会重置 3A。例如,在整个 configure() 调用期间必须保持焦点锁定。</p>
+<p>要触发 3A 操作,只需在下一个请求的设置中设置相关触发条目,以指示触发开始。例如,若要触发启动自动对焦扫描,便只需将相应请求的 ANDROID_CONTROL_AF_TRIGGER 条目设为 ANDROID_CONTROL_AF_TRIGGER_START;若要触发取消自动对焦扫描,则只需将 ANDROID_CONTROL_AF_TRIGGER 设为 ANDROID_CONTRL_AF_TRIGGER_CANCEL。否则,条目将会不存在或被设为 ANDROID_CONTROL_AF_TRIGGER_IDLE。凡是具有已设为非 IDLE 值的触发条目的请求,都会被视为独立的触发事件。</p>
+<p>在顶层,3A 由 ANDROID_CONTROL_MODE 设置控制。该设置选项包括关闭 3A (ANDROID_CONTROL_MODE_OFF)、正常自动 (AUTO) 模式 (ANDROID_CONTROL_MODE_AUTO) 以及使用场景模式 (ANDROID_CONTROL_USE_SCENE_MODE):</p>
+<ul>
+ <li>在 OFF 模式下,自动对焦 (AF)、自动曝光 (AE) 和自动白平衡 (AWB) 模式都会有效地关闭,且任何拍摄控件都不会被 3A 例程覆盖。</li>
+ <li>在 AUTO 模式下,AF、AE 和 AWB 模式都会运行各自的独立算法,且具有自己的模式、状态和触发元数据条目,如下一节所示。</li>
+ <li>在 USE_SCENE_MODE 下,必须使用 ANDROID_CONTROL_SCENE_MODE 条目的值来确定 3A 例程的行为。在除 FACE_PRIORITY 以外的 SCENE_MODE 下,HAL 必须将 ANDROID_CONTROL_AE/AWB/AF_MODE 的值替换为它倾向于让所选的 SCENE_MODE 使用的模式。例如,HAL 可能倾向于在 SCENE_MODE_NIGHT 下使用 CONTINUOUS_FOCUS AF 模式。当必须忽略这些场景模式下的场景时,用户可随意选择 AE/AWB/AF_MODE。</li>
+ <li>对于 SCENE_MODE_FACE_PRIORITY,AE/AWB/AFMODE 控件的工作方式与在 ANDROID_CONTROL_MODE_AUTO 模式下相同,但 3A 例程必须偏向测光,并对焦到场景中任何已检测到的人脸上。</li>
+</ul>
+<h2 id="auto-focus">自动对焦设置与结果条目</h2>
+<p>主要元数据条目:<br />ANDROID_CONTROL_AF_MODE:用于选择当前的自动对焦模式的控件。由请求设置中的框架进行设置。<br />AF_MODE_OFF:AF 已停用;框架/应用直接控制镜头位置。<br />AF_MODE_AUTO:单次自动对焦。该模式下镜头不会移动,除非 AF 被触发。<br />AF_MODE_MACRO:单次近距离自动对焦。该模式下镜头不会移动,除非 AF 被触发。<br />AF_MODE_CONTINUOUS_VIDEO:流畅连续对焦,用于录制视频。触发后会立刻将焦点锁定在当前位置。取消后即会恢复连续对焦。<br />AF_MODE_CONTINUOUS_PICTURE:快速连续对焦,用于快门零延迟静像拍摄。待当前处于活动状态的扫描结束后,触发即可锁定焦点。取消后即会恢复连续对焦。<br />AF_MODE_EDOF:高级扩展景深对焦。该模式下没有自动对焦扫描,所以触发或取消均无效。图像由 HAL 自动对焦。<br />ANDROID_CONTROL_AF_STATE:用于描述当前 AF 算法状态的动态元数据,由结果元数据中的 HAL 报告。<br />AF_STATE_INACTIVE:未进行对焦,或算法被重置。镜头未移动。始终处于 MODE_OFF 或 MODE_EDOF 状态。当设备开启时,必须以此状态启动。<br />AF_STATE_PASSIVE_SCAN:连续对焦算法正在扫描理想对焦。镜头正在移动。<br />AF_STATE_PASSIVE_FOCUSED:连续对焦算法认为已良好对焦。镜头未移动。HAL 可能会自发退出此状态。<br />AF_STATE_PASSIVE_UNFOCUSED:连续对焦算法认为未良好对焦。镜头未移动。HAL 可能会自发退出此状态。<br />AF_STATE_ACTIVE_SCAN:用户触发的扫描正在进行中。<br />AF_STATE_FOCUSED_LOCKED:AF 算法认为已对焦。镜头未移动。<br />AF_STATE_NOT_FOCUSED_LOCKED:AF 算法无法对焦。镜头未移动。<br />ANDROID_CONTROL_AFTRIGGER:用于启动自动对焦扫描的控件。具体意义取决于模式和状态。由框架在请求设置中进行设置。<br />AF_TRIGGER_IDLE:当前未触发。<br />AF_TRIGGER_START:触发启动 AF 扫描。扫描效果取决于模式和状态。<br />AF_TRIGGER_CANCEL:取消当前 AF 扫描(如有),并将算法重置为默认值。<br />其他元数据条目:<br />ANDROID_CONTROL_AF_REGIONS:用于选择为确定良好对焦而需使用的视野 (FOV) 区域的控件。该控件适用于所有可扫描对焦的 AF 模式。由请求设置中的框架进行设置。</p>
+<h2 id="auto-exposure">自动曝光设置和结果条目</h2>
+<p>主要元数据条目:<br />ANDROID_CONTROL_AE_MODE:用于选择当前自动曝光模式的控件。由请求设置中的框架进行设置。<br />AE_MODE_OFF:自动曝光已停用;用户控制曝光、增益、帧时长和闪光。<br />AE_MODE_ON:标准自动曝光,闪光灯控制已停用。用户可以将闪光灯设为触发或手电筒模式。<br />AE_MODE_ON_AUTO_FLASH:标准自动曝光,闪光灯听从 HAL 指令开启,以进行预拍摄和静像拍摄。允许用户控制闪光灯的功能已停用。<br />AE_MODE_ON_ALWAYS_FLASH:标准自动曝光,闪光灯始终触发以进行拍摄,并听从 HAL 指令进行预拍摄。允许用户控制闪光灯的功能已停用。<br />AE_MODE_ON_AUTO_FLASH_REDEYE:标准自动曝光,闪光灯听从 HAL 指令进行预拍摄和静像拍摄。在预拍摄序列结束时使用闪光灯,以减轻最终照片中的红眼现象。允许用户控制闪光灯的功能已停用。<br />ANDROID_CONTROL_AE_STATE:描述当前 AE 算法状态的动态元数据,在结果元数据中由 HAL 报告。<br />AE_STATE_INACTIVE:切换模式后的初始 AE 状态。当设备开启时,必须以此状态启动。<br />AE_STATE_SEARCHING:AE 没有聚焦到一个理想值,正在调整曝光参数。<br />AE_STATE_CONVERGED:AE 已经为当前场景找到了理想曝光值,且曝光参数不会变化。HAL 可能会自发退出此状态以寻找更好的解决方案。<br />AE_STATE_LOCKED:AE 已通过 AE_LOCK 控件锁定。曝光值不变。<br />AE_STATE_FLASH_REQUIRED:HAL 已聚焦曝光,但认为需要启动闪光灯以保证照片足够明亮。用于确定是否可使用零快门延迟帧。<br />AE_STATE_PRECAPTURE:HAL 正在处理预拍序列。根据 AE 模式,该模式可能包括开启闪光灯进行测光,或发出闪光脉冲以减轻红眼现象。<br />ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER:用于在拍摄高品质图像之前启动测光序列的控件。由框架在请求设置中进行设置。<br />PRECAPTURE_TRIGGER_IDLE:当前未触发。<br />PRECAPTURE_TRIGGER_START:启动预拍序列。HAL 应使用后续请求进行衡量并达到理想的曝光/白平衡,以便接下来拍摄高分辨率的照片。<br />其他元数据条目:<br />ANDROID_CONTROL_AE_LOCK:用于将 AE 控件锁定到其当前值的控件。<br />ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION:用于调整 AE 算法目标亮度点的控件。<br />ANDROID_CONTROL_AE_TARGET_FPS_RANGE:用于为 AE 算法选择目标帧速率范围的控件。AE 例程无法将帧速率变为超出这些范围的值。<br />ANDROID_CONTROL_AE_REGIONS:用于选择应该用于确定良好曝光水平的 FOV 区域的控件。该控件适用于除 OFF 模式外的所有 AE 模式。</p>
+<h2 id="auto-wb">自动白平衡设置和结果条目</h2>
+<p>主要元数据条目:<br />ANDROID_CONTROL_AWB_MODE:用于选择当前白平衡模式的控件。<br />AWB_MODE_OFF:自动白平衡已停用。用户控制颜色矩阵。<br />AWB_MODE_AUTO:自动白平衡已启用。3A 控制颜色变换,使用的变换方式可能比简单矩阵更复杂。<br />AWB_MODE_INCANDESCENT:适用于室内白炽灯(钨丝)照明的固定白平衡设置,约为 2700K。<br />AWB_MODE_FLUORESCENT:适用于荧光灯照明的固定白平衡设置,约为 5000K。<br />AWB_MODE_WARM_FLUORESCENT:适用于荧光灯照明的固定白平衡设置,约为 3000K。<br />AWB_MODE_DAYLIGHT:适用于日光的固定白平衡设置,约为 5500K。<br />AWB_MODE_CLOUDY_DAYLIGHT:适用于多云日光的固定白平衡设置,约为 6500K。<br />AWB_MODE_TWILIGHT:适用于近日落/日出的固定白平衡设置,约为 15000K。<br />AWB_MODE_SHADE:适用于非阳光直射区域的固定白平衡设置,约为 7500K。<br />ANDROID_CONTROL_AWB_STATE:描述当前 AWB 算法状态的动态元数据,在结果元数据中由 HAL 报告。<br />AWB_STATE_INACTIVE:切换模式后的初始 AWB 状态。当设备开启时,必须以此状态启动。<br />AWB_STATE_SEARCHING:AWB 未聚焦为一个理想值,正在改变颜色调整参数。<br />AWB_STATE_CONVERGED:AWB 已发现适用于当前场景的理想颜色调整值,参数不会更改。HAL 可能会自发退出此状态,以寻找更好的解决方案。<br />AWB_STATE_LOCKED:AWB 已由 AWB_LOCK 控件锁定。颜色调整值不会更改。<br />其他元数据条目:<br />ANDROID_CONTROL_AWB_LOCK:用于将 AWB 颜色调整锁定为当前值的控件。<br />ANDROID_CONTROL_AWB_REGIONS:用于选择应该用于确定良好色彩平衡的 FOV 区域的控件。该模式仅适用于自动白平衡模式。</p>
+<h2 id="state-transition">一般状态机转换说明</h2>
+<p>在 AF、AE 和 AWB 模式之间切换模式始终会将算法状态重置为 INACTIVE 状态。同样,如果 CONTROL_MODE == USE_SCENE_MODE,在 CONTROL_MODE 和 CONTROL_SCENE_MODE 之间切换也会将所有算法状态重置为 INACTIVE 状态。<br />下表列出了各模式的情况。</p>
+<h2 id="af-state">AF 状态机</h2>
+<table>
+ <tbody><tr>
+ <td><strong>模式 = AF_MODE_OFF 或 AF_MODE_EDOF</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td></td>
+ <td></td>
+ <td>AF 已停用</td>
+ </tr>
+ <tr>
+ <td><strong>模式 = AF_MODE_AUTO 或 AF_MODE_MACRO</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>AF_TRIGGER</td>
+ <td>ACTIVE_SCAN</td>
+ <td>开始 AF 扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>ACTIVE_SCAN</td>
+ <td>AF 扫描已完成</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>若 AF 成功
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>ACTIVE_SCAN</td>
+ <td>AF 扫描已完成</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>若 AF 成功
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>ACTIVE_SCAN</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>取消/重置 AF
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>取消/重置 AF</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>ACTIVE_SCAN</td>
+ <td>开始新的扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>取消/重置 AF</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>ACTIVE_SCAN</td>
+ <td>开始新的扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>所有状态</td>
+ <td>模式更改</td>
+ <td>INACTIVE</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><strong>模式 = AF_MODE_CONTINUOUS_VIDEO</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>HAL 启动新的扫描</td>
+ <td>PASSIVE_SCAN</td>
+ <td>开始 AF 扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF 状态查询
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>HAL 完成当前扫描</td>
+ <td>PASSIVE_FOCUSED</td>
+ <td>结束 AF 扫描
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>若对焦理想,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>若对焦不良,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重置镜头位置
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>HAL 启动新的扫描</td>
+ <td>PASSIVE_SCAN</td>
+ <td>开始 AF 扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>若对焦理想,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>若对焦不良,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>无效果</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重新启动 AF 扫描</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>无效果</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重新启动 AF 扫描</td>
+ </tr>
+ <tr>
+ <td><strong>模式 = AF_MODE_CONTINUOUS_PICTURE</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>HAL 启动新的扫描</td>
+ <td>PASSIVE_SCAN</td>
+ <td>开始 AF 扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF 状态查询
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>HAL 完成当前扫描</td>
+ <td>PASSIVE_FOCUSED</td>
+ <td>结束 AF 扫描
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>一旦对焦理想,则进行最终转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>若无法对焦,则进行最终转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_SCAN</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重置镜头位置
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>HAL 启动新的扫描</td>
+ <td>PASSIVE_SCAN</td>
+ <td>开始 AF 扫描
+镜头正在移动</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>若对焦理想,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>PASSIVE_FOCUSED</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>若对焦不良,则立即转换
+镜头现已锁定</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>FOCUSED_LOCKED</td>
+ <td>无效果</td>
+ </tr>
+ <tr>
+ <td>FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重新启动 AF 扫描</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_TRIGGER</td>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>无效果</td>
+ </tr>
+ <tr>
+ <td>NOT_FOCUSED_LOCKED</td>
+ <td>AF_CANCEL</td>
+ <td>INACTIVE</td>
+ <td>重新启动 AF 扫描</td>
+ </tr>
+</tbody></table>
+<h2 id="ae-wb">AE 和 AWB 状态机</h2>
+<p>AE 和 AWB 状态机大致上相同。但 AE 具有额外的 FLASH_REQUIRED 和 PRECAPTURE 状态。因此,对于 AWB 状态机,应忽略下表中这两个状态对应的行。</p>
+<table>
+ <tbody><tr>
+ <td><strong>模式 = AE_MODE_OFF/AWB 模式不是 AUTO</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td></td>
+ <td></td>
+ <td>AE/AWB 已停用</td>
+ </tr>
+ <tr>
+ <td><strong>模式 = AE_MODE_ON_ * / AWB_MODE_AUTO</strong></td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <th>状态</th>
+ <th>转换原因</th>
+ <th>新状态</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>HAL 启动 AE/AWB 扫描</td>
+ <td>SEARCHING</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>INACTIVE</td>
+ <td>AE/AWB_LOCK 已开启</td>
+ <td>LOCKED</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>SEARCHING</td>
+ <td>HAL 完成 AE/AWB 扫描</td>
+ <td>CONVERGED</td>
+ <td>理想值,不作改变</td>
+ </tr>
+ <tr>
+ <td>SEARCHING</td>
+ <td>HAL 完成 AE 扫描</td>
+ <td>FLASH_REQUIRED</td>
+ <td>已聚焦,但无闪光灯导致过暗</td>
+ </tr>
+ <tr>
+ <td>SEARCHING</td>
+ <td>AE/AWB_LOCK 已开启</td>
+ <td>LOCKED</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>CONVERGED</td>
+ <td>HAL 启动 AE/AWB 扫描</td>
+ <td>SEARCHING</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>CONVERGED</td>
+ <td>AE/AWB_LOCK 已开启</td>
+ <td>LOCKED</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>FLASH_REQUIRED</td>
+ <td>HAL 启动 AE/AWB 扫描</td>
+ <td>SEARCHING</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>FLASH_REQUIRED</td>
+ <td>AE/AWB_LOCK 已开启</td>
+ <td>LOCKED</td>
+ <td>值已锁定</td>
+ </tr>
+ <tr>
+ <td>LOCKED</td>
+ <td>AE/AWB_LOCK 已关闭</td>
+ <td>SEARCHING</td>
+ <td>解锁后值不理想</td>
+ </tr>
+ <tr>
+ <td>LOCKED</td>
+ <td>AE/AWB_LOCK 已关闭</td>
+ <td>CONVERGED</td>
+ <td>解锁后值理想</td>
+ </tr>
+ <tr>
+ <td>LOCKED</td>
+ <td>AE_LOCK 已关闭</td>
+ <td>FLASH_REQUIRED</td>
+ <td>曝光良好但过暗</td>
+ </tr>
+ <tr>
+ <td>所有 AE 状态</td>
+ <td>PRECAPTURE_START</td>
+ <td>PRECAPTURE</td>
+ <td>开始预拍序列</td>
+ </tr>
+ <tr>
+ <td>PRECAPTURE</td>
+ <td>序列完成,AE_LOCK 已关闭</td>
+ <td>CONVERGED</td>
+ <td>高质量拍摄就绪</td>
+ </tr>
+ <tr>
+ <td>PRECAPTURE</td>
+ <td>序列完成,AE_LOCK 已开启</td>
+ <td>LOCKED</td>
+ <td>高质量拍摄就绪</td>
+ </tr>
+</tbody></table>
+<h2 id="manual-control">启用手动控制</h2>
+<p>配置设备 3A 块以实现直接应用控制的过程还涉及到多个控件。</p>
+<p>用于 3A 控制的 HAL 模式的运作方式为:对于每个请求,HAL 都会检查 3A 控制字段的状态。如果启用了任何 3A 例程,则该例程会覆盖与该例程相关的控制变量,然后这些覆盖值会在该拍摄的结果元数据中提供。例如,如果在请求中启用自动曝光,则 HAL 应覆盖请求的曝光、增益和帧时长字段(还可能包括闪光灯字段,具体取决于 AE 模式)。相关控件如下:</p>
+<table>
+ <tbody><tr>
+ <th>控件名称</th>
+ <th>单位</th>
+ <th>备注</th>
+ </tr>
+ <tr>
+ <td>android.control.mode</td>
+ <td>枚举:OFF、AUTO、USE_SCENE_MODE</td>
+ <td>高级 3A 控制。当设为 OFF 时,所有由 HAL 启用的 3A 控件都会被停用。应用必须为拍摄参数本身设置字段。当设为 AUTO 时,android.control.* 中的单个算法控件(例如 android.control.afMode)会生效。当设为 USE_SCENE_MODE 时,android.control.* 中的各控件大都被停用;HAL 根据需要,实现其中的一个场景模式设置(如 ACTION、SUNSET 或 PARTY)。</td>
+ </tr>
+ <tr>
+ <td>android.control.afMode</td>
+ <td>枚举</td>
+ <td>OFF 表示使用 android.lens.focusDistance 手动控制镜头。</td>
+ </tr>
+ <tr>
+ <td>android.control.aeMode</td>
+ <td>枚举</td>
+ <td>OFF 表示使用 android.sensor.exposureTime / .sensitivity / .frameDuration 手动控制曝光/增益/帧时长。</td>
+ </tr>
+ <tr>
+ <td>android.control.awbMode</td>
+ <td>枚举</td>
+ <td>OFF 表示手动控制白平衡。</td>
+ </tr>
+</tbody></table>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/camera/camera3_crop_reprocess.html b/zh-cn/devices/camera/camera3_crop_reprocess.html
new file mode 100644
index 00000000..d496bf5d
--- /dev/null
+++ b/zh-cn/devices/camera/camera3_crop_reprocess.html
@@ -0,0 +1,67 @@
+<html devsite><head>
+ <title>输出流和剪裁</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<h2 id="output-stream">输出流</h2>
+<p>与具有 3 至 4 种从相机生成数据的不同方式(基于 ANativeWindow 的预览操作、预览回调、视频回调和 takePicture 回调)的旧版相机子系统不同,新版相机子系统针对所有分辨率和输出格式都仅在基于 ANativeWindow 的通道上运行。您可以同时配置多路这样的输出流,以便将单个帧发送至多个目标,例如:GPU、视频编码器、RenderScript,或应用可见的缓冲区(RAW Bayer 缓冲区、经处理的 YUV 缓冲区或经 JPEG 编码的缓冲区)。</p>
+<p>出于优化的目的,这些输出流必须提前配置,而且只有有限的输出流可同时存在。这样一来,就可以预先分配内存缓冲区和配置相机硬件,以便在提交列有多个或者不同输出通道的请求时,不会出现请求延迟执行的情况。</p>
+<p>为了使当前的 camera API 具有向后兼容性,相机子系统必须至少同时支持 3 路 YUV 输出流,外加一路 JPEG 流。要支持视频快照,同时使应用也可接收 YUV 缓冲区,则必须满足上述要求:</p>
+<ul>
+ <li>一路视频流(不透明的 YUV 格式)流向 GPU/SurfaceView 以用于预览</li>
+ <li>一路视频流(不透明的 YUV 格式)流向视频编码器以用于录制</li>
+ <li>一路视频流(已知的 YUV 格式)流向应用以用于预览帧回调</li>
+ <li>一路视频流 (JPEG) 流向应用以用于视频快照</li>
+</ul>
+<p>由于相应的 API 尚未最终确定,确切的要求仍未敲定。</p>
+<h2>剪裁</h2>
+<p>完整像素阵列的剪裁(用于数字变焦和需要更小 FOV 的其他使用情况)通过 ANDROID_SCALER_CROP_REGION 设置进行传递。这个设置可按需更改,这种方式对于实现平滑的数字变焦至关重要。</p>
+<p>该区域被定义为矩形(x 和 y 分别表示宽和高),其中 (x,y) 表示矩形的左上角。该矩形在传感器有源像素阵列的坐标系中进行定义,其中 (0,0) 对应有源像素阵列的左上角像素。因此,宽度和高度不能大于 ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY 静态信息字段中所报告的尺寸。允许的最小宽度和高度由 HAL 通过 ANDROID_SCALER_MAX_DIGITAL_ZOOM 静态信息字段进行报告,该字段描述了所支持的缩放因子的最大值。因此,最小剪裁区域的宽度和高度为:</p>
+<pre class="devsite-click-to-copy">
+ {width, height} =
+ { floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[0] /
+ ANDROID_SCALER_MAX_DIGITAL_ZOOM),
+ floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[1] /
+ ANDROID_SCALER_MAX_DIGITAL_ZOOM) }
+</pre>
+<p>如果剪裁区域需要满足特定需求(例如:要求起始位置坐标为偶数,并且其宽度/高度需均为偶数),则 HAL 必须进行必要的舍入运算,并写出输出结果元数据中所用的最终剪裁区域。同样,HAL 要实现视频防抖功能,则必须调整结果剪裁区域,以描述在应用视频防抖功能后输出结果中实际包含的区域。一般情况下,使用相机的应用必须能够根据剪裁区域、图像传感器的尺寸和镜头焦距确定其接收的视野范围。</p>
+<p>由于剪裁区域适用于所有视频流,这些视频流的宽高比可能与剪裁区域的不同,所以每路视频流所用的实际传感器区域可能小于剪裁区域。具体而言,每路视频流应尽量避免进一步剪裁已定义的剪裁区域,以维持方形像素及其宽高比。如果视频流的宽高比大于剪裁区域,则该视频流应该在垂直方向上进一步剪裁,如果视频流的宽高比小于剪裁区域,则该视频流应该在水平方向上进一步剪裁。</p>
+<p>在所有情况下,视频流剪裁均必须位于整个剪裁区域的中心位置,并且相对于整个剪裁区域,每路视频流要么在水平方向上进行剪裁,要么在垂直方向上进行剪裁,但绝不能在这两个方向上同时进行剪裁。</p>
+<p>例如,如果两路视频流分别定义为 640x480(宽高比为 4:3)和 1280x720(宽高比为 16:9),并假设传感器为 300 万像素级(2000 x 1500 像素阵列),则下面展示了针对几个样本剪裁区域,每路视频流的预期输出区域。</p>
+<p></p>剪裁区域:(500、375、1000、750)(宽高比为 4:3)<br />640x480 视频流剪裁:(500、375、1000、750)(与剪裁区域相同)<br />1280x720 视频流剪裁:(500、469、1000、562)<p></p>
+ <img src="images/crop-region-43-ratio.png" alt="crop-region-43-ratio" id="figure1"/>
+<p class="img-caption">
+ <strong>图 1.</strong> 宽高比为 4:3</p>
+<p>剪裁区域:(500、375、1333、750)(宽高比为 16:9)<br />640x480 视频流剪裁:(666、375、1000、750)<br />1280×720 视频流剪裁:(500、375、1333、750)(与剪裁区域相同)</p>
+ <img src="images/crop-region-169-ratio.png" alt="crop-region-169-ratio" id="figure2"/>
+<p class="img-caption">
+ <strong>图 2. </strong>宽高比为 16:9</p>
+<p>剪裁区域:(500、375、750、750)(宽高比为 1:1)<br />640x480 视频流剪裁:(500、469、750、562)<br />1280x720 视频流剪裁:(500、543、750、414)</p>
+ <img src="images/crop-region-11-ratio.png" alt="crop-region-11-ratio" id="figure3"/>
+<p class="img-caption">
+ <strong>图 3. </strong>宽高比为 1:1</p>
+<p>最后一个示例是宽高比为 1024×1024(方形)的视频流,而不是 480p 视频流:<br />剪裁区域:(500、375、1000、750)(宽高比为 4:3)<br />1024x1024 视频流剪裁:(625、375、750、750)<br />1280x720 视频流剪裁:(500、469、1000、562)</p>
+ <img src="images/crop-region-43-square-ratio.png" alt="crop-region-43-square-ratio" id="figure4"/>
+<p class="img-caption">
+ <strong>图 4. </strong>宽高比为 4:3(方形)</p>
+<h2 id="reprocessing">重新处理</h2>
+<p>对原始图片文件提供额外的支持功能,即 RAW Bayer 数据重新处理支持功能。该支持功能允许相机通道处理之前捕获的 RAW 缓冲区和元数据(之前记录的整个帧),以生成新渲染的 YUV 或 JPEG 输出。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/arch-sv-glsv.html b/zh-cn/devices/graphics/arch-sv-glsv.html
new file mode 100644
index 00000000..8a6ebacf
--- /dev/null
+++ b/zh-cn/devices/graphics/arch-sv-glsv.html
@@ -0,0 +1,110 @@
+<html devsite><head>
+ <title>SurfaceView 和 GLSurfaceView</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android 应用框架界面是以使用 View 开头的对象层次结构为基础。所有界面元素都会经过一个复杂的测量和布局过程,该过程会将这些元素融入到矩形区域中,并且所有可见 View 对象都会渲染到一个由 SurfaceFlinger 创建的 Surface(在应用置于前台时,由 WindowManager 进行设置)。应用的界面线程会执行布局并渲染到单个缓冲区(不考虑 Layout 和 View 的数量以及 View 是否已经过硬件加速)。</p>
+
+<p>SurfaceView 采用与其他视图相同的参数,因此您可以为 SurfaceView 设置位置和大小,并在其周围填充其他元素。但是,当需要渲染时,内容会变得完全透明;SurfaceView 的 View 部分只是一个透明的占位符。</p>
+
+<p>当 SurfaceView 的 View 组件即将变得可见时,框架会要求 WindowManager 命令 SurfaceFlinger 创建一个新的 Surface。(这个过程并非同步发生,因此您应该提供回调,以便在 Surface 创建完毕后收到通知。)默认情况下,新的 Surface 将放置在应用界面 Surface 的后面,但可以替换默认的 Z 排序,将 Surface 放在顶层。</p>
+
+<p>渲染到该 Surface 上的内容将会由 SurfaceFlinger(而非应用)进行合成。这是 SurfaceView 的真正强大之处:您获得的 Surface 可以由单独的线程或单独的进程进行渲染,并与应用界面执行的任何渲染隔离开,而缓冲区可直接转至 SurfaceFlinger。您不能完全忽略界面线程,因为您仍然需要与 Activity 生命周期相协调,并且如果 View 的大小或位置发生变化,您可能需要调整某些内容,但是您可以拥有整个 Surface。与应用界面和其他图层的混合由 Hardware Composer 处理。</p>
+
+<p>新的 Surface 是 BufferQueue 的生产者端,其消费者是 SurfaceFlinger 层。您可以使用任意提供 BufferQueue 的机制(例如,提供 Surface 的 Canvas 函数)来更新 Surface,附加 EGLSurface 并使用 GLES 进行绘制,或者配置 MediaCodec 视频解码器以便于写入。</p>
+
+<h2 id="composition">合成与硬件缩放</h2>
+
+<p>我们来仔细研究一下 <code>dumpsys SurfaceFlinger</code>。当在 Nexus 5 上,以纵向方向在 Grafika 的“播放视频 (SurfaceView)”活动中播放电影时,采用以下输出;视频是 QVGA (320x240):</p>
+<p></p><pre>
+ type | source crop | frame name
+------------+-----------------------------------+--------------------------------
+ HWC | [ 0.0, 0.0, 320.0, 240.0] | [ 48, 411, 1032, 1149] SurfaceView
+ HWC | [ 0.0, 75.0, 1080.0, 1776.0] | [ 0, 75, 1080, 1776] com.android.grafika/com.android.grafika.PlayMovieSurfaceActivity
+ HWC | [ 0.0, 0.0, 1080.0, 75.0] | [ 0, 0, 1080, 75] StatusBar
+ HWC | [ 0.0, 0.0, 1080.0, 144.0] | [ 0, 1776, 1080, 1920] NavigationBar
+ FB TARGET | [ 0.0, 0.0, 1080.0, 1920.0] | [ 0, 0, 1080, 1920] HWC_FRAMEBUFFER_TARGET
+</pre><p></p>
+
+<ul>
+<li><strong>列表顺序</strong>是从后到前:SurfaceView 的 Surface 位于后面,应用界面层位于其上,其次是处于最前方的状态栏和导航栏。</li>
+<li><strong>源剪裁</strong>值表示 Surface 缓冲区中 SurfaceFlinger 将显示的部分。应用界面会获得一个与显示屏的完整尺寸 (1080x1920) 一样大的 Surface,但是由于渲染和合成将被状态栏和导航栏遮挡的像素毫无意义,因此将源剪裁为一个矩形(上自离顶部 75 个像素,下至离底部 144 个像素)。状态栏和导航栏的 Surface 较小,并且源剪裁描述了一个矩形(起点位于左上角 (0,0) 并且会横跨其内容)。</li>
+<li><strong>框架</strong>值指定在显示屏上显示像素的矩形。对于应用界面层,框架会与源剪裁匹配,因为我们会将与显示屏同样大小的图层的一部分复制(或叠加)到另一个与显示屏同样大小的图层中的相同位置。对于状态栏和导航栏,两者的框架矩形大小相同,但是位置经过调整,所以导航栏出现在屏幕底部。</li>
+<li><strong>SurfaceView 层</strong>容纳我们的视频内容。源剪裁与视频的大小相匹配,而 SurfaceFlinger 了解该信息,因为 MediaCodec 解码器(缓冲区生成器)正在将同样大小的缓冲区移出队列。框架矩形具有完全不同的尺寸:984x738。</li>
+</ul>
+
+<p>SurfaceFlinger 通过缩放(根据需要放大或缩小)缓冲区内容来填充框架矩形,以处理大小差异。之所以选择这种特定尺寸,是因为它具有与视频相同的宽高比 (4:3),并且由于 View 布局的限制(为了美观,在屏幕边缘处留有一定的内边距),因此应尽可能地宽。</p>
+
+<p>如果您在同一 Surface 上开始播放不同的视频,底层 BufferQueue 会将缓冲区自动重新分配为新的大小,而 SurfaceFlinger 将调整源剪裁。如果新视频的宽高比不同,则应用需要强制重新布局 View 才能与之匹配,这将导致 WindowManager 通知 SurfaceFlinger 更新框架矩形。</p>
+
+<p>如果您通过其他方式(如 GLES)在 Surface 上进行渲染,则可以使用 <code>SurfaceHolder#setFixedSize()</code> 调用设置 Surface 尺寸。例如,您可以将游戏配置为始终采用 1280x720 的分辨率进行渲染,这将大大减少填充 2560x1440 平板电脑或 4K 电视机屏幕所需处理的像素数。显示处理器会处理缩放。如果您不希望给游戏加上水平或垂直黑边,您可以通过设置尺寸来调整游戏的宽高比,使窄尺寸为 720 像素,但长尺寸设置为维持物理显示屏的宽高比(例如,设置为 1152x720 来匹配 2560x1600 的显示屏)。有关此方法的示例,请参阅 Grafika 的“硬件缩放练习程序”活动。</p>
+
+<h2 id="glsurfaceview">GLSurfaceView</h2>
+
+<p>GLSurfaceView 类提供帮助程序类,用于管理 EGL 上下文、线程间通信以及与 Activity 生命周期的交互。这就是其功能。您无需使用 GLSurfaceView 来应用 GLES。</p>
+
+<p>例如,GLSurfaceView 创建一个渲染线程,并配置 EGL 上下文。当活动暂停时,状态将自动清除。大多数应用都不需要知道 EGL,便可通过 GESurfaceView 使用 GLES。</p>
+
+<p>在大多数情况下,GLSurfaceView 非常实用,可简化 GLES 的使用。但在某些情况下,却会造成妨碍。请在有用时使用,无用时弃用。</p>
+
+<h2 id="activity">SurfaceView 和 Activity 生命周期</h2>
+
+<p>当使用 SurfaceView 时,使用主界面线程之外的线程渲染 Surface 是很好的做法。不过,这样就会产生一些与线程和 Activity 生命周期之间的交互相关的问题。</p>
+
+<p>对于具有 SurfaceView 的 Activity,存在两个单独但相互依赖的状态机:</p>
+
+<ol>
+<li>状态为 onCreate/onResume/onPause 的应用</li>
+<li>已创建/更改/销毁的 Surface</li>
+</ol>
+
+<p>当 Activity 开始时,将按以下顺序获得回调:</p>
+
+<ul>
+<li>onCreate</li>
+<li>onResume</li>
+<li>surfaceCreated</li>
+<li>surfaceChanged</li>
+</ul>
+
+<p>如果回击,您将得到:</p>
+
+<ul>
+<li>onPause</li>
+<li>surfaceDestroyed(在 Surface 消失前调用)</li>
+</ul>
+
+<p>如果旋转屏幕,Activity 将被消解并重新创建,而您将获得整个周期。您可以通过检查 <code>isFinishing()</code> 告知屏幕快速重新启动。启动/停止 Activity 可能非常快速,从而可能导致 <code>surfaceCreated()</code> 实际上是在 <code>onPause()</code> 之后发生。</p>
+
+<p>如果您点按电源按钮锁定屏幕,则只会得到 <code>onPause()</code>(没有 <code>surfaceDestroyed()</code>)。Surface 仍处于活跃状态,并且渲染可以继续。如果您继续请求,甚至可以持续获得 Choreographer 事件。如果您使用强制变向的锁屏,则当设备未锁定时,您的 Activity 可能会重新启动;但如果没有,您可以使用与之前相同的 Surface 脱离屏幕锁定。</p>
+
+<p>当使用具有 SurfaceView 的单独渲染器线程时,会引发一个基本问题:线程寿命是否依赖 Surface 或 Activity 的寿命?答案取决于锁屏时您想要看到的情况:(1) 在 Activity 启动/停止时启动/停止线程,或 (2) 在 Surface 创建/销毁时启动/停止线程。</p>
+
+<p>选项 1 与应用生命周期交互良好。我们在 <code>onResume()</code> 中启动渲染器线程,并在 <code>onPause()</code> 中将其停止。当创建和配置线程时,会显得有点奇怪,因为有时 Surface 已经存在,有时不存在(例如,在使用电源按钮切换屏幕后,它仍然存在)。我们必须先等待 Surface 完成创建,然后再在线程中进行一些初始化操作,但是我们不能简单地在 <code>surfaceCreated()</code> 回调中进行操作,因为如果未重新创建 Surface,将不会再次触发。因此,我们需要查询或缓存 Surface 状态,并将其转发到渲染器线程。</p>
+
+<p class="note"><strong>注意</strong>:在线程之间传递对象时要小心。最好通过处理程序消息传递 Surface 或 SurfaceHolder(而不仅仅是将其填充到线程中),以避免多核系统出现问题。有关详细信息,请参阅 <a href="http://developer.android.com/training/articles/smp.html">Android SMP Primer</a>。</p>
+
+<p>选项 2 非常具有吸引力,因为 Surface 和渲染器在逻辑上互相交织。我们在创建 Surface 后启动线程,避免了一些线程间通信问题,也可轻松转发 Surface 已创建/更改的消息。当屏幕锁定时,我们需要确保渲染停止,并在未锁定时恢复渲染;要实现这一点,可能只需告知 Choreographer 停止调用框架绘图回调。当且仅当渲染器线程正在运行时,我们的 <code>onResume()</code> 才需要恢复回调。尽管如此,如果我们根据框架之间的已播放时长进行动画绘制,我们可能发现,在下一个事件到来前存在很大的差距;应使用一个明确的暂停/恢复消息。</p>
+
+<p class="note"><strong>注意</strong>:有关选项 2 的示例,请参阅 Grafika 的“硬件缩放练习程序”。</p>
+
+<p>这两个选项主要关注如何配置渲染器线程以及线程是否正在执行。一个相关问题是,终止 Activity 时(在 <code>onPause()</code> 或 <code>onSaveInstanceState()</code> 中)从线程中提取状态;在此情况下,选项 1 最有效,因为在渲染器线程加入后,不需要使用同步基元就可以访问其状态。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/architecture.html b/zh-cn/devices/graphics/architecture.html
new file mode 100644
index 00000000..12531ce4
--- /dev/null
+++ b/zh-cn/devices/graphics/architecture.html
@@ -0,0 +1,56 @@
+<html devsite><head>
+ <title>图形架构</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p><em>每位开发者都应了解有关 Surface、SurfaceHolder、EGLSurface、SurfaceView、GLSurfaceView、SurfaceTexture、TextureView、SurfaceFlinger 和 Vulkan 方面的知识。</em></p>
+
+<p>本页将介绍 Android 系统级图形架构的基本要素,并介绍应用框架和多媒体系统如何使用这些要素。我们会重点介绍图形数据的缓冲区是如何在系统中移动的。如果您想了解 SurfaceView 和 TextureView 为何采用现有的运行方式,或者想要了解 Surface 与 EGLSurface 的交互方式,本文会为您逐一解答。</p>
+
+<p>假设您对 Android 设备和应用开发已有一定了解。您不需要掌握有关应用框架的详细知识,本文也很少提及 API 调用,但本材料与其他公开文档互不重叠。本文旨在详细介绍渲染帧以进行输出涉及的重要事件,从而帮助您在设计应用时做出明智的选择。为此,我们自下而上地介绍了 UI 类的工作原理,而不是它们的使用方法。</p>
+
+<p>本部分包括多个页面,从背景材料到 HAL 细节再到用例,进行了全面介绍。首先是对 Android 图形缓冲区进行了解释,并说明了合成和显示机制,然后继续介绍为合成器提供数据的更高级别的机制。我们建议您按照下列顺序阅读相关页面,而不要直接跳到感兴趣的主题。</p>
+
+<h2 id="low_level">低级别组件</h2>
+
+<ul>
+<li><a href="/devices/graphics/arch-bq-gralloc.html">BufferQueue 和 gralloc</a>。BufferQueue 将可生成图形数据缓冲区的组件(生产者)连接到接受数据以便进行显示或进一步处理的组件(消费者)。<em></em><em></em>通过供应商专用 HAL 接口实现的 gralloc 内存分配器将用于执行缓冲区分配任务。<em></em></li>
+
+<li><a href="/devices/graphics/arch-sf-hwc.html">SurfaceFlinger、Hardware Composer 和虚拟显示屏</a>。SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏。Hardware Composer HAL (HWC) 确定使用可用硬件合成缓冲区的最有效的方法,虚拟显示屏使合成输出可在系统内使用(录制屏幕或通过网络发送屏幕)。</li>
+
+<li><a href="/devices/graphics/arch-sh.html">Surface、Canvas 和 SurfaceHolder</a>。Surface 可生成一个通常由 SurfaceFlinger 使用的缓冲区队列。当渲染到 Surface 上时,结果最终将出现在传送给消费者的缓冲区中。Canvas API 提供一种软件实现方法(支持硬件加速),用于直接在 Surface 上绘图(OpenGL ES 的低级别替代方案)。与视图有关的任何内容均涉及到 SurfaceHolder,其 API 可用于获取和设置 Surface 参数(如大小和格式)。</li>
+
+<li><a href="/devices/graphics/arch-egl-opengl.html">EGLSurface 和 OpenGL ES</a>。OpenGL ES (GLES) 定义了用于与 EGL 结合使用的图形渲染 API。EGI 是一个规定如何通过操作系统创建和访问窗口的库(要绘制纹理多边形,请使用 GLES 调用;要将渲染放到屏幕上,请使用 EGL 调用)。此页还介绍了 ANativeWindow,它是 Java Surface 类的 C/C++ 等价类,用于通过原生代码创建 EGL 窗口表面。</li>
+
+<li><a href="/devices/graphics/arch-vulkan.html">Vulkan</a>。Vulkan 是一种用于高性能 3D 图形的低开销、跨平台 API。与 OpenGL ES 一样,Vulkan 提供用于在应用中创建高质量实时图形的工具。Vulkan 的优势包括降低 CPU 开销以及支持 <a href="https://www.khronos.org/spir">SPIR-V 二进制中间</a>语言。</li>
+
+</ul>
+
+<h2 id="high_level">高级别组件</h2>
+
+<ul>
+<li><a href="/devices/graphics/arch-sv-glsv.html">SurfaceView 和 GLSurfaceView</a>。SurfaceView 结合了 Surface 和 View。SurfaceView 的 View 组件由 SurfaceFlinger(而不是应用)合成,从而可以通过单独的线程/进程渲染,并与应用界面渲染隔离。GLSurfaceView 提供帮助程序类来管理 EGL 上下文、线程间通信以及与“Activity 生命周期”的交互(但使用 GLES 时并不需要 GLSurfaceView)。</li>
+
+<li><a href="/devices/graphics/arch-st.html">SurfaceTexture</a>。SurfaceTexture 将 Surface 和 GLES 纹理相结合来创建 BufferQueue,而您的应用是 BufferQueue 的消费者。当生产者将新的缓冲区排入队列时,它会通知您的应用。您的应用会依次释放先前占有的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。Android 7.0 增加了对安全纹理视频播放的支持,以便用户能够对受保护的视频内容进行 GPU 后处理。</li>
+
+<li><a href="/devices/graphics/arch-tv.html">TextureView</a>。TextureView 结合了 View 和 SurfaceTexture。TextureView 对 SurfaceTexture 进行包装,并负责响应回调以及获取新的缓冲区。在绘图时,TextureView 使用最近收到的缓冲区的内容作为其数据源,根据 View 状态指示,在它应该渲染的任何位置和以它应该采用的任何渲染方式进行渲染。View 合成始终通过 GLES 来执行,这意味着内容更新可能会导致其他 View 元素重绘。</li>
+</ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/automate-tests.html b/zh-cn/devices/graphics/automate-tests.html
new file mode 100644
index 00000000..d3e92cee
--- /dev/null
+++ b/zh-cn/devices/graphics/automate-tests.html
@@ -0,0 +1,102 @@
+<html devsite><head>
+ <title>自动执行测试</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>deqp 测试模块可通过多种方式集成到自动化测试系统中。最佳方式取决于现有的测试架构和目标环境。</p>
+
+<p>测试运行的主要输出始终是测试日志文件,即带 <code>.qpa</code> 后缀的文件。可以从测试日志中解析得到完整的测试结果。控制台输出仅包含调试信息,并且可能并非在所有平台上都可获得。</p>
+
+<p>测试二进制文件可以直接从测试自动化系统调用。可以针对特定用例、某个测试集或所有可用测试启动测试二进制文件。如果执行期间发生致命错误(如某些 API 错误或系统崩溃),测试执行过程将会中止。对于回归测试,最佳方式是为单个用例或小型测试集单独调用测试二进制文件,以便在发生严重故障时也可获得部分结果。</p>
+
+<p>deqp 附带命令行测试执行工具,这些工具可与执行服务结合使用,以实现更强大的集成。执行器检测测试过程的终止,然后会在下一个可用用例上恢复测试执行过程。由完整测试会话生成单个日志文件。对于不提供崩溃恢复机制的轻量级测试系统而言,该设置是一个理想之选。</p>
+
+<h2 id="command_line_test_execution_tools">命令行测试执行工具</h2>
+
+<p>当前的命令行工具集包含以下组件:远程测试执行工具、用于执行回归分析的测试日志比较生成器、测试日志转 CSV 文件的转换器、测试日志转 XML 文件的转换器和测试日志转 JUnit 的转换器。</p>
+
+<p>这些工具的源代码位于 <code>executor</code> 目录中,相关的二进制文件内置于 <code>&lt;builddir&gt;/executor</code> 目录中。</p>
+
+<h3 id="command_line_test_executor">命令行测试执行器</h3>
+
+<p>命令行测试执行器是一种便携式 C++ 工具,用于在设备上启动测试运行,并基于 TCP/IP 协议从设备收集生成的日志。该执行器与目标设备上的执行服务 (execserver) 进行通信。二者共同协作,提供从测试过程崩溃恢复等功能。以下示例演示了如何使用命令行测试执行器(使用 <code>--help</code> 可查看更多详细信息):</p>
+
+<h4 id="example_1_run_gles2_functional_tests">示例 1:在 Android 设备上运行 GLES2 功能测试:</h4>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+executor --connect=127.0.0.1 --port=50016 --binaryname=
+com.drawelements.deqp/android.app.NativeActivity
+--caselistdir=caselists
+--testset=dEQP-GLES2.* --out=BatchResult.qpa
+--cmdline="--deqp-crashhandler=enable --deqp-watchdog=enable
+--deqp-gl-config-name=rgba8888d24s8"
+</pre>
+
+<h4 id="example_2_continue_a_partial_opengl">示例 2:在本地继续执行部分 OpenGL ES 2 测试:</h4>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+executor --start-server=execserver/execserver --port=50016
+--binaryname=deqp-gles2 --workdir=modules/opengl
+--caselistdir=caselists
+--testset=dEQP-GLES2.* --exclude=dEQP-GLES2.performance.* --in=BatchResult.qpa
+--out=BatchResult.qpa
+</pre>
+
+<h3 id="test_log_csv_export_and_compare">以 CSV 格式导出测试日志并进行比较</h3>
+
+<p>deqp 具有将测试日志(.<code>qpa </code>文件)转换为 CSV 文件的工具。CSV 输出中包含一系列测试用例及其结果。该工具还可以比较两个或多个批处理结果,并仅列出在输入批处理结果中具有不同状态代码的测试用例。该比较还会列出匹配用例的数量。</p>
+
+<p>CSV 格式的输出内容非常实用,可用于通过标准命令行实用程序或电子表格编辑器进行进一步处理。使用命令行参数 <code>--format=text</code> 还可以选择其他人类可读的纯文本格式。</p>
+
+<h4 id="example_1_export_test_log_in_csv_format">示例 1:以 CSV 格式导出测试日志</h4>
+
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">testlog-to-csv --value=code BatchResult.qpa &gt; Result_statuscodes.csv</code>
+<code class="devsite-terminal">testlog-to-csv --value=details BatchResult.qpa &gt; Result_statusdetails.csv</code>
+</pre>
+
+<h4 id="example_2_list_differences">示例 2:列出两个测试日志中测试结果之间的差异</h4>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+testlog-to-csv --mode=diff --format=text Device_v1.qpa Device_v2.qpa
+</pre>
+
+<p class="note"><strong>注</strong>:参数 <code>--value=code</code> 可输出测试结果代码,如“Pass”或“Fail”。参数 <code>--value=details</code> 可选择对性能、功能或精度测试产生的结果或数值做进一步说明。</p>
+
+<h3 id="test_log_xml_export">以 XML 格式导出测试日志</h3>
+
+<p>测试日志文件可以使用 <code>testlog-to-xml</code> 实用程序转换为有效的 XML 文档。日志支持两种输出模式:</p>
+
+<ul>
+ <li>独立文档模式,其中每个测试用例和 <code>caselist.xml</code> 汇总文档都会写入目标目录
+ </li><li>单个文件模式,其中 <code>.qpa</code> 文件中的所有结果都将写入单个 XML 文档。
+</li></ul>
+
+<p>可使用 XML 样式表在浏览器中查看导出的测试日志文件。示例样式表文档(<code>testlog.xsl</code> 和 <code>testlog.css</code>)位于 <code>doc/testlog-stylesheet</code> 目录中。若要在浏览器中查看日志文件,可将两个样式表文件复制到导出的 XML 文档所在的同一目录。</p>
+
+<p>如果您使用的是 Google Chrome,则必须通过 HTTP 访问这些文件,因为 Chrome 出于安全考虑,会限制对本地文件的访问。标准的 Python 安装包括一个基本的 HTTP 服务器,该服务器可通过 <code>python –m SimpleHTTPServer 8000</code> 命令启动,以作为当前目录。启动服务器后,只需将 Chrome 浏览器指向 <code>http://localhost:8000</code> 即可查看测试日志。</p>
+
+<h3 id="conversion_to_a_junit_test_log">转换为 JUnit 测试日志</h3>
+
+<p>很多测试自动化系统都可以从 JUnit 输出生成测试运行结果报告。可使用 testlog-to-junit 工具将 deqp 测试日志文件转换为 JUnit 输出格式。</p>
+
+<p>该工具目前仅支持转换测试用例判定表。由于 JUnit 仅支持“pass”和“fail”结果,deqp 的通过结果会映射到“JUnit pass”,其他结果则会被视为失败。原始的 deqp 结果代码可从 JUnit 输出中获得。转换时将不会保留日志消息或结果图片等其他数据。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/implement-vdisplays.html b/zh-cn/devices/graphics/implement-vdisplays.html
new file mode 100644
index 00000000..b3c16417
--- /dev/null
+++ b/zh-cn/devices/graphics/implement-vdisplays.html
@@ -0,0 +1,51 @@
+<html devsite><head>
+ <title>实现虚拟显示屏</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android 在 Hardware Composer v1.3 中添加了对虚拟显示屏的平台支持(该支持功能可由 Miracast 使用)。虚拟显示屏合成与物理显示屏类似:在 <code>prepare()</code> 中描述输入层,由 SurfaceFlinger 执行 GPU 合成,然后将图层和 GPU 帧缓冲区提供给 <code>set()</code> 中的 Hardware Composer。</p>
+
+<p>输出不会出现在屏幕上,而是被发送至 gralloc 缓冲区。Hardware Composer 将输出写入缓冲区并提供已完成的栅栏信号。缓冲区会被发送给某一使用方:视频编码器、GPU 和 CPU 等。如果显示通道可以写入内存,虚拟显示屏便可使用 2D/位块传送器或叠加层。</p>
+
+<h2 id="modes">模式</h2>
+
+<p><code>prepare()</code> 之后,每个帧处于以下三种模式之一:</p>
+
+<ul>
+<li>GLES:由 GPU 合成所有图层,GPU 会直接写入输出缓冲区,而 Hardware Composer 将不做任何操作。<em></em>这相当于使用 v1.3 版之前的 Hardware Composer 执行虚拟显示屏合成。</li>
+<li>MIXED:GPU 将一些图层合成到帧缓冲区,由 Hardware Composer 合成帧缓冲区和剩余的图层。<em></em>GPU 写入暂存缓冲区(帧缓冲区);Hardware Composer 读取暂存缓冲区并写入输出缓冲区。缓冲区可能包含不同的格式,例如 RGBA 和 YCbCr。</li>
+<li>HWC:由 Hardware Compose 合成所有图层,Hardware Compose 会直接写入输出缓冲区。<em></em></li>
+</ul>
+
+<h2 id="output_format">输出格式</h2>
+<p>输出格式取决于模式:</p>
+
+<ul>
+<li>MIXED 和 HWC 模式:<em></em>若使用方需要 CPU 访问权限,则由使用方选择格式。否则格式将为 IMPLEMENTATION_DEFINED。Gralloc 可以根据使用标记选择最佳的格式。例如,如果使用方是视频编码器,则选择 YCbCr 格式,而 Hardware Composer 可以高效地写入该格式。</li>
+<li>GLES 模式:<em></em>EGL 驱动程序在 <code>dequeueBuffer()</code> 中选择输出缓冲区格式,通常为 RGBA8888。使用方必须能够接受该格式。</li>
+</ul>
+
+<h2 id="egl_requirement">EGL 要求</h2>
+
+<p>Hardware Composer v1.3 虚拟显示屏要求 <code>eglSwapBuffers()</code> 不会立即使下一个缓冲区出列,而是推迟到渲染开始时才让该缓冲区出列。否则,EGL 将始终占有下一个输出缓冲区。SurfaceFlinger 无法在 MIXED/HWC 模式下为 Hardware Composer 获取输出缓冲区。</p>
+
+<p>若 Hardware Composer 总是将所有虚拟显示屏图层都发送至 GPU,则所有帧都会处于 GLES 模式。我们不推荐使用此方法,但您若出于某些原因需要支持 Hardware Composer v1.3,而又无法进行虚拟显示屏合成,便可使用此方法。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/port-tests.html b/zh-cn/devices/graphics/port-tests.html
new file mode 100644
index 00000000..630dfc7b
--- /dev/null
+++ b/zh-cn/devices/graphics/port-tests.html
@@ -0,0 +1,138 @@
+<html devsite><head>
+ <title>移植测试框架</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>移植 deqp 需要三个步骤:调整基础可移植性库,实现测试框架平台集成接口以及移植执行服务。</p>
+
+<p>下表列出了可能发生移植更改的位置。在此范围之外的位置很可能是有异常情况。</p>
+
+<table>
+ <tbody><tr>
+ <th>位置</th>
+ <th>说明</th>
+ </tr>
+
+ <tr>
+ <td><code>
+framework/delibs/debase<br />
+framework/delibs/dethread<br />
+framework/delibs/deutil</code></td>
+<td><p>操作系统专用代码的任何必要实现。</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/qphelper/qpCrashHandler.c</code></td>
+<td><p>可选:针对操作系统的实现。</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/qphelper/qpWatchDog.c</code></td>
+<td><p>针对操作系统的实现。当前位置是以 <code>dethread</code> 和 C 语言的标准库为基础。</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/platform</code></td>
+<td><p>新的平台端口和应用存根可按照<a href="#test_framework_platform_port">测试框架平台端口</a>中的说明来实现。</p>
+</td>
+ </tr>
+</tbody></table>
+
+<h2 id="base_portability_libraries">基础可移植性库</h2>
+
+<p>基础可移植性库已支持 Windows、大多数 Linux 变体、Mac OS、iOS 和 Android。若测试目标在其中一个操作系统上运行,很可能根本无需动用基础可移植性库。</p>
+
+<h2 id="test_framework_platform_port">测试框架平台端口</h2>
+
+<p>deqp 测试框架平台端口需要两个组件:应用入口点和平台接口实现。</p>
+
+<p>应用入口点负责创建平台对象、创建命令行 (<code>tcu::CommandLine</code>) 对象、打开测试日志 (<code>tcu::TestLog</code>) 以及迭代测试应用 (<code>tcu::App</code>)。若目标操作系统支持标准的 <code>main()</code> 入口点,<code>tcuMain.cpp</code> 可以用作入口点实现。</p>
+
+<p>以下文件详细说明了 deqp 平台 API。</p>
+
+<table>
+ <tbody><tr>
+ <th>文件</th>
+ <th>说明</th>
+ </tr>
+ <tr>
+ <td><code>
+framework/common/tcuPlatform.hpp</code></td>
+<td><p>所有平台端口的基类</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/opengl/gluPlatform.hpp</code></td>
+<td><p>OpenGL 平台接口</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/egl/egluPlatform.hpp</code></td>
+<td><p>EGL 平台接口</p>
+</td>
+ </tr>
+ <tr>
+ <td><code>
+framework/platform/tcuMain.cpp</code></td>
+<td><p>标准应用入口点</p>
+</td>
+ </tr>
+</tbody></table>
+
+<p>所有平台端口的基类都为 <code>tcu::Platform</code>。平台端口可选择性支持 GL 和 EGL 特定接口。请参见下表,大体上了解一下运行测试需要实现的内容。</p>
+
+<table>
+ <tbody><tr>
+ <th>模块</th>
+ <th>接口</th>
+ </tr>
+ <tr>
+ <td><p>OpenGL (ES) 测试模块</p>
+</td>
+ <td><p>GL 平台接口</p>
+</td>
+ </tr>
+ <tr>
+ <td><p>EGL 测试模块</p>
+</td>
+ <td><p>EGL 平台接口</p>
+</td>
+ </tr>
+</tbody></table>
+
+<p>有关实现平台端口的详细说明,请参阅移植层标头。</p>
+
+<h2 id="test_execution_service">测试执行服务</h2>
+
+<p>要使用 deqp 测试执行基础架构或命令行执行程序,目标上必须提供测试执行服务。该服务的可移植 C++ 实现是在 <code>execserver</code> 目录中提供。独立的二进制文件是作为计算机目标的 deqp 测试模块版本的一部分进行构建。您可以修改 <code>execserver/CMakeLists.txt</code>,以便在其他目标中启用相应版本。</p>
+
+<p>C++ 版的测试执行服务接受两个命令行参数:</p>
+
+<ul>
+ <li> <code>--port=&lt;port&gt;</code> 会设置服务器侦听的 TCP 端口。默认端口号为 50016。
+ </li><li> <code>--single</code> 会在客户端断开连接时终止服务器进程。默认情况下,为了进一步处理测试执行请求,服务器进程将保持运行。
+</li></ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/run-tests.html b/zh-cn/devices/graphics/run-tests.html
new file mode 100644
index 00000000..596c6b94
--- /dev/null
+++ b/zh-cn/devices/graphics/run-tests.html
@@ -0,0 +1,259 @@
+<html devsite><head>
+ <title>运行测试</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>本页将介绍如何在 Linux 和 Windows 环境中运行 deqp 测试、如何使用命令行参数,以及如何使用 Android 应用包。</p>
+
+<h2 id="linux_and_windows_environments">Linux 与 Windows 环境</h2>
+
+<p>首先,请将以下文件及目录复制到目标中。</p>
+
+<table>
+ <tbody><tr>
+ <th>模块</th>
+ <th>目录</th>
+ <th>目标</th>
+ </tr>
+
+ <tr>
+ <td>执行服务器</td>
+ <td><code>build/execserver/execserver</code></td>
+ <td><code>&lt;dst&gt;/execserver</code></td>
+ </tr>
+
+ <tr>
+ <td>EGL 模块</td>
+ <td><code>build/modules/egl/deqp-egl</code></td>
+ <td><code>&lt;dst&gt;/deqp-egl</code></td>
+ </tr>
+
+ <tr>
+ <td rowspan="2" style="vertical-align:middle">GLES2 模块</td>
+ <td><code>build/modules/gles2/deqp-gles2</code></td>
+ <td><code>&lt;dst&gt;/deqp-gles2</code></td>
+ </tr>
+
+ <tr>
+ <td><code>data/gles2</code></td>
+ <td><code>&lt;dst&gt;/gles2</code></td>
+ </tr>
+
+ <tr>
+ <td rowspan="2" style="vertical-align:middle">GLES3 模块</td>
+ <td><code>build/modules/gles3/deqp-gles3</code></td>
+ <td><code>&lt;dst&gt;/deqp-gles3</code></td>
+ </tr>
+
+ <tr>
+ <td><code>data/gles3</code></td>
+ <td><code>&lt;dst&gt;/gles3</code></td>
+ </tr>
+
+ <tr>
+ <td rowspan="2" style="vertical-align:middle">GLES3.1 模块</td>
+ <td><code>build/modules/gles31/deqp-gles31</code></td>
+ <td><code>&lt;dst&gt;/deqp-gles31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>data/gles31</code></td>
+ <td><code>&lt;dst&gt;/gles31</code></td>
+ </tr>
+
+ <tr>
+ <td rowspan="2" style="vertical-align:middle">GLES3.2 模块</td>
+ <td><code>build/modules/gles32/deqp-gles32</code></td>
+ <td><code>&lt;dst&gt;/deqp-gles32</code></td>
+ </tr>
+
+ <tr>
+ <td><code>data/gles32</code></td>
+ <td><code>&lt;dst&gt;/gles32</code></td>
+ </tr>
+
+</tbody></table>
+
+<p>您可以在目标文件系统的任意位置部署执行服务和测试二进制文件,但是测试二进制文件需要在当前的工作目录中查找数据目录。准备就绪后,在目标设备上启动测试执行服务。有关如何启动服务的详细信息,请参阅<a href="/devices/graphics/port-tests.html#test_execution_service">测试执行服务</a>一节。</p>
+
+<h2 id="command_line_arguments">命令行参数</h2>
+
+<p>下表列出了影响所有测试程序执行的命令行参数。</p>
+
+<table width="100%">
+<colgroup><col style="width:50%" />
+<col style="width:50%" />
+ </colgroup><tbody><tr>
+ <th>参数</th>
+ <th>说明</th>
+ </tr>
+
+ <tr>
+<td><code>--deqp-case=&lt;casename&gt;</code></td>
+<td>运行与指定模式匹配的用例。支持通配符 (*)。</td>
+ </tr>
+
+ <tr>
+<td><code>--deqp-log-filename=&lt;filename&gt;</code></td>
+<td>将测试结果写入文件,文件名由您提供。测试执行服务将在开始测试时设置文件名。</td>
+ </tr>
+
+ <tr>
+ <td><code>--deqp-stdin-caselist<br />
+--deqp-caselist=&lt;caselist&gt;<br />
+--deqp-caselist-file=&lt;filename&gt;</code></td>
+<td>通过 stdin 或指定的参数读取用例列表。测试执行服务将根据收到的执行请求设置参数。有关用例列表格式的说明,请参阅下一节。</td>
+ </tr>
+ <tr>
+<td><code>--deqp-test-iteration-count=&lt;count&gt;</code></td>
+<td>覆盖迭代次数可变之测试的迭代计数。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-base-seed=&lt;seed&gt;</code></td>
+ <td>为采用随机测试的测试用例设定种子。</td>
+ </tr>
+</tbody></table>
+
+<h3 id="gles2_and_gles3-specific_arguments">特定于 GLES2 及 GLES3 的参数</h3>
+
+下表列出了特定于 GLES2 及 GLES3 的参数。
+
+<table>
+</table><table width="100%">
+<colgroup><col style="width:50%" />
+<col style="width:50%" />
+ </colgroup><tbody><tr>
+ <th>参数</th>
+ <th>说明</th>
+ </tr>
+ <tr>
+ <td><code>--deqp-gl-context-type=&lt;type&gt;</code></td>
+ <td>OpenGL 上下文类型。提供的上下文类型取决于平台。在支持 EGL 的平台上,值 <code>egl</code> 可用于选择 EGL 上下文。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-gl-config-id=&lt;id&gt;</code></td>
+ <td>对所提供的 GL 配置 ID 运行测试。解译取决于平台。在 EGL 平台上,该配置 ID 为 EGL 配置 ID。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-gl-config-name=&lt;name&gt;</code></td>
+ <td><p>对已命名的 GL 配置运行测试。解译取决于平台。对于 EGL,格式为 <code>rgb(a)&lt;bits&gt;d&lt;bits&gt;s&lt;bits&gt;</code>。例如,值 <code>rgb888s8</code> 会选择第一个配置,其中颜色缓冲区为 RGB888,模板缓冲区为 8 位。</p></td>
+ </tr>
+ <tr>
+ <td><code>--deqp-gl-context-flags=&lt;flags&gt;</code></td>
+ <td>创建一个上下文。指定 <code>robust</code> 或 <code>debug</code>。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-surface-width=&lt;width&gt;<br />
+ --deqp-surface-height=&lt;height&gt;</code></td>
+ <td>尝试使用指定的尺寸创建表面。对这项功能的支持为可选项。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-surface-type=&lt;type&gt;</code></td>
+ <td>将指定的表面类型用作主测试渲染目标。可取类型为 <code>window</code>、<code>pixmap</code>、<code>pbuffer</code> 和 <code>fbo</code>。</td>
+ </tr>
+ <tr>
+ <td><code>--deqp-screen-rotation=&lt;rotation&gt;</code></td>
+ <td>对于支持该参数的平台,屏幕方向的旋转增量为 90 度。</td>
+ </tr>
+</tbody></table>
+
+<h3 id="test_case_list_format">测试用例列表格式</h3>
+
+<p>测试用例列表有两种格式。第一种选项是在标准 ASCII 文件的单独一行中列出每个测试的全名。随着测试集的增长,重复添加前缀可能会很麻烦。为避免重复添加前缀,可使用以下所示的 trie(也称为前缀树)语法。</p>
+
+<pre class="devsite-click-to-copy">
+{nodeName{firstChild{…},…lastChild{…}}}
+</pre>
+
+<p>例如:</p>
+
+<pre class="devsite-click-to-copy">
+{dEQP-EGL{config-list,create_context{rgb565_depth_stencil}}}
+</pre>
+
+<p>会转换为以下两个测试用例:</p>
+
+<pre class="devsite-click-to-copy">
+dEQP-EGL.config_list
+dEQP-EGL.create_context.rgb565_depth_stencil
+</pre>
+
+<h2 id="android">Android</h2>
+
+<p>Android 应用包包含所需的所有组件,包括测试执行服务、测试二进制文件和数据文件。测试活动是使用 EGL 的 <code>NativeActivity</code>(需要 Android 3.2 或更高版本)。</p>
+
+<p>应用包可使用以下命令安装(所示名称为 Android CTS 包中 APK 的名称;该名称因版本而异):</p>
+<pre class="devsite-terminal devsite-click-to-copy">
+adb –d install –r com.drawelements.deqp.apk
+</pre>
+
+<p>要启动测试执行服务并设置端口转发,请使用以下命令:</p>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb –d forward tcp:50016 tcp:50016</code>
+<code class="devsite-terminal">adb –d shell am start –n com.drawelements.deqp/.execserver.ServiceStarter</code>
+</pre>
+
+<p>在开始测试之前,可执行以下命令来启用调试打印:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+adb –d shell setprop log.tag.dEQP DEBUG
+</pre>
+
+<h3 id="executing_tests_on_android_without_android_cts">在没有 Android CTS 的 Android 设备上执行测试</h3>
+
+<p>要手动启动测试执行活动,需构造一个目标为 <code>android.app.NativeActivity</code> 的 Android Intent。这些活动可以在 <code>com.drawelements.deqp</code> 包中找到。在 Intent 中,命令行必须以含 <code>"cmdLine"</code> 键的额外字符串提供。</p>
+
+<p>测试日志写入 <code>/sdcard/dEQP-log.qpa</code>。若测试运行无法正常启动,请查看设备日志,了解其他调试信息。</p>
+
+<p>您可使用 <code>am</code> 实用程序从命令行启动活动。例如,要在支持 <code>NativeActivity,</code> 的平台上运行 <code>dEQP-GLES2.info</code> 测试,请执行以下命令。</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+adb -d shell am start -n com.drawelements.deqp/android.app.NativeActivity -e \
+cmdLine "deqp --deqp-case=dEQP-GLES2.info.* --deqp-log-filename=/sdcard/dEQP-Log.qpa
+</pre>
+
+<h3 id="debugging_on_android">在 Android 系统上调试</h3>
+
+<p>要采用 Android 系统中的 GDB 调试器运行测试,首先要运行以下两个脚本来编译并安装调试版本:</p>
+
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">python android/scripts/build.py --native-build-type=Debug</code>
+<code class="devsite-terminal">python android/scripts/install.py</code>
+</pre>
+
+<p>当设备上安装调试版本后,要采用主机上运行的 GDB 启动测试,请运行以下命令:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+python android/scripts/debug.py \
+--deqp-commandline="--deqp-log-filename=/sdcard/TestLog.qpa --deqp-case=dEQP-GLES2.functional.*"
+</pre>
+
+<p>deqp 命令行取决于要执行的测试用例和其他所需参数。脚本会在开始执行 deqp 时添加一个默认断点 (<code>tcu::App::App</code>)。</p>
+
+<p><code>debug.py</code> 脚本接受多个命令行参数用于相关操作,例如:设置调试断点、gdbserver 连接参数及要调试的其他二进制文件的路径(对于所有参数和解释,都执行 <code>debug.py
+--help</code>)。该脚本还会从目标设备中复制一些默认库,以获取符号列表。</p>
+
+<p>要逐步检查驱动程序代码(例如,当 GDB 需要了解具有完整调试信息的二进制文件的位置时),请执行 <code>debug.py</code> 命令行参数,以添加更多的库。该脚本从脚本文件的第 132 行开始写出 GDB 的配置文件。您还可以提供额外的二进制路径等信息,但提供正确的命令行参数就已足够。</p>
+
+<p class="note"><strong>注意</strong>:在 Windows 上,GDB 二进制文件需要使用 <code>libpython2.7.dll</code>。在启动 <code>debug.py</code> 前,请将 <code>&lt;path-to-ndk&gt;/prebuilt/windows/bin</code> 添加到 PATH 变量中。</p>
+
+<p class="note"><strong>注意</strong>:本机代码调试不适用于 Android 4.3。有关解决方法,请参考<a href="https://issuetracker.google.com/issues/36976703">相关公开错误</a>。Android 4.4 及更高版本不包含此错误。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/graphics/test-groups.html b/zh-cn/devices/graphics/test-groups.html
new file mode 100644
index 00000000..15f357e2
--- /dev/null
+++ b/zh-cn/devices/graphics/test-groups.html
@@ -0,0 +1,49 @@
+<html devsite><head>
+ <title>使用特殊测试组</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>某些测试组可能需要或支持特殊命令行选项,或在特定系统上使用时需要特别注意。</p>
+
+<h2 id="memory_allocation_stress_tests">内存分配压力测试</h2>
+
+<p>内存分配压力测试会模拟测试内存不足的情况,方法是重复分配特定资源,直到驱动程序报告内存不足错误。</p>
+
+<p>在某些平台(例如 Android 和大多数 Linux 变体)上,可能会发生以下情况:操作系统可能会终止测试进程,而非允许驱动程序处理或以其他方式产生内存不足错误。在此类平台上,旨在产生内存不足错误的测试默认处于停用状态,必须使用 <code>--deqp-test-oom=enable</code> 命令行参数来启用。建议您手动运行此类测试,以检查系统在面临资源压力时是否正常运行。不过在这种情况下,测试过程崩溃应被视为通过测试。</p>
+
+<h3 id="test_groups">测试组</h3>
+
+<pre class="devsite-click-to-copy">
+dEQP-GLES2.stress.memory.*
+dEQP-GLES3.stress.memory.*
+</pre>
+
+<h2 id="long-running_rendering_stress_tests">长时间运行的渲染压力测试</h2>
+
+<p>渲染压力测试旨在揭示持续渲染负载下的稳健性问题。默认情况下,测试仅会执行几次迭代,但可通过提供 <code>--deqp-test-iteration-count=-1</code> 命令行参数来配置为无限期运行。如果要长时间运行这些测试,应停用测试监控程序 (<code>--deqp-watchdog=disable</code>)。</p>
+
+<h3 id="test_groups2">测试组</h3>
+
+<pre class="devsite-click-to-copy">
+dEQP-GLES2.stress.long.*
+dEQP-GLES3.stress.long.*
+</pre>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/index.html b/zh-cn/devices/index.html
new file mode 100644
index 00000000..e46f65cc
--- /dev/null
+++ b/zh-cn/devices/index.html
@@ -0,0 +1,137 @@
+<html devsite><head>
+ <title>Android 接口和架构</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>
+Android 可让您自由实现您自己的设备规格和驱动程序。硬件抽象层 (HAL) 提供了一种用于在 Android 平台堆叠和硬件之间创建软件钩的标准方法。Android 操作系统也是开放源代码系统,因此您可以贡献您自己的接口和增强功能。
+</p>
+
+<p>
+为确保设备能够保持较高的质量水平并提供一致的用户体验,每部设备都必须通过兼容性测试套件 (CTS) 中的测试。CTS 可验证设备是否符合一定的质量标准,此类标准可确保应用稳定运行并提供良好的用户体验。若想详细了解 CTS,请参阅<a href="/compatibility/index.html">兼容性</a>。
+</p>
+
+<p>
+在将 Android 移植到您的硬件之前,请花点时间从更高层面上了解 Android 系统架构。由于您的驱动程序和 HAL 会与 Android 进行交互,因此了解 Android 的工作原理可帮助您浏览 Android 开放源代码项目 (AOSP) 源代码树中的多个代码层。
+</p>
+
+<img src="images/ape_fwk_all.png"/>
+
+<p class="img-caption"><strong>图 1.</strong> Android 系统架构</p>
+
+<h2 id="Application-framework">应用框架</h2>
+<p>
+应用框架最常被应用开发者使用。作为硬件开发者,您应该非常了解开发者 API,因为很多此类 API 都可直接映射到底层 HAL 接口,并可提供与实现驱动程序相关的实用信息。
+</p>
+
+<h2 id="Binder-IPC">Binder IPC</h2>
+<p>
+Binder 进程间通信 (IPC) 机制允许应用框架跨越进程边界并调用 Android 系统服务代码,从而使得高级框架 API 能与 Android 系统服务进行交互。在应用框架级别,开发者无法看到此类通信的过程,但一切似乎都在“按部就班地运行”。
+</p>
+
+<h2 id="System-services">系统服务</h2>
+<p>
+应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。服务是集中的模块化组件,例如窗口管理器、搜索服务或通知管理器。Android 包含两组服务:“系统”(诸如窗口管理器和通知管理器之类的服务)和“媒体”(与播放和录制媒体相关的服务)。<em></em><em></em>
+</p>
+
+<h2 id="Hardware-Abstraction-Layer">硬件抽象层 (HAL)</h2>
+<p>
+硬件抽象层 (HAL) 会定义一个标准接口以供硬件供应商实现,并允许 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或无需更改更高级别的系统。HAL 实现会被封装成模块 (<code>.so</code>) 文件,并会由 Android 系统适时地加载。
+</p>
+
+<img src="images/ape_fwk_hal.png"/>
+
+<p class="img-caption"><strong>图 2.</strong> 硬件抽象层 (HAL) 组件</p>
+
+<p>
+您必须为您的产品所提供的特定硬件实现相应的 HAL(和驱动程序)。HAL 实现通常会内置在共享库模块(<code>.so</code> 文件)中。Android 并不要求您的 HAL 实现与设备驱动程序之间进行标准交互,因此您可以自由地根据您的具体情况执行适当的操作。不过,要使 Android 系统能够与您的硬件正确互动,您<strong>必须</strong>遵守各个针对特定硬件的 HAL 接口中定义的合同。
+</p>
+
+<h3 id="structure">标准 HAL 结构</h3>
+<p>
+ 每个针对特定硬件的 HAL 接口均具有 <code>hardware/libhardware/include/hardware/hardware.h</code> 中定义的属性,这些属性可保证 HAL 具有可预测的结构。此类接口允许 Android 系统以一致的方式加载 HAL 模块的正确版本。HAL 接口包含两个通用组件:一个模块和一个设备。
+</p>
+<p>
+ 模块表示被封装且存储为共享库 (<code>.so file</code>) 的 HAL 实现。它会包含模块的版本、名称和作者等元数据,这些元数据有助于 Android 找到并正确加载该模块。<code>hardware/libhardware/include/hardware/hardware.h</code> 标头文件会定义一个表示模块的结构体 (<code>hw_module_t</code>),其中会包含模块的版本、作者和名称等信息。</p>
+
+ <p>另外,<code>hw_module_t</code> 结构体还会包含一个指向另一结构体 <code>hw_module_methods_t</code> 的指针,后面这个结构体则会包含一个指向相应模块的“open”函数的指针。该“open”函数用于与相关硬件(此 HAL 是其抽象形式)建立通信。每个针对特定硬件的 HAL 通常都会使用附加信息为该特定硬件扩展通用的 <code>hw_module_t</code> 结构体。例如,在相机 HAL 中,<code>camera_module_t</code> 结构体会包含一个 <code>hw_module_t</code> 结构体以及其他针对相机的函数指针:
+</p>
+
+<pre class="devsite-click-to-copy">
+typedef struct camera_module {
+ hw_module_t common;
+ int (*get_number_of_cameras)(void);
+ int (*get_camera_info)(int camera_id, struct camera_info *info);
+} camera_module_t;
+</pre>
+
+<p>当您实现 HAL 并创建模块结构体时,必须将其命名为 <code>HAL_MODULE_INFO_SYM</code>。例如,以下是 Nexus 9 音频 HAL 的示例:</p>
+
+<pre class="devsite-click-to-copy">
+struct audio_module HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "NVIDIA Tegra Audio HAL",
+ .author = "The Android Open Source Project",
+ .methods = &amp;hal_module_methods,
+ },
+};
+</pre>
+<p>
+ 设备会提取产品的实际硬件。例如,音频模块可能会包含主音频设备、USB 音频设备或蓝牙 A2DP 音频设备。设备由 <code>hw_device_t</code> 结构体表示。与模块类似,每类设备都会为通用的 <code>hw_device_t</code> 定义一个更详细的版本,其中会包含指向硬件特定功能的函数指针。例如,<code>audio_hw_device_t</code> 结构体类型会包含指向音频设备操作的函数指针:
+</p>
+
+<pre class="devsite-click-to-copy">
+struct audio_hw_device {
+ struct hw_device_t common;
+
+ /**
+ * used by audio flinger to enumerate what devices are supported by
+ * each audio_hw_device implementation.
+ *
+ * Return value is a bitmask of 1 or more values of audio_devices_t
+ */
+ uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
+ ...
+};
+typedef struct audio_hw_device audio_hw_device_t;
+</pre>
+
+<p>
+ 除了这些标准属性之外,每个针对特定硬件的 HAL 接口都可以定义更多的自有特性和要求。若想详细了解如何实现某个特定接口,请参阅 <a href="/reference/hal/">HAL 参考文档</a>以及各 HAL 的单独说明。
+</p>
+
+<h3 id="modules">HAL 模块</h3>
+<p>HAL 实现会内置在模块 (<code>.so</code>) 文件中,并会由 Android 适时地动态关联。您可通过为每个 HAL 实现创建 <code>Android.mk</code> 文件并指向源文件来构建模块。一般来说,您的共享库必须以某种格式命名,以便被找到并正确加载。各模块的命名方案略有不同,但它们都遵循以下通用模式:<code>&lt;module_type&gt;.&lt;device_name&gt;</code>。</p>
+
+ <p>若想详细了解如何为每个 HAL 设置模块构建,请参阅各 HAL 对应的文档。</p>
+
+<h2 id="Linux-kernel">Linux 内核</h2>
+<p>
+开发设备驱动程序与开发典型的 Linux 设备驱动程序类似。Android 使用的 Linux 内核版本包含一些特殊的补充功能,例如:唤醒锁(这是一种内存管理系统,可更主动地保护内存)、Binder IPC 驱动程序以及对移动嵌入式平台非常重要的其他功能。这些补充功能主要用于增强系统功能,不会影响驱动程序开发。
+
+</p><p>
+您可以使用任一版本的内核,只要它支持所需功能(如 Binder 驱动程序)。不过,我们建议您使用 Android 内核的最新版本。若想详细了解 Android 内核的最新版本,请参阅<a href="/source/building-kernels.html">构建内核</a>。
+</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/input/diagnostics.html b/zh-cn/devices/input/diagnostics.html
new file mode 100644
index 00000000..8e9ecb52
--- /dev/null
+++ b/zh-cn/devices/input/diagnostics.html
@@ -0,0 +1,465 @@
+<html devsite><head>
+ <title>dumpsys 输入诊断</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p><code>dumpsys</code> 输入命令可转储系统输入设备(例如键盘和触摸屏)的状态以及输入事件的处理。</p>
+
+<h2 id="input">输入</h2>
+<p>要转储输入系统的状态,请执行以下命令:</p>
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell dumpsys input
+</pre>
+
+<h2 id="output">输出</h2>
+
+<p>报告的信息集因 Android 版本而异,但均由以下三个部分组成:</p>
+
+<ul>
+ <li>Event Hub 状态
+ </li><li>Input Reader 状态
+ </li><li>Input Dispatcher 状态
+</li></ul>
+
+<h3 id="event_hub_state">Event Hub 状态</h3>
+
+<pre class="devsite-click-to-copy">
+INPUT MANAGER (dumpsys input)
+
+Event Hub State:
+ BuiltInKeyboardId: -2
+ Devices:
+ -1: Virtual
+ Classes: 0x40000023
+ Path: <virtual>
+ Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd
+ Location:
+ ControllerNumber: 0
+ UniqueId: <virtual>
+ Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
+ KeyLayoutFile: /system/usr/keylayout/Generic.kl
+ KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+ 1: msm8974-taiko-mtp-snd-card Headset Jack
+ Classes: 0x00000080
+ Path: /dev/input/event5
+ Descriptor: c8e3782483b4837ead6602e20483c46ff801112c
+ Location: ALSA
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
+ KeyLayoutFile:
+ KeyCharacterMapFile:
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+ 2: msm8974-taiko-mtp-snd-card Button Jack
+ Classes: 0x00000001
+ Path: /dev/input/event4
+ Descriptor: 96fe62b244c555351ec576b282232e787fb42bab
+ Location: ALSA
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
+ KeyLayoutFile: /system/usr/keylayout/msm8974-taiko-mtp-snd-card_Button_Jack.kl
+ KeyCharacterMapFile: /system/usr/keychars/msm8974-taiko-mtp-snd-card_Button_Jack.kcm
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+ 3: hs_detect
+ Classes: 0x00000081
+ Path: /dev/input/event3
+ Descriptor: 485d69228e24f5e46da1598745890b214130dbc4
+ Location:
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0000, vendor=0x0001, product=0x0001, version=0x0001
+ KeyLayoutFile: /system/usr/keylayout/hs_detect.kl
+ KeyCharacterMapFile: /system/usr/keychars/hs_detect.kcm
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+ 4: touch_dev
+ Classes: 0x00000014
+ Path: /dev/input/event1
+ Descriptor: 4e2720e99bd2b59adae8529881343531fff7c98e
+ Location:
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
+ KeyLayoutFile:
+ KeyCharacterMapFile:
+ ConfigurationFile: /system/usr/idc/touch_dev.idc
+ HaveKeyboardLayoutOverlay: false
+ 5: qpnp_pon
+ Classes: 0x00000001
+ Path: /dev/input/event0
+ Descriptor: fb60d4f4370f5dbe8267b63d38dea852987571ab
+ Location: qpnp_pon/input0
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
+ KeyLayoutFile: /system/usr/keylayout/qpnp_pon.kl
+ KeyCharacterMapFile: /system/usr/keychars/qpnp_pon.kcm
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+ 6: gpio-keys
+ Classes: 0x00000081
+ Path: /dev/input/event2
+ Descriptor: d2c52ff0f656fac4cd7b7a118d575e0109a9fe1c
+ Location: gpio-keys/input0
+ ControllerNumber: 0
+ UniqueId:
+ Identifier: bus=0x0019, vendor=0x0001, product=0x0001, version=0x0100
+ KeyLayoutFile: /system/usr/keylayout/gpio-keys.kl
+ KeyCharacterMapFile: /system/usr/keychars/gpio-keys.kcm
+ ConfigurationFile:
+ HaveKeyboardLayoutOverlay: false
+</virtual></virtual></pre>
+
+<h4 id="things-to-look-for">检查事项</h4>
+
+<ul>
+ <li>所有预期输入设备是否都存在。</li>
+
+ <li>每个输入设备是否都有适当的按键布局文件、按键字符映射文件和输入设备配置文件。如果这些文件丢失或包含语法错误,将无法加载。</li>
+
+ <li>每个输入设备是否都已正确分类。<code>Classes</code> 字段中的位是否对应 <code>EventHub.h</code> 中的标记,如 <code>INPUT_DEVICE_CLASS_TOUCH_MT</code>。</li>
+
+ <li><code>BuiltInKeyboardId</code> 是否正确。若设备未配备内置键盘,则该 ID 必须为 <code>-2</code>,否则应为内置键盘的 ID。</li>
+
+ <li>若发现 <code>BuiltInKeyboardId</code> 不是预期的 <code>-2</code>,说明在某处缺少某个特殊功能小键盘的按键字符映射文件。特殊功能小键盘设备应具有仅包含 <code>type
+ SPECIAL_FUNCTION</code> 行(即我们在前述 <code>tuna-gpio-keykad.kcm</code> 文件中看到的内容)的按键字符映射文件。</li>
+</ul>
+
+<h3 id="input-reader-state">Input Reader 状态</h3>
+<p><code>InputReader</code> 负责对来自内核的输入事件进行解码。其状态转储显示各输入设备的配置信息以及最近发生的状态变化相关信息,如按下按键或触摸触摸屏等操作。</p>
+
+<p>例如,以下为特殊功能小键盘的状态信息:</p>
+
+<pre class="devsite-click-to-copy">
+Input Reader State
+...
+ Device 3: tuna-gpio-keypad
+ IsExternal: false
+ Sources: 0x00000101
+ KeyboardType: 1
+ Keyboard Input Mapper:
+ Parameters:
+ AssociatedDisplayId: -1
+ OrientationAware: false
+ KeyboardType: 1
+ Orientation: 0
+ KeyDowns: 0 keys currently down
+ MetaState: 0x0
+ DownTime: 75816923828000
+</pre>
+
+<p>以下是触摸屏的状态信息。注意所有有关设备分辨率和所用校准参数的信息。</p>
+
+<pre class="devsite-click-to-copy">
+Input Reader State
+...
+ Device 6: Melfas MMSxxx Touchscreen
+ IsExternal: false
+ Sources: 0x00001002
+ KeyboardType: 0
+ Motion Ranges:
+ X: source=0x00001002, min=0.000, max=719.001, flat=0.000, fuzz=0.999
+ Y: source=0x00001002, min=0.000, max=1279.001, flat=0.000, fuzz=0.999
+ PRESSURE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000
+ SIZE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000
+ TOUCH_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
+ TOUCH_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
+ TOOL_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
+ TOOL_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000
+ Touch Input Mapper:
+ Parameters:
+ GestureMode: spots
+ DeviceType: touchScreen
+ AssociatedDisplay: id=0, isExternal=false
+ OrientationAware: true
+ Raw Touch Axes:
+ X: min=0, max=720, flat=0, fuzz=0, resolution=0
+ Y: min=0, max=1280, flat=0, fuzz=0, resolution=0
+ Pressure: min=0, max=255, flat=0, fuzz=0, resolution=0
+ TouchMajor: min=0, max=30, flat=0, fuzz=0, resolution=0
+ TouchMinor: unknown range
+ ToolMajor: unknown range
+ ToolMinor: unknown range
+ Orientation: unknown range
+ Distance: unknown range
+ TiltX: unknown range
+ TiltY: unknown range
+ TrackingId: min=0, max=65535, flat=0, fuzz=0, resolution=0
+ Slot: min=0, max=9, flat=0, fuzz=0, resolution=0
+ Calibration:
+ touch.size.calibration: diameter
+ touch.size.scale: 10.000
+ touch.size.bias: 0.000
+ touch.size.isSummed: false
+ touch.pressure.calibration: amplitude
+ touch.pressure.scale: 0.005
+ touch.orientation.calibration: none
+ touch.distance.calibration: none
+ SurfaceWidth: 720px
+ SurfaceHeight: 1280px
+ SurfaceOrientation: 0
+ Translation and Scaling Factors:
+ XScale: 0.999
+ YScale: 0.999
+ XPrecision: 1.001
+ YPrecision: 1.001
+ GeometricScale: 0.999
+ PressureScale: 0.005
+ SizeScale: 0.033
+ OrientationCenter: 0.000
+ OrientationScale: 0.000
+ DistanceScale: 0.000
+ HaveTilt: false
+ TiltXCenter: 0.000
+ TiltXScale: 0.000
+ TiltYCenter: 0.000
+ TiltYScale: 0.000
+ Last Button State: 0x00000000
+ Last Raw Touch: pointerCount=0
+ Last Cooked Touch: pointerCount=0
+</pre>
+
+<p>以下是由外接键盘和鼠标组合的 HID 设备的状态信息。(该设备实际并未配备鼠标,但其 HID 描述符称其配有鼠标。)</p>
+
+<pre class="devsite-click-to-copy">
+ Device 7: Motorola Bluetooth Wireless Keyboard
+ IsExternal: true
+ Sources: 0x00002103
+ KeyboardType: 2
+ Motion Ranges:
+ X: source=0x00002002, min=0.000, max=719.000, flat=0.000, fuzz=0.000
+ Y: source=0x00002002, min=0.000, max=1279.000, flat=0.000, fuzz=0.000
+ PRESSURE: source=0x00002002, min=0.000, max=1.000, flat=0.000, fuzz=0.000
+ VSCROLL: source=0x00002002, min=-1.000, max=1.000, flat=0.000, fuzz=0.000
+ Keyboard Input Mapper:
+ Parameters:
+ AssociatedDisplayId: -1
+ OrientationAware: false
+ KeyboardType: 2
+ Orientation: 0
+ KeyDowns: 0 keys currently down
+ MetaState: 0x0
+ DownTime: 75868832946000
+ Cursor Input Mapper:
+ Parameters:
+ AssociatedDisplayId: 0
+ Mode: pointer
+ OrientationAware: false
+ XScale: 1.000
+ YScale: 1.000
+ XPrecision: 1.000
+ YPrecision: 1.000
+ HaveVWheel: true
+ HaveHWheel: false
+ VWheelScale: 1.000
+ HWheelScale: 1.000
+ Orientation: 0
+ ButtonState: 0x00000000
+ Down: false
+ DownTime: 0
+</pre>
+<p>以下是操纵杆的状态信息。注意所有的轴是如何缩放到标准化范围的。轴映射可使用按键布局文件进行配置。</p>
+<pre class="devsite-click-to-copy">
+Device 18: Logitech Logitech Cordless RumblePad 2
+ IsExternal: true
+ Sources: 0x01000511
+ KeyboardType: 1
+ Motion Ranges:
+ X: source=0x01000010, min=-1.000, max=1.000, flat=0.118, fuzz=0.000
+ Y: source=0x01000010, min=-1.000, max=1.000, flat=0.118, fuzz=0.000
+ Z: source=0x01000010, min=-1.000, max=1.000, flat=0.118, fuzz=0.000
+ RZ: source=0x01000010, min=-1.000, max=1.000, flat=0.118, fuzz=0.000
+ HAT_X: source=0x01000010, min=-1.000, max=1.000, flat=0.000, fuzz=0.000
+ HAT_Y: source=0x01000010, min=-1.000, max=1.000, flat=0.000, fuzz=0.000
+ Keyboard Input Mapper:
+ Parameters:
+ AssociatedDisplayId: -1
+ OrientationAware: false
+ KeyboardType: 1
+ Orientation: 0
+ KeyDowns: 0 keys currently down
+ MetaState: 0x0
+ DownTime: 675270841000
+ Joystick Input Mapper:
+ Axes:
+ X: min=-1.00000, max=1.00000, flat=0.11765, fuzz=0.00000
+ scale=0.00784, offset=-1.00000, highScale=0.00784, highOffset=-1.00000
+ rawAxis=0, rawMin=0, rawMax=255, rawFlat=15, rawFuzz=0, rawResolution=0
+ Y: min=-1.00000, max=1.00000, flat=0.11765, fuzz=0.00000
+ scale=0.00784, offset=-1.00000, highScale=0.00784, highOffset=-1.00000
+ rawAxis=1, rawMin=0, rawMax=255, rawFlat=15, rawFuzz=0, rawResolution=0
+ Z: min=-1.00000, max=1.00000, flat=0.11765, fuzz=0.00000
+ scale=0.00784, offset=-1.00000, highScale=0.00784, highOffset=-1.00000
+ rawAxis=2, rawMin=0, rawMax=255, rawFlat=15, rawFuzz=0, rawResolution=0
+ RZ: min=-1.00000, max=1.00000, flat=0.11765, fuzz=0.00000
+ scale=0.00784, offset=-1.00000, highScale=0.00784, highOffset=-1.00000
+ rawAxis=5, rawMin=0, rawMax=255, rawFlat=15, rawFuzz=0, rawResolution=0
+ HAT_X: min=-1.00000, max=1.00000, flat=0.00000, fuzz=0.00000
+ scale=1.00000, offset=0.00000, highScale=1.00000, highOffset=0.00000
+ rawAxis=16, rawMin=-1, rawMax=1, rawFlat=0, rawFuzz=0, rawResolution=0
+ HAT_Y: min=-1.00000, max=1.00000, flat=0.00000, fuzz=0.00000
+ scale=1.00000, offset=0.00000, highScale=1.00000, highOffset=0.00000
+ rawAxis=17, rawMin=-1, rawMax=1, rawFlat=0, rawFuzz=0, rawResolution=0
+</pre>
+<p>在 Input Reader 转储的结尾部分,会显示一些关于全局配置参数的信息,例如鼠标指针移动速度。</p>
+<pre class="devsite-click-to-copy">
+ Configuration:
+ ExcludedDeviceNames: []
+ VirtualKeyQuietTime: 0.0ms
+ PointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000
+ WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000
+ PointerGesture:
+ Enabled: true
+ QuietInterval: 100.0ms
+ DragMinSwitchSpeed: 50.0px/s
+ TapInterval: 150.0ms
+ TapDragInterval: 300.0ms
+ TapSlop: 20.0px
+ MultitouchSettleInterval: 100.0ms
+ MultitouchMinDistance: 15.0px
+ SwipeTransitionAngleCosine: 0.3
+ SwipeMaxWidthRatio: 0.2
+ MovementSpeedRatio: 0.8
+ ZoomSpeedRatio: 0.3
+</pre>
+<h4 id="things-to-look-for_1">检查事项</h4>
+<ol>
+<li>
+<p>所有的预期输入设备是否都存在。</p>
+</li>
+<li>
+<p>各个输入设备是否都已配置正确。需特别留意触摸屏和操纵杆轴的配置。</p>
+</li>
+</ol>
+<h3 id="input-dispatcher-state">Input Dispatcher 状态</h3>
+<p><code>InputDispatcher</code> 负责向应用发送输入事件。其状态转储显示有关哪个窗口被触摸、输入队列的状态以及是否存在 ANR 等信息。</p>
+<pre class="devsite-click-to-copy">
+Input Dispatcher State:
+ DispatchEnabled: 1
+ DispatchFrozen: 0
+ FocusedApplication: &lt;null&gt;
+ FocusedWindow: name='Window{3fb06dc3 u0 StatusBar}'
+ TouchStates: &lt;no displays touched&gt;
+ Windows:
+ 0: name='Window{357bbbfe u0 SearchPanel}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01820100, type=0x000007e8, layer=211000, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 1: name='Window{3b14c0ca u0 NavigationBar}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01840068, type=0x000007e3, layer=201000, frame=[0,1776][1080,1920], scale=1.000000, touchableRegion=[0,1776][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 2: name='Window{2c7e849c u0 com.vito.lux}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x0089031a, type=0x000007d6, layer=191000, frame=[-495,-147][1575,1923], scale=1.000000, touchableRegion=[-495,-147][1575,1923], inputFeatures=0x00000000, ownerPid=4697, ownerUid=10084, dispatchingTimeout=5000.000ms
+ 3: name='Window{31c9f22 u0 Heads Up}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01820328, type=0x000007de, layer=161000, frame=[0,0][1794,750], scale=1.000000, touchableRegion=[0,0][1794,192], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 4: name='Window{3fb06dc3 u0 StatusBar}', displayId=0, paused=false, hasFocus=true, hasWallpaper=false, visible=true, canReceiveKeys=true, flags=0x81960040, type=0x000007d0, layer=151000, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000004, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 5: name='Window{278c1d65 u0 KeyguardScrim}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01110900, type=0x000007ed, layer=131000, frame=[0,0][1080,1776], scale=1.000000, touchableRegion=[0,0][1080,1776], inputFeatures=0x00000000, ownerPid=745, ownerUid=1000, dispatchingTimeout=5000.000ms
+ 6: name='Window{869f213 u0 com.android.systemui.ImageWallpaper}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00000318, type=0x000007dd, layer=21025, frame=[0,0][2328,1920], scale=1.000000, touchableRegion=[0,0][2328,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 7: name='Window{16ab6320 u0 InputMethod}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01800108, type=0x000007db, layer=21020, frame=[0,75][1080,1920], scale=1.000000, touchableRegion=[0,986][1080,1920], inputFeatures=0x00000000, ownerPid=8409, ownerUid=10056, dispatchingTimeout=5000.000ms
+ 8: name='Window{cf4ff0b u0 com.google.android.googlequicksearchbox/com.google.android.launcher.GEL}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x81910120, type=0x00000001, layer=21015, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=14722, ownerUid=10022, dispatchingTimeout=5000.000ms
+ 9: name='Window{1a7be08a u0 com.android.systemui/com.android.systemui.recents.RecentsActivity EXITING}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x81910120, type=0x00000001, layer=21010, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms
+ 10: name='Window{2280455f u0 com.google.android.gm/com.google.android.gm.ConversationListActivityGmail}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x81810120, type=0x00000001, layer=21005, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=9897, ownerUid=10070, dispatchingTimeout=5000.000ms
+ 11: name='Window{657fee5 u0 com.mobilityware.freecell/com.mobilityware.freecell.FreeCell}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01810520, type=0x00000001, layer=21000, frame=[0,0][1080,1776], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=3189, ownerUid=10085, dispatchingTimeout=5000.000ms
+ MonitoringChannels:
+ 0: 'WindowManager (server)'
+ RecentQueue: length=10
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217264.0ms
+ MotionEvent(deviceId=4, source=0x00001002, action=1, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217255.7ms
+ MotionEvent(deviceId=4, source=0x00001002, action=0, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (330.0, 1283.0)]), policyFlags=0x62000000, age=216805.0ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (330.0, 1287.0)]), policyFlags=0x62000000, age=216788.3ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (331.0, 1297.0)]), policyFlags=0x62000000, age=216780.0ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (332.0, 1316.0)]), policyFlags=0x62000000, age=216771.6ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (333.0, 1340.0)]), policyFlags=0x62000000, age=216763.3ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (333.0, 1362.0)]), policyFlags=0x62000000, age=216755.0ms
+ MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (332.0, 1384.0)]), policyFlags=0x62000000, age=216747.2ms
+ MotionEvent(deviceId=4, source=0x00001002, action=1, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (332.0, 1384.0)]), policyFlags=0x62000000, age=216738.9ms
+ PendingEvent: &lt;none&gt;
+ InboundQueue: &lt;empty&gt;
+ ReplacedKeys: &lt;empty&gt;
+ Connections:
+ 0: channelName='WindowManager (server)', windowName='monitor', status=NORMAL, monitor=true, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 1: channelName='278c1d65 KeyguardScrim (server)', windowName='Window{278c1d65 u0 KeyguardScrim}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 2: channelName='357bbbfe SearchPanel (server)', windowName='Window{357bbbfe u0 SearchPanel}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 3: channelName='869f213 com.android.systemui.ImageWallpaper (server)', windowName='Window{869f213 u0 com.android.systemui.ImageWallpaper}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 4: channelName='3fb06dc3 StatusBar (server)', windowName='Window{3fb06dc3 u0 StatusBar}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 5: channelName='2c7e849c (server)', windowName='Window{2c7e849c u0 com.vito.lux}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 6: channelName='cf4ff0b com.google.android.googlequicksearchbox/com.google.android.launcher.GEL (server)', windowName='Window{cf4ff0b
+u0 com.google.android.googlequicksearchbox/com.google.android.launcher.GEL}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 7: channelName='2280455f com.google.android.gm/com.google.android.gm.ConversationListActivityGmail (server)', windowName='Window{2280455f u0 com.google.android.gm/com.google.android.gm.ConversationListActivityGmail}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 8: channelName='1a7be08a com.android.systemui/com.android.systemui.recents.RecentsActivity (server)', windowName='Window{1a7be08a u0 com.android.systemui/com.android.systemui.recents.RecentsActivity EXITING}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 9: channelName='3b14c0ca NavigationBar (server)', windowName='Window{3b14c0ca u0 NavigationBar}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 10: channelName='16ab6320 InputMethod (server)', windowName='Window{16ab6320 u0 InputMethod}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 11: channelName='657fee5 com.mobilityware.freecell/com.mobilityware.freecell.FreeCell (server)', windowName='Window{657fee5 u0 com.mobilityware.freecell/com.mobilityware.freecell.FreeCell}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 12: channelName='31c9f22 Heads Up (server)', windowName='Window{31c9f22 u0 Heads Up}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ AppSwitch: not pending
+ 7: channelName='2280455f com.google.android.gm/com.google.android.gm.ConversationListActivityGmail (server)', windowName='Window{2280455f u0 com.google.android.gm/com.google.android.gm.ConversationListActivityGmail}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 8: channelName='1a7be08a com.android.systemui/com.android.systemui.recents.RecentsActivity (server)', windowName='Window{1a7be08a u0 com.android.systemui/com.android.systemui.recents.RecentsActivity EXITING}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 9: channelName='3b14c0ca NavigationBar (server)', windowName='Window{3b14c0ca u0 NavigationBar}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 10: channelName='16ab6320 InputMethod (server)', windowName='Window{16ab6320 u0 InputMethod}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 11: channelName='657fee5 com.mobilityware.freecell/com.mobilityware.freecell.FreeCell (server)', windowName='Window{657fee5 u0 com.mobilityware.freecell/com.mobilityware.freecell.FreeCell}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ 12: channelName='31c9f22 Heads Up (server)', windowName='Window{31c9f22 u0 Heads Up}', status=NORMAL, monitor=false, inputPublisherBlocked=false
+ OutboundQueue: &lt;empty&gt;
+ WaitQueue: &lt;empty&gt;
+ AppSwitch: not pending
+ Configuration:
+ KeyRepeatDelay: 50.0ms
+ KeyRepeatTimeout: 500.0ms
+</pre>
+<h4 id="things-to-look-for_2">检查事项</h4>
+<ol>
+ <li>一般而言,需检查是否所有输入事件均按预期进行处理。</li>
+ <li>若您触摸触摸屏并同时运行 dumpsys,则 <code>TouchStates</code> 行应显示您正在触摸的窗口。</li>
+</ol>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/input/keyboard-devices.html b/zh-cn/devices/input/keyboard-devices.html
new file mode 100644
index 00000000..88de137f
--- /dev/null
+++ b/zh-cn/devices/input/keyboard-devices.html
@@ -0,0 +1,6305 @@
+<html devsite><head>
+ <title>键盘设备</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android 支持各种键盘设备,包括特殊功能小键盘(音量和电源控制),紧凑型嵌入式 QWERTY 键盘和全能型 PC 式外接键盘。</p>
+<p>本文档仅介绍物理键盘。有关软键盘(输入法编辑器)的信息,请参阅 Android SDK。</p>
+<h2 id="keyboard-classification">键盘分类</h2>
+<p>只要满足以下条件之一,输入设备即可归类为键盘:</p>
+<ul>
+<li>
+<p>输入设备报告存在任何用于键盘的 Linux 按键代码(包括 <code>0</code> 到 <code>0xff</code> 或 <code>KEY_OK</code> 到 <code>KEY_MAX</code>)。</p>
+</li>
+<li>
+<p>输入设备报告存在任何用于操纵杆和游戏手柄的 Linux 按键代码(包括 <code>BTN_0</code> 到 <code>BTN_9</code>、<code>BTN_TRIGGER</code> 到 <code>BTN_DEAD</code>,或 <code>BTN_A</code> 到 <code>BTN_THUMBR</code>)。</p>
+</li>
+</ul>
+<p>操纵杆目前被归类为键盘,这是因为 <code>EV_KEY</code> 事件报告操纵杆和游戏手柄按钮的方式与报告键盘按键的方式相同,因此操纵杆和游戏手柄也利用键映射文件来进行配置。</p>
+<p>一旦输入设备被归类为键盘,系统就会为此键盘加载输入设备配置文件和键盘布局。</p>
+<p>接下来系统会尝试确定此设备的其他特性。</p>
+<ul>
+<li>
+<p>如果输入设备存在任何被映射到 <code>KEYCODE_Q</code> 的按键,则系统将认为该设备具有字母键盘(而不是数字键盘)。字母键盘功能在资源 <code>Configuration</code> 对象中会被报告为 <code>KEYBOARD_QWERTY</code>。</p>
+</li>
+<li>
+<p>如果输入设备存在任何被映射到 <code>KEYCODE_DPAD_UP</code>、<code>KEYCODE_DPAD_DOWN</code>、<code>KEYCODE_DPAD_LEFT</code>、<code>KEYCODE_DPAD_RIGHT</code> 和 <code>KEYCODE_DPAD_CENTER</code>(必须全部存在)的按键,则系统将认为此设备具有方向键盘。
+ 方向键盘功能在资源 <code>Configuration</code> 对象中会被报告为 <code>NAVIGATION_DPAD</code>。</p>
+</li>
+<li>
+<p>如果输入设备存在任何被映射到 <code>KEYCODE_BUTTON_A</code> 的按键或其他与游戏手柄相关的按键,则系统将认为此设备具有游戏手柄。</p>
+</li>
+</ul>
+<h2 id="keyboard-driver-requirements">键盘驱动程序要求</h2>
+<ol>
+<li>
+<p>键盘驱动程序只能为其实际支持的按键注册按键代码。注册过多的按键代码可能会扰乱设备分类算法,或导致系统无法正确地检测到设备的受支持键盘功能。</p>
+</li>
+<li>
+<p>键盘驱动程序应使用 <code>EV_KEY</code> 来报告按键操作;使用值 <code>0</code> 表示释放按键,使用值 <code>1</code> 来表示按下按键,使用值 <code>2</code> 或更大的值表示自动重复按键操作。</p>
+</li>
+<li>
+<p>Android 执行自己的键盘重复操作。在驱动程序中应停用自动重复功能。</p>
+</li>
+<li>
+<p>当按下按键时,键盘驱动程序可能会通过发送带 <code>MSC_SCANCODE</code> 的 <code>EV_MSC</code> 或通过 valud(用于指示用途或扫描代码),选择性地指示 HID 用途或低级扫描代码。Android 目前尚未使用此信息。</p>
+</li>
+<li>
+<p>在将 <code>EV_LED</code> 写入设备时,键盘驱动程序应支持设置 LED 状态。<code>hid-input</code> 驱动程序会自动处理这项事务。在这一写入期间,Android 会使用 <code>LED_CAPSLOCK</code>、<code>LED_SCROLLLOCK</code> 和 <code>LED_NUMLOCK</code>。只有当键盘实际上配有相关的指示灯时,系统才需要支持这些 LED 指示灯。</p>
+</li>
+<li>
+<p>应确保嵌入式键盘的键盘驱动程序(例如,使用 GPIO 矩阵)在设备即将进入休眠状态时,为尚处于按下状态的任何按键发送值为 <code>0</code> 的 <code>EV_KEY</code> 事件。否则按键可能会被卡住,并一直自动重复按键操作。</p>
+</li>
+</ol>
+<h2 id="keyboard-operation">键盘操作</h2>
+<p>下文简要汇总了 Android 设备上的键盘操作。</p>
+<ol>
+<li>
+<p><code>EventHub</code> 从 <code>evdev</code> 驱动程序中读取原始事件,并使用键盘的按键布局映射将 Linux 按键代码(有时也称扫描代码)映射到 Android 按键代码中。</p>
+</li>
+<li>
+<p><code>InputReader</code> 将消费原始事件,并更新 Meta 键状态。例如,如果您按下或释放左 Shift 键,则读取器会相应地设置或重置 <code>META_SHIFT_LEFT_ON</code> 和 <code>META_SHIFT_ON</code> 位。</p>
+</li>
+<li>
+<p><code>InputReader</code> 会向 <code>InputDispatcher</code> 发送按键事件的相关通知。</p>
+</li>
+<li>
+<p><code>InputDispatcher</code> 通过调用 <code>WindowManagerPolicy.interceptKeyBeforeQueueing</code> 询问 <code>WindowManagerPolicy</code> 如何处理按键事件。该方法(负责在按下某些按键时唤醒设备)属于关键路径的一部分。实际上,<code>EventHub</code> 会在此关键路径上一直持有唤醒锁,从而确保它运行至结束。</p>
+</li>
+<li>
+<p>如果目前正在使用 <code>InputFilter</code>,那么 <code>InputDispatcher</code> 将给予它机会来消费或转换按键。<code>InputFilter</code> 可用于实施低级别的全系统可访问性策略。</p>
+</li>
+<li>
+<p><code>InputDispatcher</code> 可将按键排入队列,以便在分配线程上对按键进行处理。</p>
+</li>
+<li>
+<p>当 <code>InputDispatcher</code> 将按键移出队列时,它会通过调用 <code>WindowManagerPolicy.interceptKeyBeforeDispatching</code> 使 <code>WindowManagerPolicy</code> 再次有机会拦截按键事件。此方法可用于处理系统快捷方式和其他功能。</p>
+</li>
+<li>
+<p>随后,<code>InputDispatcher</code> 会识别按键事件目标(活动窗口),并等待按键事件目标就绪。接下来,<code>InputDispatcher</code> 会将按键事件发送到应用。</p>
+</li>
+<li>
+<p>在应用内,按键事件会将视图层次传送到焦点视图,以进行 IME 按键预分配。</p>
+</li>
+<li>
+<p>如果按键事件未在 IME 按键预分配阶段进行处理,而某个 IME 正在使用中,那么按键事件会被发送到 IME。</p>
+</li>
+<li>
+<p>如果按键事件未被 IME 消费,则按键事件会将视图层次传送到焦点视图,从而进行标准按键分配。</p>
+</li>
+<li>
+<p>应用反过来向 <code>InputDispatcher</code> 报告有关按键事件是否被消费的情况。如果事件未被消费,则 <code>InputDispatcher</code> 会调用 <code>WindowManagerPolicy.dispatchUnhandledKey</code> 来应用“回退”行为。根据回退操作,可以使用不同的按键代码重新启动按键事件分配周期。例如,如果应用不处理 <code>KEYCODE_ESCAPE</code>,则系统可能会将按键事件作为 <code>KEYCODE_BACK</code> 再次分配。</p>
+</li>
+</ol>
+<h2 id="keyboard-configuration">键盘配置</h2>
+<p>键盘行为由键盘的按键布局、按键字符映射和输入设备配置所决定。</p>
+<p>要详细了解参与键盘配置的文件,请参阅以下部分:</p>
+<ul>
+<li><a href="key-layout-files.html">按键布局文件</a></li>
+<li><a href="key-character-map-files.html">按键字符映射文件</a></li>
+<li><a href="input-device-configuration-files.html">输入设备配置文件</a></li>
+</ul>
+<h3 id="properties">属性</h3>
+<p>以下是用于键盘的输入设备配置属性。</p>
+<h4 id="keyboardlayout"><code>keyboard.layout</code></h4>
+<p><em></em>定义:<code>keyboard.layout</code> = &lt;名称&gt;</p>
+<p>指定与输入设备相关的按键布局文件的名称(不包括 <code>.kl</code> 扩展名)。如果未找到此文件,则输入系统将改为使用默认按键布局。</p>
+<p>在查询过程中,文件名中的空格将被转换为下划线。</p>
+<p>如需了解更多详细信息,请参阅按键布局文件文档。</p>
+<h4 id="keyboardcharactermap"><code>keyboard.characterMap</code></h4>
+<p><em></em>定义:<code>keyboard.characterMap</code> = &lt;名称&gt;</p>
+<p>指定与输入设备相关的按键字符映射文件的名称(不包括 <code>.kcm</code> 扩展名)。如果未找到此文件,则输入系统将改为使用默认按键字符映射。</p>
+<p>在查询过程中,文件名中的空格将被转换为下划线。</p>
+<p>如需了解更多详细信息,请参阅按键字符映射文件文档。</p>
+<h4 id="keyboardorientationaware"><code>keyboard.orientationAware</code></h4>
+<p><em></em>定义:<code>keyboard.orientationAware</code> = <code>0</code> | <code>1</code></p>
+<p>指定键盘是否应对显示方向更改作出反应。</p>
+<ul>
+<li>
+<p>如果该值为 <code>1</code>,则当相关的显示方向发生改变时,方向键盘按键会相应地发生旋转。</p>
+</li>
+<li>
+<p>如果该值为 <code>0</code>,则键盘不受显示方向更改的影响。</p>
+</li>
+</ul>
+<p>默认值为 <code>0</code>。</p>
+<p>方向感知功能用于支持方向键盘按键的旋转(如在 Motorola Droid 上旋转按键一样)。例如,当设备从其自然方向顺时针旋转 90 度时,<code>KEYCODE_DPAD_UP</code> 会被重新映射以产生 <code>KEYCODE_DPAD_RIGHT</code>。这是因为当设备保持在该方向时,“向上”按键最后就变成了“向右”按键。</p>
+<h4 id="keyboardbuiltin"><code>keyboard.builtIn</code></h4>
+<p><em></em>定义:<code>keyboard.builtIn</code> = <code>0</code> | <code>1</code></p>
+<p>指定键盘是否是内置(物理连接)键盘。</p>
+<p>如果设备名称以 <code>-keypad</code> 作为结尾,则默认值为 <code>1</code>,否则为 <code>0</code>。</p>
+<p>内置键盘会一律获分配值为 <code>0</code> 的设备 ID。其他非内置的键盘则会获分配一个唯一非零设备 ID。</p>
+<p>对内置键盘采用值为 <code>0</code> 的 ID 有助于保持与 <code>KeyCharacterMap.BUILT_IN_KEYBOARD</code> 字段的兼容性,这样可指定内置键盘的 ID 并拥有值 <code>0</code>。API 中的该字段已弃用,但旧版应用可能仍在使用该字段。</p>
+<p>特殊功能键盘(其按键字符映射指定 <code>SPECIAL_FUNCTION</code> 类型)一律不得注册为内置键盘(无论此属性如何设置)。这是因为根据定义,特殊功能键盘并非为普通打字用途而设计。</p>
+<h3 id="example-configurations">示例配置</h3>
+<pre class="devsite-click-to-copy">
+# This is an example input device configuration file for a built-in
+# keyboard that has a DPad.
+
+# The keyboard is internal because it is part of the device.
+device.internal = 1
+
+# The keyboard is the default built-in keyboard so it should be assigned
+# an id of 0.
+keyboard.builtIn = 1
+
+# The keyboard includes a DPad which is mounted on the device. As the device
+# is rotated the orientation of the DPad rotates along with it, so the DPad must
+# be aware of the display orientation. This ensures that pressing 'up' on the
+# DPad always means 'up' from the perspective of the user, even when the entire
+# device has been rotated.
+keyboard.orientationAware = 1
+</pre>
+<h3 id="compatibility-notes">兼容性说明</h3>
+<p>在 Honeycomb 之前,键盘输入映射器没有使用任何配置属性。所有键盘都假定采用物理连接的方式并具有方向感知功能。默认的按键布局和按键字符映射会被命名为 <code>qwerty</code>,而非 <code>Generic</code>。按键字符映射格式也有很大差异,而且框架不支持 PC 式全键盘或外接键盘。</p>
+<p>将设备升级到 Honeycomb 时,请确保创建或更新必要的配置和按键映射文件。</p>
+<h2 id="hid-usages-linux-key-codes-and-android-key-codes">HID 用途、Linux 按键代码和 Android 按键代码</h2>
+<p>系统会采用几种不同的标识符来引用按键,具体取决于抽象层。</p>
+<p>对于 HID 设备,每个按键都对应相关联的 HID 用途。Linux <code>hid-input</code> 驱动程序和相关供应商和适用于特定设备的 HID 驱动程序负责解析 HID 报告,并将 HID 用途映射到 Linux 按键代码。</p>
+<p>当 Android 从 Linux 内核读取 <code>EV_KEY</code> 事件时,会根据设备的按键布局文件,将每个 Linux 按键代码转换为相应的 Android 按键代码。</p>
+<p>当按键事件被分配到应用时,<code>android.view.KeyEvent</code> 实例会将 Linux 按键代码报告为 <code>getScanCode()</code> 的值,并将 Android 按键代码报告为 <code>getKeyCode()</code> 的值。对于框架来说,只有 <code>getKeyCode()</code> 的值才是重要的。</p>
+<p>请注意,Android 本身并未使用 HID 用途信息,这些信息也不会传递给应用。</p>
+<h2 id="code-tables">代码表</h2>
+<p>下表列出了 HID 用途、Linux 按键代码和 Android 按键代码彼此之间的关系。</p>
+<p>LKC 列可采用十六进制格式指定 Linux 按键代码。</p>
+<p>AKC 列可采用十六进制格式指定 Android 按键代码。</p>
+<p>“备注”列是指附于表格后面的注释。</p>
+<p>“版本”列会指定已将该按键包含在其默认按键映射中的 Android 平台的第一个版本。当默认按键映射在版本之间有所变更时,该列中会显示多个行。已显示的最早版本是 1.6 版。</p>
+<ul>
+<li>
+<p>在 Gingerbread (2.3) 及更早的版本中,默认按键映射为 <code>qwerty.kl</code>。此按键映射仅适用于 Android 模拟器,并非为支持任意外接键盘而设计。不过,少数原始设备制造商 (OEM) 已将蓝牙键盘支持功能添加到平台上,并依赖 <code>qwerty.kl</code> 来提供必要的键盘映射。因此,正在为特定设备构建外围设备的 OEM 可能会对这些旧版本的映射颇感兴趣。请注意,这些映射与当前版本的映射大不相同,尤其是在 <code>HOME</code> 按键处理方面。我们建议您根据 Honeycomb 或较新版本的按键映射(即标准 HID)来开发所有新的外围设备。</p>
+</li>
+<li>
+<p>从 Honeycomb (3.0) 开始,默认按键映射为 <code>Generic.kl</code>。此按键映射旨在支持完全 PC 式键盘。标准 HID 键盘的大部分功能都应该支持“开箱即用”。</p>
+</li>
+</ul>
+<p>在 Linux 内核版本和 Android 版本中,按键代码映射可能有所不同。当发现 Android 默认按键映射中发生某些变化时,“版本”列中会显示这些变化。</p>
+<p>特定设备的 HID 驱动程序和按键映射所应用的映射可能与此处显示的不同。</p>
+<h3 id="hid-keyboard-and-keypad-page-0x07">HID 键盘和键盘页 (0x07)</h3>
+<table>
+<thead>
+<tr>
+<th>HID 用途</th>
+<th>HID 用途名称</th>
+<th>LKC</th>
+<th>Linux 按键代码名称</th>
+<th>版本</th>
+<th>AKC</th>
+<th>Android 按键代码名称</th>
+<th>备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>0x07 0x0001</td>
+<td>键盘错误,防冲突功能</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0002</td>
+<td>键盘 POST 失败</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0003</td>
+<td>键盘错误未定义</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0004</td>
+<td>键盘 a 和 A 键</td>
+<td>0x001e</td>
+<td>KEY_A</td>
+<td>1.6</td>
+<td>0x001d</td>
+<td>KEYCODE_A</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0005</td>
+<td>键盘 b 和 B 键</td>
+<td>0x0030</td>
+<td>KEY_B</td>
+<td>1.6</td>
+<td>0x001e</td>
+<td>KEYCODE_B</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0006</td>
+<td>键盘 c 和 C 键</td>
+<td>0x002e</td>
+<td>KEY_C</td>
+<td>1.6</td>
+<td>0x001f</td>
+<td>KEYCODE_C</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0007</td>
+<td>键盘 d 和 D 键</td>
+<td>0x0020</td>
+<td>KEY_D</td>
+<td>1.6</td>
+<td>0x0020</td>
+<td>KEYCODE_D</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0008</td>
+<td>键盘 e 和 E 键</td>
+<td>0x0012</td>
+<td>KEY_E</td>
+<td>1.6</td>
+<td>0x0021</td>
+<td>KEYCODE_E</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0009</td>
+<td>键盘 f 和 F 键</td>
+<td>0x0021</td>
+<td>KEY_F</td>
+<td>1.6</td>
+<td>0x0022</td>
+<td>KEYCODE_F</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000a</td>
+<td>键盘 g 和 G 键</td>
+<td>0x0022</td>
+<td>KEY_G</td>
+<td>1.6</td>
+<td>0x0023</td>
+<td>KEYCODE_G</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000b</td>
+<td>键盘 h 和 H 键</td>
+<td>0x0023</td>
+<td>KEY_H</td>
+<td>1.6</td>
+<td>0x0024</td>
+<td>KEYCODE_H</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000c</td>
+<td>键盘 i 和 I 键</td>
+<td>0x0017</td>
+<td>KEY_I</td>
+<td>1.6</td>
+<td>0x0025</td>
+<td>KEYCODE_I</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000d</td>
+<td>键盘 j 和 J 键</td>
+<td>0x0024</td>
+<td>KEY_J</td>
+<td>1.6</td>
+<td>0x0026</td>
+<td>KEYCODE_J</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000e</td>
+<td>键盘 k 和 K 键</td>
+<td>0x0025</td>
+<td>KEY_K</td>
+<td>1.6</td>
+<td>0x0027</td>
+<td>KEYCODE_K</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x000f</td>
+<td>键盘 l 和 L 键</td>
+<td>0x0026</td>
+<td>KEY_L</td>
+<td>1.6</td>
+<td>0x0028</td>
+<td>KEYCODE_L</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0010</td>
+<td>键盘 m 和 M 键</td>
+<td>0x0032</td>
+<td>KEY_M</td>
+<td>1.6</td>
+<td>0x0029</td>
+<td>KEYCODE_M</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0011</td>
+<td>键盘 n 和 N 键</td>
+<td>0x0031</td>
+<td>KEY_N</td>
+<td>1.6</td>
+<td>0x002a</td>
+<td>KEYCODE_N</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0012</td>
+<td>键盘 o 和 O 键</td>
+<td>0x0018</td>
+<td>KEY_O</td>
+<td>1.6</td>
+<td>0x002b</td>
+<td>KEYCODE_O</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0013</td>
+<td>键盘 p 和 P 键</td>
+<td>0x0019</td>
+<td>KEY_P</td>
+<td>1.6</td>
+<td>0x002c</td>
+<td>KEYCODE_P</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0014</td>
+<td>键盘 q 和 Q 键</td>
+<td>0x0010</td>
+<td>KEY_Q</td>
+<td>1.6</td>
+<td>0x002d</td>
+<td>KEYCODE_Q</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0015</td>
+<td>键盘 r 和 R 键</td>
+<td>0x0013</td>
+<td>KEY_R</td>
+<td>1.6</td>
+<td>0x002e</td>
+<td>KEYCODE_R</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0016</td>
+<td>键盘 s 和 S 键</td>
+<td>0x001f</td>
+<td>KEY_S</td>
+<td>1.6</td>
+<td>0x002f</td>
+<td>KEYCODE_S</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0017</td>
+<td>键盘 t 和 T 键</td>
+<td>0x0014</td>
+<td>KEY_T</td>
+<td>1.6</td>
+<td>0x0030</td>
+<td>KEYCODE_T</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0018</td>
+<td>键盘 u 和 U 键</td>
+<td>0x0016</td>
+<td>KEY_U</td>
+<td>1.6</td>
+<td>0x0031</td>
+<td>KEYCODE_U</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0019</td>
+<td>键盘 v 和 V 键</td>
+<td>0x002f</td>
+<td>KEY_V</td>
+<td>1.6</td>
+<td>0x0032</td>
+<td>KEYCODE_V</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001a</td>
+<td>键盘 w 和 W 键</td>
+<td>0x0011</td>
+<td>KEY_W</td>
+<td>1.6</td>
+<td>0x0033</td>
+<td>KEYCODE_W</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001b</td>
+<td>键盘 x 和 X 键</td>
+<td>0x002d</td>
+<td>KEY_X</td>
+<td>1.6</td>
+<td>0x0034</td>
+<td>KEYCODE_X</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001c</td>
+<td>键盘 y 和 Y 键</td>
+<td>0x0015</td>
+<td>KEY_Y</td>
+<td>1.6</td>
+<td>0x0035</td>
+<td>KEYCODE_Y</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001d</td>
+<td>键盘 z 和 Z 键</td>
+<td>0x002c</td>
+<td>KEY_Z</td>
+<td>1.6</td>
+<td>0x0036</td>
+<td>KEYCODE_Z</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001e</td>
+<td>键盘 1 和 ! 键</td>
+<td>0x0002</td>
+<td>KEY_1</td>
+<td>1.6</td>
+<td>0x0008</td>
+<td>KEYCODE_1</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x001f</td>
+<td>键盘 2 和 @ 键</td>
+<td>0x0003</td>
+<td>KEY_2</td>
+<td>1.6</td>
+<td>0x0009</td>
+<td>KEYCODE_2</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0020</td>
+<td>键盘 3 和 # 键</td>
+<td>0x0004</td>
+<td>KEY_3</td>
+<td>1.6</td>
+<td>0x000a</td>
+<td>KEYCODE_3</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0021</td>
+<td>键盘 4 和 $ 键</td>
+<td>0×0005</td>
+<td>KEY_4</td>
+<td>1.6</td>
+<td>0x000b</td>
+<td>KEYCODE_4</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0022</td>
+<td>键盘 5 和 % 键</td>
+<td>0x0006</td>
+<td>KEY_5</td>
+<td>1.6</td>
+<td>0x000c</td>
+<td>KEYCODE_5</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0023</td>
+<td>键盘 6 和 ^ 键</td>
+<td>0x0007</td>
+<td>KEY_6</td>
+<td>1.6</td>
+<td>0x000d</td>
+<td>KEYCODE_6</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0024</td>
+<td>键盘 7 和 &amp; 键</td>
+<td>0x0008</td>
+<td>KEY_7</td>
+<td>1.6</td>
+<td>0x000e</td>
+<td>KEYCODE_7</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0025</td>
+<td>键盘 8 和 * 键</td>
+<td>0x0009</td>
+<td>KEY_8</td>
+<td>1.6</td>
+<td>0x000f</td>
+<td>KEYCODE_8</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0026</td>
+<td>键盘 9 和 ( 键</td>
+<td>0x000a</td>
+<td>KEY_9</td>
+<td>1.6</td>
+<td>0x0010</td>
+<td>KEYCODE_9</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0027</td>
+<td>键盘 0 和 ) 键</td>
+<td>0x000b</td>
+<td>KEY_0</td>
+<td>1.6</td>
+<td>0x0007</td>
+<td>KEYCODE_0</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0028</td>
+<td>键盘返回 (Enter) 键</td>
+<td>0x001c</td>
+<td>KEY_ENTER</td>
+<td>1.6</td>
+<td>0x0042</td>
+<td>KEYCODE_ENTER</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0029</td>
+<td>键盘 Esc 键</td>
+<td>0x0001</td>
+<td>KEY_ESC</td>
+<td>3.0</td>
+<td>0x006f</td>
+<td>KEYCODE_ESCAPE </td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>2.3</td>
+<td>0x0004</td>
+<td>KEYCODE_BACK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x002a</td>
+<td>键盘删除 (Backspace) 键</td>
+<td>0x000e</td>
+<td>KEY_BACKSPACE</td>
+<td>1.6</td>
+<td>0x0043</td>
+<td>KEYCODE_DEL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x002b</td>
+<td>键盘 Tab 键</td>
+<td>0x000f</td>
+<td>KEY_TAB</td>
+<td>1.6</td>
+<td>0x003d</td>
+<td>KEYCODE_TAB</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x002c</td>
+<td>键盘空格键</td>
+<td>0x0039</td>
+<td>KEY_SPACE</td>
+<td>1.6</td>
+<td>0x003e</td>
+<td>KEYCODE_SPACE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x002d</td>
+<td>键盘 - 和 _ 键</td>
+<td>0x000c</td>
+<td>KEY_MINUS </td>
+<td>1.6</td>
+<td>0x0045</td>
+<td>KEYCODE_MINUS</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x002e</td>
+<td>键盘 = 和 + 键</td>
+<td>0x000d</td>
+<td>KEY_EQUAL</td>
+<td>1.6</td>
+<td>0x0046</td>
+<td>KEYCODE_EQUALS</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x002f</td>
+<td>键盘 [ 和 { 键</td>
+<td>0x001a</td>
+<td>KEY_LEFTBRACE</td>
+<td>1.6</td>
+<td>0x0047 </td>
+<td>KEYCODE_LEFT_BRACKET</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0030</td>
+<td>键盘 ] 和 } 键</td>
+<td>0x001b</td>
+<td>KEY_RIGHTBRACE</td>
+<td>1.6</td>
+<td>0x0048</td>
+<td>KEYCODE_RIGHT_BRACKET</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0031</td>
+<td>键盘 \ 和 | 键</td>
+<td>0x002b</td>
+<td>KEY_BACKSLASH</td>
+<td>1.6</td>
+<td>0x0049</td>
+<td>KEYCODE_BACKSLASH</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0032</td>
+<td>键盘非美式 # 和 ~ 键</td>
+<td>0x002b</td>
+<td>KEY_BACKSLASH</td>
+<td>1.6</td>
+<td>0x0049</td>
+<td>KEYCODE_BACKSLASH</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0033</td>
+<td>键盘 ; 和 : 键</td>
+<td>0x0027</td>
+<td>KEY_SEMICOLON</td>
+<td>1.6</td>
+<td>0x004a</td>
+<td>KEYCODE_SEMICOLON</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0034</td>
+<td>键盘 ' 和 " 键</td>
+<td>0x0028</td>
+<td>KEY_APOSTROPHE</td>
+<td>1.6</td>
+<td>0x004b</td>
+<td>KEYCODE_APOSTROPHE</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0035 </td>
+<td>键盘 ` 和 ~ 键</td>
+<td>0x0029</td>
+<td>KEY_GRAVE</td>
+<td>3.0</td>
+<td>0x0044</td>
+<td>KEYCODE_GRAVE</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0036</td>
+<td>键盘 , 和 &lt; 键</td>
+<td>0x0033</td>
+<td>KEY_COMMA</td>
+<td>1.6</td>
+<td>0x0037</td>
+<td>KEYCODE_COMMA</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0037</td>
+<td>键盘 . 和 &gt; 键</td>
+<td>0x0034</td>
+<td>KEY_DOT</td>
+<td>1.6</td>
+<td>0x0038</td>
+<td>KEYCODE_PERIOD</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0038</td>
+<td>键盘 / 和 ? 键</td>
+<td>0x0035</td>
+<td>KEY_SLASH</td>
+<td>1.6</td>
+<td>0x004c</td>
+<td>KEYCODE_SLASH</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0039</td>
+<td>键盘 Caps Lock 键</td>
+<td>0x003a</td>
+<td>KEY_CAPSLOCK</td>
+<td>3.0</td>
+<td>0x0073</td>
+<td>KEYCODE_CAPS_LOCK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003a</td>
+<td>键盘 F1 键</td>
+<td>0x003b</td>
+<td>KEY_F1</td>
+<td>3.0</td>
+<td>0x0083</td>
+<td>KEYCODE_F1</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0052</td>
+<td>KEYCODE_MENU</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003b</td>
+<td>键盘 F2 键</td>
+<td>0x003c</td>
+<td>KEY_F2</td>
+<td>3.0</td>
+<td>0x0084</td>
+<td>KEYCODE_F2</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0002</td>
+<td>KEYCODE_SOFT_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003c</td>
+<td>键盘 F3 键</td>
+<td>0x003d</td>
+<td>KEY_F3</td>
+<td>3.0</td>
+<td>0x0085</td>
+<td>KEYCODE_F3</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0×0005</td>
+<td>KEYCODE_CALL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003d</td>
+<td>键盘 F4 键</td>
+<td>0x003e</td>
+<td>KEY_F4</td>
+<td>3.0</td>
+<td>0x0086</td>
+<td>KEYCODE_F4</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0006</td>
+<td>KEYCODE_ENDCALL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003e</td>
+<td>键盘 F5 键</td>
+<td>0x003f</td>
+<td>KEY_F5</td>
+<td>3.0</td>
+<td>0x0087</td>
+<td>KEYCODE_F5</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x003f</td>
+<td>键盘 F6 键</td>
+<td>0x0040</td>
+<td>KEY_F6</td>
+<td>3.0</td>
+<td>0x0088</td>
+<td>KEYCODE_F6</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0040</td>
+<td>键盘 F7 键</td>
+<td>0x0041</td>
+<td>KEY_F7</td>
+<td>3.0</td>
+<td>0x0089</td>
+<td>KEYCODE_F7</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0041</td>
+<td>键盘 F8 键</td>
+<td>0x0042</td>
+<td>KEY_F8</td>
+<td>3.0</td>
+<td>0x008a</td>
+<td>KEYCODE_F8</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0042</td>
+<td>键盘 F9 键</td>
+<td>0x0043</td>
+<td>KEY_F9</td>
+<td>3.0</td>
+<td>0x008b</td>
+<td>KEYCODE_F9</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0043</td>
+<td>键盘 F10 键</td>
+<td>0x0044</td>
+<td>KEY_F10</td>
+<td>3.0</td>
+<td>0x008c</td>
+<td>KEYCODE_F10</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>2.3</td>
+<td>0x0052</td>
+<td>KEYCODE_MENU</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0044</td>
+<td>键盘 F11 键</td>
+<td>0x0057</td>
+<td>KEY_F11</td>
+<td>3.0</td>
+<td>0x008d</td>
+<td>KEYCODE_F11</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0045</td>
+<td>键盘 F12 键</td>
+<td>0x0058</td>
+<td>KEY_F12</td>
+<td>3.0</td>
+<td>0x008e</td>
+<td>KEYCODE_F12</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0046</td>
+<td>键盘 Print Screen 键</td>
+<td>0x0063</td>
+<td>KEY_SYSRQ</td>
+<td>3.0</td>
+<td>0x0078</td>
+<td>KEYCODE_SYSRQ</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0047</td>
+<td>键盘 Scroll Lock 键</td>
+<td>0x0046</td>
+<td>KEY_SCROLLLOCK</td>
+<td>3.0</td>
+<td>0x0074</td>
+<td>KEYCODE_SCROLL_LOCK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0048</td>
+<td>键盘 Pause 键</td>
+<td>0x0077</td>
+<td>KEY_PAUSE</td>
+<td>3.0</td>
+<td>0x0079</td>
+<td>KEYCODE_BREAK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0049</td>
+<td>键盘 Insert 键</td>
+<td>0x006e</td>
+<td>KEY_INSERT</td>
+<td>3.0</td>
+<td>0x007c</td>
+<td>KEYCODE_INSERT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004a</td>
+<td>键盘 Home 键</td>
+<td>0x0066</td>
+<td>KEY_HOME</td>
+<td>3.0</td>
+<td>0x007a</td>
+<td>KEYCODE_MOVE_HOME</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0003</td>
+<td>KEYCODE_HOME</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004b</td>
+<td>键盘 Page Up 键</td>
+<td>0x0068</td>
+<td>KEY_PAGEUP</td>
+<td>3.0</td>
+<td>0x005c</td>
+<td>KEYCODE_PAGE_UP </td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004c</td>
+<td>键盘 Delete Forward 键</td>
+<td>0x006f</td>
+<td>KEY_DELETE</td>
+<td>3.0</td>
+<td>0x0070</td>
+<td>KEYCODE_FORWARD_DEL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004d</td>
+<td>键盘 End 键</td>
+<td>0x006b</td>
+<td>KEY_END</td>
+<td>3.0</td>
+<td>0x007b</td>
+<td>KEYCODE_MOVE_END</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0006</td>
+<td>KEYCODE_ENDCALL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004e</td>
+<td>键盘 Page Down 键</td>
+<td>0x006d</td>
+<td>KEY_PAGEDOWN</td>
+<td>3.0</td>
+<td>0x005d</td>
+<td>KEYCODE_PAGE_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x004f </td>
+<td>键盘向右箭头键</td>
+<td>0x006a</td>
+<td>KEY_RIGHT</td>
+<td>1.6</td>
+<td>0x0016</td>
+<td>KEYCODE_DPAD_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0050</td>
+<td>键盘向左箭头键</td>
+<td>0x0069</td>
+<td>KEY_LEFT</td>
+<td>1.6</td>
+<td>0x0015</td>
+<td>KEYCODE_DPAD_LEFT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0051</td>
+<td>键盘向下箭头键</td>
+<td>0x006c</td>
+<td>KEY_DOWN</td>
+<td>1.6</td>
+<td>0x0014</td>
+<td> KEYCODE_DPAD_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0052</td>
+<td>键盘向上箭头键</td>
+<td>0x0067</td>
+<td>KEY_UP</td>
+<td>1.6</td>
+<td>0x0013</td>
+<td>KEYCODE_DPAD_UP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0053</td>
+<td>键盘 Num Lock 和 Clear 键</td>
+<td>0x0045</td>
+<td>KEY_NUMLOCK</td>
+<td>3.0</td>
+<td>0x008f</td>
+<td>KEYCODE_NUM_LOCK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0054</td>
+<td>小键盘 / 键</td>
+<td>0x0062</td>
+<td>KEY_KPSLASH</td>
+<td>3.0</td>
+<td>0x009a</td>
+<td>KEYCODE_NUMPAD_DIVIDE </td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0055</td>
+<td>小键盘 * 键</td>
+<td>0x0037</td>
+<td>KEY_KPASTERISK</td>
+<td>3.0</td>
+<td>0x009b</td>
+<td>KEYCODE_NUMPAD_MULTIPLY</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0056</td>
+<td>小键盘 - 键</td>
+<td>0x004a</td>
+<td>KEY_KPMINUS</td>
+<td>3.0</td>
+<td>0x009c</td>
+<td>KEYCODE_NUMPAD_SUBTRACT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0057</td>
+<td>小键盘 + 键</td>
+<td>0x004e</td>
+<td>KEY_KPPLUS</td>
+<td>3.0</td>
+<td>0x009d</td>
+<td>KEYCODE_NUMPAD_ADD</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0058</td>
+<td>小键盘 Enter 键</td>
+<td>0x0060</td>
+<td>KEY_KPENTER</td>
+<td>3.0</td>
+<td>0x00a0</td>
+<td>KEYCODE_NUMPAD_ENTER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0059</td>
+<td>小键盘 1 和 End 键</td>
+<td>0x004f</td>
+<td>KEY_KP1</td>
+<td>3.0</td>
+<td>0x0091</td>
+<td>KEYCODE_NUMPAD_1</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005a</td>
+<td>小键盘 2 和向下箭头键</td>
+<td>0x0050</td>
+<td>KEY_KP2</td>
+<td>3.0</td>
+<td>0x0092</td>
+<td>KEYCODE_NUMPAD_2</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005b</td>
+<td>小键盘 3 和 PageDn 键</td>
+<td>0x0051</td>
+<td>KEY_KP3</td>
+<td>3.0</td>
+<td>0x0093</td>
+<td>KEYCODE_NUMPAD_3</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005c</td>
+<td>小键盘 4 和向左箭头键</td>
+<td>0x004b</td>
+<td>KEY_KP4</td>
+<td>3.0</td>
+<td>0x0094</td>
+<td>KEYCODE_NUMPAD_4</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005d</td>
+<td>小键盘 5 键</td>
+<td>0x004c</td>
+<td>KEY_KP5</td>
+<td>3.0</td>
+<td>0x0095</td>
+<td>KEYCODE_NUMPAD_5</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005e</td>
+<td>小键盘 6 和向右箭头键</td>
+<td>0x004d</td>
+<td>KEY_KP6</td>
+<td>3.0</td>
+<td>0x0096</td>
+<td>KEYCODE_NUMPAD_6</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x005f</td>
+<td>小键盘 7 和 Home 键</td>
+<td>0x0047 </td>
+<td>KEY_KP7</td>
+<td>3.0</td>
+<td>0x0097</td>
+<td>KEYCODE_NUMPAD_7</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0060</td>
+<td>小键盘 8 和向上箭头键</td>
+<td>0x0048</td>
+<td>KEY_KP8</td>
+<td>3.0</td>
+<td>0x0098</td>
+<td>KEYCODE_NUMPAD_8</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0061</td>
+<td>小键盘 9 和 Page Up 键</td>
+<td>0x0049</td>
+<td>KEY_KP9</td>
+<td>3.0</td>
+<td>0x0099</td>
+<td>KEYCODE_NUMPAD_9</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0062</td>
+<td>小键盘 0 和 Insert 键</td>
+<td>0x0052</td>
+<td>KEY_KP0</td>
+<td>3.0</td>
+<td>0x0090</td>
+<td>KEYCODE_NUMPAD_0</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0063</td>
+<td>小键盘 . 和删除键</td>
+<td>0x0053</td>
+<td>KEY_KPDOT</td>
+<td>3.0</td>
+<td>0x009e</td>
+<td>KEYCODE_NUMPAD_DOT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0064</td>
+<td>键盘 Non-US \ 和 | 键</td>
+<td>0x0056</td>
+<td>KEY_102ND</td>
+<td>4.0</td>
+<td>0x0049</td>
+<td>KEYCODE_BACKSLASH</td>
+<td>1</td>
+</tr>
+<tr>
+<td>0x07 0x0065</td>
+<td>键盘应用程序键</td>
+<td>0x007f</td>
+<td>KEY_COMPOSE</td>
+<td>3.0</td>
+<td>0x0052</td>
+<td>KEYCODE_MENU</td>
+<td></td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>""</td>
+<td>1.6</td>
+<td>0x0054</td>
+<td>KEYCODE_SEARCH </td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0066</td>
+<td>键盘 Power 键</td>
+<td>0x0074</td>
+<td>KEY_POWER</td>
+<td>1.6</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0067</td>
+<td>小键盘 = 键</td>
+<td>0x0075</td>
+<td>KEY_KPEQUAL</td>
+<td>3.0</td>
+<td>0x00a1</td>
+<td>KEYCODE_NUMPAD_EQUALS</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0068</td>
+<td>键盘 F13 键</td>
+<td>0x00b7</td>
+<td>KEY_F13</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0069</td>
+<td>键盘 F14 键</td>
+<td>0x00b8</td>
+<td>KEY_F14</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006a</td>
+<td>键盘 F15 键</td>
+<td>0x00b9</td>
+<td>KEY_F15</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006b</td>
+<td>键盘 F16 键</td>
+<td>0x00ba</td>
+<td>KEY_F16</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006c</td>
+<td>键盘 F17 键</td>
+<td>0x00bb</td>
+<td>KEY_F17</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006d</td>
+<td>键盘 F18 键</td>
+<td>0x00bc</td>
+<td>KEY_F18</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006e</td>
+<td>键盘 F19 键</td>
+<td>0x00bd</td>
+<td>KEY_F19</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x006f</td>
+<td>键盘 F20 键</td>
+<td>0x00be</td>
+<td>KEY_F20</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0070</td>
+<td>键盘 F21 键</td>
+<td>0x00bf</td>
+<td>KEY_F21</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0071</td>
+<td>键盘 F22 键</td>
+<td>0x00c0</td>
+<td>KEY_F22</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0072</td>
+<td>键盘 F23 键</td>
+<td>0x00c1</td>
+<td>KEY_F23</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0073</td>
+<td>键盘 F24 键</td>
+<td>0x00c2</td>
+<td>KEY_F24</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0074</td>
+<td>键盘 Execute 键</td>
+<td>0x0086</td>
+<td>KEY_OPEN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0075</td>
+<td>键盘帮助键</td>
+<td>0x008a</td>
+<td>KEY_HELP</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0076</td>
+<td>键盘菜单键</td>
+<td>0x0082</td>
+<td>KEY_PROPS</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0077</td>
+<td>键盘 Select 键</td>
+<td>0x0084</td>
+<td>KEY_FRONT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0078</td>
+<td>键盘 Stop 键</td>
+<td>0x0080</td>
+<td>KEY_STOP</td>
+<td>3.0</td>
+<td>0x0056</td>
+<td>KEYCODE_MEDIA_STOP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0079</td>
+<td>键盘 Again 键</td>
+<td>0x0081</td>
+<td>KEY_AGAIN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007a</td>
+<td>键盘 Undo 键</td>
+<td>0x0083</td>
+<td>KEY_UNDO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007b</td>
+<td>键盘 Cut 键</td>
+<td>0x0089</td>
+<td>KEY_CUT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007c</td>
+<td>键盘 Copy 键</td>
+<td>0x0085</td>
+<td>KEY_COPY</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007d</td>
+<td>键盘 Paste 键</td>
+<td>0x0087</td>
+<td>KEY_PASTE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007e</td>
+<td>键盘 Find 键</td>
+<td>0x0088</td>
+<td>KEY_FIND</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x007f</td>
+<td>键盘 Mute 键</td>
+<td>0x0071</td>
+<td>KEY_MUTE</td>
+<td>3.0</td>
+<td>0x00a4</td>
+<td>KEYCODE_VOLUME_MUTE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0080</td>
+<td>键盘音量调高键</td>
+<td>0x0073</td>
+<td>KEY_VOLUMEUP</td>
+<td>1.6</td>
+<td>0x0018</td>
+<td>KEYCODE_VOLUME_UP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0081</td>
+<td>键盘音量调低键</td>
+<td>0x0072</td>
+<td>KEY_VOLUMEDOWN</td>
+<td>1.6</td>
+<td>0x0019</td>
+<td>KEYCODE_VOLUME_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0082</td>
+<td>键盘锁定 Caps Lock 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0083</td>
+<td>键盘锁定 Num Lock 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0084</td>
+<td>键盘锁定 Scroll Lock 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0085</td>
+<td>小键盘逗号键</td>
+<td>0x0079</td>
+<td>KEY_KPCOMMA</td>
+<td>3.0</td>
+<td>0x009f</td>
+<td>KEYCODE_NUMPAD_COMMA</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0086</td>
+<td>小键盘等号键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0087</td>
+<td>键盘 International1</td>
+<td>0x0059</td>
+<td>KEY_RO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0088</td>
+<td>键盘 International2</td>
+<td>0x005d</td>
+<td>KEY_KATAKANAHIRAGANA</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0089</td>
+<td>键盘 International3</td>
+<td>0x007c</td>
+<td>KEY_YEN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008a</td>
+<td>键盘 International4</td>
+<td>0x005c</td>
+<td>KEY_HENKAN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008b</td>
+<td>键盘 International5</td>
+<td>0x005e</td>
+<td>KEY_MUHENKAN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008c</td>
+<td>键盘 International6</td>
+<td>0x005f</td>
+<td>KEY_KPJPCOMMA</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008d</td>
+<td>键盘 International7</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008e</td>
+<td>键盘 International8</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x008f</td>
+<td>键盘 International9</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0090</td>
+<td>键盘 LANG1</td>
+<td>0x007a</td>
+<td>KEY_HANGEUL</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0091</td>
+<td>键盘 LANG2</td>
+<td>0x007b</td>
+<td>KEY_HANJA</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0092</td>
+<td>键盘 LANG3</td>
+<td>0x005a</td>
+<td>KEY_KATAKANA</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0093</td>
+<td>键盘 LANG4</td>
+<td>0x005b</td>
+<td>KEY_HIRAGANA</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0094</td>
+<td>键盘 LANG5</td>
+<td>0x0055</td>
+<td>KEY_ZENKAKUHANKAKU</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0095</td>
+<td>键盘 LANG6</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0096</td>
+<td>键盘 LANG7</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0097</td>
+<td>键盘 LANG8</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0098</td>
+<td>键盘 LANG9</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x0099</td>
+<td>键盘 Alternate Erase 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009a</td>
+<td>键盘 SysReq/Attention 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009b</td>
+<td>键盘 Cancel 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009c</td>
+<td>键盘 Clear 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009d</td>
+<td>键盘 Prior 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009e</td>
+<td>键盘 Return 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x009f</td>
+<td>键盘 Separator 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00a0</td>
+<td>键盘 Out 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00a1</td>
+<td>键盘 Oper 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00a2</td>
+<td>键盘 Clear/Again 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00a3</td>
+<td>键盘 CrSel/Props 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00a4</td>
+<td>键盘 ExSel 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b0</td>
+<td>小键盘 00</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b1</td>
+<td>小键盘 000</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b2</td>
+<td>千位分隔符</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b3</td>
+<td>十进制分隔符</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b4</td>
+<td>货币单位</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b5</td>
+<td>货币次单位</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b6</td>
+<td>小键盘 ( 键</td>
+<td>0x00b3</td>
+<td>KEY_KPLEFTPAREN</td>
+<td>3.0</td>
+<td>0x00a2</td>
+<td>KEYCODE_NUMPAD_LEFT_PAREN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b7</td>
+<td>小键盘 ) 键</td>
+<td>0x00b4</td>
+<td>KEY_KPRIGHTPAREN</td>
+<td>3.0</td>
+<td>0x00a3</td>
+<td>KEYCODE_NUMPAD_RIGHT_PAREN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b8</td>
+<td>小键盘 { 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00b9</td>
+<td>小键盘 } 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ba</td>
+<td>小键盘 Tab 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00bb</td>
+<td>小键盘 Backspace 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00bc</td>
+<td>小键盘 A 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00bd</td>
+<td>小键盘 B 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00be</td>
+<td>小键盘 C 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00bf</td>
+<td>小键盘 D 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c0</td>
+<td>小键盘 E 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c1</td>
+<td>小键盘 F 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c2</td>
+<td>小键盘 XOR 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c3</td>
+<td>小键盘 ^ 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c4</td>
+<td>小键盘 % 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c5</td>
+<td>小键盘 &lt; 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c6</td>
+<td>小键盘 &gt; 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c7</td>
+<td>小键盘 &amp; 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c8</td>
+<td>小键盘 &amp;&amp; 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00c9</td>
+<td>小键盘 | 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ca</td>
+<td>小键盘 || 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00cb</td>
+<td>小键盘 : 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00cc</td>
+<td>小键盘 # 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00cd</td>
+<td>小键盘空格键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ce</td>
+<td>小键盘 @ 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00cf</td>
+<td>小键盘 ! 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d0</td>
+<td>小键盘 Memory Store 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d1</td>
+<td>小键盘 Memory Recall 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d2</td>
+<td>小键盘 Memory Clear 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d3</td>
+<td>小键盘 Memory Add 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d4</td>
+<td>小键盘 Memory Subtract 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d5</td>
+<td>小键盘 Memory Multiply 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d6</td>
+<td>小键盘 Memory Divide 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d7</td>
+<td>小键盘 +/- 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d8</td>
+<td>小键盘 Clear 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00d9</td>
+<td>小键盘 Clear Entry 键</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00da</td>
+<td>小键盘二进制数</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00db</td>
+<td>小键盘八进制数</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00dc</td>
+<td>小键盘十进制数</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00dd</td>
+<td>小键盘十六进制数</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e0</td>
+<td>键盘左 Ctrl 键</td>
+<td>0x001d</td>
+<td>KEY_LEFTCTRL</td>
+<td>3.0</td>
+<td>0x0071</td>
+<td>KEYCODE_CTRL_LEFT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e1</td>
+<td>键盘左 Shift 键</td>
+<td>0x002a</td>
+<td>KEY_LEFTSHIFT</td>
+<td>1.6</td>
+<td>0x003b</td>
+<td>KEYCODE_SHIFT_LEFT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e2</td>
+<td>键盘左 Alt 键</td>
+<td>0x0038</td>
+<td>KEY_LEFTALT</td>
+<td>1.6</td>
+<td>0x0039</td>
+<td>KEYCODE_ALT_LEFT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e3</td>
+<td>键盘左 GUI 键</td>
+<td>0x007d</td>
+<td>KEY_LEFTMETA</td>
+<td>3.0</td>
+<td>0x0075</td>
+<td>KEYCODE_META_LEFT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e4</td>
+<td>键盘右 Ctrl 键</td>
+<td>0x0061</td>
+<td>KEY_RIGHTCTRL</td>
+<td>3.0</td>
+<td>0x0072</td>
+<td>KEYCODE_CTRL_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e5</td>
+<td>键盘右 Shift 键</td>
+<td>0x0036</td>
+<td>KEY_RIGHTSHIFT</td>
+<td>1.6</td>
+<td>0x003c</td>
+<td>KEYCODE_SHIFT_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e6</td>
+<td>键盘右 Alt 键</td>
+<td>0x0064</td>
+<td>KEY_RIGHTALT</td>
+<td>1.6</td>
+<td>0x003a</td>
+<td>KEYCODE_ALT_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e7</td>
+<td>键盘右 GUI 键</td>
+<td>0x007e</td>
+<td>KEY_RIGHTMETA</td>
+<td>3.0</td>
+<td>0x0076</td>
+<td>KEYCODE_META_RIGHT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e8</td>
+<td></td>
+<td>0x00a4</td>
+<td>KEY_PLAYPAUSE</td>
+<td>3.0</td>
+<td>0x0055</td>
+<td>KEYCODE_MEDIA_PLAY_PAUSE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00e9</td>
+<td></td>
+<td>0x00a6</td>
+<td>KEY_STOPCD</td>
+<td>3.0</td>
+<td>0x0056</td>
+<td>KEYCODE_MEDIA_STOP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ea</td>
+<td></td>
+<td>0x00a5</td>
+<td>KEY_PREVIOUSSONG </td>
+<td>3.0</td>
+<td>0x0058</td>
+<td>KEYCODE_MEDIA_PREVIOUS</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00eb</td>
+<td></td>
+<td>0x00a3</td>
+<td>KEY_NEXTSONG</td>
+<td>3.0</td>
+<td>0x0057</td>
+<td>KEYCODE_MEDIA_NEXT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ec</td>
+<td></td>
+<td>0x00a1</td>
+<td>KEY_EJECTCD</td>
+<td>3.0</td>
+<td>0x0081</td>
+<td>KEYCODE_MEDIA_EJECT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ed</td>
+<td></td>
+<td>0x0073</td>
+<td>KEY_VOLUMEUP</td>
+<td>1.6</td>
+<td>0x0018</td>
+<td>KEYCODE_VOLUME_UP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ee</td>
+<td></td>
+<td>0x0072</td>
+<td>KEY_VOLUMEDOWN</td>
+<td>1.6</td>
+<td>0x0019</td>
+<td>KEYCODE_VOLUME_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00ef</td>
+<td></td>
+<td>0x0071</td>
+<td>KEY_MUTE</td>
+<td>3.0</td>
+<td>0x00a4</td>
+<td>KEYCODE_VOLUME_MUTE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f0</td>
+<td></td>
+<td>0x0096</td>
+<td>KEY_WWW </td>
+<td>1.6</td>
+<td>0x0040</td>
+<td>KEYCODE_EXPLORER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f1</td>
+<td></td>
+<td>0x009e</td>
+<td>KEY_BACK</td>
+<td>1.6</td>
+<td>0x0004</td>
+<td>KEYCODE_BACK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f2</td>
+<td></td>
+<td>0x009f</td>
+<td>KEY_FORWARD</td>
+<td>3.0</td>
+<td>0x007d</td>
+<td>KEYCODE_FORWARD</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f3</td>
+<td></td>
+<td>0x0080</td>
+<td>KEY_STOP</td>
+<td>3.0</td>
+<td>0x0056</td>
+<td>KEYCODE_MEDIA_STOP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f4</td>
+<td></td>
+<td>0x0088</td>
+<td>KEY_FIND</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f5</td>
+<td></td>
+<td>0x00b1</td>
+<td>KEY_SCROLLUP</td>
+<td>3.0</td>
+<td>0x005c</td>
+<td>KEYCODE_PAGE_UP </td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f6</td>
+<td></td>
+<td>0x00b2 </td>
+<td>KEY_SCROLLDOWN</td>
+<td>3.0</td>
+<td>0x005d</td>
+<td>KEYCODE_PAGE_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f7</td>
+<td></td>
+<td>0x00b0</td>
+<td>KEY_EDIT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f8</td>
+<td></td>
+<td>0x008e</td>
+<td>KEY_SLEEP</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00f9</td>
+<td></td>
+<td>0x0098</td>
+<td>KEY_COFFEE</td>
+<td>4.0</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00fa</td>
+<td></td>
+<td>0x00ad</td>
+<td>KEY_REFRESH</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x07 0x00fb</td>
+<td></td>
+<td>0x008c</td>
+<td>KEY_CALC</td>
+<td>4.0.3</td>
+<td>0x00d2</td>
+<td>KEYCODE_CALCULATOR</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<h3 id="hid-generic-desktop-page-0x01">HID 普通桌面用途页 (0x01)</h3>
+<table>
+<thead>
+<tr>
+<th>HID 用途</th>
+<th>HID 用途名称</th>
+<th>LKC</th>
+<th>Linux 按键代码名称</th>
+<th>版本</th>
+<th>AKC</th>
+<th>Android 按键代码名称</th>
+<th>备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>0x01 0x0081</td>
+<td>系统电源中断</td>
+<td>0x0074</td>
+<td>KEY_POWER</td>
+<td>1.6</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0082</td>
+<td>系统休眠</td>
+<td>0x008e</td>
+<td>KEY_SLEEP</td>
+<td>4.0</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0083</td>
+<td>系统唤醒</td>
+<td>0x008f</td>
+<td>KEY_WAKEUP</td>
+<td>4.0</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0084</td>
+<td>系统上下文菜单</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0085</td>
+<td>系统主要菜单</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0086</td>
+<td>系统应用菜单</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0087</td>
+<td>系统菜单帮助</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0088</td>
+<td>系统菜单退出</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x0089</td>
+<td>系统菜单选择</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008a</td>
+<td>系统菜单向右</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008b</td>
+<td>系统菜单向左</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008c</td>
+<td>系统菜单向上</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008d</td>
+<td>系统菜单向下</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008e</td>
+<td>系统冷重启</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x008f</td>
+<td>系统热重启</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a0</td>
+<td>系统停靠</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a1</td>
+<td>系统取消停靠</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a2 </td>
+<td>系统设置</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a3</td>
+<td>系统中断</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a4</td>
+<td>系统调试程序中断</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a5</td>
+<td>应用中断</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a6</td>
+<td>应用调试程序中断</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a7</td>
+<td>系统扬声器静音</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00a8</td>
+<td>系统休眠</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b0</td>
+<td>系统反转显示</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b1</td>
+<td>系统内部显示</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b2</td>
+<td>系统外部显示</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b3</td>
+<td>系统内外部显示</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b4</td>
+<td>系统双向显示</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b5</td>
+<td>系统显示切换 Int/Ext</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b6</td>
+<td>系统显示交换 Prim./Sec.</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x01 0x00b7</td>
+<td>系统显示 LCD 自动调节</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<h3 id="hid-consumer-page-0x0c">HID 消费方页面 (0x0c)</h3>
+<table>
+<thead>
+<tr>
+<th>HID 用途</th>
+<th>HID 用途名称</th>
+<th>LKC</th>
+<th>Linux 按键代码名称</th>
+<th>版本</th>
+<th>AKC</th>
+<th>Android 按键代码名称</th>
+<th>备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>0x0c 0x0030</td>
+<td>电源</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0031</td>
+<td>重置</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0032</td>
+<td>休眠</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0033</td>
+<td>休眠倒计时</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0034</td>
+<td>休眠模式</td>
+<td>0x008e</td>
+<td>KEY_SLEEP</td>
+<td>4.0</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0040</td>
+<td>菜单</td>
+<td>0x008b</td>
+<td>KEY_MENU</td>
+<td>1.6</td>
+<td>0x0052</td>
+<td>KEYCODE_MENU</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0041</td>
+<td>菜单选取</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0042</td>
+<td>菜单向上</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0043</td>
+<td>菜单向下</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0044</td>
+<td>菜单向左</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0045</td>
+<td>菜单向右</td>
+<td>0x0181</td>
+<td>KEY_RADIO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0046</td>
+<td>菜单取消</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0047</td>
+<td>菜单数值增加</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0048</td>
+<td>菜单数值减少</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0081</td>
+<td>指派选择</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0082</td>
+<td>模式步骤</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0083</td>
+<td>撤回上一个</td>
+<td>0x0195</td>
+<td>KEY_LAST</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0084</td>
+<td>输入频道</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0085</td>
+<td>订购影片</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0088</td>
+<td>媒体选择计算机</td>
+<td>0x0178</td>
+<td>KEY_PC</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0089</td>
+<td>媒体选择电视机</td>
+<td>0x0179</td>
+<td>KEY_TV</td>
+<td>3.0</td>
+<td>0x00aa</td>
+<td>KEYCODE_TV</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008a</td>
+<td>媒体选择 WWW</td>
+<td>0x0096</td>
+<td>KEY_WWW </td>
+<td>1.6</td>
+<td>0x0040</td>
+<td>KEYCODE_EXPLORER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008b</td>
+<td>媒体选择 DVD</td>
+<td>0x0185</td>
+<td>KEY_DVD</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008c</td>
+<td>媒体选择电话</td>
+<td>0x00a9</td>
+<td>KEY_PHONE</td>
+<td>3.0</td>
+<td>0×0005</td>
+<td>KEYCODE_CALL</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008d</td>
+<td>媒体选择节目预告</td>
+<td>0x016a</td>
+<td>KEY_PROGRAM</td>
+<td>3.0</td>
+<td>0x00ac</td>
+<td>KEYCODE_GUIDE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008e</td>
+<td>媒体选择视频电话</td>
+<td>0x01a0</td>
+<td>KEY_VIDEOPHONE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x008f</td>
+<td>媒体选择游戏</td>
+<td>0x01a1</td>
+<td>KEY_GAMES</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0090</td>
+<td>媒体选择消息</td>
+<td>0x018c</td>
+<td>KEY_MEMO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0091</td>
+<td>媒体选择 CD</td>
+<td>0x017f</td>
+<td>KEY_CD</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0092</td>
+<td>媒体选择 VCR</td>
+<td>0x017b</td>
+<td>KEY_VCR</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0093</td>
+<td>媒体选择调谐器</td>
+<td>0x0182</td>
+<td>KEY_TUNER</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0094</td>
+<td>退出</td>
+<td>0x00ae</td>
+<td>KEY_EXIT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0095</td>
+<td>帮助</td>
+<td>0x008a</td>
+<td>KEY_HELP</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0096</td>
+<td>媒体选择磁带</td>
+<td>0x0180</td>
+<td>KEY_TAPE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0097</td>
+<td>媒体选择电缆</td>
+<td>0x017a</td>
+<td>KEY_TV2</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0098</td>
+<td>媒体选择卫星</td>
+<td>0x017d</td>
+<td>KEY_SAT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0099</td>
+<td>媒体选择安全</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x009a</td>
+<td>媒体选择起点</td>
+<td>0x016e</td>
+<td>KEY_PVR</td>
+<td>3.0</td>
+<td>0x00ad</td>
+<td>KEYCODE_DVR</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x009c</td>
+<td>频道增加</td>
+<td>0x0192</td>
+<td>KEY_CHANNELUP</td>
+<td>3.0</td>
+<td>0x00a6</td>
+<td>KEYCODE_CHANNEL_UP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x009d</td>
+<td>频道减少</td>
+<td>0x0193</td>
+<td>KEY_CHANNELDOWN</td>
+<td>3.0</td>
+<td>0x00a7</td>
+<td>KEYCODE_CHANNEL_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x009e</td>
+<td>媒体选择 SAP</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00a0</td>
+<td>VCR +</td>
+<td>0x017c</td>
+<td>KEY_VCR2</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00a1</td>
+<td>1 次</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00a2</td>
+<td>每天</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00a3</td>
+<td>每周</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00a4</td>
+<td>每月</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b0</td>
+<td>播放</td>
+<td>0x00cf</td>
+<td>KEY_PLAY</td>
+<td>3.0</td>
+<td>0x007e</td>
+<td>KEYCODE_MEDIA_PLAY</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b1</td>
+<td>暂停</td>
+<td>0x0077</td>
+<td>KEY_PAUSE</td>
+<td>3.0</td>
+<td>0x0079</td>
+<td>KEYCODE_BREAK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b2</td>
+<td>录制</td>
+<td>0x00a7</td>
+<td>KEY_RECORD</td>
+<td>3.0</td>
+<td>0x0082</td>
+<td>KEYCODE_MEDIA_RECORD</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b3</td>
+<td>快进</td>
+<td>0x00d0</td>
+<td>KEY_FASTFORWARD</td>
+<td>3.0</td>
+<td>0x005a</td>
+<td>KEYCODE_MEDIA_FAST_FORWARD</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b4</td>
+<td>快退</td>
+<td>0x00a8</td>
+<td>KEY_REWIND</td>
+<td>3.0</td>
+<td>0x0059</td>
+<td>KEYCODE_MEDIA_REWIND</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b5</td>
+<td>扫描下一曲目</td>
+<td>0x00a3</td>
+<td>KEY_NEXTSONG</td>
+<td>3.0</td>
+<td>0x0057</td>
+<td>KEYCODE_MEDIA_NEXT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b6</td>
+<td>扫描上一曲目</td>
+<td>0x00a5</td>
+<td>KEY_PREVIOUSSONG </td>
+<td>3.0</td>
+<td>0x0058</td>
+<td>KEYCODE_MEDIA_PREVIOUS</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b7</td>
+<td>停止</td>
+<td>0x00a6</td>
+<td>KEY_STOPCD</td>
+<td>3.0</td>
+<td>0x0056</td>
+<td>KEYCODE_MEDIA_STOP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b8</td>
+<td>弹出</td>
+<td>0x00a1</td>
+<td>KEY_EJECTCD</td>
+<td>3.0</td>
+<td>0x0081</td>
+<td>KEYCODE_MEDIA_EJECT</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00b9</td>
+<td>随机播放</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00ba</td>
+<td>选择磁盘</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00bb</td>
+<td>放入磁盘</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00bc</td>
+<td>重复</td>
+<td>0x01b7</td>
+<td>KEY_MEDIA_REPEAT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00be</td>
+<td>一般跟踪</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c0</td>
+<td>画面向前</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c1</td>
+<td>画面向后</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c2</td>
+<td>标记</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c3</td>
+<td>清除标记</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c4</td>
+<td>从标记处重复</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c5</td>
+<td>返回标记处</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c6</td>
+<td>正向搜索标记</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c7</td>
+<td>反向搜索标记</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c8</td>
+<td>计数器重设</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00c9</td>
+<td>显示计数器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00ca</td>
+<td>跟踪增加</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00cb</td>
+<td>跟踪减少</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00cc</td>
+<td>停止/弹出</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00cd</td>
+<td>播放/暂停</td>
+<td>0x00a4</td>
+<td>KEY_PLAYPAUSE</td>
+<td>3.0</td>
+<td>0x0055</td>
+<td>KEYCODE_MEDIA_PLAY_PAUSE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00ce</td>
+<td>播放/跳过</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e2</td>
+<td>静音</td>
+<td>0x0071</td>
+<td>KEY_MUTE</td>
+<td>3.0</td>
+<td>0x00a4</td>
+<td>KEYCODE_VOLUME_MUTE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e5</td>
+<td>低音增强</td>
+<td>0x00d1</td>
+<td>KEY_BASSBOOST</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e6</td>
+<td>环绕模式</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e7</td>
+<td>音量</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e8</td>
+<td>MPX</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00e9</td>
+<td>音量增大</td>
+<td>0x0073</td>
+<td>KEY_VOLUMEUP</td>
+<td>1.6</td>
+<td>0x0018</td>
+<td>KEYCODE_VOLUME_UP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x00ea</td>
+<td>音量减小</td>
+<td>0x0072</td>
+<td>KEY_VOLUMEDOWN</td>
+<td>1.6</td>
+<td>0x0019</td>
+<td>KEYCODE_VOLUME_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0181</td>
+<td>AL 启动按钮配置工具</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0182</td>
+<td>AL 可编程按钮配置</td>
+<td>0x009c</td>
+<td>KEY_BOOKMARKS</td>
+<td>3.0</td>
+<td>0x00ae</td>
+<td>KEYCODE_BOOKMARK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0183</td>
+<td>AL 消费方控制配置</td>
+<td>0x00ab</td>
+<td>KEY_CONFIG</td>
+<td>4.0.3</td>
+<td>0x00d1</td>
+<td>KEYCODE_MUSIC </td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0184</td>
+<td>AL 文字处理器</td>
+<td>0x01a5</td>
+<td>KEY_WORDPROCESSOR</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0185</td>
+<td>AL 文本编辑器</td>
+<td>0x01a6</td>
+<td>KEY_EDITOR</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0186</td>
+<td>AL 电子表格</td>
+<td>0x01a7</td>
+<td>KEY_SPREADSHEET</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0187</td>
+<td>AL 图形编辑器</td>
+<td>0x01a8</td>
+<td>KEY_GRAPHICSEDITOR</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0188</td>
+<td>AL 演示应用</td>
+<td>0x01a9</td>
+<td>KEY_PRESENTATION</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0189</td>
+<td>AL 数据库应用</td>
+<td>0x01aa</td>
+<td>KEY_DATABASE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018a</td>
+<td>AL 电子邮件阅读器</td>
+<td>0x009b</td>
+<td>KEY_MAIL</td>
+<td>1.6</td>
+<td>0x0041</td>
+<td>KEYCODE_ENVELOPE</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018b</td>
+<td>AL 新闻阅读器</td>
+<td>0x01ab</td>
+<td>KEY_NEWS</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018c</td>
+<td>AL 语音信箱</td>
+<td>0x01ac</td>
+<td>KEY_VOICEMAIL</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018d</td>
+<td>AL 联系人/通讯录</td>
+<td>0x01ad</td>
+<td>KEY_ADDRESSBOOK</td>
+<td>4.0.3</td>
+<td>0x00cf</td>
+<td>KEYCODE_CONTACTS</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018e</td>
+<td>AL 日程表/时间表</td>
+<td>0x018d</td>
+<td>KEY_CALENDAR</td>
+<td>4.0.3</td>
+<td>0x00d0</td>
+<td>KEYCODE_CALENDAR</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x018f</td>
+<td>AL 任务/项目管理器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0190</td>
+<td>AL 日志/日记/工作时间记录卡</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0191</td>
+<td>AL 支票簿/财务</td>
+<td>0x00db</td>
+<td>KEY_FINANCE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0192</td>
+<td>AL 计算器</td>
+<td>0x008c</td>
+<td>KEY_CALC</td>
+<td>4.0.3</td>
+<td>0x00d2</td>
+<td>KEYCODE_CALCULATOR</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0193</td>
+<td>AL A/V 捕捉/播放</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0194</td>
+<td>AL 本地计算机浏览器</td>
+<td>0x0090</td>
+<td>KEY_FILE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0195</td>
+<td>AL LAN/WAN 浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0196</td>
+<td>AL 互联网浏览器</td>
+<td>0x0096</td>
+<td>KEY_WWW </td>
+<td>1.6</td>
+<td>0x0040</td>
+<td>KEYCODE_EXPLORER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0197</td>
+<td>AL 远程网络/ISP 连接</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0198</td>
+<td>AL 网络会议</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0199</td>
+<td>AL 网络聊天</td>
+<td>0x00d8</td>
+<td>KEY_CHAT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019a</td>
+<td>AL 电话/拨号器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019b</td>
+<td>AL 登录</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019c</td>
+<td>AL 注销</td>
+<td>0x01b1</td>
+<td>KEY_LOGOFF</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019d</td>
+<td>AL 登录/注销</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019e</td>
+<td>AL 终端锁定/屏幕保护程序</td>
+<td>0x0098</td>
+<td>KEY_COFFEE</td>
+<td>4.0</td>
+<td>0x001a</td>
+<td>KEYCODE_POWER</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x019f</td>
+<td>AL 控制面板</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a0</td>
+<td>AL 命令行处理器/运行</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a1</td>
+<td>AL 进程/任务管理器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a2</td>
+<td>AL 选择任务/应用</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a3</td>
+<td>AL 下一项任务/应用</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a4</td>
+<td>AL 上一项任务/应用</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a5</td>
+<td>AL 优先暂停任务/应用</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a6</td>
+<td>AL 集成帮助中心</td>
+<td>0x008a</td>
+<td>KEY_HELP</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a7</td>
+<td>AL 文档</td>
+<td>0x00eb</td>
+<td>KEY_DOCUMENTS</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a8</td>
+<td>AL 词典</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01a9</td>
+<td>AL 字典</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01aa</td>
+<td>AL 桌面</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01ab</td>
+<td>AL 拼写检查</td>
+<td>0x01b0</td>
+<td>KEY_SPELLCHECK</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01ac</td>
+<td>AL 语法检查</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01ad</td>
+<td>AL 无线状态</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01ae</td>
+<td>AL 键盘布局</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01af</td>
+<td>AL 病毒防护</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b0</td>
+<td>AL 加密</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b1</td>
+<td>AL 屏保</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b2</td>
+<td>AL 闹钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b3</td>
+<td>AL 时钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b4</td>
+<td>AL 文件浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b5</td>
+<td>AL 电源状态</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b6</td>
+<td>AL 图片浏览器</td>
+<td>0x00e2</td>
+<td>KEY_MEDIA</td>
+<td>3.0</td>
+<td>0x004f</td>
+<td>KEYCODE_HEADSETHOOK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b7</td>
+<td>AL 音频浏览器</td>
+<td>0x00d5</td>
+<td>KEY_SOUND</td>
+<td>4.0.3</td>
+<td>0x00d1</td>
+<td>KEYCODE_MUSIC </td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b8</td>
+<td>AL 影片浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01b9</td>
+<td>AL 数字版权管理器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01ba</td>
+<td>AL 数字钱包</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01bc</td>
+<td>AL 即时消息传输</td>
+<td>0x01ae</td>
+<td>KEY_MESSENGER</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01bd</td>
+<td>AL OEM 功能/提示管理器</td>
+<td>0x0166</td>
+<td>KEY_INFO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01be</td>
+<td>AL OEM 帮助</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01bf</td>
+<td>AL 在线社区</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c0</td>
+<td>AL 娱乐内容浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c1</td>
+<td>AL 在线购物浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c2</td>
+<td>AL SmartCard 信息/帮助</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c3</td>
+<td>AL 市场/金融浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c4</td>
+<td>AL 自定义公司新闻浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c5</td>
+<td>AL 在线活动浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c6</td>
+<td>AL 研究/搜索浏览器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x01c7</td>
+<td>AL 音频播放器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0201</td>
+<td>AC 新建</td>
+<td>0x00b5</td>
+<td>KEY_NEW</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0202</td>
+<td>AC 打开</td>
+<td>0x0086</td>
+<td>KEY_OPEN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0203</td>
+<td>AC 关闭</td>
+<td>0x00ce</td>
+<td>KEY_CLOSE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0204</td>
+<td>AC 退出</td>
+<td>0x00ae</td>
+<td>KEY_EXIT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0205</td>
+<td>AC 最大化</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0206</td>
+<td>AC 最小化</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0207</td>
+<td>AC 保存</td>
+<td>0x00ea</td>
+<td>KEY_SAVE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0208</td>
+<td>AC 打印</td>
+<td>0x00d2</td>
+<td>KEY_PRINT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0209</td>
+<td>AC 属性</td>
+<td>0x0082</td>
+<td>KEY_PROPS</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021a</td>
+<td>AC 撤消</td>
+<td>0x0083</td>
+<td>KEY_UNDO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021b</td>
+<td>AC 复制</td>
+<td>0x0085</td>
+<td>KEY_COPY</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021c</td>
+<td>AC 剪切</td>
+<td>0x0089</td>
+<td>KEY_CUT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021d</td>
+<td>AC 粘贴</td>
+<td>0x0087</td>
+<td>KEY_PASTE</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021e</td>
+<td>AC 全选</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x021f</td>
+<td>AC 查找</td>
+<td>0x0088</td>
+<td>KEY_FIND</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0220</td>
+<td>AC 查找和替换</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0221</td>
+<td>AC 搜索</td>
+<td>0x00d9</td>
+<td>KEY_SEARCH</td>
+<td>1.6</td>
+<td>0x0054</td>
+<td>KEYCODE_SEARCH </td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0222</td>
+<td>AC 转到</td>
+<td>0x0162</td>
+<td>KEY_GOTO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0223</td>
+<td>AC 起始</td>
+<td>0x00ac</td>
+<td>KEY_HOMEPAGE</td>
+<td>3.0</td>
+<td>0x0003</td>
+<td>KEYCODE_HOME</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0224</td>
+<td>AC 后退</td>
+<td>0x009e</td>
+<td>KEY_BACK</td>
+<td>1.6</td>
+<td>0x0004</td>
+<td>KEYCODE_BACK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0225</td>
+<td>AC 前进</td>
+<td>0x009f</td>
+<td>KEY_FORWARD</td>
+<td>3.0</td>
+<td>0x007d</td>
+<td>KEYCODE_FORWARD</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0226</td>
+<td>AC 停止</td>
+<td>0x0080</td>
+<td>KEY_STOP</td>
+<td>3.0</td>
+<td>0x0056</td>
+<td>KEYCODE_MEDIA_STOP</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0227</td>
+<td>AC 刷新</td>
+<td>0x00ad</td>
+<td>KEY_REFRESH</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0228</td>
+<td>AC 上一个链接</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0229</td>
+<td>AC 下一个链接</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022a</td>
+<td>AC 书签</td>
+<td>0x009c</td>
+<td>KEY_BOOKMARKS</td>
+<td>3.0</td>
+<td>0x00ae</td>
+<td>KEYCODE_BOOKMARK</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022b</td>
+<td>AC 历史记录</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022c</td>
+<td>AC 订阅</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022d</td>
+<td>AC 放大</td>
+<td>0x01a2</td>
+<td>KEY_ZOOMIN</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022e</td>
+<td>AC 缩小</td>
+<td>0x01a3</td>
+<td>KEY_ZOOMOUT</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x022f</td>
+<td>AC 缩放</td>
+<td>0x01a4</td>
+<td>KEY_ZOOMRESET</td>
+<td></td>
+<td></td>
+<td></td>
+<td>(2)</td>
+</tr>
+<tr>
+<td>0x0c 0x0230</td>
+<td>AC 全屏视图</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0231</td>
+<td>AC 普通视图</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0232</td>
+<td>AC 视图切换</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0233</td>
+<td>AC 向上滚动</td>
+<td>0x00b1</td>
+<td>KEY_SCROLLUP</td>
+<td>3.0</td>
+<td>0x005c</td>
+<td>KEYCODE_PAGE_UP </td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0234 </td>
+<td>AC 向下滚动</td>
+<td>0x00b2 </td>
+<td>KEY_SCROLLDOWN</td>
+<td>3.0</td>
+<td>0x005d</td>
+<td>KEYCODE_PAGE_DOWN</td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0236</td>
+<td>AC 向左平移</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0237</td>
+<td>AC 向右平移</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0239</td>
+<td>AC 新窗口</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023a</td>
+<td>AC 横向平铺</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023b</td>
+<td>AC 纵向平铺</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023c</td>
+<td>AC 格式</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023d</td>
+<td>AC 编辑</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023e</td>
+<td>AC 粗体</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x023f</td>
+<td>AC 斜体</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0240</td>
+<td>AC 下划线</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0241</td>
+<td>AC 删除线</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0242</td>
+<td>AC 下标</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0243</td>
+<td>AC 上标</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0244</td>
+<td>AC 全部大写</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0245</td>
+<td>AC 旋转</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0246</td>
+<td>AC 调整大小</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0247</td>
+<td>AC 水平翻转</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0248</td>
+<td>AC 垂直翻转</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0249</td>
+<td>AC 水平镜像</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024a</td>
+<td>AC 垂直镜像</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024b</td>
+<td>AC 字体选择</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024c</td>
+<td>AC 字体颜色</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024d</td>
+<td>AC 字体大小</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024e</td>
+<td>AC 左对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x024f</td>
+<td>AC 水平居中对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0250</td>
+<td>AC 右对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0251</td>
+<td>AC 水平块对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0252</td>
+<td>AC 顶部对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0253</td>
+<td>AC 垂直居中对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0254</td>
+<td>AC 底部对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0255</td>
+<td>AC 垂直块对齐</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0256</td>
+<td>AC 减少缩进</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0257</td>
+<td>AC 增加缩进</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0258</td>
+<td>AC 编号列表</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0259</td>
+<td>AC 重新开始编号</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025a</td>
+<td>AC 项目符号列表</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025b</td>
+<td>AC 升级</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025c</td>
+<td>AC 降级</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025d</td>
+<td>AC 是</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025e</td>
+<td>AC 否</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x025f</td>
+<td>AC 取消</td>
+<td>0x00df</td>
+<td>KEY_CANCEL</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0260</td>
+<td>AC 目录</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0261</td>
+<td>AC 购买/结账</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0262</td>
+<td>AC 添加到购物车</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0263</td>
+<td>AC 展开</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0264</td>
+<td>AC 全部展开</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0265</td>
+<td>AC 收起</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0266</td>
+<td>AC 全部收起</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0267</td>
+<td>AC 打印预览</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0268</td>
+<td>AC 选择性粘贴</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0269</td>
+<td>AC 插入模式</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026a</td>
+<td>AC 删除</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026b</td>
+<td>AC 锁定</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026c</td>
+<td>AC 解锁</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026d</td>
+<td>AC 保护</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026e</td>
+<td>AC 取消保护</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x026f</td>
+<td>AC 添加评论</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0270</td>
+<td>AC 删除评论</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0271</td>
+<td>AC 查看评论</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0272</td>
+<td>AC 选择字词</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0273</td>
+<td>AC 选择句子</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0274</td>
+<td>AC 选择段落</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0275</td>
+<td>AC 选择列</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0276</td>
+<td>AC 选择行</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0277</td>
+<td>AC 选择表格</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0278</td>
+<td>AC 选择对象</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0279</td>
+<td>AC 重做/重复</td>
+<td>0x00b6</td>
+<td>KEY_REDO</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027a</td>
+<td>AC 排序</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027b</td>
+<td>AC 升序排序</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027c</td>
+<td>AC 降序排序</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027d</td>
+<td>AC 过滤器</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027e</td>
+<td>AC 设置时钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x027f</td>
+<td>AC 查看时钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0280</td>
+<td>AC 选择时区</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0281</td>
+<td>AC 编辑时区</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0282</td>
+<td>AC 设置闹钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0283</td>
+<td>AC 清除闹钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0284</td>
+<td>AC 延后闹钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0285</td>
+<td>AC 重置闹钟</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0286</td>
+<td>AC 同步</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0287</td>
+<td>AC 发送/接收</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0288 </td>
+<td>AC 发送至</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0289</td>
+<td>AC 回复</td>
+<td>0x00e8</td>
+<td>KEY_REPLY</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028a</td>
+<td>AC 回复全部</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028b</td>
+<td>AC 转发消息</td>
+<td>0x00e9</td>
+<td>KEY_FORWARDMAIL</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028c</td>
+<td>AC 发送</td>
+<td>0x00e7</td>
+<td>KEY_SEND</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028d</td>
+<td>AC 附加文件</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028e</td>
+<td>AC 上传</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x028f</td>
+<td>AC 下载(目标文件另存为)</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0290</td>
+<td>AC 设置边框</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0291</td>
+<td>AC 插入行</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0292</td>
+<td>AC 插入列</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0293</td>
+<td>AC 插入文件</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0294</td>
+<td>AC 插入图片</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0295</td>
+<td>AC 插入对象</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0296</td>
+<td>AC 插入符号</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0297</td>
+<td>AC 保存并关闭</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0298</td>
+<td>AC 重命名</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x0299</td>
+<td>AC 合并</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x029a</td>
+<td>AC 分割</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x029b</td>
+<td>AC 水平分布</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>0x0c 0x029c</td>
+<td>AC 垂直分布</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<h3 id="additional-non-hid-mappings">其他非 HID 映射</h3>
+<p>下列映射描述了未出现在 HID 中但存在 Linux 按键代码的函数。</p>
+<table>
+<thead>
+<tr>
+<th>LKC</th>
+<th>Linux 按键代码名称</th>
+<th>版本</th>
+<th>AKC</th>
+<th>Android 按键代码名称</th>
+<th>备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>0x01d0</td>
+<td>KEY_FN</td>
+<td>3.0</td>
+<td>0x0077</td>
+<td>KEYCODE_FUNCTION</td>
+<td></td>
+</tr>
+<tr>
+<td>0x01d1</td>
+<td>KEY_FN_ESC</td>
+<td>3.0</td>
+<td>0x006f</td>
+<td>KEYCODE_ESCAPE </td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d2</td>
+<td>KEY_FN_F1</td>
+<td>3.0</td>
+<td>0x0083</td>
+<td>KEYCODE_F1</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d3</td>
+<td>KEY_FN_F2</td>
+<td>3.0</td>
+<td>0x0084</td>
+<td>KEYCODE_F2</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d4</td>
+<td>KEY_FN_F3</td>
+<td>3.0</td>
+<td>0x0085</td>
+<td>KEYCODE_F3</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d5</td>
+<td>KEY_FN_F4</td>
+<td>3.0</td>
+<td>0x0086</td>
+<td>KEYCODE_F4</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d6</td>
+<td>KEY_FN_F5</td>
+<td>3.0</td>
+<td>0x0087</td>
+<td>KEYCODE_F5</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d7</td>
+<td>KEY_FN_F6</td>
+<td>3.0</td>
+<td>0x0088</td>
+<td>KEYCODE_F6</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d8</td>
+<td>KEY_FN_F7</td>
+<td>3.0</td>
+<td>0x0089</td>
+<td>KEYCODE_F7</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01d9</td>
+<td>KEY_FN_F8</td>
+<td>3.0</td>
+<td>0x008a</td>
+<td>KEYCODE_F8</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01da</td>
+<td>KEY_FN_F9</td>
+<td>3.0</td>
+<td>0x008b</td>
+<td>KEYCODE_F9</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01db</td>
+<td>KEY_FN_F10</td>
+<td>3.0</td>
+<td>0x008c</td>
+<td>KEYCODE_F10</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01dc</td>
+<td>KEY_FN_F11</td>
+<td>3.0</td>
+<td>0x008d</td>
+<td>KEYCODE_F11</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01dd</td>
+<td>KEY_FN_F12</td>
+<td>3.0</td>
+<td>0x008e</td>
+<td>KEYCODE_F12</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01de</td>
+<td>KEY_FN_1</td>
+<td>3.0</td>
+<td>0x0008</td>
+<td>KEYCODE_1</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01df</td>
+<td>KEY_FN_2</td>
+<td>3.0</td>
+<td>0x0009</td>
+<td>KEYCODE_2</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01e0</td>
+<td>KEY_FN_D</td>
+<td>3.0</td>
+<td>0x0020</td>
+<td>KEYCODE_D</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01e1</td>
+<td>KEY_FN_E</td>
+<td>3.0</td>
+<td>0x0021</td>
+<td>KEYCODE_E</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01e2</td>
+<td>KEY_FN_F</td>
+<td>3.0</td>
+<td>0x0022</td>
+<td>KEYCODE_F</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01e3</td>
+<td>KEY_FN_S</td>
+<td>3.0</td>
+<td>0x002f</td>
+<td>KEYCODE_S</td>
+<td>3</td>
+</tr>
+<tr>
+<td>0x01e4</td>
+<td>KEY_FN_B</td>
+<td>3.0</td>
+<td>0x001e</td>
+<td>KEYCODE_B</td>
+<td>3</td>
+</tr>
+</tbody>
+</table>
+<h3 id="legacy-unsupported-keys">不受支持的旧版按键</h3>
+<p>以下这些映射出现在以往的 Android 版本中,但与 HID 不一致或采用了非标准 Linux 按键代码。这些映射已不再受支持。</p>
+<table>
+<thead>
+<tr>
+<th>LKC</th>
+<th>Linux 按键代码名称</th>
+<th>版本</th>
+<th>AKC</th>
+<th>Android 按键代码名称</th>
+<th>备注</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>0x00db</td>
+<td>KEY_EMAIL</td>
+<td>1.6</td>
+<td>0x004d</td>
+<td>KEYCODE_AT</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e3</td>
+<td>KEY_STAR</td>
+<td>1.6</td>
+<td>0x0011</td>
+<td>KEYCODE_STAR</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e4</td>
+<td>KEY_SHARP</td>
+<td>1.6</td>
+<td>0x0012</td>
+<td>KEYCODE_POUND</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e5</td>
+<td>KEY_SOFT1</td>
+<td>1.6</td>
+<td>0x0052</td>
+<td>KEYCODE_MENU</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e6</td>
+<td>KEY_SOFT2</td>
+<td>1.6</td>
+<td>0x0002</td>
+<td>KEYCODE_SOFT_RIGHT</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e7</td>
+<td>KEY_SEND</td>
+<td>1.6</td>
+<td>0×0005</td>
+<td>KEYCODE_CALL</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e8</td>
+<td>KEY_CENTER</td>
+<td>1.6</td>
+<td>0x0017</td>
+<td>KEYCODE_DPAD_CENTER</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00e9</td>
+<td>KEY_HEADSETHOOK</td>
+<td>1.6</td>
+<td>0x004f</td>
+<td>KEYCODE_HEADSETHOOK</td>
+<td>4</td>
+</tr>
+<tr>
+<td>""</td>
+<td>""</td>
+<td>4.0</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00ea</td>
+<td>KEY_0_5</td>
+<td>1.6</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+<tr>
+<td>0x00eb</td>
+<td>KEY_2_5</td>
+<td>1.6</td>
+<td></td>
+<td></td>
+<td>4</td>
+</tr>
+</tbody>
+</table>
+<h3 id="notes">备注</h3>
+<ol>
+<li>
+<p>与常用字母数字和符号按键相关联的 Android 按键代码可能会因键盘布局和语言而异。由于历史原因,与键盘上的按键相关联的物理扫描代码和 HID 用途通常是根据位置进行定义的,即使这些按键上所打印的标签可能存在语言差异。</p>
+<p>在美式英语 (QWERTY) 键盘上,左上角的字母按键会标记为 Q,而在法式 (AZERTY) 键盘上,位于相同位置的按键则会标记为 A。尽管标签不同,但位于两个键盘左上角的字母按键均表示使用 HID 用途 0x07 0x0014(已映射到 Linux 按键代码 KEY_Q)。</p>
+<p>当 Android 配置有美式英语键盘布局时,Linux 按键代码 KEY_Q 将被映射到 Android 按键代码 KEYCODE_Q,并将产生字符“Q”和“q”。然而,当 Android 配置有法式键盘布局时,Linux 按键代码 KEY_Q 将被映射到 Android 按键代码 KEYCODE_A,并将产生字符“A”和“a”。</p>
+<p>Android 按键代码通常反映按键特定于语言的解释,因此不同的 Android 按键代码可能会用于不同的语言。</p>
+</li>
+<li>
+<p><code>0x0c 0x022f AC Zoom</code> 在 HID 中定义为线性控件,但内核会将其映射为按键(这很可能是错误的)。</p>
+</li>
+<li>
+<p>Linux 功能键 <code>KEY_FN_*</code> 可被映射到更简单的按键代码,但也会被分配已设置为 True 的<code>META_FUNCTION</code> Meta 状态位。</p>
+</li>
+<li>
+<p>在 Android Ice Cream Sandwich 4.0 之前,默认的键盘布局包含一些未在主线 Linux 内核头文件中定义的其他按键代码的映射。这些映射此后已被移除,因为这些以前未定义的按键代码在较新版本的 Linux 内核中已被赋予了不同的含义。</p>
+</li>
+</ol>
+<h3 id="sources">来源</h3>
+<ol>
+<li><a href="http://www.usb.org/developers/hidpage/Hut1_12v2.pdf">USB HID 用途表 v1.12</a></li>
+<li>Linux 2.6.39 内核:include/linux/input.h、drivers/hid/hid-input.c</li>
+<li>Android ICS:qwerty.kl、Generic.kl、KeyEvent.java</li>
+</ol>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/media/index.html b/zh-cn/devices/media/index.html
new file mode 100644
index 00000000..6a8851dd
--- /dev/null
+++ b/zh-cn/devices/media/index.html
@@ -0,0 +1,84 @@
+<html devsite><head>
+ <title>媒体</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<img style="float: right; margin: 0px 15px 15px 15px;" src="images/ape_fwk_hal_media.png" alt="Android 媒体 HAL 图标"/>
+
+<p>Android 包含 Stagefright。Stagefright 是位于 Native 层的媒体播放引擎,内置了基于软件的编解码器,且适用于热门媒体格式。</p>
+
+<p>Stagefright 音频和视频播放功能包括集成 OpenMAX 编解码器、会话管理、基于时间的同步渲染、传输控制和 DRM。</p>
+
+<p>Stagefright 还支持集成您提供的自定义硬件编解码器。要设置编码和解码媒体的硬件路径,您必须将基于硬件的编解码器作为 OpenMax IL(集成层)组件进行实现。</p>
+
+<p class="note"><strong>注意</strong>:Stagefright 更新可通过 Android <a href="/security/bulletin/index.html">每月安全更新</a>过程,作为 Android 操作系统版本的一部分进行更新。</p>
+
+<h2 id="architecture">架构</h2>
+<p>媒体应用根据以下架构与 Android Native 多媒体框架进行交互。</p>
+<img src="/devices/media/images/ape_fwk_media.png" alt="Android 媒体架构" id="figure1"/><p class="img-caption"><strong>图 1.</strong> 媒体架构</p>
+
+<dl>
+<dt>应用框架</dt>
+<dd>应用代码位于应用框架层,可利用 <a href="http://developer.android.com/reference/android/media/package-summary.html">android.media</a> API 与多媒体硬件进行交互。</dd>
+
+<dt>Binder IPC</dt>
+<dd>Binder IPC 代理用于促进跨越进程边界的通信。它们位于 <code>frameworks/av/media/libmedia</code> 目录中,并以字母“I”开头。</dd>
+
+<dt>Native 多媒体框架</dt>
+<dd>在 Native 层,Android 提供了一个利用 Stagefright 引擎进行音频和视频录制及播放的多媒体框架。Stagefright 随附支持的软件编解码器的默认列表,并且您可以使用 OpenMax 集成层标准实现自己的硬件编解码器。有关实现的更多详细信息,请参阅位于 <code>frameworks/av/media</code> 中的 MediaPlayer 和 Stagefright 组件。</dd>
+
+<dt>OpenMAX 集成层 (IL)</dt>
+<dd>OpenMAX IL 为 Stagefright 提供了一种标准化的方式来识别和使用基于硬件的自定义多媒体编解码器(称为组件)。您必须以名为 <code>libstagefrighthw.so</code> 的共享库的形式提供 OpenMAX 插件。此插件将 Stagefright 与您的自定义编解码器组件相连接,并且该组件必须根据 OpenMAX IL 组件标准来实现。</dd>
+</dl>
+
+<h2 id="codecs">实现自定义编解码器</h2>
+<p>Stagefright 随附适用于通用媒体格式的内置软件编解码器,但您也可以添加自己的自定义硬件编解码器作为 OpenMAX 组件。为此,您必须创建 OMX 组件和一个 OMX 插件,将您的自定义编解码器与 Stagefright 框架相结合。关于组件,请参阅 <code>hardware/ti/omap4xxx/domx/</code>;关于 Galaxy Nexus 的示例插件,请参阅 <code>hardware/ti/omap4xx/libstagefrighthw</code>。</p>
+
+<p>添加您自己的编解码器:</p>
+<ol>
+<li>根据 OpenMAX IL 组件标准创建您的组件。组件接口位于 <code>frameworks/native/include/media/OpenMAX/OMX_Component.h</code> 文件中。要详细了解 OpenMAX IL 规范,请访问 <a href="http://www.khronos.org/openmax/">OpenMAX 网站</a>。</li>
+<li>创建一个将您的组件与 Stagefright 服务相连接的 OpenMAX 插件。关于创建插件的接口,请参阅 <code>frameworks/native/include/media/hardware/OMXPluginBase.h</code> 和 <code>HardwareAPI.h</code> 标头文件。</li>
+<li>将您的插件构建为产品 Makefile 中名为 <code>libstagefrighthw.so</code> 的共享库。例如:
+<br />
+<pre class="devsite-click-to-copy">
+LOCAL_MODULE := libstagefrighthw
+</pre>
+<p>在设备的 Makefile 中,确保将模块声明为产品包:</p>
+<pre class="devsite-click-to-copy">
+PRODUCT_PACKAGES += \
+ libstagefrighthw \
+ ...
+</pre>
+</li>
+</ol>
+
+<h2 id="expose">将编解码器暴露给框架</h2>
+<p>Stagefright 服务解析 <code>system/etc/media_codecs.xml</code> 和 <code>system/etc/media_profiles.xml</code>,从而向应用开发者暴露设备支持的编解码器和配置文件(通过 <code>android.media. MediaCodecList</code> 和 <code>android.media.CamcorderProfile</code> 类)。您必须在 <code>device/&lt;company&gt;/&lt;device&gt;/</code> 目录中创建两个文件,并将其复制到设备 Makefile 中系统映像的 <code>system/etc</code> 目录中。例如:</p>
+<pre class="devsite-click-to-copy">
+PRODUCT_COPY_FILES += \
+ device/samsung/tuna/media_profiles.xml:system/etc/media_profiles.xml \
+ device/samsung/tuna/media_codecs.xml:system/etc/media_codecs.xml \
+</pre>
+
+<p>有关完整示例,请参阅 <code>device/samsung/tuna/media_codecs.xml</code> 和 <code>device/samsung/tuna/media_profiles.xml</code>。</p>
+
+<p class="note"><strong>注意</strong>:从 Android 4.1 开始,不再支持媒体编解码器的 <code>&lt;Quirk&gt;</code> 元素。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/sensors/batching.html b/zh-cn/devices/sensors/batching.html
new file mode 100644
index 00000000..75047b90
--- /dev/null
+++ b/zh-cn/devices/sensors/batching.html
@@ -0,0 +1,128 @@
+<html devsite><head>
+ <title>批处理</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<h2 id="what_is_batching">什么是批处理?</h2>
+<p>“批处理”是指将传感器事件存储在硬件 FIFO 中,然后通过 <a href="hal-interface.html">HAL</a> 报告它们,而非立即进行报告。</p>
+<p>批处理不会唤醒 SoC 来接收每个事件,而会将事件分组到一起进行处理,从而节省大量电量。</p>
+<p>FIFO 越大,节省的电量也越多。实施批处理是一种以牺牲硬件内存来降低功耗的做法。</p>
+<p>当传感器配有硬件 FIFO (<code>sensor_t.fifoMaxEventCount &gt; 0</code>) 时,便会进行批处理,并且会出现以下两种情况之一:</p>
+<ul>
+ <li> <code>max_report_latency &gt; 0</code>,这意味着此特定传感器的传感器事件最长可延迟 <code>max_report_latency</code> 再通过 HAL 进行报告。</li>
+ <li>或 SoC 处于挂起模式且该传感器为非唤醒传感器,这意味着在等待 SoC 唤醒时必须存储事件。</li>
+</ul>
+<p>有关详情,请参阅 <a href="hal-interface.html#batch_sensor_flags_sampling_period_maximum_report_latency">HAL 批处理函数</a>一节。</p>
+<p>与批处理相对的是轮询操作,其中事件不经过缓冲而立即被报告。轮询操作对应于以下情况:</p>
+<ul>
+ <li>当 <code>max_report_latency = 0</code> 且可将事件传递给应用时,这意味着:
+ <ul>
+ <li>SoC 处于唤醒状态</li>
+ <li>或传感器是唤醒传感器</li>
+ </ul>
+ </li>
+ <li>或者,当传感器没有硬件 FIFO (<code>sensor_t.fifoMaxEventCount =
+ 0</code>) 时,在这种情况下:
+ <ul>
+ <li>如果 SoC 处于唤醒状态或传感器是唤醒传感器,则会报告事件</li>
+ <li>如果 SoC 处于休眠状态并且传感器不是唤醒传感器,则会丢失事件</li>
+ </ul>
+ </li>
+</ul>
+<h2 id="wake-up_fifos_and_non-wake-up_fifos">唤醒 FIFO 和非唤醒 FIFO</h2>
+<p>来自<a href="suspend-mode.html#wake-up_sensors">唤醒传感器</a>的传感器事件必须存储到唤醒 FIFO 中。可以是每个传感器配一个唤醒 FIFO,或者更常见的情况是,使用一个较大的共享唤醒 FIFO,来自所有唤醒传感器的事件交错存储于该 FIFO 中。也可使用其他方案,例如一些唤醒传感器具有专用的 FIFO,其余唤醒传感器则共用同一个 FIFO。</p>
+<p>同样,来自<a href="suspend-mode.html#non-wake-up_sensors">非唤醒传感器</a>的传感器事件必须存储在非唤醒 FIFO 中,并且可以有一个或多个非唤醒 FIFO。</p>
+<p>在所有情况下,唤醒传感器事件和非唤醒传感器事件都不能交错存储在同一个 FIFO 中。唤醒事件进入唤醒 FIFO,非唤醒事件进入非唤醒 FIFO。</p>
+<p>对于唤醒 FIFO,“一个较大的共享 FIFO”设计可带来最佳的能耗效益。对于非唤醒 FIFO,使用“一个较大的共享 FIFO”和“几个较小的预留 FIFO”之间没有优劣之分。有关如何确定每个 FIFO 的规格,请参阅 <a href="#fifo_allocation_priority">FIFO 分配优先级</a>一节。</p>
+<h2 id="behavior_outside_of_suspend_mode">非挂起模式下的行为</h2>
+<p>当 SoC 处于唤醒状态(未处于挂起模式)时,只要事件延迟不超过 <code>max_report_latency</code>,则可将事件临时存储在其 FIFO 中。</p>
+<p>只要 SoC 不进入挂起模式,事件就不会被丢弃或丢失。如果内部硬件 FIFO 在达到 <code>max_report_latency</code> 之前就已存满,则会在该时间点报告事件,以确保无事件丢失。</p>
+<p>当多个传感器共用一个 FIFO 时,如果其中一个传感器已达到 <code>max_report_latency</code>,则会立即报告来自该 FIFO 的所有事件,即使其他传感器尚未达到 <code>max_report_latency</code> 也是如此。总的来说,就是要减少按批次报告事件的次数,因此当有一个事件必须报告时,就可以报告来自所有传感器的所有事件。</p>
+<p>例如,如果以下传感器处于启用状态:</p>
+<ul>
+ <li>在 <code>max_report_latency</code> = 20s 时进行批处理的加速度计</li>
+ <li>在 <code>max_report_latency</code> = 5s 时进行批处理的陀螺仪</li>
+</ul>
+<p>那么,在报告陀螺仪批次(每 5 秒钟)的同时就可以报告加速度计批次,即使加速度计和陀螺仪未共用同一个 FIFO 也可以报告。</p>
+<h2 id="behavior_in_suspend_mode">挂起模式下的行为</h2>
+<p>如果希望在不使 SoC 保持唤醒的情况下从后台收集传感器数据,则采用批处理特别有用。由于传感器驱动程序和 HAL 实现被禁止持有唤醒锁*,因此 SoC 可在收集传感器数据时进入挂起模式。</p>
+<p>SoC 挂起时的传感器行为取决于传感器是否为唤醒传感器。有关详情,请参阅<a href="suspend-mode.html#wake-up_sensors">唤醒传感器</a>一节。</p>
+<p>当非唤醒 FIFO 存满时,它必须环绕并像环形缓冲区一样运作,覆盖较旧的事件:即新事件替换旧事件。
+ 在挂起模式下,<code>max_report_latency</code> 对非唤醒 FIFO 没有影响。</p>
+<p>当唤醒 FIFO 存满时,或者当其中一个唤醒传感器的 <code>max_report_latency</code> 已过时,硬件必须唤醒 SoC 并报告数据。</p>
+<p>在这两种情况下(唤醒和非唤醒),只要 SoC 退出挂起模式,即使一些传感器的 <code>max_report_latency</code> 未过,也会产生一个包含所有 FIFO 内容的批处理。这样可最大限度地降低 SoC 再次挂起而必须重新将其唤醒的风险。这进而可以最大限度地降低功耗。</p>
+<p>*不允许驱动程序持有唤醒锁的一个明显例外情况是,在 <code>max_report_latency</code> 小于 1 秒时,启用<a href="report-modes.html#continuous">轮询报告模式</a>的唤醒传感器。在此情况下,驱动程序可以持有唤醒锁,这是因为 SoC 在进入挂起模式前会被唤醒事件唤醒,因此没有机会进入挂起模式。</p>
+<h2 id="precautions_to_take_when_batching_wake-up_sensors">批处理唤醒传感器时的注意事项</h2>
+<p>根据设备不同,SoC 可能需要几毫秒才能完全退出挂起模式并开始刷新 FIFO。因此必须在 FIFO 中分配足够的头空间,才能让设备完全退出挂起状态,而不造成唤醒 FIFO 溢出。不得丢失任何事件,并且必须遵照 <code>max_report_latency</code>。</p>
+<h2 id="precautions_to_take_when_batching_non-wake-up_on-change_sensors">批处理采用 On-change 触发方式的非唤醒传感器时的注意事项</h2>
+<p>采用 On-change 触发方式的传感器仅在测量值发生变化时才会生成事件。如果测量值在 SoC 处于挂起模式时发生变化,则应用预计会在 SoC 唤醒时立即收到事件。因此,如果采用 On-change 触发方式的<a href="suspend-mode.html#non-wake-up_sensors">非唤醒</a>传感器与其他传感器共用 FIFO,则在执行该传感器事件的批处理时,必须小心。每个采用 On-change 触发方式的传感器所生成的最后一个事件都必须保存在共享 FIFO 之外,使其永远不会被其他事件覆盖。当 SoC 唤醒时,在报告 FIFO 中的所有事件后,还必须报告最后一个采用 On-change 触发方式的传感器事件。</p>
+<p>以下是我们希望避免的情况:</p>
+<ol>
+ <li>应用同时注册到共用同一个 FIFO 的非唤醒计步器(采用 On-change 触发方式)和非唤醒加速度计(轮询模式)</li>
+ <li>应用收到一个计步器事件“step_count = 1000 步”</li>
+ <li>SoC 转至挂起状态</li>
+ <li>用户步行 20 步,导致计步器和加速度计事件交错存储,最后的计步器事件为 “step_count = 1020 步”</li>
+ <li>用户长时间不动,导致加速度计事件在 FIFO 中继续累积,最终覆盖共享 FIFO 中的各 step_count 事件</li>
+ <li>SoC 唤醒并将 FIFO 中的所有事件发送到应用</li>
+ <li>应用只收到了加速度计事件,并认为用户没有走步(糟糕!)</li>
+</ol>
+<p>通过将最后的计步器事件保存在 FIFO 之外的存储区,即使所有其他计步器事件都被加速度计事件覆盖,HAL 仍可以在 SoC 唤醒时报告最后的事件。这样,当 SoC 唤醒时,应用就会收到“step_count = 1020 步”。</p>
+<h2 id="implementing_batching">实现批处理</h2>
+<p>批处理无法在软件中模拟,而必须借助硬件 FIFO 完全在硬件中实现。批处理尤其不能在 SoC 上实现(例如在 HAL 中实现),因为这样会产生相反效果。进行批处理是为了大幅节省电量。批处理必须在不借助 SoC 的情况下实现。在批处理期间应允许 SoC 处于挂起模式。</p>
+<p>可随时修改 <code>max_report_latency</code>,特别是在已启用指定传感器的情况下;并且该操作不应导致事件丢失。</p>
+<h2 id="fifo_allocation_priority">FIFO 分配优先级</h2>
+<p>在硬件 FIFO 大小有限的平台上,系统设计人员可能必须选择为各传感器预留多少 FIFO 空间。为便于选择,下面列出了在不同传感器上实现批量处理时可能有帮助的应用。</p>
+<h3 id="high_value_low_power_pedestrian_dead_reckoning">高值:低功率行人航位推算</h3>
+<p>目标批处理时间:1 到 10 分钟</p>
+<p>待批处理的传感器:</p>
+<ul>
+ <li>唤醒步测器</li>
+ <li>唤醒游戏旋转矢量传感器(频率 5 Hz)</li>
+ <li>唤醒气压计(频率 5 Hz)</li>
+ <li>唤醒未校准磁力计(频率 5 Hz)</li>
+</ul>
+<p>批处理此类数据,可在 SoC 处于挂起模式时执行行人航位推算。</p>
+<h3 id="high_value_medium_power_intermittent_activity_gesture_recognition">高值:中等功率间歇性动作/手势识别</h3>
+<p>目标批处理时间:3 秒</p>
+<p>带批处理的传感器:非唤醒加速度计(频率 50 Hz)</p>
+<p>批处理此类数据,可定期识别任意动作和手势,而无需在收集数据时保持 SoC 处于唤醒状态。</p>
+<h3 id="medium_value_medium_power_continuous_activity_gesture_recognition">中等值:中等功率连续动作/手势识别</h3>
+<p>目标批处理时间:1 到 3 分钟</p>
+<p>待批处理的传感器:唤醒加速度计(频率 50Hz)</p>
+<p>批处理此类数据,可持续识别任意动作和手势,而无需在收集数据时保持 SoC 处于唤醒状态。</p>
+<h3 id="medium-high_value_interrupt_load_reduction">中高值:减少中断负载</h3>
+<p>目标批处理时间:小于 1 秒</p>
+<p>待批处理的传感器:任意高频传感器(通常为非唤醒传感器)。</p>
+<p>如果陀螺仪设置为 240 Hz,仅仅批处理 10 个陀螺仪事件就可以将中断次数从 240 次/秒减少到 24 次/秒。</p>
+<h3 id="medium_value_continuous_low_frequency_data_collection">中等值:连续低频数据采集</h3>
+<p>目标批处理时间:1 到 10 分钟</p>
+<p>待批处理的传感器:</p>
+<ul>
+ <li>唤醒气压计(频率 1 Hz)</li>
+ <li>唤醒湿度传感器(频率 1 Hz)</li>
+ <li>其他类似频率的低频唤醒传感器</li>
+</ul>
+<p>可创建低功耗的监控应用。</p>
+<h3 id="medium-low_value_continuous_full-sensors_collection">中低值:连续全传感器采集</h3>
+<p>目标批处理时间:1 到 10 分钟</p>
+<p>待批处理的传感器:所有唤醒传感器(在高频下运行)</p>
+<p>允许在 SoC 处于挂起模式的情况下,完整收集传感器数据。只需考虑 FIFO 空间是否构成问题。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/sensors/sensor-types.html b/zh-cn/devices/sensors/sensor-types.html
new file mode 100644
index 00000000..fe2379a3
--- /dev/null
+++ b/zh-cn/devices/sensors/sensor-types.html
@@ -0,0 +1,492 @@
+<html devsite><head>
+ <title>传感器类型</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>本部分介绍了传感器坐标轴、基础传感器和复合传感器(动作传感器、姿势传感器、未校准传感器和互动传感器)。</p>
+
+<h2 id="sensor_axis_definition">传感器坐标轴</h2>
+<p>许多传感器的传感器事件值在相对于设备静止的特定坐标系中表示。
+
+</p><h3 id="phone_axes">移动设备坐标轴</h3>
+<p>Sensor API 仅与屏幕的自然方向相关(当设备的屏幕方向更改时,坐标轴不会发生交换)。</p>
+
+<img src="https://developer.android.com/images/axis_device.png" alt="移动设备的 Sensor API 坐标系"/>
+<p class="img-caption"><strong>图 1.</strong> Sensor API 使用的坐标系(相对于移动设备)。</p>
+
+<h3 id="auto_axes">汽车坐标轴</h3>
+<p>在 Android Automotive 实现中,坐标轴相对于车身坐标系进行定义:</p>
+
+<img src="images/axis_auto.png" alt="汽车设备的 Sensor API 坐标系"/>
+<p class="img-caption"><strong>图 2.</strong> Sensor API 使用的坐标系(相对于汽车设备)。</p>
+
+<ul>
+<li>X 轴沿车辆右侧延伸</li>
+<li>Y 轴沿车架前方延伸</li>
+<li>Z 轴沿车架顶部延伸</li>
+</ul>
+
+<p>从坐标轴的正方向观察时,正旋转方向为逆时针方向。因此,当车辆向左转时,z 轴的陀螺仪转速应该为正值。</p>
+
+<h2 id="base_sensors">基础传感器</h2>
+<p>基础传感器类型以其代表的物理传感器命名。这些传感器会转发来自单个物理传感器的数据(与通过其他传感器生成数据的复合传感器相反)。基础传感器类型的示例包括:</p>
+<ul>
+ <li><code>SENSOR_TYPE_ACCELEROMETER</code></li>
+ <li><code>SENSOR_TYPE_GYROSCOPE</code></li>
+ <li><code>SENSOR_TYPE_MAGNETOMETER</code></li>
+</ul>
+
+<p class="note"><strong>注意</strong>:有关 Android 传感器类型的详细信息,请查看以下部分。</p>
+
+<p>但是,基础传感器不等同于其底层物理传感器,也不得与其相混淆。来自基础传感器的数据<strong>不是</strong>物理传感器的原始输出信息,因为数据已进行了校正(如偏差补偿和温度补偿)。</p>
+
+<p>例如,在以下使用情况下,基础传感器的特性可能与其底层物理传感器的特性有所不同:</p>
+<ul>
+<li>额定偏差范围为 1 度/秒的陀螺仪芯片。
+ <ul>
+ <li>在出厂校准后,通过应用温度补偿和偏差补偿,使 Android 传感器的实际偏差得到降低,最终偏差可能低于 0.01 度/秒。</li>
+ <li>在此情况下,即使底层传感器的数据表显示偏差为 1 度/秒,我们仍认为 Android 传感器的偏差低于 0.01 度/秒。</li>
+ </ul>
+</li>
+<li>功耗为 100 uW 的气压计。<ul>
+ <li>由于生成的数据需要从芯片传输到 SoC,因此从气压计 Android 传感器收集数据的实际功耗可能会高得多,例如 1000 uW。</li>
+ <li>在此情况下,即使在气压计芯片引线上测得的功耗为 100 uW,我们仍认为 Android 传感器的功耗为 1000 uW。</li>
+ </ul>
+</li>
+<li>校准后功耗为 100 uW 的磁力计(但校准时会消耗更多功率)。
+ <ul>
+ <li>其校准程序可能需要激活陀螺仪(消耗 5000 uW),并运行一些算法(额外消耗 900 uW)。</li>
+ <li>在此情况下,我们认为(磁力计)Android 传感器的最大功耗为 6000 uW。</li>
+ <li>在此情况下,平均功耗是更为实用的测量指标,系统会通过 HAL 在传感器静态特性中报告平均功耗。</li>
+ </ul>
+</li>
+</ul>
+<h3 id="accelerometer">加速度计</h3>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_ACCELEROMETER)</code> 返回一个非唤醒传感器<em></em></p>
+<p>加速度计传感器可报告设备沿 3 个传感器坐标轴的加速度。测量的加速度包括物理加速度(速度变化)和重力加速度。测量结果在 sensor_event_t.acceleration 的 x、y 和 z 字段中报告。</p>
+<p>所有值均采用国际单位制单位 (m/s^2),测量结果为设备加速度减去沿 3 个传感器坐标轴的重力加速度。</p>
+<p>示例如下:</p>
+<ul>
+ <li>自由落体时,(x, y, z) 的范数应接近于 0。</li>
+ <li>当设备平放在桌子上并从其左侧向右推动时,x 轴加速度值为正。</li>
+ <li>当设备平放在桌子上时,z 轴上的加速度值为 +9.81,相当于设备的加速度 (0 m/s^2) 减去重力加速度 (-9.81 m/s^2)。</li>
+ <li>当设备平放在桌子上并向上抬起时,加速度值大于 +9.81,相当于设备的加速度 (+A m/s^2) 减去重力加速度 (-9.81 m/s^2)。</li>
+</ul>
+<p>读数根据以下参数进行校准:</p>
+<ul>
+ <li>温度补偿</li>
+ <li>在线偏差校准</li>
+ <li>在线尺度校准</li>
+</ul>
+<p>仅当传感器已禁用时,才可更新偏差校准和尺度校准,以避免流式传输时出现值激增。</p>
+<p>加速度计还通过 <code>sensors_event_t.acceleration.status</code> 报告其预测的读数精度。要详细了解此字段的可能值,请参阅 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html">SensorManager</a> 的 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH"><code>SENSOR_STATUS_* </code></a>常量。</p>
+<h3 id="ambient_temperature">环境温度传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_AMBIENT_TEMPERATURE)</code> 返回一个非唤醒传感器<em></em></p>
+<p>该传感器可提供环境(室内)温度,单位是摄氏度。</p>
+<h3 id="magnetic_field_sensor">磁场传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_MAGNETIC_FIELD)</code> 返回一个非唤醒传感器<em></em></p>
+<p><code>SENSOR_TYPE_GEOMAGNETIC_FIELD == SENSOR_TYPE_MAGNETIC_FIELD</code></p>
+<p>磁场传感器(也称为磁力计)可报告沿 3 个传感器坐标轴测量的环境磁场。</p>
+<p>测量结果在 <code>sensors_event_t.magnetic</code> 的 x、y 和 z 字段中报告,且所有值单位均是微特斯拉 (uT)。</p>
+<p>磁力计还通过 <code>sensors_event_t.magnetic.status</code> 报告其预测的读数精度。要详细了解此字段的可能值,请参阅 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html">SensorManager</a> 的 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH"><code>SENSOR_STATUS_*</code></a> 常量。</p>
+<p>读数根据以下参数进行校准:</p>
+<ul>
+ <li>温度补偿</li>
+ <li>出厂(或在线)软铁校准</li>
+ <li>在线硬铁校准</li>
+</ul>
+<h3 id="gyroscope">陀螺仪</h3>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GYROSCOPE)</code> 返回一个非唤醒传感器<em></em></p>
+<p>陀螺传感器可报告设备围绕 3 个传感器坐标轴的旋转速率。</p>
+<p>逆时针方向为正转方向(右手规则)。即,如果位于原点的设备逆时针旋转,观察者从设备 x、y 或 z 轴某个正位置看过去,将报告正向旋转。请注意,这是正向旋转的标准数学定义,与航空航天领域对转动的定义并不一致。</p>
+<p>测量结果在 <code>sensors_event_t.gyro</code> 的 x、y 和 z 字段中报告,且所有值的单位均为每秒转数 (rad/s)。</p>
+<p>读数根据以下参数进行校准:</p>
+<ul>
+ <li>温度补偿</li>
+ <li>出厂(或在线)尺度补偿</li>
+ <li>在线偏差校准(以去除漂移)</li>
+</ul>
+<p>陀螺仪还通过 <code>sensors_event_t.gyro.status</code> 报告其预测的读数精度。要详细了解此字段的可能值,请参阅 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html">SensorManager</a> 的 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH"><code>SENSOR_STATUS_*</code></a> 常量。</p>
+<p>陀螺仪不能基于磁力计和加速度计进行模拟,因为这样将导致局部一致性和响应速度降低。它必须基于常见的陀螺仪芯片。</p>
+<h3 id="heart_rate">心率传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_HEART_RATE)</code> 返回一个非唤醒传感器<em></em></p>
+<p>心率传感器可报告触摸设备的人员当前的心率。</p>
+<p>以每分钟心跳次数 (BPM) 表示的当前心率在 <code>sensors_event_t.heart_rate.bpm</code> 中报告,而传感器的状态在 <code>sensors_event_t.heart_rate.status</code> 中报告。要详细了解此字段的可能值,请参阅 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html">SensorManager</a> 的 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH"><code>SENSOR_STATUS_*</code></a> 常量。特别是在第一次激活时,除非系统已知设备未随身携带,否则首次事件的状态字段必须设置为 <code>SENSOR_STATUS_UNRELIABLE</code>。因为传感器采用变化模式,当且仅当 <code>heart_rate.bpm</code> 或 <code>heart_rate.status</code> 自上次事件后已发生变化时才会触发事件。事件生成速度不会大于每隔 <code>sampling_period</code> 一次。</p>
+<p><code>sensor_t.requiredPermission</code> 始终是 <code>SENSOR_PERMISSION_BODY_SENSORS</code>。</p>
+<h3 id="light">光线传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_LIGHT)</code> 返回一个非唤醒传感器<em></em></p>
+<p>光线传感器可报告当前照明度,采用国际单位勒克斯 (lux)。</p>
+<p>测量结果在 <code>sensors_event_t.light</code> 中报告。</p>
+<h3 id="proximity">近程传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p>通常定义为唤醒传感器</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_PROXIMITY)</code> 返回唤醒传感器<em></em></p>
+<p>近程传感器可报告从传感器到最近的可见表面的距离。</p>
+<p>在 Android KitKat 版本或更早版本中,近程传感器一直是唤醒传感器,也就是说,此类传感器在检测到近程距离发生变化时会唤醒 SoC。对于 Android KitKat 之后的版本,我们建议您首先实现该传感器的唤醒版本,因为该版本在打电话时用于开启和关闭屏幕。</p>
+<p>测量结果在 <code>sensors_event_t.distance</code> 中报告(以厘米为单位)。请注意,一些近程传感器仅支持二元“近”或“远”测量结果。在此情况下,传感器检测到“远”状态时报告值 <code>sensor_t.maxRange</code>,检测到“近”状态时报告一个小于 <code>sensor_t.maxRange</code> 的值。</p>
+<h3 id="pressure">压力传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_PRESSURE)</code> 返回一个非唤醒传感器<em></em></p>
+<p>压力传感器(也称为气压计)可报告大气压力,以百帕斯卡 (hPa) 为单位。</p>
+<p>使用以下参数校准读数:</p>
+<ul>
+ <li>温度补偿</li>
+ <li>出厂偏差校准</li>
+ <li>出厂尺度校准</li>
+</ul>
+<p>气压计通常用于估算高度变化。要估算绝对高度,必须将海平面压力(随天气变化)作为参照点。</p>
+<h3 id="relative_humidity">相对湿度传感器</h3>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_RELATIVE_HUMIDITY)</code> 返回一个非唤醒传感器<em></em></p>
+<p>相对湿度传感器用于测量环境空气相对湿度,并返回百分比值。</p>
+
+<h2 id="composite_sensor_types">复合传感器类型</h2>
+<p>复合传感器通过处理和/或融合来自一个或多个物理传感器的数据来生成数据。(任何非基础传感器的传感器均称为复合传感器。)复合传感器的示例包括:</p>
+<ul>
+<li><a href="#step_detector">步测器</a>和<a href="#significant_motion">大幅度动作传感器</a>,通常基于加速度计,但是也可基于其他传感器(如果功耗和精度可接受)。</li>
+<li><a href="#game_rotation_vector">游戏旋转矢量传感器</a>,基于加速度计和陀螺仪。</li>
+<li><a href="#gyroscope_uncalibrated">未校准陀螺仪</a>,类似于陀螺仪基础传感器,但是单独报告偏差校准(而非在测量结果中校正)。</li>
+</ul>
+<p>与基础传感器一样,复合传感器的特性来自于其最终数据的特性。例如,游戏旋转矢量传感器的功耗可能等于加速度计芯片、陀螺仪芯片、数据处理芯片和传输数据的总线的功耗之和。另外,游戏旋转矢量传感器的漂移既取决于校准算法的质量,也取决于物理传感器的特性。</p>
+
+<p>下表列出了可用的复合传感器类型。每种复合传感器都依赖于来自一个或多个物理传感器的数据。请避免选择使用其他底层物理传感器来估算结果,因为这样带来的用户体验较差。</p>
+<p class="note"><strong>注意</strong>:当且仅当设备没有配备陀螺仪时,您才可以在不使用陀螺仪的情况下,实现旋转矢量传感器、线性加速度传感器和重力传感器。</p>
+
+<table>
+ <tbody><tr>
+ <th width="34%">传感器类型</th>
+ <th width="10%">类别</th>
+ <th width="34%">底层物理传感器</th>
+ <th width="19%">报告模式</th>
+ </tr>
+ <tr>
+ <td><p><a href="#game_rotation_vector">游戏旋转矢量传感器</a></p></td>
+ <td><p>姿势类</p></td>
+ <td><p>加速度计、陀螺仪,不得使用磁力计</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#geomagnetic_rotation_vector">地磁旋转矢量传感器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>姿势类</p></td>
+ <td><p>加速度计、磁力计,不得使用陀螺仪</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><a href="#glance_gesture">快览传感器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/><p></p></td>
+ <td><p>互动类</p></td>
+ <td><p>未定义</p></td>
+ <td><p>单次模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#gravity">重力传感器</a></p></td>
+ <td><p>姿势类</p></td>
+ <td><p>加速度计、陀螺仪</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#gyroscope_uncalibrated">未校准陀螺仪传感器</a></p></td>
+ <td><p>未校准类</p></td>
+ <td><p>陀螺仪</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#linear_acceleration">线性加速度传感器</a></p></td>
+ <td><p>动作类</p></td>
+ <td><p>加速度计、陀螺仪(如有)或磁力计(如果没有陀螺仪)</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#magnetic_field_uncalibrated">未校准磁场传感器</a></p></td>
+ <td><p>未校准类</p></td>
+ <td><p>磁力计</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#orientation_deprecated">方向传感器</a>(已弃用)</p></td>
+ <td><p>姿势类</p></td>
+ <td><p>加速度计、磁力计,优先使用陀螺仪</p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#pick_up_gesture">拿起手势传感器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>互动类</p></td>
+ <td><p>未定义</p></td>
+ <td><p>单次模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#rotation_vector">旋转矢量传感器</a></p></td>
+ <td><p>姿势类</p></td>
+ <td><p>加速度计、磁力计和陀螺仪(如有)<em></em></p></td>
+ <td><p>连续模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#significant_motion">大幅度动作传感器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>动作类</p></td>
+ <td><p>加速度计(或其他功耗极低的传感器)</p></td>
+ <td><p>单次模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#step_counter">计步器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>动作类</p></td>
+ <td><p>加速度计</p></td>
+ <td><p>变化模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#step_detector">步测器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td> <td><p>动作类</p></td>
+ <td><p>加速度计</p></td>
+ <td><p>特殊模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#tilt_detector">倾斜检测器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>动作类</p></td>
+ <td><p>加速度计</p></td>
+ <td><p>特殊模式</p></td>
+ </tr>
+ <tr>
+ <td><p><a href="#wake_up_gesture">唤醒手势传感器</a> <img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/></p></td>
+ <td><p>互动类</p></td>
+ <td><p>未定义</p></td>
+ <td><p>单次模式</p></td>
+ </tr>
+</tbody></table>
+<p><img src="images/battery_icon.png" width="20" height="20" alt="低功耗传感器"/> 表示低功耗传感器</p>
+<h2 id="activity_composite_sensors">动作复合传感器</h2>
+<h3 id="linear_acceleration">线性加速度传感器</h3>
+<p>底层物理传感器:加速度计和(如有)陀螺仪(或如果没有陀螺仪,则使用磁力计)</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_LINEAR_ACCELERATION)</code> 返回一个非唤醒传感器<em></em></p>
+<p>线性加速度传感器可报告传感器框架内设备的线性加速度(不包括重力加速度)。</p>
+<p>从概念上看,输出结果为:<a href="#accelerometer">加速度计</a>的输出结果减去<a href="#gravity">重力传感器</a>的输出结果。结果在 <code>sensors_event_t.acceleration</code> 的 x、y 和 z 字段中报告(单位为 m/s^2)。</p>
+<p>当设备不动时,所有轴上的读数应接近 0。</p>
+<p>如果设备配备陀螺仪,则线性加速度传感器必须将陀螺仪和加速度计作为输入源。</p>
+<p>如果设备未配备陀螺仪,则线性加速度传感器必须将加速度计和磁力计作为输入源。</p>
+<h3 id="significant_motion">大幅度动作传感器</h3>
+<p>底层物理传感器:加速度计(或其他低功耗的传感器)</p>
+<p>报告模式:<em><a href="report-modes.html#one-shot">单次模式</a></em></p>
+<p>低功耗</p>
+<p>仅实现该传感器的唤醒版本。</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_SIGNIFICANT_MOTION)</code> 返回唤醒传感器<em></em></p>
+<p>当检测到“大幅度动作”时,会触发大幅度动作传感器;大幅度动作是指可能导致用户位置发生变化的动作。</p>
+<p>此类大幅度动作示例如下:</p>
+<ul>
+ <li>步行或骑自行车</li>
+ <li>乘坐在正在行驶的汽车、巴士或火车内</li>
+</ul>
+<p>不会触发大幅度动作的情况示例:</p>
+<ul>
+ <li>手机放在口袋里并且人不动</li>
+ <li>手机放在桌子上,而桌子由于附近的交通或洗衣机而轻微摇晃</li>
+</ul>
+<p>从更高层面来看,大幅度动作传感器可用于降低位置测定的功耗。当定位算法检测到设备静止时,可将设备切换到低功耗模式,在该模式下,这些算法依赖用户改变位置时发生的大幅度动作来唤醒设备。</p>
+<p>该传感器必须具备低功耗特性。这样可以节省功耗,但可能会导致少量漏报情况。这样做是出于以下几个原因:</p>
+<ul>
+ <li>该传感器的目标是节省电量。</li>
+ <li>用户不动时触发事件(误报)会消耗大量电量,因此应尽量加以避免。</li>
+ <li>只要用户移动时不触发事件(漏报)的情况没有频繁发生,则此类错误是可接受的。如果用户已经行走了 10 秒钟,则在这 10 秒内不触发事件是不可接受的。</li>
+</ul>
+<p>每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1</p>
+<h3 id="step_detector">步测器</h3>
+<p>底层物理传感器:加速度计(可能还有其他低功耗计量器)</p>
+<p>报告模式:<em>特殊模式<a href="report-modes.html#special"></a>(一步触发一个事件)</em></p>
+<p>低功耗</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_STEP_DETECTOR)</code> 返回一个非唤醒传感器<em></em></p>
+<p>用户每走一步,步测器就触发一个事件。</p>
+<p>事件 <code>sensors_event_t.timestamp</code> 的时间戳对应脚部触地的时刻,此时会产生较大的加速度变化。</p>
+<p>与计步器相比,步测器的延迟较低(小于 2 秒)。步测器和计步器都可以在用户步行、跑步和走楼梯时进行感测。当用户骑自行车、驾驶或乘坐其他交通工具时,不应触发检测。</p>
+<p>该传感器必须具备低功耗特性。也就是说,如果硬件中无法完成步数检测,则不应对该传感器进行定义。尤其是,当启用步测器但未启用加速度计时,只有步数(而非所有加速度计读数)会触发中断。</p>
+<p><code>sampling_period_ns</code> 对步测器没有影响。</p>
+<p>每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1</p>
+<h3 id="step_counter">计步器</h3>
+<p>底层物理传感器:加速度计(可能还有其他低功耗计量器)</p>
+<p>报告模式:<em><a href="report-modes.html#on-change">变化模式</a></em></p>
+<p>低功耗</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_STEP_COUNTER)</code> 返回一个非唤醒传感器<em></em></p>
+<p>计步器报告自激活后上一次重新启动以来用户行走的步数。</p>
+<p>测量结果在 <code>sensors_event_t.step_counter</code> 中报告为 <code>uint64_t</code>,并仅在系统重新启动时重置为零。</p>
+<p>事件的时间戳设置为该事件最后一步的采集时间。</p>
+<p>请参阅<a href="#step_detector">步测器</a>传感器类型,了解一步所对应的时间的意义。</p>
+<p>与步测器相比,计步器可能具有更高的延迟(最多 10 秒)。也正因这种延迟,该传感器具备较高的准确性;完成一整天的测量后,步数应在实际步数的 10% 偏差范围内。步测器和计步器都可以在用户行走、跑步和走楼梯时进行检测。当用户骑自行车、驾驶或乘坐其他交通工具时,不应触发检测。</p>
+<p>硬件必须确保内部步数始终不会溢出。硬件内部计数器的大小下限应为 16 位。在即将发生溢出时(最多约每 2^16 步一次),可以唤醒 SoC,以便驱动程序可进行计数器维护。</p>
+<p>正如在<a href="interaction.html">互动传感器</a>中所述,当该传感器工作时,不得干扰任何其他传感器,特别是很可能正在使用中的加速度计。</p>
+<p>如果特定设备不支持此类操作模式,则此类传感器类型不能由 HAL 进行报告,即不应在 HAL 中“模拟”该传感器。</p>
+<p>该传感器必须具备低功耗特性。也就是说,如果硬件中无法完成步数检测,则不应对该传感器进行定义。尤其是,当启用步测器但未启用加速度计时,只有步数(而非加速度计数据)会触发中断。</p>
+<h3 id="tilt_detector">倾斜检测器</h3>
+<p>底层物理传感器:加速度计(可能还有其他低功耗计量器)</p>
+<p>报告模式:<em><a href="report-modes.html#special">特殊模式</a></em></p>
+<p>低功耗</p>
+<p>仅实现该传感器的唤醒版本。</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_TILT_DETECTOR)</code> 返回唤醒传感器<em></em></p>
+<p>每次检测到倾斜事件时,倾斜检测器会生成一个事件。</p>
+<p>倾斜事件定义如下:自激活或自传感器生成的最后一次事件起,2 秒时隙内平均重力加速度方向变化至少 35 度。算法如下:</p>
+<ul>
+ <li> <code>reference_estimated_gravity</code> = 激活后的第一秒内加速度计的平均测量值或生成最后一次倾斜事件时的估算重力。</li>
+ <li> <code>current_estimated_gravity</code> = 过去 2 秒内加速度计的平均测量值。</li>
+ <li>当 <code>angle(reference_estimated_gravity, current_estimated_gravity) &gt; 35
+ degrees</code> 时触发。 </li>
+</ul>
+<p>当加速度较大而手机方向未发生改变时,不应触发倾斜事件。例如,驾驶汽车时急转弯或猛烈加速不应触发倾斜事件,即使平均加速度的角度变化可能超过 35 度亦如此。通常情况下,只需借助加速度计就能实现该传感器。也可以使用其他传感器(如果功耗增加不明显的话)。这是一个低功耗传感器,应允许 SoC 进入挂起模式。请勿在 HAL 中模拟该传感器。每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1。</p>
+<h2 id="attitude_composite_sensors">姿势复合传感器</h2>
+<h3 id="rotation_vector">旋转矢量传感器</h3>
+<p>底层物理传感器:加速度计、磁力计和陀螺仪</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_ROTATION_VECTOR)</code> 返回一个非唤醒传感器<em></em></p>
+<p>旋转矢量传感器可报告设备相对于东北天坐标系的方向。通常情况下,该数据通过整合加速度计、陀螺仪和磁力计的读数获得。东北天坐标系是指完全正交基,其中:</p>
+<ul>
+ <li>X 轴指向东,与地面相切。</li>
+ <li>Y 轴指向北,与地面相切。</li>
+ <li>Z 轴指向上,与地面垂直。</li>
+</ul>
+<p>手机方向表示为东北天坐标系与手机坐标系对齐所需的旋转幅度。也就是说,对世界坐标系 (X,Y,Z) 应用这一幅度的旋转将使该坐标系与手机坐标系 (x,y,z) 对齐。</p>
+<p>该旋转可看作围绕轴 rot_axis 将手机旋转 θ 角度,从参照(与东北天对齐)设备方向转到当前设备方向。该旋转被编码为一个单位四元数的四个无量纲 x、y、z、w 分量:</p>
+<ul>
+ <li> <code>sensors_event_t.data[0] = rot_axis.x*sin(theta/2)</code> </li>
+ <li> <code>sensors_event_t.data[1] = rot_axis.y*sin(theta/2)</code> </li>
+ <li> <code>sensors_event_t.data[2] = rot_axis.z*sin(theta/2)</code> </li>
+ <li> <code>sensors_event_t.data[3] = cos(theta/2)</code> </li>
+</ul>
+<p>其中:</p>
+<ul>
+ <li><code>rot_axis</code> 的 x、y 和 z 字段是表示旋转轴的单位长度向量的东北天坐标</li>
+ <li> <code>theta</code> 是旋转角度</li>
+</ul>
+<p>四元数是一个单位四元数:其范数必须为 1。不满足此要求将导致客户端行为不稳定。</p>
+<p>此外,该传感器会报告估算的首向精度:</p>
+<p><code>sensors_event_t.data[4] = estimated_accuracy</code>(以弧度为单位)</p>
+<p>在 95% 的时间里,首向误差必须小于 <code>estimated_accuracy</code>。该传感器必须使用陀螺仪作为主要方向变化输入源。</p>
+<p>该传感器还使用加速度计和磁力计输入源来弥补陀螺仪漂移,但不能仅使用加速度计和磁力计来实现该传感器。</p>
+<h3 id="game_rotation_vector">游戏旋转矢量传感器</h3>
+<p>底层物理传感器:加速度计和陀螺仪(无磁力计)</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GAME_ROTATION_VECTOR)</code> 返回一个非唤醒传感器<em></em></p>
+<p>游戏旋转矢量传感器类似于旋转矢量传感器,但不使用地磁场。因此,Y 轴不指向北,而是指向其他参照坐标。该参考坐标可以漂移与陀螺仪沿 Z 轴漂移时的幅度相同数量级的幅度。</p>
+<p>请参阅<a href="#rotation_vector">旋转矢量</a>传感器,详细了解如何设置 <code>sensors_event_t.data[0-3]</code>。该传感器不报告估算的首向精度:保留 <code>sensors_event_t.data[4]</code>,并应将其设置为 0。</p>
+<p>理想情况下,经过旋转并返回到与现实世界方向同向的手机应该报告相同的游戏旋转矢量。</p>
+<p>该传感器必须基于陀螺仪和加速度计。不能使用磁力计作为输入源,也不可通过估算陀螺仪偏差间接作为输入源。</p>
+<h3 id="gravity">重力传感器</h3>
+<p>底层物理传感器:加速度计和(如有)陀螺仪(或如果陀螺仪不存在,则使用磁力计)</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GRAVITY)</code> 返回一个非唤醒传感器<em></em></p>
+<p>重力传感器可报告设备坐标系中重力的方向和大小。</p>
+<p>重力矢量分量在 <code>sensors_event_t.acceleration</code> 的 x、y 和 z 字段中以 m/s^2 表示。</p>
+<p>当设备静止时,重力传感器的输出结果应与加速度计的输出结果相同。在地球上,重力加速度约为 9.8 m/s^2。</p>
+<p>如果设备具有陀螺仪,则重力传感器必须使用陀螺仪和加速度计作为输入源。</p>
+<p>如果设备不具有陀螺仪,则重力传感器必须使用加速度计和磁力计作为输入源。</p>
+<h3 id="geomagnetic_rotation_vector">地磁旋转矢量传感器</h3>
+<p>底层物理传感器:加速度计和磁力计(无陀螺仪)</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p>低功耗</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)</code> 返回一个非唤醒传感器<em></em></p>
+<p>地磁旋转矢量传感器与旋转矢量传感器类似,但它使用磁力计而不是陀螺仪。</p>
+<p>该传感器必须基于磁力计。该传感器不能使用陀螺仪来实现,并且不能使用陀螺仪输入源。</p>
+<p>请参阅<a href="#rotation_vector">旋转矢量</a>传感器,详细了解如何设置 <code>sensors_event_t.data[0-4]</code>。</p>
+<p>与旋转矢量传感器类似,在 95% 的时间里,首向误差必须小于估算精度 (<code>sensors_event_t.data[4]</code>)。</p>
+<p>该传感器必须具备低功耗特性,因此必须在硬件中实现。</p>
+<h3 id="orientation_deprecated">方向传感器(已弃用)</h3>
+<p>底层物理传感器:加速度计、磁力计和(如有)陀螺仪</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_ORIENTATION)</code> 返回一个非唤醒传感器<em></em></p>
+<p class="note"><strong>注意</strong>:这是已在 Android SDK 中弃用的旧版传感器类型。它已由定义更为清晰的旋转矢量传感器取代。尽可能使用旋转矢量传感器来替代方向传感器。</p>
+<p>方向传感器可报告设备的姿势。测量结果在 <code>sensors_event_t.orientation</code> 的 x、y 和 z 字段中报告(以度为单位)。</p>
+<ul>
+ <li> <code>sensors_event_t.orientation.x</code>:方位角,磁北方向与 Y 轴之间的夹角,绕 Z 轴转动 (<code>0&lt;=azimuth&lt;360</code>)。0 = 北,90 = 东,180 = 南,270 = 西</li>
+ <li> <code>sensors_event_t.orientation.y</code>:俯仰,绕 X 轴旋转 (<code>-180&lt;=pitch&lt;=180</code>),当 z 轴向 y 轴移动时为正值。</li>
+ <li> <code>sensors_event_t.orientation.z</code>:滚动,绕 Y 轴旋转 (<code>-90&lt;=roll&lt;=90</code>),当 x 轴向 z 轴移动时为正值。</li>
+</ul>
+<p>请注意,因历史原因,滚动角度在顺时针方向为正。(从数学上讲,逆时针方向应为正):</p>
+<div class="attempt-right" style="width:264px">
+ <img src="images/axis_positive_roll.png" alt="相对于设备的方向描述" height="253"/>
+ <p class="img-caption">
+ <strong>图 3.</strong> 相对于设备的方向。
+ </p>
+</div>
+<p>该定义与航空中使用的偏航、俯仰和滚动不同,其中 X 轴沿飞机长边(机尾到机头)延伸。</p>
+<p>方向传感器还通过 sensors_event_t.orientation.status 报告其预测的度数精度。要详细了解该字段的可能值,请参阅 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html">SensorManager</a> 的 <a href="https://developer.android.com/reference/android/hardware/SensorManager.html#SENSOR_STATUS_ACCURACY_HIGH">SENSOR_STATUS_</a>* 常量。</p>
+<h2 id="uncalibrated_sensors">未校准传感器</h2>
+<p>未校准传感器可提供更多的原始结果,可能包括一些偏差,还包含校准后更正结果中的少数“激增”值。一些应用可能更倾向于使用这些未校准结果,因为此类结果更流畅、可靠。例如,如果应用试图自己进行传感器融合,则引入校准可能会使结果失真。</p>
+<h3 id="gyroscope_uncalibrated">未校准陀螺仪传感器</h3>
+<p>底层物理传感器:陀螺仪</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GYROSCOPE_UNCALIBRATED)</code> 返回一个非唤醒传感器<em></em></p>
+<p>未校准陀螺仪可报告围绕传感器坐标轴的旋转速率(未应用偏差补偿)以及偏差估值。所有值均以弧度/秒为单位,并在 <code>sensors_event_t.uncalibrated_gyro</code> 的字段中报告:</p>
+<ul>
+ <li> <code>x_uncalib</code>:围绕 X 轴的角速度(无漂移补偿)</li>
+ <li> <code>y_uncalib</code>:围绕 Y 轴的角速度(无漂移补偿)</li>
+ <li> <code>z_uncalib</code>:围绕 Z 轴的角速度(无漂移补偿)</li>
+ <li> <code>x_bias</code>:围绕 X 轴的漂移估值</li>
+ <li> <code>y_bias</code>:围绕 Y 轴的漂移估值</li>
+ <li> <code>z_bias</code>:围绕 Z 轴的漂移估值</li>
+</ul>
+<p>在概念上看,未校准的测量结果是校准测量结果和偏差估值之和:<code>_uncalibrated = _calibrated + _bias</code>。</p>
+<p>一旦偏差估值发生变化,<code>x/y/z_bias</code> 值就会激增,而在其余时间则应保持不变。</p>
+<p>有关所用坐标系的详细信息,请参阅<a href="#gyroscope">陀螺仪</a>传感器的定义。</p>
+<p>必须将出厂校准和温度补偿应用于测量结果。此外,必须实现陀螺仪漂移估算,以便在 <code>x_bias</code>、<code>y_bias</code> 和 <code>z_bias</code> 中报告合理的估值。如果该实现不能估算漂移,则不得实现该传感器。</p>
+<p>如果存在此传感器,则相应的陀螺仪传感器也必须存在,并且这两个传感器必须共用相同的 <code>sensor_t.name</code> 和 <code>sensor_t.vendor</code> 值。</p>
+<h3 id="magnetic_field_uncalibrated">未校准磁场传感器</h3>
+<p>底层物理传感器:磁力计</p>
+<p>报告模式:<em><a href="report-modes.html#continuous">连续模式</a></em></p>
+<p><code>getDefaultSensor(SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED)</code> 返回一个非唤醒传感器<em></em></p>
+<p>未校准磁场传感器可报告环境磁场以及硬铁校准估值。所有值均以微特斯拉 (uT) 为单位,并在 <code>sensors_event_t.uncalibrated_magnetic</code> 的字段中报告:</p>
+<ul>
+ <li> <code>x_uncalib</code>:沿 X 轴的磁场(无硬铁补偿)</li>
+ <li> <code>y_uncalib</code>:沿 Y 轴的磁场(无硬铁补偿)</li>
+ <li> <code>z_uncalib</code>:沿 Z 轴的磁场(无硬铁补偿)</li>
+ <li> <code>x_bias</code>:沿 X 轴的估算硬铁偏差</li>
+ <li> <code>y_bias</code>:沿 Y 轴的估算硬铁偏差</li>
+ <li> <code>z_bias</code>:沿 Z 轴的估算硬铁偏差</li>
+</ul>
+<p>在概念上看,未校准的测量结果是校准测量结果和偏差估值之和:<code>_uncalibrated = _calibrated + _bias</code>。</p>
+<p>对于未校准的磁力计,可使用更高级别的算法来处理不良的硬铁估算。一旦硬铁估值发生变化,<code>x/y/z_bias</code> 值就会激增,而在其余时间则应保持不变。</p>
+<p>必须将软铁校准和温度补偿应用于测量结果。此外,必须实现硬铁估算,以便在 <code>x_bias</code>、<code>y_bias</code> 和 <code>z_bias</code> 中报告合理的估值。如果该实现不能估算漂移,则不得实现该传感器。</p>
+<p>如果存在此传感器,则必须存在相应的磁场传感器,并且这两个传感器必须共用相同的 <code>sensor_t.name</code> 和 <code>sensor_t.vendor</code> 值。</p>
+<h2 id="interaction_composite_sensors">互动复合传感器</h2>
+<p>一些传感器主要用于检测与用户的互动。我们没有定义这些传感器的实现方式,但它们必须具备低功耗特性,并且设备制造商有责任验证它们在用户体验方面的质量。</p>
+<h3 id="wake_up_gesture">唤醒手势传感器</h3>
+<p>底层物理传感器:未定义(任何低功耗传感器)</p>
+<p>报告模式:<em><a href="report-modes.html#one-shot">单次模式</a></em></p>
+<p>低功耗</p>
+<p>仅实现该传感器的唤醒版本。</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_WAKE_GESTURE)</code> 返回唤醒传感器<em></em></p>
+<p>唤醒手势传感器可以使用特定设备动作来唤醒设备。当该传感器被触发时,设备会开启屏幕,就如同按下电源按钮一样。用户可在设备设置中禁用这种设备行为(当该传感器被触发时开启屏幕)。更改设置不会影响传感器的行为:仅改变当该传感器被触发时,Android 框架是否开启屏幕。未指定待检测的实际手势,可由设备制造商进行选择。</p>
+<p>该传感器必须具备低功耗特性,因为它可能全天候开启。</p>
+<p>每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1。</p>
+<h3 id="pick_up_gesture">拿起手势传感器</h3>
+<p>底层物理传感器:未定义(任何低功耗传感器)</p>
+<p>报告模式:<em><a href="report-modes.html#one-shot">单次模式</a></em></p>
+<p>低功耗</p>
+<p>仅实现该传感器的唤醒版本。</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_PICK_UP_GESTURE)</code> 返回唤醒传感器<em></em></p>
+<p>拿起手势传感器仅在拿起设备时被触发,并且不考虑设备在拿起前的所在位置(桌面、口袋里或袋子里)。</p>
+<p>每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1。</p>
+<h3 id="glance_gesture">快览手势传感器</h3>
+<p>底层物理传感器:未定义(任何低功耗传感器)</p>
+<p>报告模式:<em><a href="report-modes.html#one-shot">单次模式</a></em></p>
+<p>低功耗</p>
+<p>仅实现该传感器的唤醒版本。</p>
+<p><code>getDefaultSensor(SENSOR_TYPE_GLANCE_GESTURE)</code> 返回唤醒传感器<em></em></p>
+<p>快览手势传感器可短暂开启屏幕,方便用户使用特定动作浏览屏幕内容。当该传感器被触发时,设备将短暂开启屏幕,让用户可以在设备处于锁定且非互动状态(低电耗模式)时浏览通知或其他内容,然后屏幕将再次关闭。用户可在设备设置中禁用这种行为(当该传感器被触发时,短暂开启屏幕)。更改设置不会影响传感器的行为:仅改变当该传感器被触发时,Android 框架是否短暂开启屏幕。未指定待检测的实际手势,可由设备制造商进行选择。</p>
+<p>该传感器必须具备低功耗特性,因为它可能全天候开启。每个传感器事件在 <code>sensors_event_t.data[0]</code> 中报告 1。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/sensors/versioning.html b/zh-cn/devices/sensors/versioning.html
new file mode 100644
index 00000000..69a89bd2
--- /dev/null
+++ b/zh-cn/devices/sensors/versioning.html
@@ -0,0 +1,125 @@
+<html devsite><head>
+ <title>HAL 版本弃用</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>在 Android L 版本中,我们将停止对某些传感器 HAL 版本的支持,仅支持 <code>SENSORS_DEVICE_API_VERSION_1_0
+</code> 和 <code>SENSORS_DEVICE_API_VERSION_1_3</code> 版本。</p>
+
+<p>在后面的版本中,我们也可能会停止对 1_0 的支持。</p>
+
+<p>1_0 没有批处理的概念。如果条件允许,所有使用 1_0 的设备都应升级到 1_3。</p>
+
+<p>1_1 和 1_2 都没有充分定义批处理概念,并且不再受支持</p>
+
+<p>目前使用 1_1 或 1_2 的所有设备都必须升级到 1_3。</p>
+
+<p>在 1_3 中,我们简化了批处理的概念并引入了唤醒传感器。</p>
+
+<p>要升级到 1_3,请按照下文所列更改执行操作。</p>
+
+<h2>实现 batch 函数</h2>
+
+<p>即使您没有实施批处理(您的硬件没有 FIFO),您也必须实现 <code>batch</code> 函数。<code>batch</code> 用于设置指定传感器的采样周期和最大报告延迟时间。它可以取代 <code>setDelay</code>。<code>setDelay</code> 将不再得到调用。</p>
+
+<p>如果您不实施批处理,则可以利用提供的 <code>sampling_period_ns</code> 参数通过仅调用现有的 <code>setDelay</code> 函数来实现 <code>batch</code>。</p>
+
+<h2>实现 Flush 函数</h2>
+
+<p>即使不实施批处理,也必须实现 <code>flush</code> 函数。</p>
+
+<p>如果不实施批处理,则 <code>flush</code> 必须生成一个 <code>META_DATA_FLUSH_COMPLETE</code> 事件并返回 0(成功)。</p>
+
+<h2>更改 sensors_poll_device_t.common.version</h2>
+
+<pre class="prettyprint">
+your_poll_device.common.version = SENSORS_DEVICE_API_VERSION_1_3
+</pre>
+
+<h2>在传感器定义中添加新字段</h2>
+
+<p>定义每个传感器时,除了以下常规 <a href="/devices/sensors/hal-interface.html#sensor_t">sensor_t</a> 字段外:</p>
+
+<pre class="prettyprint">
+.name = "My magnetic field Sensor",
+.vendor = "My company",
+.version
+= 1,
+.handle = mag_handle,
+.type = SENSOR_TYPE_MAGNETIC_FIELD,
+.maxRange = 200.0f,
+.resolution = CONVERT_M,
+.power = 5.0f,
+.minDelay =
+ 16667,
+</pre>
+
+<p>您还必须设置在 1_0 和 1_3 之间定义的新字段:</p>
+
+<pre class="prettyprint">
+.fifoReservedEventCount = 0,
+.fifoMaxEventCount = 0,
+.stringType = 0,
+.requiredPermission = 0,
+.maxDelay = 200000
+.flags =
+SENSOR_FLAG_CONTINUOUS_MODE,
+</pre>
+
+<p><em></em>fifoReservedEventCount:如果不实施批处理,请将此字段设置为 0。</p>
+
+<p><em></em>fifoMaxEventCount:如果不实施批处理,请将此字段设置为 0。</p>
+
+<p><em></em>stringType:针对所有官方 Android 传感器(在 sensors.h 中定义的传感器),请将此字段设置为 0,因为该值会被框架覆盖。对于非官方传感器,请参阅 <a href="/devices/sensors/hal-interface.html#sensor_t">sensor_t</a>,详细了解如何对其进行设置。</p>
+
+<p><em></em>requiredPermission:这是应用访问传感器所必备的权限。通常情况下,您可以针对所有传感器将此字段设置为 0;但对于类型为 <code>HEART_RATE</code> 的传感器,则必须将此字段设置为 <code>SENSOR_PERMISSION_BODY_SENSORS.</code></p>
+
+<p><em></em>maxDelay:这个值很重要,您将需要根据传感器及其驱动程序的功能对此字段进行设置。</p>
+
+<p>仅对连续 (continuous) 和中断 (on-change) 模式下的传感器定义此值。此值是两个传感器事件之间的延迟时间,其中传感器事件对应传感器支持的最低频率。当通过 <code>batch</code> 函数请求较低的频率时,将以该频率生成事件。框架或应用可以用它来预测批处理 FIFO 可能存满的时间。如果此值设置不正确,CTS 将失败。对于单次 (one-shot) 和特殊 (special) 报告模式下的传感器,请将 <code>maxDelay</code> 设置为 0。</p>
+
+<p>对于连续模式下的传感器,请将此字段设置为允许的最大采样周期(以微秒为单位)。</p>
+
+<p>以下内容适用于 <code>period_ns</code>、<code>maxDelay</code> 和 <code>minDelay</code>:</p>
+<ul>
+<li><code>period_ns</code> 以纳秒为单位,而 <code>maxDelay</code>/<code>minDelay</code> 以微秒为单位。</li>
+<li><code>maxDelay</code> 应始终是 32 位的带符号整数。仅出于二进制兼容性原因,才允许在 64 位架构上将其声明为 64 位整数。</li>
+</ul>
+
+<p><em></em>flags:该字段会定义传感器的报告模式以及传感器是否为唤醒传感器。</p>
+
+<p>如果您不实施批处理,只是从 1.0 升级到 1.3,请将此字段设置为:</p>
+
+<p><code>SENSOR_FLAG_WAKE_UP | SENSOR_FLAG_ONE_SHOT_MODE</code> - <a href="/devices/sensors/report-modes.html#one-shot">单次 (one-shot) </a>模式下的传感器</p>
+
+<p><code>SENSOR_FLAG_CONTINUOUS_MODE</code> - <a href="/devices/sensors/report-modes.html#continuous">连续 (continuous)</a> 模式下的传感器;<code>SENSOR_FLAG_ON_CHANGE_MODE</code> - <a href="/devices/sensors/report-modes.html#on-change">中断 (on-change) </a>模式下的传感器(<a href="#proximity">近程</a>传感器除外);<code>SENSOR_FLAG_SPECIAL_REPORTING_MODE</code> - <a href="/devices/sensors/report-modes.html#special">特殊 (special) </a>报告模式下的传感器(<a href="/devices/sensors/sensor-types.html#tilt_detector">倾斜检测器</a>传感器除外)。</p>
+
+<p><code>SENSOR_FLAG_WAKE_UP | SENSOR_FLAG_ON_CHANGE_MODE</code> - <a href="/devices/sensors/sensor-types.html#proximity">近程</a>传感器和 Android 官方<a href="/devices/sensors/sensor-types.html#tilt_detector">倾斜检测器</a>传感器。</p>
+
+<h2>从 1_1 或 1_2 升级时的注意事项</h2>
+<ul>
+ <li>现在,即使是不支持批处理的传感器,<code>batch</code> 函数几乎也总能成功,而且不受超时参数值的影响。可能导致 <code>batch </code> 函数失败的情形仅包括:内部错误、<code>sensor_handle,</code> 不良、<code>sampling_period_ns </code>值为负或 <code>max_report_latency_ns</code> 值为负。
+ </li><li>传感器是否支持批处理取决于它是否具有大于 0 的 <code>fifoMaxEventCount </code>。(在以前的版本中,它是以 <code>batch()</code> 的返回值为依据。)
+ </li><li>支持批处理的传感器在以前的版本中始终处于“批处理模式”:即使 <code>max_report_latency_ns</code> 参数为 0,仍必须对传感器进行批处理操作,这意味着当 SoC 进入挂起模式时,事件必须存储在 FIFO 中。
+ </li><li>将不再使用 <code>batch</code> 函数的 <code>flags </code> 参数。<code>DRY_RUN</code> 和 <code>WAKE_UPON_FIFO_FULL</code> 两者都已弃用,将永远不会被传递给 <code>batch</code> 函数。
+ </li><li>批处理超时参数现称为 <code>max_report_latency</code> 参数。
+</li></ul>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/storage/index.html b/zh-cn/devices/storage/index.html
new file mode 100644
index 00000000..7e1482a6
--- /dev/null
+++ b/zh-cn/devices/storage/index.html
@@ -0,0 +1,48 @@
+<html devsite><head>
+ <title>存储</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<img style="float: right; margin: 0px 15px 15px 15px;" src="images/ape_fwk_hal_extstor.png" alt="Android external storage HAL icon"/>
+<p>Android 一直在不断发展,可支持各种存储设备类型和功能。所有 Android 版本均支持配有<a href="/devices/storage/traditional.html">传统存储</a>(包括便携式存储和内置存储)的设备。便携式存储是指物理介质(如 SD 卡或 USB 设备),用于进行临时数据传输/文件存储。<em></em>物理介质可以随设备一起保留更长时间,但并非固定在设备上,可以移除。自 Android 1.0 开始,SD 卡已可用作便携式存储;Android 6.0 增加对 USB 的支持。“内置”存储可通过将部分内部存储暴露于模拟层来实现存储,并且从 Android 3.0 开始便已支持此功能。<em></em></p>
+
+<p>从 Android 6.0 开始,Android 支持<a href="/devices/storage/adoptable.html">适配的存储设备</a>,此类存储是指物理介质(如 SD 卡或 USB 设备),已进行加密和格式化,能像内部存储一样运行。<em></em>适配的存储设备可存储各类应用数据。</p>
+
+<h2 id="permissions">权限</h2>
+<p>采用各种 Android 权限保护对外部存储设备的访问。从 Android 1.0 开始,采用 <code>WRITE_EXTERNAL_STORAGE</code> 权限保护写入访问。从 Android 4.1 开始,采用 <code>READ_EXTERNAL_STORAGE</code> 权限保护读取访问。</p>
+<p>从 Android 4.4 开始,外部存储设备上的文件所有者、组和模式根据目录结构合成。这样,应用可在外部存储设备上管理其特定文件包的目录,而无需获得广泛的 <code>WRITE_EXTERNAL_STORAGE</code> 权限。例如,文件包名称为 <code>com.example.foo</code> 的应用现在可以自由访问外部存储设备上的 <code>Android/data/com.example.foo/</code>,没有权限限制。通过将原始存储设备封装在 FUSE 守护进程中,可实现此类合成权限。</p>
+
+<h3 id="runtime_permissions">运行时权限</h3>
+
+<p>Android 6.0 引入了一种新的<a href="/devices/tech/config/runtime_perms.html">运行时权限</a>模式,在该模式中,应用可在运行时根据需要请求功能。由于新模式包含 <code>READ/WRITE_EXTERNAL_STORAGE</code> 权限,因此平台需要动态授予存储访问权限,而不会终止或重新启动已运行的应用。通过维护所有安装存储设备的三个不同视图可实现该模式:</p>
+
+<ul>
+ <li><code>/mnt/runtime/default</code> 是向无特殊存储权限的应用以及 <code>adbd</code> 和其他系统组件所在的根命名空间显示。
+ </li><li><code>/mnt/runtime/read</code> 是向具有 <code>READ_EXTERNAL_STORAGE</code> 的应用显示
+ </li><li><code>/mnt/runtime/write</code> 是向具有 <code>WRITE_EXTERNAL_STORAGE</code> 的应用显示
+</li></ul>
+
+<p>在 Zygote 进行 fork 操作时,我们会为各运行应用创建装载命名空间,并将相应的初始视图挂载到位。稍后,当授予运行时权限时,<code>vold</code> 将跳转到已运行应用的装载命名空间,并将升级后的视图挂载到位。请注意,权限降级定会导致应用被终止。</p>
+
+<p>用于实现此特性的 <code>setns()</code> 功能至少需要运行 Linux 3.8,但补丁程序已反向移植至 Linux 3.4。<code>PermissionsHostTest</code> CTS 测试可用于验证内核行为是否正确。</p>
+
+<p>在 Android 6.0 中,第三方应用无权访问 <code>sdcard_r</code> 和 <code>sdcard_rw</code> GID。相反,访问通过仅为该应用装载适当的运行时视图来控制。用户间交互使用 <code>everybody</code> GID 来阻止。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/tech/dalvik/dex-format.html b/zh-cn/devices/tech/dalvik/dex-format.html
index cd1e3105..3791cda0 100644
--- a/zh-cn/devices/tech/dalvik/dex-format.html
+++ b/zh-cn/devices/tech/dalvik/dex-format.html
@@ -113,7 +113,7 @@
</tbody>
</table>
-</p><p>变量 <code>uleb128p1</code> 用于表示一个有符号值,其表示法是<i></i>编码为 <code>uleb128</code> 的值加 1。这使得编码 <code>-1</code>(或被视为无符号值 <code>0xffffffff</code>)成为一个单字节(但没有任何其他负数),并且该编码在下面这些明确说明的情况下非常实用:所表示的数值必须为非负数或 <code>-1</code>(或 <code>0xffffffff</code>);不允许任何其他负值(或不太可能需要使用较大的无符号值)。</p>
+</p><p>变量 <code>uleb128p1</code> 用于表示一个有符号值,其表示法是编码为 <code>uleb128</code> 的值加 1。<i></i>这使得编码 <code>-1</code>(或被视为无符号值 <code>0xffffffff</code>)成为一个单字节(但没有任何其他负数),并且该编码在下面这些明确说明的情况下非常实用:所表示的数值必须为非负数或 <code>-1</code>(或 <code>0xffffffff</code>);不允许任何其他负值(或不太可能需要使用较大的无符号值)。</p>
<p>以下是这类格式的一些示例:</p>
@@ -218,7 +218,7 @@
<p>常量数组/字符串 <code>DEX_FILE_MAGIC</code> 是字节列表,这类字节必须出现在 <code>.dex</code> 文件的开头,以便系统将其原样识别。该值会特意包含一个换行符(<code>"\n"</code> 或 <code>0x0a</code>)和空字节(<code>"\0"</code> 或 <code>0x00</code>),以便协助检测某些形式的损坏问题。该值还可以将格式版本号编码为 3 个十进制数字;随着格式的演变,预计该值会单调递增。</p>
-<pre>
+<pre class="devsite-click-to-copy">
ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x38 0x00 }
= "dex\n038\0"
</pre>
@@ -234,7 +234,7 @@ ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x38 0x00 }
<p>常量 <code>ENDIAN_CONSTANT</code> 用于表示在文件中发现的字节序。虽然标准的 <code>.dex</code> 格式采用小端字节序,但具体实现可能会选择执行字节交换。如果实现遇到其 <code>endian_tag</code> 为 <code>REVERSE_ENDIAN_CONSTANT</code>(而非 <code>ENDIAN_CONSTANT</code>)的标头,则会识别该文件已从预期格式进行过字节交换。</p>
-<pre>
+<pre class="devsite-click-to-copy">
uint ENDIAN_CONSTANT = 0x12345678;
uint REVERSE_ENDIAN_CONSTANT = 0x78563412;
</pre>
@@ -248,7 +248,7 @@ uint REVERSE_ENDIAN_CONSTANT = 0x78563412;
<p><code>NO_INDEX</code> 的选定值可表示为 <code>uleb128p1</code> 编码中的单个字节。</p>
-<pre>
+<pre class="devsite-click-to-copy">
uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
</pre>
@@ -278,21 +278,21 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<tr>
<td>ACC_PRIVATE</td>
<td>0x2</td>
- <td><super>*</super> <code>private</code>:仅对定义类可见</td>
+ <td><super>*</super><code>private</code>:仅对定义类可见</td>
<td><code>private</code>:仅对定义类可见</td>
<td><code>private</code>:仅对定义类可见</td>
</tr>
<tr>
<td>ACC_PROTECTED</td>
<td>0x4</td>
- <td><super>*</super> <code>protected</code>:对软件包和子类可见</td>
+ <td><super>*</super><code>protected</code>:对软件包和子类可见</td>
<td><code>protected</code>:对软件包和子类可见</td>
<td><code>protected</code>:对软件包和子类可见</td>
</tr>
<tr>
<td>ACC_STATIC</td>
<td>0x8</td>
- <td><super>*</super> <code>static</code>:未通过外部 <code>this</code> 引用进行构建</td>
+ <td><super>*</super><code>static</code>:未通过外部 <code>this</code> 引用进行构建</td>
<td><code>static</code>:对定义类全局可见</td>
<td><code>static</code>:不采用 <code>this</code> 参数</td>
</tr>
@@ -763,7 +763,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
</tr>
<tr>
<td class="bar">|</td>
- <td><code>'&lt;'</code> <i></i>SimpleName <code>'&gt;'</code></td>
+ <td><code>'&lt;'</code> <i>SimpleName</i> <code>'&gt;'</code></td>
</tr>
</tbody></table>
@@ -781,14 +781,14 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<tr><td colspan="2" class="def"><i></i>OptionalPackagePrefix →</td></tr>
<tr>
<td>
- </td><td><i></i>(SimpleName <code>'/'</code>)*</td>
+ </td><td>(<i>SimpleName</i> <code>'/'</code>)*</td>
</tr>
</tbody></table>
<h3 id="typedescriptor"><i>TypeDescriptor</i></h3>
<h4>由 type_id_item 使用</h4>
-<p><i></i>TypeDescriptor 是任何类型的表示形式,包括基元、类、数组和 <code>void</code>。请参阅下文,了解各版本的含义。</p>
+<p>TypeDescriptor 是任何类型的表示形式,包括基元、类、数组和 <code>void</code>。<i></i>请参阅下文,了解各版本的含义。</p>
<table class="bnf">
<tbody><tr><td colspan="2" class="def"><i></i>TypeDescriptor →</td></tr>
@@ -809,7 +809,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<tr>
<td class="bar">|</td>
<td>(<code>'['</code> * 1…255)
- NonArrayFieldTypeDescriptor<i></i></td>
+ <i>NonArrayFieldTypeDescriptor</i></td>
</tr>
<tr>
@@ -849,7 +849,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
</tr>
<tr>
<td class="bar">|</td>
- <td><code>'L'</code> <i></i>FullClassName <code>';'</code></td>
+ <td><code>'L'</code> <i>FullClassName</i> <code>';'</code></td>
</tr>
</tbody></table>
@@ -1082,7 +1082,6 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<td>field_ids_off</td>
<td>uint</td>
<td>从文件开头到字段标识符列表的偏移量;如果 <code>field_ids_size == 0</code>,则该值为 <code>0</code>。该偏移量(如果为非零值)应该是到 <code>field_ids</code> 区段开头的偏移量。</td>
-
</tr>
<tr>
<td>method_ids_size</td>
@@ -1143,7 +1142,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<tr>
<td>list</td>
<td>map_item[size]</td>
- <td>该列表的元素数量</td>
+ <td>列表的元素</td>
</tr>
</tbody>
</table>
@@ -2120,7 +2119,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<code>type_idx</code>:该类型的类型索引<br />
<code>sig_idx</code>:该类型签名的字符串索引</td>
<td>在当前地址中引入一个带有类型签名的本地变量。<code>name_idx</code>、<code>type_idx</code> 或 <code>sig_idx</code> 中的任何一个都可能是 <code>NO_INDEX</code>,用于表示该值是未知的(即便 <code>sig_idx</code> 为 <code>-1</code>,使用操作码 <code>DBG_START_LOCAL</code> 也可以更有效地表示相同的数据)。
- <p class="note"><strong>注意</strong>:请参阅“<code>dalvik.annotation.Signature</code>”下的讨论,了解关于处理签名的注意事项。</p>
+ <p class="note"><strong>注意</strong>:请参阅 <code>dalvik.annotation.Signature</code> 下的讨论,了解关于处理签名的注意事项。</p>
</td>
</tr>
<tr>
@@ -2179,7 +2178,7 @@ uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int
<p>值在 <code>0x0a</code> 和 <code>0xff</code>(含)之间的操作码会将 <code>line</code> 和 <code>address</code> 寄存器移动一小部分,然后发出 (emit) 一个新的位置表条目。这些增量的公式如下所示:</p>
-<pre>
+<pre class="devsite-click-to-copy">
DBG_FIRST_SPECIAL = 0x0a // the smallest special opcode
DBG_LINE_BASE = -4 // the smallest line number increment
DBG_LINE_RANGE = 15 // the number of line increments represented
@@ -2574,7 +2573,7 @@ address += (adjusted_opcode / DBG_LINE_RANGE)
<h3 id="dalvik-innerclass">dalvik.annotation.InnerClass</h3>
<h4>在类中显示</h4>
-<p><code>InnerClass</code> 注释会附加到已在其他类定义的词法作用域中定义的各个类。<i></i><i></i>具有此注释的所有类还必须具有 <code>EnclosingClass</code> 注释或 <code>EnclosingMethod</code> 注释。</p>
+<p><code>InnerClass</code> 注释会附加到已在其他类定义的词法作用域中定义的各个类。具有此注释的所有类还必须具有 <code>EnclosingClass</code> 注释或 <code>EnclosingMethod</code> 注释。<i></i><i></i></p>
<table class="format">
<thead>
diff --git a/zh-cn/devices/tech/debug/gdb.html b/zh-cn/devices/tech/debug/gdb.html
index f9c74d5d..e4eabfbd 100644
--- a/zh-cn/devices/tech/debug/gdb.html
+++ b/zh-cn/devices/tech/debug/gdb.html
@@ -54,7 +54,7 @@ gdbclient <var>APP_PID</var>
<p>最后,在 <code>gdb</code> 提示处输入 <strong>continue</strong>。</p>
-<p class="note"><strong>注意</strong>:如果您指定了错误的 <code>gdbserver</code>,将会收到没任何帮助的错误消息(例如“<code>Reply contains invalid hex digit 59</code>”)。</p>
+<p class="note"><strong>注意</strong>:如果您指定了错误的 <code>gdbserver</code>,将会收到无用的错误消息(例如“<code>Reply contains invalid hex digit 59</code>”)。</p>
<h2 id="app-startup">调试应用启动</h2>
@@ -64,7 +64,7 @@ gdbclient <var>APP_PID</var>
<p>要调试应用启动,请使用“设置”中的开发者选项,指示应用等待附加 Java 调试程序:</p>
<ol>
-<li>请依次转到“设置”&gt;“开发者选项”&gt;“选择调试应用”<em></em>,并从列表中选择您的应用,然后按<strong>等待调试程序</strong>。</li>
+<li>请依次转到“设置”&gt;“开发者选项”&gt;“选择调试应用”,并从列表中选择您的应用,然后按<strong>等待调试程序</strong>。<em></em></li>
<li>启动应用,您可以从启动器启动,也可以在命令行中运行以下命令来启动:<pre class="devsite-terminal devsite-click-to-copy">
am start -a android.intent.action.MAIN -n <var>APP_NAME</var>/.<var>APP_ACTIVITY</var>
@@ -94,13 +94,13 @@ am start -a android.intent.action.MAIN -n <var>APP_NAME</var>/.<var>APP_ACTIVITY
<code class="devsite-terminal">adb shell setprop debug.db.uid 999999</code>
</pre>
-<p>在寻常的崩溃输出结束后,<code>debuggerd</code> 会提供有关如何使用命令连接 <code>gdb</code> 的说明:</p><pre class="devsite-terminal devsite-click-to-copy">
+<p>在寻常崩溃输出的结尾处,<code>debuggerd</code> 会提供有关如何使用以下命令来连接 <code>gdb</code> 的说明:</p><pre class="devsite-terminal devsite-click-to-copy">
gdbclient <var>PID</var>
</pre>
<h2 id="symbols">无符号调试</h2>
-<p>对于 32 位 ARM,如果您没有符号,<code>gdb</code> 就会搞不清楚要反汇编的指令集(ARM 或 Thumb)。要在缺失符号信息时指定已选为默认项的指令集,请设置以下属性:</p>
+<p>对于 32 位 ARM,如果您的指令中没有符号,<code>gdb</code> 就不清楚自己正在反汇编哪个指令集(ARM 或 Thumb)。要指定缺少符号信息时选为默认指令集的指令集,请设置以下属性:</p>
<pre class="devsite-terminal devsite-click-to-copy">
set arm fallback-mode arm # or thumb
diff --git a/zh-cn/devices/tech/debug/index.html b/zh-cn/devices/tech/debug/index.html
index c0038c42..aaee8248 100644
--- a/zh-cn/devices/tech/debug/index.html
+++ b/zh-cn/devices/tech/debug/index.html
@@ -20,9 +20,11 @@
limitations under the License.
-->
-<p>本部分总结了开发平台级功能时,可用于调试、跟踪和分析原生 Android 平台代码的实用工具和相关命令。本页面介绍了 <code>debuggerd</code> 和 GNU 项目调试程序 (GDB) 的用法。debuggerd 是一种用于在应用崩溃后收集错误信息的守护进程。</p>
+<p>本部分总结了开发平台级功能时,可用于调试、跟踪和分析原生 Android 平台代码的实用工具和相关命令。</p>
-<p>本部分的其他页面介绍了如何通过 <a href="/devices/tech/debug/dumpsys.html">Dumpsys</a> 和多种其他调适工具了解系统服务状况,其中包括查看<a href="/devices/tech/debug/native-memory.html">本地内存</a>、<a href="/devices/tech/debug/netstats.html">网络</a>和 <a href="/devices/tech/debug/procstats.html">RAM</a> 使用情况、使用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a> 检测原生代码中的内存错误、评估<a href="/devices/tech/debug/eval_perf.html">性能问题</a>(包括 <a href="/devices/tech/debug/systrace">systrace</a>)。</p>
+<p class="note"><strong>注意</strong>:本节和本网站其他部分的页面建议您使用 <code>adb</code> 与 <code>setprop</code> 参数一起调试 Android 的某些方面。请注意,在 Android 操作系统的 O 版本之前,属性名称的长度上限为 32 个字符。也就是说,要创建一个包含应用名称的 wrap 属性,您需要截断该名称以使其符合字符数限制。在 Android O 及更高版本中,此字符数上限值要大得多,应该不需要截断。</p>
+
+<p>本页面介绍了 <code>debuggerd</code> 的用法,debuggerd 是一种用于在应用崩溃后收集错误信息的守护进程。本部分的其他页面介绍了如何通过 <a href="https://developer.android.com/studio/command-line/dumpsys.html">Dumpsys</a> 了解系统服务状况,其中包括查看<a href="/devices/tech/debug/native-memory.html">本地内存</a>、<a href="https://developer.android.com/studio/command-line/dumpsys.html#network">网络</a>和 <a href="https://developer.android.com/studio/command-line/dumpsys.html#procstats">RAM</a> 使用情况、使用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a> 检测原生代码中的内存错误、评估<a href="/devices/tech/debug/eval_perf.html">性能问题</a>(包括 <a href="/devices/tech/debug/systrace">systrace</a>),以及使用 <a href="/devices/tech/debug/gdb.html">GNU 项目调试程序 (GDB)</a> 和其他调试工具。</p>
<h2 id="debuggerd">使用 debuggerd</h2>
@@ -32,7 +34,7 @@
<p><code>debuggerd</code> 输出示例(已去除时间戳和无关信息):</p>
-<pre class="no-pretty-print">
+<pre class="devsite-click-to-copy">
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys'
Revision: '0'
@@ -55,14 +57,18 @@ backtrace:
Tombstone written to: /data/tombstones/tombstone_06
</pre>
-<p><code>debuggerd</code> 输出的最后一行会向日志转储一个摘要,并向磁盘写入完整的 tombstone<em></em>。tombstone 仅仅是一个包含与崩溃进程相关的额外数据的文件;文件中的信息在调试崩溃时会非常有用,尤其是对崩溃进程中的所有线程(而不只是捕捉到信号的线程)和完整内存映射进行堆栈跟踪时。</p>
+<p><code>debuggerd</code> 输出的最后一行会向日志转储一个摘要,并向磁盘写入完整的 tombstone。<em></em>tombstone 仅仅是一个包含与崩溃进程相关的额外数据的文件;文件中的信息在调试崩溃时会非常有用,尤其是对崩溃进程中的所有线程(而不只是捕捉到信号的线程)和完整内存映射进行堆栈跟踪时。</p>
<p>假设可以找到未剥离的二进制文件,您可以将上述示例粘贴到 <code>development/scripts/stack</code>,从而获取更详细的展开信息(包含行数信息):</p>
<p class="key-point"><strong>提示</strong>:为方便起见,如果您已启动 <code>stack</code>,它将在您的 $PATH 上显示,因此您无需提供完整路径。</p>
-<pre>
-$ development/tools/stack
+<pre class="devsite-terminal devsite-click-to-copy">
+development/tools/stack
+</pre>
+
+<p>输出示例:</p>
+<pre class="devsite-click-to-copy">
Reading native crash info from stdin
03-02 23:53:49.477 17951 17951 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-02 23:53:49.477 17951 17951 F DEBUG : Build fingerprint: 'Android/aosp_angler/angler:7.1.1/NYC/enh12211018:eng/test-keys'
@@ -106,75 +112,17 @@ Stack Trace:
0001a7e5 __start_thread+34 bionic/libc/bionic/clone.cpp:46 (discriminator 1)
</pre>
-<p class="note"><strong>注意</strong>:某些系统库使用 <code>LOCAL_STRIP_MODULE := keep_symbols</code> 构建,可直接从 <code>debuggerd</code> 提供可用的回溯,而不会像未剥离版本那样占用较大的空间。</p>
+<p class="note"><strong>注意</strong>:某些系统库是使用 <code>LOCAL_STRIP_MODULE := keep_symbols</code> 编译的,可直接从 <code>debuggerd</code> 提供可用的回溯,而不会像未剥离版本那样占用较大的空间。</p>
<p>您也可以 <code>stack</code> 整个 tombstone。示例:</p>
-<pre>
-$ stack &lt; FS/data/tombstones/tombstone_05
+<pre class="devsite-terminal devsite-click-to-copy">
+stack &lt; FS/data/tombstones/tombstone_05
</pre>
<p>如果您刚刚在当前目录中解压过错误报告,这将非常有用。要详细了解如何诊断原生代码崩溃和 tombstone,请参阅<a href="/devices/tech/debug/native-crash.html">诊断原生代码崩溃</a>。
</p>
-<h3>从正在运行的进程获取堆栈跟踪/tombstone</h3>
-
-<p>您也可以对正在运行的进程使用 <code>debuggerd</code>。在命令行中,使用进程 ID (PID) 调用 <code>debuggerd</code>,以将完整的 tombstone 转储至 <code>stdout</code>。要确切获取进程中每个线程的堆栈,请添加 <code>-b</code> 或 <code>--backtrace</code> 标记。
-
-</p><h2 id="native">使用 GDB</h2>
-
-<p>GNU 项目调试程序 (GDB) 是常用的 Unix 调试程序。</p>
-
-<h3 id="running">调试正在运行的应用</h3>
-
-<p>要连接到已在运行的应用或本机守护进程,请配合使用 <code>gdbclient</code> 和 PID。例如,要调试 PID 为 1234 的进程,请运行:</p>
-
-<pre class="no-pretty-print">
-$ gdbclient 1234
-</pre>
-
-<p>此脚本会设置端口转发,在设备上启动相应的 <code>gdbserver</code>,在主机上启动相应的 <code>gdb</code>,配置 <code>gdb</code> 以找出符号,然后将 <code>gdb</code> 连接到远程 <code>gdbserver</code>。</p>
-
-<h3 id="starts">在本机进程启动时对其进行调试</h3>
-
-<p>要在进程启动时对其进行调试,请使用 <code>gdbserver</code> 或 <code>gdbserver64</code>(适用于 64 位进程)。例如:</p>
-
-<pre class="no-pretty-print">
-$ adb shell gdbserver :5039 /system/bin/<em>my_test_app</em>
-Process my_test_app created; pid = 3460
-Listening on port 5039
-</pre>
-
-<p>接着,从 <code>gdbserver</code> 输出结果中找出应用 PID,并将其用于其他终端窗口:</p>
-
-<pre class="no-pretty-print">
-$ gdbclient <em>&lt;app pid&gt;</em>
-</pre>
-
-<p>最后,在 <code>gdb</code> 提示处输入 <strong>continue</strong>。</p>
-
-<p class="note"><strong>注意</strong>:如果您使用的是错误的 <code>gdbserver</code>,则会收到没用的错误消息(如“<code>Reply contains invalid hex digit 59</code>”)。</p>
-
-<h3 id="crash">调试崩溃的进程</h3>
-
-<p>如果您希望 <code>debuggerd</code> 暂停崩溃的进程,以便您可以附加 <code>gdb</code>,请设置相应的属性:</p>
-
-<pre class="no-pretty-print">
-# Android 7.0 Nougat and later.
-$ adb shell setprop debug.debuggerd.wait_for_gdb true
+<h2 id="tombstone">从正在运行的进程获取堆栈跟踪/tombstone</h2>
-# Android 6.0 Marshmallow and earlier.
-$ adb shell setprop debug.db.uid 999999
-</pre>
-
-<p>在寻常崩溃输出的结尾处,<code>debuggerd</code> 会提供有关如何使用以下命令来连接 <code>gdb</code> 的说明:</p><pre class="no-pretty-print">
-$ gdbclient &lt;pid&gt;
-</pre>
-
-<h3 id="symbols">无符号调试</h3>
-
-<p>对于 32 位 ARM,如果您的指令中没有符号,<code>gdb</code> 就不清楚自己正在反汇编哪个指令集(ARM 或 Thumb)。要指定缺少符号信息时选为默认指令集的指令集,请设置以下属性:</p>
-
-<pre class="no-pretty-print">
-$ set arm fallback-mode arm # or thumb
-</pre>
+<p>您也可以对正在运行的进程使用 <code>debuggerd</code>。在命令行中,使用进程 ID (PID) 调用 <code>debuggerd</code>,以将完整的 tombstone 转储至 <code>stdout</code>。要确切获取进程中每个线程的堆栈,请添加 <code>-b</code> 或 <code>--backtrace</code> 标记。</p>
</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/tech/ota/device_code.html b/zh-cn/devices/tech/ota/device_code.html
index dc4f5fc0..575b1571 100644
--- a/zh-cn/devices/tech/ota/device_code.html
+++ b/zh-cn/devices/tech/ota/device_code.html
@@ -28,9 +28,11 @@
<p>分区映射文件由 TARGET_RECOVERY_FSTAB 指定;recovery 二进制文件和软件包编译工具均使用该文件。您可以在 BoardConfig.mk 中的 TARGET_RECOVERY_FSTAB 中指定映射文件的名称。</p>
<p>分区映射文件示例可能如下所示:</p>
-<p><code>device/yoyodyne/tardis/recovery.fstab</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/recovery.fstab
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
# mount point fstype device [device2] [options (3.0+ only)]
/sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0
@@ -66,16 +68,18 @@
<p>对于 <a href="https://developer.android.com/things/hardware/index.html">Android Things</a> 设备,您可以在 Android Things 控制台中上传压缩文件,以便在所选产品中包含图片。</p>
-<p class="note"><strong>注意</strong>:这些图片必须符合 Android <a href="/source/brands">品牌指南</a>。</p>
+<p class="note"><strong>注意</strong>:这些图片必须符合 Android <a href="/source/brands">品牌推广指南</a>。</p>
<h2 id="recovery-ui">恢复界面</h2>
<p>要支持配备不同可用硬件(物理按钮、LED、屏幕等)的设备,您可以自定义恢复界面以显示状态,并访问每台设备的手动操作隐藏功能。</p>
<p>您的目标是编译一个包含一些 C++ 对象的小型静态库,以提供设备专属功能。默认情况下会使用 <code>
<b>bootable/recovery/default_device.cpp</b></code> 文件,该文件正好可在为设备编写此文件的版本时供您复制。</p>
-<p><code>device/yoyodyne/tardis/recovery/recovery_ui.cpp</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/recovery/recovery_ui.cpp
+</pre>
-<pre>
+<pre class="prettyprint">
#include &lt;linux/input.h&gt;
#include "common.h"
@@ -86,7 +90,7 @@
<h3 id="header-item-functions">Headers 和 Item 函数</h3>
<p>Device 类需要相关函数来返回隐藏恢复菜单中出现的标头和项。Headers 介绍了如何操作菜单(例如,用于更改/选择突出显示项的控制功能)。</p>
-<pre>
+<pre class="prettyprint">
static const char* HEADERS[] = { "Volume up/down to move highlight;",
"power button to select.",
"",
@@ -104,7 +108,7 @@ static const char* ITEMS[] = {"reboot system now",
<h3 id="customize-checkkey">自定义 CheckKey</h3>
<p>接下来,请定义您设备的 RecoveryUI 实现。本例假设 <b>tardis</b> 设备配有屏幕,因此,您可以沿用内置 ScreenRecoveryUIimplementation(请参阅有关<a href="#devices-without-screens">无屏幕设备</a>的说明)。可通过 ScreenRecoveryUI 自定义的唯一函数是 <code>CheckKey()</code>,该函数会执行初始异步键处理操作:</p>
-<pre>
+<pre class="prettyprint">
class TardisUI : public ScreenRecoveryUI {
public:
virtual KeyAction CheckKey(int key) {
@@ -132,7 +136,7 @@ CheckKey()</code>:菜单切换为关闭状态时、菜单处于打开状态时
</code> 调用了 <code>IsKeyPressed(A)</code>,则会返回 true)。</p>
<p><code>CheckKey()</code> 可以在其类中保持状态,这有助于检测键的序列。本示例展示的是一个稍微复杂的设置:按住电源键并按下音量提高键可切换显示状态,连续按五次电源按钮可立即重新启动设备(无需使用其他键):</p>
-<pre>
+<pre class="prettyprint">
class TardisUI : public ScreenRecoveryUI {
private:
int consecutive_power_keys;
@@ -162,13 +166,13 @@ class TardisUI : public ScreenRecoveryUI {
<p class="note"><strong>注意</strong>:通过最新的 <code>interlace-frames.py</code> 脚本,您可以将 <code>animation_fps</code> 信息存储到图片中。在早期版本的 Android 中,您必须自行设置 <code>animation_fps</code>。</p>
-<p>要设置变量 <code>animation_fps</code>,请替换子类中的 <code>ScreenRecoveryUI::Init()</code> 函数。设置值,然后调用 <code>parent Init() </code> 函数以完成初始化。默认值 (20 FPS) 对应默认恢复图片;您在使用这些图片时无需提供 <code>Init()</code> 函数。
+<p>要设置变量 <code>animation_fps</code>,请替换子类中的 <code>ScreenRecoveryUI::Init()</code> 函数。设置值,然后调用 <code>parent Init() </code>函数以完成初始化。默认值 (20 FPS) 对应默认恢复图片;您在使用这些图片时无需提供 <code>Init()</code> 函数。
有关图片的详细信息,请参阅<a href="#recovery-ui-images">恢复界面图片</a>。</p>
<h3 id="device-class">Device 类</h3>
<p>执行 RecoveryUI 实现后,请定义您的 Device 类(由内置 Device 类派生的子类)。它应该会创建您的 UI 类的单个实例,并通过 <code>GetUI()</code> 函数返回该实例:</p>
-<pre>
+<pre class="prettyprint">
class TardisDevice : public Device {
private:
TardisUI* ui;
@@ -184,7 +188,7 @@ class TardisDevice : public Device {
<h3 id="startrecovery">StartRecovery</h3>
<p><code>StartRecovery()</code> 方法的调用时机是:恢复开始时,界面已初始化且参数已解析之后,但在执行任何操作之前。默认的实现不会执行任何操作,因此,如果您没有可执行的操作,则无需在子类中提供此项。</p>
-<pre>
+<pre class="prettyprint">
void StartRecovery() {
// ... do something tardis-specific here, if needed ....
}
@@ -193,7 +197,7 @@ class TardisDevice : public Device {
<h3 id="supply-manage-recovery-menu">提供和管理恢复菜单</h3>
<p>系统会调用两种方法来获取标头行列表和项列表。在此实现中,系统会返回文件顶部定义的静态数组:</p>
-<pre>
+<pre class="prettyprint">
const char* const* GetMenuHeaders() { return HEADERS; }
const char* const* GetMenuItems() { return ITEMS; }
</pre>
@@ -201,7 +205,7 @@ const char* const* GetMenuItems() { return ITEMS; }
<h4 id="handlemenukey">HandleMenuKey</h4>
<p>接下来,提供 <code>HandleMenuKey()</code> 函数,该函数会提取按键和当前菜单可见性,并确定要执行哪项操作。</p>
-<pre>
+<pre class="prettyprint">
int HandleMenuKey(int key, int visible) {
if (visible) {
switch (key) {
@@ -232,7 +236,7 @@ const char* const* GetMenuItems() { return ITEMS; }
<p>要查看作为辅助键按下的键,请调用您自己的界面对象的 <code>IsKeyPressed()
</code> 方法。例如,在某些设备上,在恢复系统中按 Alt-W 会启动数据清除(无论菜单是否可见)。您可以按如下方式实现:</p>
-<pre>
+<pre class="prettyprint">
int HandleMenuKey(int key, int visible) {
if (ui-&gt;IsKeyPressed(KEY_LEFTALT) &amp;&amp; key == KEY_W) {
return 2; // position of the "wipe data" item in the menu
@@ -246,7 +250,7 @@ const char* const* GetMenuItems() { return ITEMS; }
<h4 id="invokemenuitem">InvokeMenuItem</h4>
<p>接下来,提供 <code>InvokeMenuItem()</code> 方法,将由 <code>GetMenuItems()</code> 返回的项数组中的整数位置映射到相应的操作。对于 tardis 示例中的项数组,请使用:</p>
-<pre>
+<pre class="prettyprint">
BuiltinAction InvokeMenuItem(int menu_position) {
switch (menu_position) {
case 0: return REBOOT;
@@ -269,7 +273,7 @@ const char* const* GetMenuItems() { return ITEMS; }
</ul>
<p>最后一种方法 <code>WipeData()</code> 是可选项,只要系统执行数据清除操作(通过菜单从退出恢复系统中执行,或当用户从主系统中选择恢复出厂设置时),就会调用此方法。该方法在清除 userdata 和 cache 分区之前调用。如果您的设备将用户数据存储在这两个分区之外的其他位置,您应在此处清空数据。您应返回 0 以表示成功,返回其他值以表示失败,不过目前系统会忽略返回值。无论您返回成功还是失败,userdata 和 cache 分区都会被清除。</p>
-<pre>
+<pre class="prettyprint">
int WipeData() {
// ... do something tardis-specific here, if needed ....
return 0;
@@ -279,7 +283,7 @@ const char* const* GetMenuItems() { return ITEMS; }
<h4 id="make-device">生成设备</h4>
<p>最后,在创建并返回您的 Device 类实例的 <code>make_device()</code> 函数的 recovery_ui.cpp 文件末尾包含一些样板文件。</p>
-<pre>
+<pre class="prettyprint">
class TardisDevice : public Device {
// ... all the above methods ...
};
@@ -292,9 +296,11 @@ Device* make_device() {
<h3 id="build-link-device-recovery">编译并链接到设备 recovery 分区</h3>
<p>完成 recovery_ui.cpp 文件后,编译该文件并将其链接到您设备上的 recovery 分区。在 Android.mk 中,创建一个只包含此 C++ 文件的静态库:</p>
-<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/recovery/Android.mk
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -310,7 +316,7 @@ include $(BUILD_STATIC_LIBRARY)
<p>然后,在该设备的板配置中,将静态库指定为 TARGET_RECOVERY_UI_LIB 的值。</p>
-<pre>
+<pre class="devsite-click-to-copy">
device/yoyodyne/tardis/BoardConfig.mk
[...]
@@ -329,11 +335,11 @@ TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
<tbody>
<tr>
<td>
-<img src="../images/icon_error.png" alt="image shown during ota error"/>
+<img src="/devices/tech/images/icon_error.png" alt="image shown during ota error"/>
<p class="img-caption"><strong>图 1.</strong> icon_error.png</p>
</td>
<td>
-<img src="../images/icon_installing_5x.png" alt="image shown during ota install" height="275"/>
+<img src="/devices/tech/images/icon_installing_5x.png" alt="image shown during ota install" height="275"/>
<p class="img-caption"><strong>图 2.</strong> icon_installing.png</p>
</td>
</tr>
@@ -351,18 +357,18 @@ TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
<tbody>
<tr>
<td rowspan="2">
-<img src="../images/icon_installing.png" alt="image shown during ota install"/>
+<img src="/devices/tech/images/icon_installing.png" alt="image shown during ota install"/>
<p class="img-caption"><strong>图 3.</strong> icon_installing.png</p>
</td>
<td>
-<img src="../images/icon_installing_overlay01.png" alt="image shown as first overlay"/>
+<img src="/devices/tech/images/icon_installing_overlay01.png" alt="image shown as first overlay"/>
<p class="img-caption"><strong>图 4.</strong> icon-installing_overlay01.png
</p>
</td>
</tr>
<tr>
<td>
-<img src="../images/icon_installing_overlay07.png" alt="image shown as seventh overlay"/>
+<img src="/devices/tech/images/icon_installing_overlay07.png" alt="image shown as seventh overlay"/>
<p class="img-caption"><strong>图 5.</strong> icon_installing_overlay07.png
</p>
</td>
@@ -375,10 +381,10 @@ TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
<table style="border-collapse:collapse;">
<tbody>
<tr>
-<td><img align="center" src="../images/composite01.png" alt="composite image of install plus first overlay"/>
+<td><img align="center" src="/devices/tech/images/composite01.png" alt="composite image of install plus first overlay"/>
<p class="img-caption"><strong>图 6.</strong> “正在安装”动画帧 1 (icon_installing.png + icon_installing_overlay01.png)
</p></td>
-<td><img align="center" src="../images/composite07.png" alt="composite image of install plus seventh overlay"/>
+<td><img align="center" src="/devices/tech/images/composite07.png" alt="composite image of install plus seventh overlay"/>
<p class="img-caption"><strong>图 7.</strong> “正在安装”动画帧 7 (icon_installing.png + icon_installing_overlay07.png)
</p></td>
</tr>
@@ -397,7 +403,7 @@ TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
<p>恢复文本字符串的示例图片:</p>
-<img src="../images/installing_text.png" alt="image of recovery text"/>
+<img src="/devices/tech/images/installing_text.png" alt="image of recovery text"/>
<p class="img-caption"><strong>图 8.</strong> 恢复消息的本地化文本</p>
<p>恢复文本会显示以下消息:</p>
@@ -418,18 +424,18 @@ src/com/android/recovery_l10n/Main.java</code> 中的注解。
<h2 id="progress-bars">进度条</h2>
<p>进度条会显示在主要图片(或动画)的下方。进度条由两张输入图片(大小必须相同)合并而成:</p>
-<img src="../images/progress_empty.png" alt="empty progress bar"/>
+<img src="/devices/tech/images/progress_empty.png" alt="empty progress bar"/>
<p class="img-caption"><strong>图 9.</strong> progress_empty.png</p>
-<img src="../images/progress_fill.png" alt="full progress bar"/>
+<img src="/devices/tech/images/progress_fill.png" alt="full progress bar"/>
<p class="img-caption"><strong>图 10.</strong> progress_fill.png</p>
<p>fill 图片的左端显示在 empty 图片右端的旁边,从而形成进度条。<i></i><i></i>两张图片之间的边界位置会不时变更,以表示相应的进度。以上述几对输入图片为例,显示效果为:</p>
-<img src="../images/progress_1.png" alt="progress bar at 1%"/>
+<img src="/devices/tech/images/progress_1.png" alt="progress bar at 1%"/>
<p class="img-caption"><strong>图 11.</strong> 进度条显示为 1%&gt;</p>
-<img src="../images/progress_10.png" alt="progress bar at 10%"/>
+<img src="/devices/tech/images/progress_10.png" alt="progress bar at 10%"/>
<p class="img-caption"><strong>图 12.</strong> 进度条显示为 10%</p>
-<img src="../images/progress_50.png" alt="progress bar at 50%"/>
+<img src="/devices/tech/images/progress_50.png" alt="progress bar at 50%"/>
<p class="img-caption"><strong>图 13.</strong> 进度条显示为 50%</p>
<p>您可以将这些图片的设备专属版本放入(在本例中)<code>device/yoyodyne/tardis/recovery/res/images</code> 中,以提供这类版本的图片。
@@ -446,8 +452,10 @@ src/com/android/recovery_l10n/Main.java</code> 中的注解。
<h2 id="updater">更新程序</h2>
<p>您可以提供自己的扩展函数(可从您的更新程序脚本中调用),从而在安装更新程序包的过程中使用设备专属代码。以下是适用于 tardis 设备的示例函数:</p>
-<p><code>device/yoyodyne/tardis/recovery/recovery_updater.c</code></p>
-<pre>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/recovery/recovery_updater.c
+</pre>
+<pre class="prettyprint">
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
@@ -456,7 +464,7 @@ src/com/android/recovery_l10n/Main.java</code> 中的注解。
<p>每个扩展函数都采用相同的签名。具体参数即调用函数的名称,<code>State*</code> Cookie、传入参数的数量和表示参数的 <code>Expr*</code> 指针数组。返回值是新分配的 <code>Value*</code>。</p>
-<pre>
+<pre class="prettyprint">
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
@@ -468,7 +476,7 @@ Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[])
<p>假设该函数需要两种参数:字符串值的 <b>key</b> 和 blob 值的 <b>image</b>。您可能会看到如下参数:</p>
-<pre>
+<pre class="prettyprint">
Value* key = EvaluateValue(state, argv[0]);
if (key == NULL) {
return NULL;
@@ -493,7 +501,7 @@ Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[])
<p>为多个参数检查 NULL 并释放之前评估的参数可能会很繁琐。<code>ReadValueArgs()</code> 函数会让此变得更简单。您可以不使用上面的代码,而是写入下面的代码:</p>
-<pre>
+<pre class="prettyprint">
Value* key;
Value* image;
if (ReadValueArgs(state, argv, 2, &amp;key, &amp;image) != 0) {
@@ -512,7 +520,7 @@ ReadValueVarArgs()</code> 便捷函数来评估数量不定的参数(它会返
<p>对参数进行评估后,执行以下函数:</p>
-<pre>
+<pre class="devsite-click-to-copy">
// key-&gt;data is a NUL-terminated string
// image-&gt;data and image-&gt;size define a block of binary data
//
@@ -524,7 +532,7 @@ ReadValueVarArgs()</code> 便捷函数来评估数量不定的参数(它会返
<p>在这种情况下,您需要返回 true 或 false 值来表示成功。请记住以下惯例:空字符串为 false,所有其他字符串均为 true。<i></i><i></i>您必须使用要返回的常量字符串的经过 malloc 处理的副本来分配 Value 对象,因为调用程序会 <code>free()
</code> 这两者。请切记对通过评估参数获得的对象调用 <code>FreeValue()</code>!</p>
-<pre>
+<pre class="prettyprint">
FreeValue(key);
FreeValue(image);
@@ -538,7 +546,7 @@ ReadValueVarArgs()</code> 便捷函数来评估数量不定的参数(它会返
<p>便捷函数 <code>StringValue()</code> 会将字符串封装到新的 Value 对象中。使用此函数可使上述代码的编写更加简洁:</p>
-<pre>
+<pre class="prettyprint">
FreeValue(key);
FreeValue(image);
@@ -546,9 +554,9 @@ ReadValueVarArgs()</code> 便捷函数来评估数量不定的参数(它会返
}
</pre>
-<p>要将函数挂接到 edify 解释程序中,请提供函数 <code>Register_<i>foo</i></code>(其中 <i>foo</i> 是包含此代码的静态库的名称)。调用 <code>RegisterFunction()</code> 以注册各个扩展函数。按照惯例,需要对设备专属函数 <code><i>device</i>.<i>whatever</i></code> 进行命名,以免与将来添加的内置函数发生冲突。</p>
+<p>要将函数挂接到 edify 解释程序中,请提供函数 <code>Register_<i>foo</i></code>(其中 <i>foo</i> 是包含此代码的静态库的名称)。调用 <code>RegisterFunction()</code> 即可注册各个扩展函数。按照惯例,您需要对设备专属函数 <code><i>device</i>.<i>whatever</i></code> 进行命名,以免与将来添加的内置函数发生冲突。</p>
-<pre>
+<pre class="prettyprint">
void Register_librecovery_updater_tardis() {
RegisterFunction("tardis.reprogram", ReprogramTardisFn);
}
@@ -556,9 +564,11 @@ void Register_librecovery_updater_tardis() {
<p>现在,您可以配置 makefile,以使用您的代码编译静态库(此 makefile 即是之前的区段中用于自定义恢复界面的 makefile;您设备的两个静态库可能都是在此定义的)。</p>
-<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/recovery/Android.mk
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
include $(CLEAR_VARS)
LOCAL_SRC_FILES := recovery_updater.c
LOCAL_C_INCLUDES += bootable/recovery
@@ -566,16 +576,18 @@ LOCAL_C_INCLUDES += bootable/recovery
<p>静态库的名称必须与其中所包含的 <code>Register_<i>libname</i></code> 函数的名称匹配。</p>
-<pre>
+<pre class="devsite-click-to-copy">
LOCAL_MODULE := librecovery_updater_tardis
include $(BUILD_STATIC_LIBRARY)
</pre>
-<p>最后,配置 recovery 的版本号以拉入您的库。将您的库添加到 TARGET_RECOVERY_UPDATER_LIBS(它可能包含多个库;所有库均已注册)。如果您的代码依赖于本身不是 edify 扩展程序的其他静态库(即,它们没有 <code>Register_<i>libname</i></code> 函数),您可以将其列于 TARGET_RECOVERY_UPDATER_EXTRA_LIBS 中,以将其链接到更新程序,而无需调用其(不存在的)注册函数。例如,如果您的设备专属代码需要使用 zlib 解压缩数据,您可以在此处包含 libz。</p>
+<p>最后,配置 recovery 的版本号以拉入您的库。将您的库添加到 TARGET_RECOVERY_UPDATER_LIBS(它可能包含多个库;所有库均已注册)。如果您的代码依赖于本身不是 edify 扩展程序的其他静态库(即,它们没有 <code>Register_<i>libname</i></code> 函数),您可以将其列于 TARGET_RECOVERY_UPDATER_EXTRA_LIBS 中,以将其链接到更新程序,而无需调用其(不存在)的注册函数。例如,如果您的设备专属代码需要使用 zlib 解压缩数据,您可以在此处包含 libz。</p>
-<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/BoardConfig.mk
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
[...]
# add device-specific extensions to the updater binary
@@ -591,8 +603,10 @@ package_extract_file()</code>,该函数会将从更新程序包中提取的文
<p>最终的组件是获取 OTA 更新包生成工具以了解您的设备专属数据,并发出 (emit) 包含对您的扩展函数进行调用的更新程序脚本。</p>
<p>首先,让编译系统了解设备专属数据 blob。假设您的数据文件位于 <code>device/yoyodyne/tardis/tardis.dat</code> 中,请在您设备的 AndroidBoard.mk 中做出以下声明:</p>
-<p><code>device/yoyodyne/tardis/AndroidBoard.mk</code></p>
-<pre>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/AndroidBoard.mk
+</pre>
+<pre class="devsite-click-to-copy">
[...]
$(call add-radio-file,tardis.dat)
@@ -600,8 +614,10 @@ $(call add-radio-file,tardis.dat)
<p>您也可以将其放在 Android.mk 中,但是之后必须通过设备检查提供保护,因为无论编译什么设备,树中的所有 Android.mk 文件都会加载(如果您的树中包含多个设备,那么您只需要在编译 tardis 设备时添加 tardis.dat 文件即可)。</p>
-<p><code>device/yoyodyne/tardis/Android.mk</code></p>
-<pre>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/Android.mk
+</pre>
+<pre class="devsite-click-to-copy">
[...]
# an alternative to specifying it in AndroidBoard.mk
@@ -615,8 +631,10 @@ endif
<h3 id="python-module">Python 模块</h3>
<p>要扩展发布工具,请编写工具(如果有)可以调用的 Python 模块(必须命名为 releasetools.py)。示例:</p>
-<p><code>device/yoyodyne/tardis/releasetools.py</code></p>
-<pre>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/releasetools.py
+</pre>
+<pre class="prettyprint">
import common
def FullOTA_InstallEnd(info):
@@ -630,7 +648,7 @@ def FullOTA_InstallEnd(info):
</pre>
<p>独立的函数可以处理生成增量 OTA 更新包的情况。在本例中,假设您只需要在两个版本号之间的 tardis.dat 文件发生更改时重新编程 tardis。</p>
-<pre>
+<pre class="prettyprint">
def IncrementalOTA_InstallEnd(info):
# copy the data into the package.
source_tardis_dat = info.source_zip.read("RADIO/tardis.dat")
@@ -677,13 +695,13 @@ def IncrementalOTA_InstallEnd(info):
</p>
<ul>
<li><b>info.input_zip</b>:(仅限完整 OTA)输入 target-files .zip 的 <code>zipfile.ZipFile</code> 对象。</li>
-<li><b>info.source_zip</b>:(仅限增量 OTA)源 target-files .zip 的 <code>zipfile.ZipFile
+<li><b>info.source_zip</b>:(仅限增量 OTA)源 target-files .zip <code>zipfile.ZipFile
</code> 对象(安装增量包时版本号已在设备上)。</li>
<li><b>info.target_zip</b>:(仅限增量 OTA)目标 target-files .zip 的 <code>zipfile.ZipFile
</code> 对象(增量包置于设备上的版本号)。</li>
<li><b>info.output_zip</b>:正在创建的更新包;为进行写入而打开的 <code>zipfile.ZipFile
</code> 对象。使用 common.ZipWriteStr(info.output_zip、<i>filename</i>、<i>data</i>)将文件添加到文件包。</li>
-<li><b>info.script</b>:可以附加命令的目标脚本对象。调用 <code>info.script.AppendExtra(<i>script_text</i>)</code> 以将文本输出到脚本。请确保输出文本以分号结尾,这样就不会运行到随后发出 (emit) 的命令中。</li>
+<li><b>info.script</b>:可以附加命令的目标脚本对象。调用 <code>info.script.AppendExtra(<i>script_text</i>)</code> 以将文本输出到脚本中。请确保输出文本以分号结尾,这样就不会运行到随后发出 (emit) 的命令中。</li>
</ul>
<p>有关 info 对象的详细信息,请参阅<a href="http://docs.python.org/library/zipfile.html">针对 ZIP 归档的 Python 软件基础文档</a>。</p>
@@ -691,9 +709,11 @@ def IncrementalOTA_InstallEnd(info):
<h4 id="specify-module-location">指定模块位置</h4>
<p>指定您设备的 releasetools.py 脚本在 BoardConfig.mk 文件中的位置:</p>
-<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p>
+<pre class="devsite-click-to-copy">
+device/yoyodyne/tardis/BoardConfig.mk
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
[...]
TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
@@ -706,29 +726,14 @@ $(TARGET_DEVICE_DIR)/../common</code> 目录(在本例中为 <code>device/yoyo
<p>当您运行发布工具(<code>img_from_target_files</code> 或 <code>ota_from_target_files</code>)时,target-files .zip 中的 releasetools.py 脚本(如果存在)将优先于 Android 源代码树中的脚本而执行。您还可以通过优先级最高的 <code>-s</code>(或 <code>--device_specific</code>)选项明确指定设备专属扩展程序的路径。这样一来,您就可以在发布工具扩展程序中更正错误及做出更改,并将这些更改应用于旧的目标文件。</p>
<p>现在,当您运行 <code>ota_from_target_files</code> 时,它会自动从 target_files .zip 文件获取设备专属模块,并在生成 OTA 更新包时使用该模块:</p>
-<pre>
-% <b>./build/tools/releasetools/ota_from_target_files \
- -i PREVIOUS-tardis-target_files.zip \
- dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
-unzipping target target-files...
-<b>using device-specific extensions from target_files</b>
-unzipping source target-files...
- [...]
-done.
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">./build/tools/releasetools/ota_from_target_files -i PREVIOUS-tardis-target_files.zip dist_output/tardis-target_files.zip incremental_ota_update.zip</code>
</pre>
<p>或者,您可以在运行 <code>ota_from_target_files</code> 时指定设备专属扩展程序。</p>
-<pre>
-% <b>./build/tools/releasetools/ota_from_target_files \
- -s device/yoyodyne/tardis \ # specify the path to device-specific extensions
- -i PREVIOUS-tardis-target_files.zip \
- dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
-unzipping target target-files...
-<b>loaded device-specific extensions from device/yoyodyne/tardis</b>
-unzipping source target-files...
- [...]
-done.
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">./build/tools/releasetools/ota_from_target_files -s device/yoyodyne/tardis -i PREVIOUS-tardis-target_files.zip dist_output/tardis-target_files.zip incremental_ota_update.zip</code>
</pre>
<p class="note"><strong>注意</strong>:如需查看完整的选项列表,请参阅 <code>
diff --git a/zh-cn/devices/tech/power/mgmt.html b/zh-cn/devices/tech/power/mgmt.html
index e262b250..481fde6e 100644
--- a/zh-cn/devices/tech/power/mgmt.html
+++ b/zh-cn/devices/tech/power/mgmt.html
@@ -25,14 +25,14 @@
<ul>
<li><a href="#app-standby">应用待机模式</a>。平台会使未使用的应用进入应用待机模式,从而暂时限制此类应用访问网络,并延迟其同步和作业。</li>
-<li><a href="#doze">低电耗模式</a>。如果用户长时间没有主动使用其设备(屏幕处于关闭和静止状态),则平台会使设备进入深度休眠状态(定期恢复正常操作)。此外,当用户关闭设备屏幕但仍处于移动状态时,Android 7.0 及更高版本还会启用低电耗模式,以触发一系列轻度优化。</li>
-<li><a href="#exempt-apps">豁免</a>。默认情况下,在设备上预加载的系统应用和云消息传递服务通常能够获得豁免,不会进入应用待机模式和低电耗模式(尽管应用开发者可以特意将这样的设置运用到其应用上)。用户可以通过“设置”菜单豁免应用。</li>
+<li><a href="#doze">低电耗模式</a>。如果用户长时间没有主动使用其设备(处于静止状态且屏幕已关闭),则平台会使设备进入深度休眠状态(定期恢复正常操作)。此外,当用户关闭设备屏幕但仍处于移动状态时,Android 7.0 及更高版本还会启用低电耗模式,以触发一系列轻度优化。</li>
+<li><a href="#exempt-apps">豁免</a>。默认情况下,在设备上预装的系统应用和云消息传递服务通常能够获得豁免,不会进入应用待机模式和低电耗模式(尽管应用开发者可以特意将这样的设置运用到其应用上)。用户可以通过“设置”菜单豁免应用。</li>
</ul>
<p>下列部分对这些增强功能进行了具体说明。</p>
<h2 id="app-standby">应用待机模式</h2>
-<p>应用待机模式会针对用户未主动使用的应用延迟后台网络活动和作业,从而延长电池续航时间。</p>
+<p>对于用户未主动使用的应用,应用待机模式会延迟其后台网络活动和作业,从而延长电池续航时间。</p>
<h3 id="app-standby-life">应用待机模式生命周期</h3>
<p>平台检测到未活动的应用,并使其进入应用待机模式,直到用户开始主动与相应应用互动为止。</p>
@@ -70,11 +70,11 @@
<h3 id="testing_app_standby">测试应用待机模式</h3>
<p>您可以使用以下 <code>adb</code> 命令手动测试应用待机模式:</p>
-<pre>
-$ adb shell dumpsys battery unplug
-$ adb shell am set-idle packageName true
-$ adb shell am set-idle packageName false
-$ adb shell am get-idle packageName
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell dumpsys battery unplug</code>
+<code class="devsite-terminal">adb shell am set-idle packageName true</code>
+<code class="devsite-terminal">adb shell am set-idle packageName false</code>
+<code class="devsite-terminal">adb shell am get-idle packageName</code>
</pre>
<h2 id="doze">低电耗模式</h2>
@@ -139,7 +139,7 @@ $ adb shell am get-idle packageName
</table>
<p>在屏幕关闭期间、设备处于闲置状态之前,Android 7.0 及更高版本通过启用轻度休眠模式来延长设备处于低电耗模式的时间。</p>
-<p><img src="../images/doze_lightweight.png"/></p>
+<p><img src="/devices/tech/images/doze_lightweight.png"/></p>
<p class="img-caption">图 1. 非静止和静止设备的低电耗模式。</p>
<table>
@@ -191,10 +191,10 @@ $ adb shell am get-idle packageName
<ol>
<li>确认设备已安装云消息传递服务。</li>
-<li>在设备覆盖配置文件 <code>overlay/frameworks/base/core/res/res/values/config.xml</code> 中,将 <code>config_enableAutoPowerModes</code> 设置为 <strong>true</strong>:<pre>
-bool name="config_enableAutoPowerModes"&gt;true&lt;/bool&gt;
+<li>在设备覆盖配置文件 <code>overlay/frameworks/base/core/res/res/values/config.xml</code> 中,将 <code>config_enableAutoPowerModes</code> 设置为 <strong>true</strong>:<pre class="devsite-click-to-copy">
+&lt;bool name="config_enableAutoPowerModes"&gt;true&lt;/bool&gt;
</pre>
-<br />在 AOSP 中,该参数默认设为“false”(已停用低电耗模式)。<br />
+在 AOSP 中,该参数默认设为 false(已停用低电耗模式)。<br />
</li>
<li>确认预加载的应用和服务满足以下要求:<ul>
<li>遵循<a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html">节电优化指南</a>。有关详情,请参阅<a href="#test-apps">测试和优化应用</a>。
diff --git a/zh-cn/devices/tv/index.html b/zh-cn/devices/tv/index.html
new file mode 100644
index 00000000..57daed68
--- /dev/null
+++ b/zh-cn/devices/tv/index.html
@@ -0,0 +1,425 @@
+<html devsite><head>
+ <title>TV Input Framework</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<img style="float: right; margin: 0px 15px 15px 15px;" src="images/ape_fwk_hal_tv.png" alt="Android TV HAL 图标"/>
+
+<p>Android TV Input Framework (TIF) 简化了向 Android TV 传送直播内容的过程。Android TIF 为制造商提供了一个标准 API,用于创建能够控制 Android TV 的输入模块,并让他们可以通过 TV Input 发布的元数据来搜索和推荐直播电视内容。</p>
+<p>此框架的目的并不在于实施电视标准或区域性要求,而是在于让设备制造商不必重新实现就能够更轻松地满足区域性数字电视广播标准。对于想要创建自定义 TV Input 的第三方应用开发者来说,本部分文档可能也非常实用。</p>
+
+<h2 id="components">组件</h2>
+
+<p>Android TIF 的实现包括 TV Input Manager。TIF 可与 TV 应用(一款第三方应用无法替代的系统应用)搭配使用来访问内置频道和 IP 调谐器频道。此 TV 应用通过 TV Input Manager 与设备制造商或其他方提供的 TV Input 模块进行通信。</p>
+
+<p>TIF 由以下几个部分组成:</p>
+
+<ul>
+ <li>TV Provider (<code>com.android.providers.tv.TvProvider</code>):具有频道、节目和相关权限的数据库
+ </li><li>TV 应用 (<code>com.android.tv.TvActivity</code>):处理用户互动操作的应用
+ </li><li>TV Input Manager (<code>android.media.tv.TvInputManager</code>):使 TV Input 可与 TV 应用进行通信
+ </li><li>TV Input:代表物理或虚拟调谐器和输入端口的应用
+ </li><li>TV Input HAL(<code>tv_input</code> 模块):一种硬件定义,实现后可让系统 TV Input 访问电视专用硬件
+ </li><li>家长控制:用于屏蔽频道和节目的技术
+ </li><li>HDMI-CEC:使用户可通过 HDMI 远程控制各种设备的技术
+</li></ul>
+
+<p>下面将详细介绍这些组件。有关 Android TIF 架构的详细视图,请参见下图。</p>
+
+<img src="images/TIF_Overview.png" alt="Android TIF 架构概述"/>
+<p class="img-caption"><strong>图 1.</strong> Android TV Input Framework (TIF) 架构</p>
+
+<h2 id="flow">流程</h2>
+
+<p>下面列出了此架构的运作流程:</p>
+
+<ol>
+ <li>用户看到 TV 应用(一款第三方应用无法替代的系统应用)并与该应用进行互动。
+ </li><li>TV 应用显示来自 TV Input 的 AV 内容。
+ </li><li>TV 应用无法直接与 TV Input 通信。TV Input Manager 可为 TV 应用识别 TV Input 的状态。有关使用限制的更多详情,请参阅下文的“TV Input Manager”部分。<em></em>
+</li></ol>
+
+<h2 id="permissions">权限</h2>
+
+<ul>
+ <li>只有 <code><a href="http://developer.android.com/guide/topics/manifest/permission-element.html#plevel">signatureOrSystem</a></code> TV Input 和 TV 应用拥有对 TV Provider 数据库的完全访问权限,并且能够接收 KeyEvent。
+ </li><li>只有系统 TV Input 可以通过 TV Input Manager Service 访问 TV Input HAL。系统通过 TV Input Manager 会话对 TV Input 进行一对一访问。
+ </li><li>第三方 TV Input 拥有对 TV Provider 数据库的访问权限(软件包已锁定),只能对匹配的软件包行进行读写。
+ </li><li>第三方 TV Input 可以显示自己的内容,也可显示来自设备制造商提供的直通 TV Input(如 HDMI1)上的内容。它们不能显示来自非直通 TV Input(如内置调谐器或 IPTV 调谐器)的内容。
+ </li><li>硬件 TV Input 应用的 <code>TV_INPUT_HARDWARE</code> 权限,向 TV Input Manager Service 发送信号,以通知 TV Input Service 在启动时调用 TV Input Manager Service 并添加其 TV Input。借助此权限,硬件 TV Input 应用可通过一个 TV Input Service 支持多个 TV Input,并能够动态地添加和移除支持的 TV Input。
+</li></ul>
+
+<h2 id="tv_provider">TV Provider</h2>
+
+<p>TV Provider 数据库会存储来自 TV Input 的频道和节目。TV Provider 还发布和管理相关权限,以使 TV Input 只能查看自身的记录。例如,特定的 TV Input 只能查看它自己提供的频道和节目,并被禁止访问任何其他 TV Input 的频道和节目。</p>
+
+<p>TV Provider 在内部将“广播类型”映射到“规范类型”。TV Input 负责使用基本广播标准中的值填充“广播类型”,而“规范类型”字段将使用来自 <code>android.provider.TvContract.Genres</code> 的正确相关类型自动填充。例如,对于广播标准 ATSC A/65 和类型为 0x25(意为“体育”)的节目,TV Input 将使用字符串“Sports”填充“广播类型”,并且 TV Provider 将使用映射的值 <code>android.provider.TvContract.Genres.SPORTS</code> 填充“规范类型”字段。</p>
+
+<p>有关 TV Provider 的详细视图,请参见下图。</p>
+
+<img src="images/TIF_TV_Provider.png" alt="Android TV Provider"/>
+<p class="img-caption"><strong>图 2.</strong> Android TV Provider</p>
+
+<p><em>只有在经授权的系统分区中的应用才能读取整个 TV Provider 数据库。</em></p>
+
+<p>直通 TV Input 不存储频道和节目。</p>
+
+<p>除了频道和节目的标准字段以外,TV Provider 数据库还在 TV Input 可能用来存储任意数据的每个表格中提供 BLOB 类型字段 (<code>COLUMN_INTERNAL_PROVIDER_DATA</code>)。该 BLOB 数据可能包括自定义信息(如相关调谐器的频率),并可通过协议缓冲区或其他形式提供。还提供“可搜索”字段,用于确保搜索结果中不显示某些频道(例如,为了满足某些国家/地区对于内容保护的特定要求)。</p>
+
+<h3 id="tv_provider_database_field_examples">数据库字段示例</h3>
+
+<p>TV Provider 支持频道 (<code>android.provider.TvContract.Channels</code>) 和节目 (<code>android.provider.TvContract.Programs</code>) 表格中的结构化数据。这些表格由 TV Input 和系统应用(如 TV 应用)进行填充和访问。这些表格具有四种类型的字段:</p>
+
+<ul>
+ <li><strong>显示</strong>:显示字段包含应用可能希望向用户显示的信息,如频道名称 (<code>COLUMN_DISPLAY_NAME</code>) 或数字 (<code>COLUMN_DISPLAY_NUMBER</code>) 或正在观看的节目的标题。
+ </li><li><strong>元数据</strong>:根据相关标准,有三个字段可用于识别内容,如频道的传输流 ID (<code>COLUMN_TRANSPORT_STREAM_ID</code>)、原始网络 ID (<code>COLUMN_ORIGINAL_NETWORK_ID</code>) 和服务 ID (<code>COLUMN_SERVICE_ID</code>)。
+ </li><li><strong>内部数据</strong>:用于自定义 TV Input 用途的字段。<br />某些字段(如 <code>COLUMN_INTERNAL_PROVIDER_DATA</code>)是可自定义的 BLOB 字段,TV Input 可以在这些字段中存储有关其频道或节目的任意元数据。
+ </li><li><strong>标记</strong>:标记字段表示是否应禁止搜索、浏览或查看某个频道。只能在频道级别进行此设置。所有节目均应遵循此项频道设置。
+ <ul>
+ <li><code>COLUMN_SEARCHABLE</code>:在某些地区可能要求禁止搜索某些频道。<code>COLUMN_SEARCHABLE = 0</code> 表示不应在搜索结果中显示此频道。
+ </li><li><code>COLUMN_BROWSABLE</code>:仅对系统应用可见。禁止应用浏览频道。<code>COLUMN_BROWSABLE = 0</code> 表示频道列表中不应包含此频道。
+ </li><li><code>COLUMN_LOCKED</code>:仅对系统应用可见。禁止未输入 PIN 码的无效帐号观看频道。<code>COLUMN_LOCKED = 1</code> 表示此频道应受家长控制保护。
+ </li></ul>
+</li></ul>
+
+<p>有关这些字段的更为详尽的列表,请参阅 <code>android/frameworks/base/media/java/android/media/tv/TvContract.java</code></p>
+
+<h3 id="permissions_and_access_control">权限和访问控制</h3>
+
+<p>有权访问相应行的任何人都可以查看所有字段。用户无法直接访问任何字段;他们仅可看到 TV 应用、系统应用或 TV Input 显示的内容。</p>
+
+<ul>
+ <li>每一行都具有 <code>PACKAGE_NAME</code>,即拥有该行的软件包(应用),可通过 TvProvider.java 在“查询”、“插入”、“更新”语句中获得该名称。TV Input 仅可以访问它自己写入的信息,无法访问其他 TV Input 提供的信息。
+ </li><li>通过 AndroidManifest.xml 读取、写入权限(需用户同意)来确定可用的频道。
+ </li><li>只有 <code>signatureOrSystem</code> 应用才可以获取访问整个数据库的 <code>ACCESS_ALL_EPG_DATA</code> 权限。
+</li></ul>
+
+<h2 id="tv_input_manager">TV Input Manager</h2>
+
+<p>TV Input Manager 为整个 Android TIF 提供了一个中央系统 API。它对应用与 TV Input 之间的交互进行控制,并提供家长控制功能。TV Input Manager 必须与 TV Input 创建一对一的会话。TV Input Manager 允许应用访问安装的 TV Input,以便应用可以:</p>
+
+<ul>
+ <li>列出 TV Input 并查看其状态</li><li>创建会话并管理监听器</li></ul>
+
+<p>对于会话,TV Input(除了可使用 <code>TvContract.buildChannelUriForPassthroughInput()</code> 调谐的直通 TV Input)只能由 TV 应用调谐至已被 TV 应用添加到 TV Provider 数据库中的 URI。TV Input 也可以自己设置音量。由设备制造商(签名应用)或安装于系统分区中的其他应用提供和签名的 TV Input 具有对整个 TV Provider 数据库的访问权限。此访问权限可用于构建应用,以浏览和搜索所有可用的电视频道和节目。</p>
+
+<p>应用可以通过 <code>android.media.tv.TvInputManager</code> 创建和注册一个 <code>TvInputCallback</code>,并在 TV Input 的状态发生改变或添加/移除 TV Input 时进行该回调。例如,TV 应用可以在 TV Input 断开连接时做出以下响应:显示该 TV Input 已断开连接并阻止它被选中。</p>
+
+<p>TV Input Manager 使 TV 应用和 TV Input 之间的通信变得抽象化。TV Input Manager 和 TV Input 标准界面使多个设备制造商可以创建自己的 TV 应用,同时让所有第三方 TV Input 适用于所有 TV 应用。</p>
+
+<h2 id="tv_inputs">TV Input</h2>
+
+<p>TV Input 具有 AndroidManifest.xml 并且会预安装或通过 Play 商店、旁加载进行安装,因此是 Android 应用。Android TV 支持预安装的系统应用、由设备制造商签名的应用和第三方 TV Input。</p>
+
+<p>某些输入源(如 HDMI 或内置调谐器输入源)只能由制造商提供,因为它们与底层硬件直接通信。其他输入源(如 IPTV、易地播放和外接机顶盒)可由第三方将其作为 APK 在 Google Play 商店中进行提供。一旦被下载并安装,便可以在 TV 应用中选择这一新的输入源。</p>
+
+<h3 id="passthrough_input_example">直通输入源示例</h3>
+
+<img src="images/TIF_HDMI_TV_Input.png" alt="Android TV 系统输入源"/>
+<p class="img-caption"><strong>图 3.</strong> Android TV 系统输入源</p>
+
+<p>在上述示例中,由设备制造商提供的 TV Input 是可信输入源,并拥有对 TV Provider 的完全访问权限。作为直通 TV Input,它不会向 TV Provider 注册任何频道或节目。要获取用于引用直通输入源的 URI,请使用 <code>android.media.tv.TvContract</code> 实用程序方法 <code>buildChannelUriForPassthroughInput(String inputId)</code>。TV 应用与 TV Input Manager 进行通信,从而访问 HDMI TV Input。</p>
+
+<h3 id="built-in_tuner_example">内置调谐器示例</h3>
+
+<img src="images/Built-in_Tuner_TV_Input.png" alt="Android TV 内置调谐器输入源"/>
+<p class="img-caption"><strong>图 4.</strong> Android TV 内置调谐器输入源</p>
+
+<p>在上述示例中,由设备制造商提供的内置调谐器 TV Input 是可信输入源,具有对 TV Provider 的完全访问权限。</p>
+
+<h3 id="third-party_input_example">第三方输入源示例</h3>
+
+<img src="images/Third-party_Input_HDMI.png" alt="Android TV 第三方输入源"/>
+<p class="img-caption"><strong>图 5.</strong> Android TV 第三方输入源</p>
+
+<p>在上述示例中,外接机顶盒 TV Input 由第三方提供。由于此 TV Input 无法直接访问传入的 HDMI 视频 Feed,所以必须借助 TV Input Manager 并使用设备制造商提供的 HDMI TV Input。</p>
+
+<p>通过 TV Input Manager,外接机顶盒 TV Input 可以与 HDMI TV Input 进行通信,并请求它在 HDMI1 上显示视频。因此,机顶盒 TV Input 可以控制电视,而制造商提供的 HDMI TV Input 则可呈现视频。</p>
+
+<h3 id="picture_in_picture_pip_example">画中画 (PIP) 示例</h3>
+
+<img src="images/TIF_PIP-PAP.png" alt="Android TV KeyEvent"/>
+<p class="img-caption"><strong>图 6.</strong> Android TV KeyEvent</p>
+
+<p>上图显示了遥控器上的按钮事件如何传递到特定的 TV Input,从而实现画中画 (PIP) 显示。按下按钮的操作由设备制造商提供的硬件驱动程序进行解析,从而将硬件扫描码转换为 Android 键码,并将它们作为 <a href="http://developer.android.com/reference/android/view/KeyEvent.html">KeyEvent</a> 传递到标准的 Android <a href="/devices/input/overview.html">输入通道</a> <code>InputReader</code> 和 <code>InputDispatcher</code> 函数。当 TV 应用获得焦点时,它们就会在 TV 应用上触发事件。</p>
+
+<p>只有系统 TV Input 才有资格接收 <code>InputEvents</code>(前提是这些系统 TV Input 具有 <code>RECEIVE_INPUT_EVENT</code> 系统权限)。TV Input 负责确定要消费哪些 InputEvent,并允许 TV 应用处理它不需要消费的按键。</p>
+
+<p>TV 应用负责确定哪些系统 TV Input 处于有效状态(即用户已选择)、区分传入的 <code>KeyEvents</code> 并将它们路由到正确的 TV Input Manager 会话,以及调用 <code>dispatchInputEvent()</code> 以将事件传递到相关联的 TV Input。</p>
+
+<h3 id="mheg-5_input_example">MHEG-5 输入源示例</h3>
+
+<p>下图详细说明了 <code>KeyEvents</code> 如何通过 Android TIF 进行路由。</p>
+
+<img src="images/TIF_MHEG5_app.png" alt="Android TV 红色按钮示例"/>
+<p class="img-caption"><strong>图 7.</strong> Android TV 红色按钮示例</p>
+
+<p>上图描绘了红色按钮应用的流程,该按钮在欧洲较为常用,使用户能够访问电视机上的交互式应用。应用可以通过此传输流程进行传送。用户点击此按钮后,便可以与这些广播应用进行交互。例如,您可以使用这些广播应用来访问相关网页或体育赛事比分。</p>
+
+<p><em></em>请参阅“广播应用”部分,了解广播应用如何与 TV 应用进行互动。</p>
+
+<p>在此示例中:</p>
+
+<ol>
+ <li>TV 应用获得焦点并接收所有按键事件。
+ </li><li><code>KeyEvents</code>(例如:红色按钮)作为 <code>InputEvents.</code> 被传递到处于有效状态的 TV Input。
+ </li><li>系统 TV Input 与 MHEG-5 堆栈进行集成,并拥有 <code>RECEIVE_INPUT_EVENT</code> 系统权限。
+ </li><li>TV Input 在接收到激活键码(例如:红色按钮)后激活广播应用。
+ </li><li>TV Input 将 <code>KeyEvents</code> 当做 <code>InputEvents</code> 进行消费,然后广播应用获得焦点并处理 <code>InputEvents</code> 直到应用被关闭。
+</li></ol>
+
+<p class="note"><strong>注意</strong>:第三方 TV Input 从不接收按键事件。</p>
+
+<h2 id="tv_input_hal">TV Input HAL</h2>
+
+<p>在开发 TV Input 以访问电视专用硬件的过程中,TV Input HAL 起到了辅助作用。与其他 Android HAL 一样,TV Input HAL (<code>tv_input</code>) 可在 AOSP 源码树中获取,由供应商制定其实现方法。</p>
+
+<h2 id="tv_app">TV 应用</h2>
+
+<p>系统 TV 应用向用户呈现直播电视内容。Android 平台提供了一个参考 TV 应用 (Live TV),设备制造商可以直接按原样使用该应用、对其进行定制、扩展或将其替换掉。Android 开放源代码项目中提供了<a href="https://android.googlesource.com/platform/packages/apps/TV/">源代码</a>,您可以按照<a href="/devices/tv/reference-tv-app.html">参考 TV 应用</a>一文中的说明开始构建 TV 应用。</p>
+
+<p>设备制造商可以扩展他们的 TV 应用来实现适用于特定设备制造商或国家/地区的功能,但这不属于 TIF 或参考 TV 应用的职责范畴。</p>
+
+<p>系统 TV 应用至少需处理以下任务:</p>
+
+<h3 id="setup_and_configuration">设置和配置</h3>
+
+<ul>
+ <li>自动检测 TV Input
+ </li><li>让 TV Input 启动频道设置
+ </li><li>控制家长设置
+ </li><li>修改频道
+</li></ul>
+
+<h3 id="viewing">查看</h3>
+
+<ul>
+ <li>访问和浏览所有电视频道
+ </li><li>访问电视节目信息栏
+ </li><li>显示电子收视指南 (EPG) 数据
+ </li><li>支持多个音频和字幕轨道
+ </li><li>提供家长控制 PIN 码输入口令
+ </li><li>允许 TV Input 界面叠加层以执行:
+ <ul>
+ <li>电视标准(HbbTV 等)
+ </li></ul>
+ </li><li>填充电视频道和节目的搜索结果
+ </li><li>显示应用链接卡片
+ </li><li>支持时移 API
+ </li><li>处理 DVR 功能并支持电视录制 API
+</li></ul>
+
+<p>随着新 Android 版本的发布,平台 TIF API 得到扩展,此功能集将有所增加。CTS 验证程序涵盖了相关的兼容性测试。</p>
+
+<h3 id="support_for_third-party_tv_inputs">支持第三方 TV Input</h3>
+
+<p>Android TV 提供面向第三方 TV Input 的开发者 API,使安装的应用能够将软件频道与直播电视体验相融合。为确保 Android 设备实现保持兼容性,系统 TV 应用有责任向用户显示第三方 TV Input 和频道。参考 Live TV 应用提供了兼容的实现方法;如果要替换系统 TV 应用,则设备制造商必须确保自己的应用提供类似的兼容性,以满足开发者对所有 Android TV 设备的期望。</p>
+
+<p>系统 TV 应用必须在设备的默认直播电视服务旁边显示第三方输入源。开发者 API 的承诺是,用户能够在其标准电视体验中找到频道(安装后)。</p>
+
+<p>根据 Android CDD 的“TV 应用”部分的定义,内置频道和第三方频道之间可存在外观差异。</p>
+
+<p>以下部分说明了 Live TV 应用如何满足 CDD 要求。</p>
+
+<h4 id="new_channel_setup">新频道设置</h4>
+
+<p>用户可首先通过从应用商店(如 Google Play)中查找和安装 TV Input,开始添加新的第三方输入源/频道。</p>
+
+<p>某些第三方 TV Input 可自动将频道添加到 TvProvider 数据库中。然而,大多数 TV Input 将提供“设置”操作组件,使用户能够设置他们的频道、提供登录详细信息及执行其他操作。系统 TV 应用需要确保用户可以启用此“设置”操作组件,因此 CDD 要求在主 TV 应用中只需极少的导航操作便可进入第三方输入源。</p>
+
+<p>参考 Live TV 应用提供了“频道来源”菜单,以供用户访问输入源。</p>
+
+<img src="images/LiveChannels_settings.png" alt="转至“设置”"/>
+<p class="img-caption"><strong>图 8.</strong> 转到<strong>设置</strong>。</p>
+
+<img src="images/LiveChannels_channel_sources.png" alt="转至“设置”中的频道来源"/>
+<p class="img-caption"><strong>图 9.</strong> 转到“设置”中的<strong>频道来源</strong>。</p>
+
+<img src="images/LiveChannels_sources.png" alt="从列表中选择您的频道来源。"/>
+<p class="img-caption"><strong>图 10.</strong> 从列表中选择您的频道来源。</p>
+
+<img src="images/LiveChannels_Add_channel.png" alt="从您的频道来源中添加频道"/>
+<p class="img-caption"><strong>图 11.</strong> 从您的频道来源中添加频道</p>
+
+<p>此外,在安装新的 TvInput 之后,TV 应用菜单的顶部会出现一张通知卡片,让用户直接转到“设置”页面:</p>
+
+<img src="images/LiveChannels_set_up_sources.png" alt="表示有可用新频道来源的通知。"/>
+<p class="img-caption"><strong>图 12.</strong> 表示有可用新频道来源的通知。</p>
+
+<p>如果用户通过通知进行操作,他们可以选择设置频道来源,如图 10 所示。</p>
+<p>请参阅<a href="http://developer.android.com/training/tv/tif/tvinput.html#setup">定义您的 TV Input Service</a>,了解开发者对此领域的期望。</p>
+
+<h4 id="customize_the_channel_list">自定义频道列表</h4>
+
+<p>设备制造商可以提供一个界面来隐藏某些频道,并让用户能够管理自己的 EPG。Live TV 包括此项功能。</p>
+
+<img src="images/LiveChannels_channel_list.png" alt="在“设置”中打开频道列表。"/>
+<p class="img-caption"><strong>图 13.</strong> 在<strong>设置</strong>中打开频道列表。</p>
+
+<img src="images/LiveChannels_customize_channel-list.png" alt="自定义您的频道列表。"/>
+<p class="img-caption"><strong>图 14.</strong> 自定义您的频道列表。</p>
+
+<h4 id="epg">EPG</h4>
+
+<p>第三方输入源开发者需要确信,用户可以在常规使用过程中在所有兼容的 Android TV 设备上轻松转到他们的频道。</p>
+
+<p>来自第三方输入源的频道必须作为设备的标准直播电视体验 EPG 的一部分展示出来。可以对第三方频道在外观上加以区别或将其归入单独的类别(请参阅 Android CDD 的“TV 应用”部分),而最重要的是让用户能够找到所安装的频道。</p>
+
+<h4 id="search">搜索</h4>
+
+<p>为确保最佳用户体验,制造商必须实现以下 TV 应用功能:纳入能够满足全局搜索请求的搜索结果。Live TV 提供了一种实现方法(请参阅 <a href="https://android.googlesource.com/platform/packages/apps/TV/+/android-live-tv/src/com/android/tv/search/TvProviderSearch.java">com.android.tv.search.TvProviderSearch</a>),它可提供来自第三方输入源(对于平台兼容性而言是必要的)以及内置输入源的结果。</p>
+
+<h4 id="time-shifting">时移</h4>
+<p>对于运行 Android 6.0 及更高版本的设备,TV 应用必须支持 Android 框架<a href="https://developer.android.com/reference/android/media/tv/TvView.html">时移 API</a>。此外,制造商必须在 TV 应用中实现播放控件,让用户可以对播放内容执行暂停、继续、快退和快进播放等操作。
+</p>
+<p>对于支持时移的 TV Input,TV 应用需显示播放控件。
+</p>
+
+<p>
+<img src="images/TIF_timeshift.png" alt="播放控件"/>
+</p>
+<p class="img-caption"><strong>图 15.</strong> 播放控件</p>
+
+<h4 id="dvr">DVR</h4>
+<p>对于运行 Android 7.0 及更高版本的设备,TV 应用必须支持 Android 框架<a href="https://developer.android.com/reference/android/media/tv/TvRecordingClient.html">电视录制 API</a>,从而支持、列出和播放录制的节目。
+</p>
+<p>这样,设备制造商就可以将其 DVR 子系统插入 TIF,并显著减少在电视设备上启用或集成 DVR 功能所需的集成工作量。它还使第三方能够提供可插入 Android TV 设备的售后市场 DVR 系统。
+</p>
+<p>除了录制直播内容外,TV 应用还可以处理资源冲突。例如,如果设备配备了两个调谐器,它便可以同时录制两档节目。如果用户要求录制三档节目,则 TV 应用必须处理这种冲突,并且应该显示通知或要求用户为这些请求安排优先级。
+</p>
+<p>TV 应用还可以实现更复杂的逻辑安排,例如,在用户请求录制一集剧集时询问用户是否希望录制所有后续剧集。
+</p>
+<p>请参阅以下图表,了解可以在 Android TV 中完成的 DVR 实现。</p>
+<p>
+<img src="images/TV_Input_DVR.png" alt="Android TV 中的数字录像功能"/>
+</p>
+<p class="img-caption"><strong>图 16.</strong> Android TV 中的数字录像功能</p>
+
+<ol>
+<li>TV Input Service 通知 TV 应用可用的调谐器数量,以便 TV 应用可以处理潜在的资源冲突。
+</li><li>TV 应用接收用户发起的电视节目录制请求。
+</li><li>TV 应用将录制时间表存储于内部数据库中。
+</li><li>当到了录制时刻,TV 应用会传递相应请求,以将频道调谐到与录制请求相关的频道。
+</li><li>TV Input Service 接收该请求,回应是否有合适的资源,并调谐到该频道。
+</li><li>然后 TV 应用将开始录制的请求传递给 TV Input Manger。
+</li><li>TV Input Service 接收该请求并开始录制。
+</li><li>TV Input Service 将实际视频数据存储在存储空间中(可能是外部存储空间或云端存储空间)。
+</li><li>当完成录制时,TV 应用将停止录制的请求传递给 TV Input Manager。
+</li><li>一旦 TV Input Service 接收到该请求,它将停止录制并将其相关联的元数据添加到 TV Provider,以便 TV 应用可以在收到请求时向用户显示录制内容。</li>
+</ol>
+
+<p>要详细了解如何在 TV Input Service 中实现录制功能,请参阅<a href="https://developer.android.com/preview/features/tv-recording-api.html">电视录制</a>一文。
+</p>
+
+<h3 id="useful_resources">实用资源</h3>
+
+<ul>
+ <li><a href="/compatibility/android-cdd.pdf">Android CDD</a> 和开发者 API 文档是最具权威性的参考资料。
+ </li><li>CTS 验证程序会在兼容性测试计划过程中执行 API。对照 Live TV 运行 CTS 验证程序可能是一种在第三方输入源环境中查看 EPG、搜索、家长控制和其他要求的实用方法。
+ </li><li>请参阅<a href="http://developer.android.com/training/tv/tif/tvinput.html#setup">定义您的 TV Input Service</a>,了解开发者对此领域的期望。
+</li></ul>
+
+<h2 id="parental_control">家长控制</h2>
+
+<p>家长控制使用户能够屏蔽不希望播放的频道和节目,但通过输入 PIN 码便可绕过该屏蔽。</p>
+
+<p>TV 应用、TV Input Manager Service、TV Provider 和 TV Input 共同承担实现家长控制功能的责任。</p>
+
+<p>家长控制是强制性的,且在 CTS 验证程序的涵盖范围之内。</p>
+
+<p>许多国家/地区已定义了 TV Input 可以通过 <a href="https://developer.android.com/reference/android/media/tv/TvContentRating.html">TVContentRating API</a> 使用的分级制度。此外,TV Input 可以按照 CTS 验证程序测试(引入了“假”分级制度)所演示的步骤注册自己的自定义分级制度。在存在标准分级制度的国家/地区,我们鼓励设备制造商将 TIF 家长控制与他们可能包含的任何其他机制结合到一起。</p>
+
+<h3 id="tv_provider">TV Provider</h3>
+
+<p>现在,每个频道行都有一个 <code>COLUMN_LOCKED</code> 字段,用于锁定特定频道,使用户在未输入 PIN 码的情况下无法观看这些频道。节目字段 <code>COLUMN_CONTENT_RATING</code> 仅针对显示操作,而不用于落实家长控制。</p>
+
+<h3 id="tv_input_manager">TV Input Manager</h3>
+
+<p>TV Input Manager 会存储所有已屏蔽的 <code>TvContentRating</code>,并对 <code>isRatingBlocked()</code> 作出响应,从而建议是否应该屏蔽具有给定评级的内容。</p>
+
+<h3 id="tv_input">TV Input</h3>
+
+<p>当所显示内容的评级发生变化(因节目或频道发生变化)或家长控制设置发生变化(在 <code>ACTION_BLOCKED_RATINGS_CHANGED</code> 和 <code>ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED</code> 上)时,TV Input 可通过对 TV Input Manager 调用 <code>isRatingBlocked()</code> 来检查是否应该屏蔽当前内容。如果应屏蔽此内容,TV Input 会停用相关音频和视频,并通过调用 <code>notifyContentBlocked(TvContentRating)</code> 通知 TV 应用当前内容已被屏蔽。如果不应屏蔽此内容,TV Input 将启用音频和视频,并通过调用 <code>notifyContentAllowed()</code> 通知 TV 应用当前内容可播放。</p>
+
+<h3 id="tv_app">TV 应用</h3>
+
+<p>要满足家长控制 API 的要求并创建一个兼容的平台,系统 TV 应用需要为用户提供一种管理家长控制的方式,包括使具体应用能够注册任何自定义评级制度。</p>
+
+<p>当 TV Input 通知 TV 应用当前内容已被屏蔽或当用户尝试查看已屏蔽的频道时,TV 应用将显示 PIN 码界面。</p>
+
+<p>TV 应用不直接存储家长控制设置。当用户更改家长控制设置时,TV Input Manager 会存储所有已屏蔽的 <code>TvContentRating</code>,TV Provider 则存储已屏蔽的频道。</p>
+
+<p>TV 应用需要声明 <code>android.permission.MODIFY_PARENTAL_CONTROLS</code> 权限,才能更改家长控制设置。</p>
+
+<p>我们鼓励设备制造商进行如下操作:</p>
+<ul>
+ <li>对照作为参考的 Live TV 应用进行 CTS 验证程序家长控制测试,以对兼容性要求进行验证。</li>
+ <li>使用 Live TV 应用作为自己的 TV 应用的参考:请重点参阅 <a href="https://android.googlesource.com/platform/packages/apps/TV/+/android-live-tv/src/com/android/tv/parental/ContentRatingsManager.java">ContentRatingsManager</a> 和 <a href="https://android.googlesource.com/platform/packages/apps/TV/+/android-live-tv-l-mr1/src/com/android/tv/ui/sidepanel/parentalcontrols/RatingSystemsFragment.java">RatingSystemsFragment</a> 源代码,了解二者处理自定义评级的方式。</li>
+</ul>
+
+<h2 id="hdmi-cec">HDMI-CEC</h2>
+
+<p>借助 HDMI-CEC,一台设备可以控制另一台设备,从而让用户通过单个遥控器控制家庭影院中的多台设备。Android TV 使用 HDMI-CEC 来加快设置过程,并允许通过中央 TV 应用远程控制多个 TV Input。例如,它可以切换输入源、开启或关闭设备等。</p>
+
+<p>Android TIF 可将 HDMI-CEC 作为 HDMI 控制服务进行实现,以便设备制造商可以跳过更加复杂的商业逻辑,只需开发与轻量级 Android TV HAL 进行交互的低级驱动程序。Android 提供标准实现的目的是,通过减少分散的实现和选择性功能支持来消除兼容性问题。HDMI 控制服务会使用现有的 Android 服务(包括输入和电源)。</p>
+
+<p>这意味着现有 HDMI-CEC 实现将需要重新设计,才能与 Android TIF 进行互操作。我们建议硬件平台纳入微处理器,以接收 CEC 开机命令和其他命令。</p>
+
+<img src="images/TV_App_CEC_integration.png" alt="Android TV 上的 CEC 集成"/>
+<p class="img-caption"><strong>图 17.</strong> Android TV 上的 CEC 集成</p>
+
+<ol>
+ <li>CEC 总线从当前活动来源接收切换到不同来源的命令。
+ </li><li>驱动程序将命令传递给 HDMI-CEC HAL。</li><li>HAL 通知所有 <code>ActiveSourceChangeListeners</code>。
+ </li><li>HDMI 控制服务通过 <code>ActiveSourceChangeListener</code> 获取来源更改通知。
+ </li><li>TV Input Manager Service 为 TV 应用生成切换来源的 Intent。
+ </li><li>TV 应用随后为充当切换目标的 TV Input 创建 TV Input Manager 会话,并对该会话调用 <code>setMain</code>。
+ </li><li>TV Input Manager 会话将此信息传递给 HDMI TV Input。
+ </li><li>HDMI TV Input 请求设置 sideband Surface。
+ </li><li>对 Surface 进行设置后,TV Input Manager Service 生成相应的路由控制命令并将其返回到 HDMI 控制服务。
+</li></ol>
+
+<h2 id="tv_integration_guidelines">电视集成指南</h2>
+
+<h3 id="broadcast_app">广播应用</h3>
+
+<p>由于每个国家/地区都具有针对广播的特定要求(MHEG、电视文字广播、HbbTV 等),制造商需要为广播应用提供他们自己的解决方案,例如:</p>
+
+<ul>
+ <li>MHEG:原生堆栈
+ </li><li>电视文字广播:原生堆栈
+ </li><li>HbbTV:由 Opera 浏览器修改过的 webkit
+</li></ul>
+
+<p>在 Android L 版本中,Android TV 希望设备制造商针对区域性电视堆栈使用系统集成器或 Android 解决方案,将 Surface 传递到电视软件堆栈,或传递与传统堆栈进行交互所需的按键代码。</p>
+
+<p>广播应用和 TV 应用的交互方式如下:</p>
+
+<ol>
+ <li>TV 应用获得焦点,接收所有按键事件。
+ </li><li>TV 应用将按键(如红色按钮)事件传递到 TV Input 设备。
+ </li><li>TV Input 设备在内部与传统电视堆栈进行集成。
+ </li><li>在接收到激活键码(如红色按钮)时,TV Input 设备将激活广播应用。
+ </li><li>广播应用获得 TV 应用中的焦点,并处理用户操作。
+</li></ol>
+
+<p>对于语音搜索/推荐功能,广播应用可能支持以语音搜索的方式进行应用内搜索。</p>
+
+</body></html> \ No newline at end of file
diff --git a/zh-cn/devices/tv/reference-tv-app.html b/zh-cn/devices/tv/reference-tv-app.html
new file mode 100644
index 00000000..deb1325e
--- /dev/null
+++ b/zh-cn/devices/tv/reference-tv-app.html
@@ -0,0 +1,154 @@
+<html devsite><head>
+ <title>参考 TV 应用</title>
+ <meta name="project_path" value="/_project.yaml"/>
+ <meta name="book_path" value="/_book.yaml"/>
+ </head>
+ <body>
+ <!--
+ Copyright 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<p>Android TV 设备需要安装可播放电视直播内容的 TV 应用。Android 平台随附一个参考 TV 应用 (<a href="https://play.google.com/store/apps/details?id=com.google.android.tv">Live TV</a>),该应用可按原样使用,亦可进行自定义、扩展或替换成其他应用。其<a href="https://android.googlesource.com/platform/packages/apps/TV/">源代码</a>可在 Android 开放源代码项目中获取。</p>
+
+<p>本文总结了如何基于 Live TV 为您的 Android 电视设备构建和自定义系统 TV 应用。(您可以通过扩展您的 TV 应用来实现特定于设备制造商或国家/地区的功能,但这不属于参考 TV 应用的使用范围。)</p>
+
+<h2 id="dependencies">依赖关系</h2>
+
+<p>TV 应用是<a href="/devices/tv/">电视输入框架</a> (TIF) 的一个组件,不能独立于其他组件使用。这就意味着只有具有 TIF 的设备才能运行 <a href="https://play.google.com/store/apps/details?id=com.google.android.tv">Live TV</a> 应用。</p>
+
+<p>Live TV 应用依赖于 Android API。不同的分支所依赖的 API 级别也不同:</p>
+
+<p class="table-caption" id="table-1">
+ <strong>表 1.</strong> Live TV 分支</p>
+<table>
+ <tbody><tr>
+ <th>分支</th>
+ <th>目标 API 级别</th>
+ <th>最低 API 级别</th>
+ </tr>
+ <tr>
+ <td><a href="https://android.googlesource.com/platform/packages/apps/TV/+/master">master</a></td>
+ <td>24 (Android 7.0)</td>
+ <td>23</td>
+ </tr>
+
+ <tr>
+ <td><a href="https://android.googlesource.com/platform/packages/apps/TV/+/android-live-tv">android-live-tv</a></td>
+ <td>23 (Android 6.0)</td>
+ <td>21</td>
+ </tr>
+ <tr>
+ <td><a href="https://android.googlesource.com/platform/packages/apps/TV/+/android-live-tv-l-mr1">android-live-tv-l-mr1</a></td>
+ <td>22 (Android 5.1)</td>
+ <td>21</td>
+ </tr>
+</tbody></table>
+
+<h2 id="get_the_source">获取源代码</h2>
+
+<p>首选,请从 Git 中选择您想要的 Live TV 版本。以下说明面向的是最新版的 Live TV,但您也可以通过将分支从 master 更改为上表中所列的其他分支,来选择一个更早的版本。</p>
+
+<pre>
+$ mkdir live-tv &amp;&amp; cd live-tv
+$ repo init -u <a href="https://android.googlesource.com/platform/manifest">https://android.googlesource.com/platform/manifest</a> -b master
+$ repo sync -j8 -c
+</pre>
+
+<h2 id="build">构建</h2>
+
+<p>要构建 Live TV 代码,请运行:</p>
+
+<pre>
+$ . build/envsetup.sh
+$ tapas LiveTv x86
+$ make LiveTv
+</pre>
+
+<h2 id="push">推送</h2>
+
+<p>要将 Live TV 推送到测试设备,请运行:</p>
+
+<pre>
+$ adb install -r -d $OUT/system/priv-app/LiveTv/LiveTv.apk
+</pre>
+
+<p>如果开发者想让 Live TV 应用拥有系统权限,则在首次安装时,需要通过运行以下命令将该应用推送到 /system/priv-app:</p>
+
+<pre>adb push $OUT/system/priv-app/LiveTv/LiveTv.apk /system/priv-app/LiveTv/</pre>
+
+<h2 id="test">测试</h2>
+
+<p>在设备上安装 Live TV 后,您需要测试该应用是否已正确集成。除了对 TV 应用运行<a href="/compatibility/cts/index.html">兼容性测试套件</a>和 <a href="http://source.android.com/compatibility/cts/verifier.html">CTS 验证程序测试</a>外,还可使用以下这些测试:</p>
+
+<h3 id="unit_tests">单元测试</h3>
+
+<p>可对 Live TV 应用运行单元测试和功能测试。您必须连接一台设备(或模拟器)才能运行这类测试。</p>
+
+<pre>
+$ adb shell logcat -c
+m LiveTv TVTestInput TVUnitTests -j20 &amp;&amp;\
+adb install -r -d $OUT/system/priv-app/LiveTv/LiveTv.apk &amp;&amp;\
+adb install -r -d $OUT/system/app/TVTestInput/TVTestInput.apk &amp;&amp; \
+adb install -r -d $OUT/data/app/TVUnitTests/TVUnitTests.apk &amp;&amp; \
+adb shell pm clear <a href="http://com.android.providers.tv/">com.android.providers.tv</a> &amp;&amp; \
+adb shell pm clear <a href="http://com.google.android.tv/">com.google.android.tv</a> &amp;&amp; \
+adb shell am instrument \
+ -e testSetupMode unit \
+ -w com.android.tv.testinput/.instrument.TestSetupInstrumentation &amp;&amp;\
+adb shell input keyevent KEYCODE_HOME &amp;&amp;\
+adb shell am instrument \
+ -w 'com.android.tv.tests/android.support.test.runner.AndroidJUnitRunner'
+</pre>
+
+<h3 id="functional_tests">功能测试</h3>
+
+<pre>
+$ adb shell logcat -c
+m LiveTv TVTestInput TVFuncTests -j20 &amp;&amp;\
+adb install -r -d $OUT/system/priv-app/LiveTv/LiveTv.apk &amp;&amp;\
+adb install -r -d $OUT/system/app/TVTestInput/TVTestInput.apk &amp;&amp; \
+adb install -r -d $OUT/data/app/TVFuncTests/TVFuncTests.apk &amp;&amp; \
+adb shell pm clear <a href="http://com.android.providers.tv/">com.android.providers.tv</a> &amp;&amp; \
+adb shell pm clear <a href="http://com.google.android.tv/">com.google.android.tv</a> &amp;&amp; \
+adb shell am instrument \
+ -e testSetupMode func \
+ -w com.android.tv.testinput/.instrument.TestSetupInstrumentation &amp;&amp;\
+adb shell input keyevent KEYCODE_HOME &amp;&amp;\
+adb shell am instrument \
+ -w 'com.android.tv.tests.ui/android.support.test.runner.AndroidJUnitRunner'
+</pre>
+
+<h3 id="jank_tests">Jank 测试</h3>
+
+<p>Jank 测试用于检查是否存在丢帧和渲染延迟。</p>
+
+<pre>
+$ adb shell logcat -c
+m LiveTv TVTestInput TVJankTests -j20 &amp;&amp;\
+adb install -r -d $OUT/system/priv-app/LiveTv/LiveTv.apk &amp;&amp;\
+adb install -r -d $OUT/system/app/TVTestInput/TVTestInput.apk &amp;&amp;\
+adb install -r -d $OUT/data/app/TVJankTests/TVJankTests.apk &amp;&amp;\
+adb shell pm clear <a href="http://com.android.providers.tv/">com.android.providers.tv</a> &amp;&amp;\
+adb shell pm clear <a href="http://com.google.android.tv/">com.google.android.tv</a> &amp;&amp;\
+echo "Creating a lot of channels and EPG data, this may take a while" &amp;&amp;\
+adb shell am instrument \
+ -e testSetupMode jank \
+ -w com.android.tv.testinput/.instrument.TestSetupInstrumentation &amp;&amp;\
+adb shell input keyevent KEYCODE_HOME &amp;&amp;\
+adb shell am instrument \
+ -w 'com.android.tv.tests.jank/android.support.test.runner.AndroidJUnitRunner'
+</pre>
+
+</body></html> \ No newline at end of file