Merge "Fix for Don't allow adding 64-bit files(4086708)" into honeycomb-mr1
diff --git a/api/current.xml b/api/current.xml
index 4996e6a..3f8b5fe 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -28643,6 +28643,17 @@
visibility="public"
>
</method>
+<method name="dismissAllowingStateLoss"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDialog"
return="android.app.Dialog"
abstract="false"
@@ -72654,6 +72665,17 @@
<parameter name="message" type="java.lang.String">
</parameter>
</constructor>
+<field name="TYPE_ACQUIRE_DRM_INFO_FAILED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2008"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TYPE_NOT_SUPPORTED"
type="int"
transient="false"
@@ -73007,6 +73029,17 @@
visibility="public"
>
</field>
+<field name="TYPE_RIGHTS_REMOVED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TYPE_WAIT_FOR_RIGHTS"
type="int"
transient="false"
@@ -94415,6 +94448,17 @@
visibility="public"
>
</method>
+<method name="getDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getManufacturer"
return="java.lang.String"
abstract="false"
@@ -94437,7 +94481,7 @@
visibility="public"
>
</method>
-<method name="getType"
+<method name="getUri"
return="java.lang.String"
abstract="false"
native="false"
@@ -94869,82 +94913,12 @@
extends="java.lang.Object"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
<implements name="android.os.Parcelable">
</implements>
-<method name="bulkTransfer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
-</parameter>
-<parameter name="buffer" type="byte[]">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="timeout" type="int">
-</parameter>
-</method>
-<method name="claimInterface"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intf" type="android.hardware.usb.UsbInterface">
-</parameter>
-<parameter name="force" type="boolean">
-</parameter>
-</method>
-<method name="close"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="controlTransfer"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="requestType" type="int">
-</parameter>
-<parameter name="request" type="int">
-</parameter>
-<parameter name="value" type="int">
-</parameter>
-<parameter name="index" type="int">
-</parameter>
-<parameter name="buffer" type="byte[]">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="timeout" type="int">
-</parameter>
-</method>
<method name="describeContents"
return="int"
abstract="false"
@@ -95037,17 +95011,6 @@
visibility="public"
>
</method>
-<method name="getFileDescriptor"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getInterface"
return="android.hardware.usb.UsbInterface"
abstract="false"
@@ -95083,17 +95046,6 @@
visibility="public"
>
</method>
-<method name="getSerial"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getVendorId"
return="int"
abstract="false"
@@ -95105,30 +95057,6 @@
visibility="public"
>
</method>
-<method name="releaseInterface"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intf" type="android.hardware.usb.UsbInterface">
-</parameter>
-</method>
-<method name="requestWait"
- return="android.hardware.usb.UsbRequest"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="writeToParcel"
return="void"
abstract="false"
@@ -95155,11 +95083,136 @@
>
</field>
</class>
+<class name="UsbDeviceConnection"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="bulkTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="claimInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+<parameter name="force" type="boolean">
+</parameter>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="controlTransfer"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="requestType" type="int">
+</parameter>
+<parameter name="request" type="int">
+</parameter>
+<parameter name="value" type="int">
+</parameter>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="buffer" type="byte[]">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="timeout" type="int">
+</parameter>
+</method>
+<method name="getFileDescriptor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSerial"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="releaseInterface"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intf" type="android.hardware.usb.UsbInterface">
+</parameter>
+</method>
+<method name="requestWait"
+ return="android.hardware.usb.UsbRequest"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="UsbEndpoint"
extends="java.lang.Object"
abstract="false"
static="false"
- final="true"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
@@ -95198,17 +95251,6 @@
visibility="public"
>
</method>
-<method name="getDevice"
- return="android.hardware.usb.UsbDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getDirection"
return="int"
abstract="false"
@@ -95231,17 +95273,6 @@
visibility="public"
>
</method>
-<method name="getInterface"
- return="android.hardware.usb.UsbInterface"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getInterval"
return="int"
abstract="false"
@@ -95322,17 +95353,6 @@
visibility="public"
>
</method>
-<method name="getDevice"
- return="android.hardware.usb.UsbDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
<method name="getEndpoint"
return="android.hardware.usb.UsbEndpoint"
abstract="false"
@@ -95457,30 +95477,30 @@
visibility="public"
>
</method>
-<method name="isFunctionEnabled"
+<method name="hasPermission"
return="boolean"
abstract="false"
native="false"
synchronized="false"
- static="true"
+ static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="function" type="java.lang.String">
+<parameter name="device" type="android.hardware.usb.UsbDevice">
</parameter>
</method>
-<method name="isFunctionSupported"
+<method name="hasPermission"
return="boolean"
abstract="false"
native="false"
synchronized="false"
- static="true"
+ static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="function" type="java.lang.String">
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
</parameter>
</method>
<method name="openAccessory"
@@ -95497,7 +95517,7 @@
</parameter>
</method>
<method name="openDevice"
- return="boolean"
+ return="android.hardware.usb.UsbDeviceConnection"
abstract="false"
native="false"
synchronized="false"
@@ -95509,6 +95529,36 @@
<parameter name="device" type="android.hardware.usb.UsbDevice">
</parameter>
</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="device" type="android.hardware.usb.UsbDevice">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="requestPermission"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="accessory" type="android.hardware.usb.UsbAccessory">
+</parameter>
+<parameter name="pi" type="android.app.PendingIntent">
+</parameter>
+</method>
<field name="ACTION_USB_ACCESSORY_ATTACHED"
type="java.lang.String"
transient="false"
@@ -95553,17 +95603,6 @@
visibility="public"
>
</field>
-<field name="ACTION_USB_STATE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""android.hardware.usb.action.USB_STATE""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="EXTRA_ACCESSORY"
type="java.lang.String"
transient="false"
@@ -95586,99 +95625,11 @@
visibility="public"
>
</field>
-<field name="USB_CONFIGURATION"
+<field name="EXTRA_PERMISSION_GRANTED"
type="java.lang.String"
transient="false"
volatile="false"
- value=""configuration""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_CONNECTED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""connected""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ACCESSORY"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""accessory""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ADB"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""adb""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_DISABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""disabled""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_ENABLED"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""enabled""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_MASS_STORAGE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""mass_storage""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_MTP"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""mtp""
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="USB_FUNCTION_RNDIS"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value=""rndis""
+ value=""permission""
static="true"
final="true"
deprecated="not deprecated"
@@ -95756,6 +95707,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
+</parameter>
<parameter name="endpoint" type="android.hardware.usb.UsbEndpoint">
</parameter>
</method>
@@ -112529,255 +112482,6 @@
</package>
<package name="android.mtp"
>
-<class name="MtpClient"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="MtpClient"
- type="android.mtp.MtpClient"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="context" type="android.content.Context">
-</parameter>
-</constructor>
-<method name="addListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.mtp.MtpClient.Listener">
-</parameter>
-</method>
-<method name="close"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="deleteObject"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getDevice"
- return="android.mtp.MtpDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-</method>
-<method name="getDevice"
- return="android.mtp.MtpDevice"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="id" type="int">
-</parameter>
-</method>
-<method name="getDeviceList"
- return="java.util.List<android.mtp.MtpDevice>"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getObject"
- return="byte[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-<parameter name="objectSize" type="int">
-</parameter>
-</method>
-<method name="getObjectInfo"
- return="android.mtp.MtpObjectInfo"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getObjectList"
- return="java.util.List<android.mtp.MtpObjectInfo>"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="storageId" type="int">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="getStorageList"
- return="java.util.List<android.mtp.MtpStorageInfo>"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-</method>
-<method name="getThumbnail"
- return="byte[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-</method>
-<method name="importFile"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="deviceName" type="java.lang.String">
-</parameter>
-<parameter name="objectHandle" type="int">
-</parameter>
-<parameter name="destPath" type="java.lang.String">
-</parameter>
-</method>
-<method name="isCamera"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.hardware.usb.UsbDevice">
-</parameter>
-</method>
-<method name="removeListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.mtp.MtpClient.Listener">
-</parameter>
-</method>
-</class>
-<interface name="MtpClient.Listener"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="deviceAdded"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.mtp.MtpDevice">
-</parameter>
-</method>
-<method name="deviceRemoved"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="device" type="android.mtp.MtpDevice">
-</parameter>
-</method>
-</interface>
<class name="MtpConstants"
extends="java.lang.Object"
abstract="false"
@@ -113612,7 +113316,7 @@
<parameter name="objectHandle" type="int">
</parameter>
</method>
-<method name="getStorageID"
+<method name="getStorageId"
return="long"
abstract="false"
native="false"
@@ -113687,7 +113391,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="manager" type="android.hardware.usb.UsbManager">
+<parameter name="connection" type="android.hardware.usb.UsbDeviceConnection">
</parameter>
</method>
</class>
@@ -211308,8 +211012,8 @@
visibility="public"
>
</method>
-<method name="getMotionAxes"
- return="int[]"
+<method name="getMotionRange"
+ return="android.view.InputDevice.MotionRange"
abstract="false"
native="false"
synchronized="false"
@@ -211318,6 +211022,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="axis" type="int">
+</parameter>
</method>
<method name="getMotionRange"
return="android.view.InputDevice.MotionRange"
@@ -211331,6 +211037,19 @@
>
<parameter name="axis" type="int">
</parameter>
+<parameter name="source" type="int">
+</parameter>
+</method>
+<method name="getMotionRanges"
+ return="java.util.List<android.view.InputDevice.MotionRange>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
</method>
<method name="getName"
return="java.lang.String"
@@ -211696,6 +211415,17 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="getAxis"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFlat"
return="float"
abstract="false"
@@ -211751,6 +211481,17 @@
visibility="public"
>
</method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<class name="InputEvent"
extends="java.lang.Object"
@@ -244856,6 +244597,25 @@
<parameter name="realm" type="java.lang.String">
</parameter>
</method>
+<method name="onReceivedLoginRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.webkit.WebView">
+</parameter>
+<parameter name="realm" type="java.lang.String">
+</parameter>
+<parameter name="account" type="java.lang.String">
+</parameter>
+<parameter name="args" type="java.lang.String">
+</parameter>
+</method>
<method name="onReceivedSslError"
return="void"
abstract="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 930c6b0..b6581e9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -74,7 +74,7 @@
static public int staticGetMemoryClass() {
// Really brain dead right now -- just take this from the configured
// vm heap size, and assume it is in megabytes and thus ends with "m".
- String vmHeapSize = SystemProperties.get("dalvik.vm.growthlimit", "");
+ String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
if (vmHeapSize != null && !"".equals(vmHeapSize)) {
return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 539e946..cc1f81c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -401,10 +401,10 @@
return new UiModeManager();
}});
- registerService(USB_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
+ registerService(USB_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(USB_SERVICE);
- return new UsbManager(IUsbManager.Stub.asInterface(b));
+ return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
}});
registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index dee1ef3..cce7cd6 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -258,6 +258,16 @@
dismissInternal(false);
}
+ /**
+ * Version of {@link #dismiss()} that uses
+ * {@link FragmentTransaction#commitAllowingStateLoss()
+ * FragmentTransaction.commitAllowingStateLoss()}. See linked
+ * documentation for further details.
+ */
+ public void dismissAllowingStateLoss() {
+ dismissInternal(true);
+ }
+
void dismissInternal(boolean allowStateLoss) {
if (mDismissed) {
return;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 440cb54..efe2633 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1150,8 +1150,12 @@
* fail (most commonly returning {@link #ENCRYPTION_STATUS_ACTIVE}).
*
* <p>This policy controls encryption of the secure (application data) storage area. Data
- * written to other areas (e.g. the directory returned by
- * {@link android.os.Environment#getExternalStorageDirectory()} may or may not be encrypted.
+ * written to other storage areas may or may not be encrypted, and this policy does not require
+ * or control the encryption of any other storage areas.
+ * There is one exception: If {@link android.os.Environment#isExternalStorageEmulated()} is
+ * {@code true}, then the directory returned by
+ * {@link android.os.Environment#getExternalStorageDirectory()} must be written to disk
+ * within the encrypted storage area.
*
* <p>Important Note: On some devices, it is possible to encrypt storage without requiring
* the user to create a device PIN or Password. In this case, the storage is encrypted, but
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 6539711..55368d6 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -110,11 +110,16 @@
if (DEBUG) Slog.d(TAG, "Restoring wallpaper image w=" + options.outWidth
+ " h=" + options.outHeight);
- // how much does the image differ from our preference?
+ // How much does the image differ from our preference? The threshold
+ // here is set to accept any image larger than our target, because
+ // scaling down is acceptable; but to reject images that are deemed
+ // "too small" to scale up attractively. The value 1.33 is just barely
+ // too low to pass Nexus 1 or Droid wallpapers for use on a Xoom, but
+ // will pass anything relatively larger.
double widthRatio = mDesiredMinWidth / options.outWidth;
double heightRatio = mDesiredMinHeight / options.outHeight;
- if (widthRatio > 0.8 && widthRatio < 1.25
- && heightRatio > 0.8 && heightRatio < 1.25) {
+ if (widthRatio > 0 && widthRatio < 1.33
+ && heightRatio > 0 && heightRatio < 1.33) {
// sufficiently close to our resolution; go ahead and use it
if (DEBUG) Slog.d(TAG, "wallpaper dimension match; using");
f.renameTo(new File(WALLPAPER_IMAGE));
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index dd4096b..2111cce 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -2051,8 +2051,8 @@
if (rv.length == 4) {
Q[0] = rv[3];
} else {
- //In this case, the w component of the quaternion is known to be a positive number
- Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+ Q[0] = 1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2];
+ Q[0] = (Q[0] > 0) ? (float)Math.sqrt(Q[0]) : 0;
}
Q[1] = rv[0];
Q[2] = rv[1];
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index be65bdb..5df2343 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -16,6 +16,7 @@
package android.hardware.usb;
+import android.app.PendingIntent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
@@ -43,13 +44,32 @@
/* Sets the default package for a USB device
* (or clears it if the package name is null)
*/
- oneway void setDevicePackage(in UsbDevice device, String packageName);
+ void setDevicePackage(in UsbDevice device, String packageName);
- /* Sets the default package for a USB device
+ /* Sets the default package for a USB accessory
* (or clears it if the package name is null)
*/
void setAccessoryPackage(in UsbAccessory accessory, String packageName);
+ /* Returns true if the caller has permission to access the device. */
+ boolean hasDevicePermission(in UsbDevice device);
+
+ /* Returns true if the caller has permission to access the accessory. */
+ boolean hasAccessoryPermission(in UsbAccessory accessory);
+
+ /* Requests permission for the given package to access the device.
+ * Will display a system dialog to query the user if permission
+ * had not already been given.
+ */
+ void requestDevicePermission(in UsbDevice device, String packageName, in PendingIntent pi);
+
+ /* Requests permission for the given package to access the accessory.
+ * Will display a system dialog to query the user if permission
+ * had not already been given. Result is returned via pi.
+ */
+ void requestAccessoryPermission(in UsbAccessory accessory, String packageName,
+ in PendingIntent pi);
+
/* Grants permission for the given UID to access the device */
void grantDevicePermission(in UsbDevice device, int uid);
@@ -57,8 +77,8 @@
void grantAccessoryPermission(in UsbAccessory accessory, int uid);
/* Returns true if the USB manager has default preferences or permissions for the package */
- boolean hasDefaults(String packageName, int uid);
+ boolean hasDefaults(String packageName);
/* Clears default preferences and permissions for the package */
- oneway void clearDefaults(String packageName, int uid);
+ void clearDefaults(String packageName);
}
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 6cd9178..cc174d4 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -30,18 +30,21 @@
private final String mManufacturer;
private final String mModel;
- private final String mType;
+ private final String mDescription;
private final String mVersion;
+ private final String mUri;
/**
* UsbAccessory should only be instantiated by UsbService implementation
* @hide
*/
- public UsbAccessory(String manufacturer, String model, String type, String version) {
+ public UsbAccessory(String manufacturer, String model, String description,
+ String version, String uri) {
mManufacturer = manufacturer;
mModel = model;
- mType = type;
+ mDescription = description;
mVersion = version;
+ mUri = uri;
}
/**
@@ -51,8 +54,9 @@
public UsbAccessory(String[] strings) {
mManufacturer = strings[0];
mModel = strings[1];
- mType = strings[2];
+ mDescription = strings[2];
mVersion = strings[3];
+ mUri = strings[4];
}
/**
@@ -74,12 +78,12 @@
}
/**
- * Returns the type of the accessory.
+ * Returns a user visible description of the accessory.
*
- * @return the accessory type
+ * @return the accessory description
*/
- public String getType() {
- return mType;
+ public String getDescription() {
+ return mDescription;
}
/**
@@ -91,6 +95,17 @@
return mVersion;
}
+ /**
+ * Returns the URI for the accessory.
+ * This is an optional URI that might show information about the accessory
+ * or provide the option to download an application for the accessory
+ *
+ * @return the accessory URI
+ */
+ public String getUri() {
+ return mUri;
+ }
+
private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null);
return s1.equals(s2);
@@ -102,18 +117,29 @@
UsbAccessory accessory = (UsbAccessory)obj;
return (compare(mManufacturer, accessory.getManufacturer()) &&
compare(mModel, accessory.getModel()) &&
- compare(mType, accessory.getType()) &&
- compare(mVersion, accessory.getVersion()));
+ compare(mDescription, accessory.getDescription()) &&
+ compare(mVersion, accessory.getVersion()) &&
+ compare(mUri, accessory.getUri()));
}
return false;
}
@Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mDescription == null ? 0 : mDescription.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()) ^
+ (mUri == null ? 0 : mUri.hashCode()));
+ }
+
+ @Override
public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel +
- ", mType=" + mType +
- ", mVersion=" + mVersion + "]";
+ ", mDescription=" + mDescription +
+ ", mVersion=" + mVersion +
+ ", mUri=" + mUri + "]";
}
public static final Parcelable.Creator<UsbAccessory> CREATOR =
@@ -121,9 +147,10 @@
public UsbAccessory createFromParcel(Parcel in) {
String manufacturer = in.readString();
String model = in.readString();
- String type = in.readString();
+ String description = in.readString();
String version = in.readString();
- return new UsbAccessory(manufacturer, model, type, version);
+ String uri = in.readString();
+ return new UsbAccessory(manufacturer, model, description, version, uri);
}
public UsbAccessory[] newArray(int size) {
@@ -138,7 +165,8 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mManufacturer);
parcel.writeString(mModel);
- parcel.writeString(mType);
+ parcel.writeString(mDescription);
parcel.writeString(mVersion);
+ parcel.writeString(mUri);
}
}
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 37bd82b..9e536a7 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -19,33 +19,24 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileDescriptor;
-
/**
* A class representing a USB device.
*/
-public final class UsbDevice implements Parcelable {
+public class UsbDevice implements Parcelable {
private static final String TAG = "UsbDevice";
- private String mName;
- private int mVendorId;
- private int mProductId;
- private int mClass;
- private int mSubclass;
- private int mProtocol;
- private Parcelable[] mInterfaces;
-
- // used by the JNI code
- private int mNativeContext;
-
- private UsbDevice() {
- }
-
+ private final String mName;
+ private final int mVendorId;
+ private final int mProductId;
+ private final int mClass;
+ private final int mSubclass;
+ private final int mProtocol;
+ private final Parcelable[] mInterfaces;
/**
* UsbDevice should only be instantiated by UsbService implementation
@@ -150,114 +141,6 @@
return (UsbInterface)mInterfaces[index];
}
- /* package */ boolean open(ParcelFileDescriptor pfd) {
- return native_open(mName, pfd.getFileDescriptor());
- }
-
- /**
- * Releases all system resources related to the device.
- */
- public void close() {
- native_close();
- }
-
- /**
- * Returns an integer file descriptor for the device, or
- * -1 if the device is not opened.
- * This is intended for passing to native code to access the device
- */
- public int getFileDescriptor() {
- return native_get_fd();
- }
-
- /**
- * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
- * This must be done before sending or receiving data on any
- * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
- * @param intf the interface to claim
- * @param force true to disconnect kernel driver if necessary
- * @return true if the interface was successfully claimed
- */
- public boolean claimInterface(UsbInterface intf, boolean force) {
- return native_claim_interface(intf.getId(), force);
- }
-
- /**
- * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
- *
- * @return true if the interface was successfully released
- */
- public boolean releaseInterface(UsbInterface intf) {
- return native_release_interface(intf.getId());
- }
-
- /**
- * Performs a control transaction on endpoint zero for this device.
- * The direction of the transfer is determined by the request type.
- * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
- * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
- * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
- * is a read.
- *
- * @param requestType request type for this transaction
- * @param request request ID for this transaction
- * @param value value field for this transaction
- * @param index index field for this transaction
- * @param buffer buffer for data portion of transaction,
- * or null if no data needs to be sent or received
- * @param length the length of the data to send or receive
- * @param timeout in milliseconds
- * @return length of data transferred (or zero) for success,
- * or negative value for failure
- */
- public int controlTransfer(int requestType, int request, int value,
- int index, byte[] buffer, int length, int timeout) {
- return native_control_request(requestType, request, value, index, buffer, length, timeout);
- }
-
- /**
- * Performs a bulk transaction on the given endpoint.
- * The direction of the transfer is determined by the direction of the endpoint
- *
- * @param endpoint the endpoint for this transaction
- * @param buffer buffer for data to send or receive,
- * @param length the length of the data to send or receive
- * @param timeout in milliseconds
- * @return length of data transferred (or zero) for success,
- * or negative value for failure
- */
- public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) {
- return native_bulk_request(endpoint.getAddress(), buffer, length, timeout);
- }
-
- /**
- * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
- * Note that this may return requests queued on multiple
- * {@link android.hardware.usb.UsbEndpoint}s.
- * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
- * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
- * how to process the result of this function.
- *
- * @return a completed USB request, or null if an error occurred
- */
- public UsbRequest requestWait() {
- UsbRequest request = native_request_wait();
- if (request != null) {
- request.dequeue();
- }
- return request;
- }
-
- /**
- * Returns the serial number for the device.
- * This will return null if the device has not been opened.
- *
- * @return the device serial number
- */
- public String getSerial() {
- return native_get_serial();
- }
-
@Override
public boolean equals(Object o) {
if (o instanceof UsbDevice) {
@@ -270,6 +153,11 @@
}
@Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
public String toString() {
return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId +
",mProductId=" + mProductId + ",mClass=" + mClass +
@@ -287,11 +175,7 @@
int subClass = in.readInt();
int protocol = in.readInt();
Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
- UsbDevice result = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces);
- for (int i = 0; i < interfaces.length; i++) {
- ((UsbInterface)interfaces[i]).setDevice(result);
- }
- return result;
+ return new UsbDevice(name, vendorId, productId, clasz, subClass, protocol, interfaces);
}
public UsbDevice[] newArray(int size) {
@@ -321,17 +205,6 @@
return native_get_device_name(id);
}
- private native boolean native_open(String deviceName, FileDescriptor pfd);
- private native void native_close();
- private native int native_get_fd();
- private native boolean native_claim_interface(int interfaceID, boolean force);
- private native boolean native_release_interface(int interfaceID);
- private native int native_control_request(int requestType, int request, int value,
- int index, byte[] buffer, int length, int timeout);
- private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout);
- private native UsbRequest native_request_wait();
- private native String native_get_serial();
-
private static native int native_get_device_id(String name);
private static native String native_get_device_name(int id);
}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
new file mode 100644
index 0000000..876287c
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package android.hardware.usb;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+
+
+/**
+ * A class representing a USB device.
+ */
+public class UsbDeviceConnection {
+
+ private static final String TAG = "UsbDeviceConnection";
+
+ private final UsbDevice mDevice;
+
+ // used by the JNI code
+ private int mNativeContext;
+
+ /**
+ * UsbDevice should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbDeviceConnection(UsbDevice device) {
+ mDevice = device;
+ }
+
+ /* package */ boolean open(String name, ParcelFileDescriptor pfd) {
+ return native_open(name, pfd.getFileDescriptor());
+ }
+
+ /**
+ * Releases all system resources related to the device.
+ */
+ public void close() {
+ native_close();
+ }
+
+ /**
+ * Returns an integer file descriptor for the device, or
+ * -1 if the device is not opened.
+ * This is intended for passing to native code to access the device
+ */
+ public int getFileDescriptor() {
+ return native_get_fd();
+ }
+
+ /**
+ * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
+ * This must be done before sending or receiving data on any
+ * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
+ * @param intf the interface to claim
+ * @param force true to disconnect kernel driver if necessary
+ * @return true if the interface was successfully claimed
+ */
+ public boolean claimInterface(UsbInterface intf, boolean force) {
+ return native_claim_interface(intf.getId(), force);
+ }
+
+ /**
+ * Releases exclusive access to a {@link android.hardware.usb.UsbInterface}.
+ *
+ * @return true if the interface was successfully released
+ */
+ public boolean releaseInterface(UsbInterface intf) {
+ return native_release_interface(intf.getId());
+ }
+
+ /**
+ * Performs a control transaction on endpoint zero for this device.
+ * The direction of the transfer is determined by the request type.
+ * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
+ * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
+ * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
+ * is a read.
+ *
+ * @param requestType request type for this transaction
+ * @param request request ID for this transaction
+ * @param value value field for this transaction
+ * @param index index field for this transaction
+ * @param buffer buffer for data portion of transaction,
+ * or null if no data needs to be sent or received
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int controlTransfer(int requestType, int request, int value,
+ int index, byte[] buffer, int length, int timeout) {
+ return native_control_request(requestType, request, value, index, buffer, length, timeout);
+ }
+
+ /**
+ * Performs a bulk transaction on the given endpoint.
+ * The direction of the transfer is determined by the direction of the endpoint
+ *
+ * @param endpoint the endpoint for this transaction
+ * @param buffer buffer for data to send or receive,
+ * @param length the length of the data to send or receive
+ * @param timeout in milliseconds
+ * @return length of data transferred (or zero) for success,
+ * or negative value for failure
+ */
+ public int bulkTransfer(UsbEndpoint endpoint, byte[] buffer, int length, int timeout) {
+ return native_bulk_request(endpoint.getAddress(), buffer, length, timeout);
+ }
+
+ /**
+ * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
+ * Note that this may return requests queued on multiple
+ * {@link android.hardware.usb.UsbEndpoint}s.
+ * When multiple endpoints are in use, {@link android.hardware.usb.UsbRequest#getEndpoint} and
+ * {@link android.hardware.usb.UsbRequest#getClientData} can be useful in determining
+ * how to process the result of this function.
+ *
+ * @return a completed USB request, or null if an error occurred
+ */
+ public UsbRequest requestWait() {
+ UsbRequest request = native_request_wait();
+ if (request != null) {
+ request.dequeue();
+ }
+ return request;
+ }
+
+ /**
+ * Returns the serial number for the device.
+ * This will return null if the device has not been opened.
+ *
+ * @return the device serial number
+ */
+ public String getSerial() {
+ return native_get_serial();
+ }
+
+ private native boolean native_open(String deviceName, FileDescriptor pfd);
+ private native void native_close();
+ private native int native_get_fd();
+ private native boolean native_claim_interface(int interfaceID, boolean force);
+ private native boolean native_release_interface(int interfaceID);
+ private native int native_control_request(int requestType, int request, int value,
+ int index, byte[] buffer, int length, int timeout);
+ private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout);
+ private native UsbRequest native_request_wait();
+ private native String native_get_serial();
+}
diff --git a/core/java/android/hardware/usb/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java
index a48d88f..bc2c2c1 100644
--- a/core/java/android/hardware/usb/UsbEndpoint.java
+++ b/core/java/android/hardware/usb/UsbEndpoint.java
@@ -23,16 +23,12 @@
/**
* A class representing an endpoint on a {@link android.hardware.usb.UsbInterface}.
*/
-public final class UsbEndpoint implements Parcelable {
+public class UsbEndpoint implements Parcelable {
- private int mAddress;
- private int mAttributes;
- private int mMaxPacketSize;
- private int mInterval;
- private UsbInterface mInterface;
-
- private UsbEndpoint() {
- }
+ private final int mAddress;
+ private final int mAttributes;
+ private final int mMaxPacketSize;
+ private final int mInterval;
/**
* UsbEndpoint should only be instantiated by UsbService implementation
@@ -119,29 +115,6 @@
return mInterval;
}
- /**
- * Returns the {@link android.hardware.usb.UsbInterface} this endpoint belongs to.
- *
- * @return the endpoint's interface
- */
- public UsbInterface getInterface() {
- return mInterface;
- }
-
- /**
- * Returns the {@link android.hardware.usb.UsbDevice} this endpoint belongs to.
- *
- * @return the endpoint's device
- */
- public UsbDevice getDevice() {
- return mInterface.getDevice();
- }
-
- // only used for parcelling
- /* package */ void setInterface(UsbInterface intf) {
- mInterface = intf;
- }
-
@Override
public String toString() {
return "UsbEndpoint[mAddress=" + mAddress + ",mAttributes=" + mAttributes +
diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index b3b0e81..2b4c7c0 100644
--- a/core/java/android/hardware/usb/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -25,15 +25,11 @@
*/
public class UsbInterface implements Parcelable {
- private int mId;
- private int mClass;
- private int mSubclass;
- private int mProtocol;
- private UsbDevice mDevice;
- private Parcelable[] mEndpoints;
-
- private UsbInterface() {
- }
+ private final int mId;
+ private final int mClass;
+ private final int mSubclass;
+ private final int mProtocol;
+ private final Parcelable[] mEndpoints;
/**
* UsbInterface should only be instantiated by UsbService implementation
@@ -104,20 +100,6 @@
return (UsbEndpoint)mEndpoints[index];
}
- /**
- * Returns the {@link android.hardware.usb.UsbDevice} this interface belongs to.
- *
- * @return the interface's device
- */
- public UsbDevice getDevice() {
- return mDevice;
- }
-
- // only used for parcelling
- /* package */ void setDevice(UsbDevice device) {
- mDevice = device;
- }
-
@Override
public String toString() {
return "UsbInterface[mId=" + mId + ",mClass=" + mClass +
@@ -133,11 +115,7 @@
int subClass = in.readInt();
int protocol = in.readInt();
Parcelable[] endpoints = in.readParcelableArray(UsbEndpoint.class.getClassLoader());
- UsbInterface result = new UsbInterface(id, Class, subClass, protocol, endpoints);
- for (int i = 0; i < endpoints.length; i++) {
- ((UsbEndpoint)endpoints[i]).setInterface(result);
- }
- return result;
+ return new UsbInterface(id, Class, subClass, protocol, endpoints);
}
public UsbInterface[] newArray(int size) {
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 6683179..7bf278a 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -17,6 +17,8 @@
package android.hardware.usb;
+import android.app.PendingIntent;
+import android.content.Context;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -53,6 +55,8 @@
* {@link #USB_FUNCTION_MASS_STORAGE}, {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS},
* {@link #USB_FUNCTION_MTP} and {@link #USB_FUNCTION_ACCESSORY}.
* </ul>
+ *
+ * {@hide}
*/
public static final String ACTION_USB_STATE =
"android.hardware.usb.action.USB_STATE";
@@ -98,7 +102,7 @@
*
* This intent is sent when a USB accessory is detached.
* <ul>
- * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
* for the attached accessory that was detached
* </ul>
*/
@@ -108,42 +112,56 @@
/**
* Boolean extra indicating whether USB is connected or disconnected.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
*/
public static final String USB_CONNECTED = "connected";
/**
* Integer extra containing currently set USB configuration.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
*/
public static final String USB_CONFIGURATION = "configuration";
/**
* Name of the USB mass storage USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
/**
* Name of the adb USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_ADB = "adb";
/**
* Name of the RNDIS ethernet USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_RNDIS = "rndis";
/**
* Name of the MTP USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_MTP = "mtp";
/**
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_ACCESSORY = "accessory";
@@ -151,6 +169,8 @@
* Value indicating that a USB function is enabled.
* Used in {@link #USB_CONFIGURATION} extras bundle for the
* {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_ENABLED = "enabled";
@@ -158,6 +178,8 @@
* Value indicating that a USB function is disabled.
* Used in {@link #USB_CONFIGURATION} extras bundle for the
* {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
*/
public static final String USB_FUNCTION_DISABLED = "disabled";
@@ -176,12 +198,22 @@
*/
public static final String EXTRA_ACCESSORY = "accessory";
- private IUsbManager mService;
+ /**
+ * Name of extra added to the {@link android.app.PendingIntent}
+ * passed into {@link #requestPermission(UsbDevice, PendingIntent)}
+ * or {@link #requestPermission(UsbAccessory, PendingIntent)}
+ * containing a boolean value indicating whether the user granted permission or not.
+ */
+ public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+ private final Context mContext;
+ private final IUsbManager mService;
/**
* {@hide}
*/
- public UsbManager(IUsbManager service) {
+ public UsbManager(Context context, IUsbManager service) {
+ mContext = context;
mService = service;
}
@@ -215,19 +247,22 @@
* @param device the device to open
* @return true if we successfully opened the device
*/
- public boolean openDevice(UsbDevice device) {
+ public UsbDeviceConnection openDevice(UsbDevice device) {
try {
- ParcelFileDescriptor pfd = mService.openDevice(device.getDeviceName());
- if (pfd == null) {
- return false;
+ String deviceName = device.getDeviceName();
+ ParcelFileDescriptor pfd = mService.openDevice(deviceName);
+ if (pfd != null) {
+ UsbDeviceConnection connection = new UsbDeviceConnection(device);
+ boolean result = connection.open(deviceName, pfd);
+ pfd.close();
+ if (result) {
+ return connection;
+ }
}
- boolean result = device.open(pfd);
- pfd.close();
- return result;
} catch (Exception e) {
Log.e(TAG, "exception in UsbManager.openDevice", e);
- return false;
}
+ return null;
}
/**
@@ -245,7 +280,7 @@
return new UsbAccessory[] { accessory };
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getAccessoryList" , e);
+ Log.e(TAG, "RemoteException in getAccessoryList", e);
return null;
}
}
@@ -260,11 +295,99 @@
try {
return mService.openAccessory(accessory);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openAccessory" , e);
+ Log.e(TAG, "RemoteException in openAccessory", e);
return null;
}
}
+ /**
+ * Returns true if the caller has permission to access the device.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbDevice, PendingIntent)} or
+ * by the user choosing the caller as the default application for the device.
+ *
+ * @param device to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbDevice device) {
+ try {
+ return mService.hasDevicePermission(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in hasPermission", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbAccessory, PendingIntent)} or
+ * by the user choosing the caller as the default application for the accessory.
+ *
+ * @param accessory to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbAccessory accessory) {
+ try {
+ return mService.hasAccessoryPermission(accessory);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in hasPermission", e);
+ return false;
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the device.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
+ * The following extras will be added to pi:
+ * <ul>
+ * <li> {@link #EXTRA_DEVICE} containing the device passed into this call
+ * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+ * permission was granted by the user
+ * </ul>
+ *
+ * @param device to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbDevice device, PendingIntent pi) {
+ try {
+ mService.requestDevicePermission(device, mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in requestPermission", e);
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the accessory.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the accessory only
+ * until the device is disconnected.
+ *
+ * The following extras will be added to pi:
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
+ * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+ * permission was granted by the user
+ * </ul>
+ *
+ * @param accessory to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+ try {
+ mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in requestPermission", e);
+ }
+ }
+
private static File getFunctionEnableFile(String function) {
return new File("/sys/class/usb_composite/" + function + "/enable");
}
@@ -275,6 +398,8 @@
*
* @param function name of the USB function
* @return true if the USB function is supported.
+ *
+ * {@hide}
*/
public static boolean isFunctionSupported(String function) {
return getFunctionEnableFile(function).exists();
@@ -285,6 +410,8 @@
*
* @param function name of the USB function
* @return true if the USB function is enabled.
+ *
+ * {@hide}
*/
public static boolean isFunctionEnabled(String function) {
try {
@@ -300,7 +427,7 @@
/**
* Enables or disables a USB function.
*
- * @hide
+ * {@hide}
*/
public static boolean setFunctionEnabled(String function, boolean enable) {
try {
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 80085c1..5fe6c8c 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -23,9 +23,9 @@
/**
* A class representing USB request packet.
* This can be used for both reading and writing data to or from a
- * {@link android.hardware.usb.UsbDevice}.
+ * {@link android.hardware.usb.UsbDeviceConnection}.
* UsbRequests are sent asynchronously via {@link #queue} and the results
- * are read by {@link android.hardware.usb.UsbDevice#requestWait}.
+ * are read by {@link android.hardware.usb.UsbDeviceConnection#requestWait}.
*/
public class UsbRequest {
@@ -53,10 +53,9 @@
* @param endpoint the endpoint to be used for this request.
* @return true if the request was successfully opened.
*/
- public boolean initialize(UsbEndpoint endpoint) {
+ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
mEndpoint = endpoint;
- return native_init(endpoint.getDevice(),
- endpoint.getAddress(), endpoint.getAttributes(),
+ return native_init(connection, endpoint.getAddress(), endpoint.getAttributes(),
endpoint.getMaxPacketSize(), endpoint.getInterval());
}
@@ -94,7 +93,7 @@
* This can be used in conjunction with {@link #setClientData}
* to associate another object with this request, which can be useful for
* maintaining state between calls to {@link #queue} and
- * {@link android.hardware.usb.UsbDevice#requestWait}
+ * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
*
* @return the client data for the request
*/
@@ -107,7 +106,7 @@
* This can be used in conjunction with {@link #getClientData}
* to associate another object with this request, which can be useful for
* maintaining state between calls to {@link #queue} and
- * {@link android.hardware.usb.UsbDevice#requestWait}
+ * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
*
* @param data the client data for the request
*/
@@ -121,7 +120,7 @@
* For IN endpoints, the endpoint will attempt to read the given number of bytes
* into the specified buffer.
* If the queueing operation is successful, we return true and the result will be
- * returned via {@link android.hardware.usb.UsbDevice#requestWait}
+ * returned via {@link android.hardware.usb.UsbDeviceConnection#requestWait}
*
* @param buffer the buffer containing the bytes to write, or location to store
* the results of a read
@@ -166,8 +165,8 @@
return native_cancel();
}
- private native boolean native_init(UsbDevice device, int ep_address, int ep_attributes,
- int ep_max_packet_size, int ep_interval);
+ private native boolean native_init(UsbDeviceConnection connection, int ep_address,
+ int ep_attributes, int ep_max_packet_size, int ep_interval);
private native void native_close();
private native boolean native_queue_array(byte[] buffer, int length, boolean out);
private native void native_dequeue_array(byte[] buffer, int length, boolean out);
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ec5030c..e308c2c 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -423,9 +423,16 @@
/**
* Returns whether the device has an external storage device which is
- * emulated. If true, the device does not have real external storage
- * and certain system services such as the package manager use this
+ * emulated. If true, the device does not have real external storage, and the directory
+ * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
+ * the internal storage system.
+ *
+ * <p>Certain system services, such as the package manager, use this
* to determine where to install an application.
+ *
+ * <p>Emulated external storage may also be encrypted - see
+ * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
+ * android.content.ComponentName, boolean)} for additional details.
*/
public static boolean isExternalStorageEmulated() {
if (mIsExternalStorageEmulated == null) {
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 2b609ea..ad0bc84 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -1049,7 +1049,7 @@
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.replace(com.android.internal.R.id.prefs, f);
- transaction.commit();
+ transaction.commitAllowingStateLoss();
}
/**
@@ -1144,7 +1144,7 @@
} else {
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
}
- transaction.commit();
+ transaction.commitAllowingStateLoss();
}
/**
@@ -1184,7 +1184,7 @@
}
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.addToBackStack(BACK_STACK_PREFS);
- transaction.commit();
+ transaction.commitAllowingStateLoss();
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c078c08..0cf7ae6 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -609,7 +609,7 @@
DisplayList displayList = view.getDisplayList();
if (displayList != null) {
if (canvas.drawDisplayList(displayList, mRedrawClip)) {
- if (mRedrawClip.isEmpty()) {
+ if (mRedrawClip.isEmpty() || view.getParent() == null) {
view.invalidate();
} else {
view.getParent().invalidateChild(view, mRedrawClip);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index def1161..98d4eb9 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -20,7 +20,9 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Describes the capabilities of a particular input device.
@@ -43,8 +45,7 @@
private int mSources;
private int mKeyboardType;
- private final SparseArray<MotionRange> mMotionRanges = new SparseArray<MotionRange>();
- private int[] mMotionAxes;
+ private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
/**
* A mask for input source classes.
@@ -354,6 +355,11 @@
/**
* Gets information about the range of values for a particular {@link MotionEvent} axis.
+ * If the device supports multiple sources, the same axis may have different meanings
+ * for each source. Returns information about the first axis found for any source.
+ * To obtain information about the axis for a specific source, use
+ * {@link #getMotionRange(int, int)}.
+ *
* @param axis The axis constant.
* @return The range of values, or null if the requested axis is not
* supported by the device.
@@ -363,30 +369,55 @@
* @see #getSupportedAxes()
*/
public MotionRange getMotionRange(int axis) {
- return mMotionRanges.get(axis);
+ final int numRanges = mMotionRanges.size();
+ for (int i = 0; i < numRanges; i++) {
+ final MotionRange range = mMotionRanges.get(i);
+ if (range.mAxis == axis) {
+ return range;
+ }
+ }
+ return null;
}
/**
- * Gets the axis ids of all motion axes supported by this device.
- * @return The axis ids of all motion axes supported by this device.
+ * Gets information about the range of values for a particular {@link MotionEvent} axis
+ * used by a particular source on the device.
+ * If the device supports multiple sources, the same axis may have different meanings
+ * for each source.
*
- * @see #getMotionRange(int)
+ * @param axis The axis constant.
+ * @param source The source for which to return information.
+ * @return The range of values, or null if the requested axis is not
+ * supported by the device.
+ *
+ * @see MotionEvent#AXIS_X
+ * @see MotionEvent#AXIS_Y
+ * @see #getSupportedAxes()
*/
- public int[] getMotionAxes() {
- synchronized (this) {
- if (mMotionAxes == null) {
- final int count = mMotionRanges.size();
- mMotionAxes = new int[count];
- for (int i = 0; i < count; i++) {
- mMotionAxes[i] = mMotionRanges.keyAt(i);
- }
+ public MotionRange getMotionRange(int axis, int source) {
+ final int numRanges = mMotionRanges.size();
+ for (int i = 0; i < numRanges; i++) {
+ final MotionRange range = mMotionRanges.get(i);
+ if (range.mAxis == axis && range.mSource == source) {
+ return range;
}
- return mMotionAxes;
}
+ return null;
}
- private void addMotionRange(int axis, float min, float max, float flat, float fuzz) {
- mMotionRanges.append(axis, new MotionRange(min, max, flat, fuzz));
+ /**
+ * Gets the ranges for all axes supported by the device.
+ * @return The motion ranges for the device.
+ *
+ * @see #getMotionRange(int, int)
+ */
+ public List<MotionRange> getMotionRanges() {
+ return mMotionRanges;
+ }
+
+ private void addMotionRange(int axis, int source,
+ float min, float max, float flat, float fuzz) {
+ mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
}
/**
@@ -395,12 +426,16 @@
* @see InputDevice#getMotionRange(int)
*/
public static final class MotionRange {
+ private int mAxis;
+ private int mSource;
private float mMin;
private float mMax;
private float mFlat;
private float mFuzz;
- private MotionRange(float min, float max, float flat, float fuzz) {
+ private MotionRange(int axis, int source, float min, float max, float flat, float fuzz) {
+ mAxis = axis;
+ mSource = source;
mMin = min;
mMax = max;
mFlat = flat;
@@ -408,6 +443,22 @@
}
/**
+ * Gets the axis id.
+ * @return The axis id.
+ */
+ public int getAxis() {
+ return mAxis;
+ }
+
+ /**
+ * Gets the source for which the axis is defined.
+ * @return The source.
+ */
+ public int getSource() {
+ return mSource;
+ }
+
+ /**
* Gets the inclusive minimum value for the axis.
* @return The inclusive minimum value.
*/
@@ -480,7 +531,8 @@
if (axis < 0) {
break;
}
- addMotionRange(axis, in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+ addMotionRange(axis, in.readInt(),
+ in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
}
}
@@ -491,11 +543,11 @@
out.writeInt(mSources);
out.writeInt(mKeyboardType);
- final int numAxes = mMotionRanges.size();
- for (int i = 0; i < numAxes; i++) {
- int axis = mMotionRanges.keyAt(i);
- MotionRange range = mMotionRanges.valueAt(i);
- out.writeInt(axis);
+ final int numRanges = mMotionRanges.size();
+ for (int i = 0; i < numRanges; i++) {
+ MotionRange range = mMotionRanges.get(i);
+ out.writeInt(range.mAxis);
+ out.writeInt(range.mSource);
out.writeFloat(range.mMin);
out.writeFloat(range.mMax);
out.writeFloat(range.mFlat);
@@ -528,7 +580,7 @@
}
description.append("\n");
- description.append(" Sources: ").append(Integer.toHexString(mSources)).append(" (");
+ description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
@@ -541,10 +593,10 @@
final int numAxes = mMotionRanges.size();
for (int i = 0; i < numAxes; i++) {
- int axis = mMotionRanges.keyAt(i);
- MotionRange range = mMotionRanges.valueAt(i);
- description.append(" ").append(MotionEvent.axisToString(axis));
- description.append(": min=").append(range.mMin);
+ MotionRange range = mMotionRanges.get(i);
+ description.append(" ").append(MotionEvent.axisToString(range.mAxis));
+ description.append(": source=0x").append(Integer.toHexString(range.mSource));
+ description.append(" min=").append(range.mMin);
description.append(" max=").append(range.mMax);
description.append(" flat=").append(range.mFlat);
description.append(" fuzz=").append(range.mFuzz);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 3c39149..a17db5d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2157,6 +2157,8 @@
* MotionEvent. For touch events, clients can use this to determine if the
* user's finger was touching the edge of the display.
*
+ * This property is only set for {@link #ACTION_DOWN} events.
+ *
* @see #EDGE_LEFT
* @see #EDGE_TOP
* @see #EDGE_RIGHT
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6ef680b..f9692da 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3680,7 +3680,7 @@
// flag coming from the child that initiated the invalidate
if (view != null) {
if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
- view.getSolidColor() == 0 && !view.isOpaque()) {
+ view.getSolidColor() == 0) {
opaqueFlag = DIRTY;
}
if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 11908bb..a53c6d0 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -498,15 +498,21 @@
mAttachInfo.mHardwareAccelerationRequested = false;
// Try to enable hardware acceleration if requested
- if (attrs != null &&
- (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
+ final boolean hardwareAccelerated =
+ (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+
+ if (attrs != null && hardwareAccelerated) {
// Only enable hardware acceleration if we are not in the system process
// The window manager creates ViewRoots to display animated preview windows
// of launching apps and we don't want those to be hardware accelerated
- if (!HardwareRenderer.sRendererDisabled) {
+
+ final boolean systemHwAccelerated =
+ (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM) != 0;
+
+ if (!HardwareRenderer.sRendererDisabled || systemHwAccelerated) {
// Don't enable hardware acceleration when we're not on the main thread
- if (Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ if (!systemHwAccelerated && Looper.getMainLooper() != Looper.myLooper()) {
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ "acceleration outside of the main thread, aborting");
return;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index ca932e9..8a18aaf 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -665,6 +665,17 @@
* XML attribute is set to true on an activity or on the application.</p>
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
+
+ /**
+ * Like {@link #FLAG_HARDWARE_ACCELERATED} except for trusted system windows
+ * that need hardware acceleration (e.g. LockScreen), where hardware acceleration
+ * is generally disabled. This flag must be specified in addition to
+ * {@link #FLAG_HARDWARE_ACCELERATED} to enable hardware acceleration for system
+ * windows.
+ *
+ * @hide
+ */
+ public static final int FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000;
// ----- HIDDEN FLAGS.
// These start at the high bit and go down.
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index ab4bfe1..c7a7374 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -1237,11 +1237,17 @@
}
}
-
/*package*/ SearchBox getSearchBox() {
return mSearchBox;
}
+ /**
+ * Called by JNI when processing the X-Auto-Login header.
+ */
+ private void autoLogin(String realm, String account, String args) {
+ mCallbackProxy.onReceivedLoginRequest(realm, account, args);
+ }
+
//==========================================================================
// native functions
//==========================================================================
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index c66d701..23fd12d 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -117,6 +117,7 @@
private static final int AUTH_CREDENTIALS = 137;
private static final int SET_INSTALLABLE_WEBAPP = 138;
private static final int NOTIFY_SEARCHBOX_LISTENERS = 139;
+ private static final int AUTO_LOGIN = 140;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -770,7 +771,7 @@
(WebHistoryItem) msg.obj, msg.arg1);
}
break;
- case AUTH_CREDENTIALS:
+ case AUTH_CREDENTIALS: {
String host = msg.getData().getString("host");
String realm = msg.getData().getString("realm");
username = msg.getData().getString("username");
@@ -778,6 +779,7 @@
mWebView.setHttpAuthUsernamePassword(
host, realm, username, password);
break;
+ }
case SET_INSTALLABLE_WEBAPP:
if (mWebChromeClient != null) {
mWebChromeClient.setInstallableWebApp();
@@ -789,6 +791,17 @@
@SuppressWarnings("unchecked")
List<String> suggestions = (List<String>) msg.obj;
searchBox.handleSuggestions(msg.getData().getString("query"), suggestions);
+ break;
+ case AUTO_LOGIN: {
+ if (mWebViewClient != null) {
+ String realm = msg.getData().getString("realm");
+ String account = msg.getData().getString("account");
+ String args = msg.getData().getString("args");
+ mWebViewClient.onReceivedLoginRequest(mWebView, realm,
+ account, args);
+ }
+ break;
+ }
}
}
@@ -1051,6 +1064,20 @@
sendMessage(msg);
}
+ void onReceivedLoginRequest(String realm, String account, String args) {
+ // Do an unsynchronized quick check to avoid posting if no callback has
+ // been set.
+ if (mWebViewClient == null) {
+ return;
+ }
+ Message msg = obtainMessage(AUTO_LOGIN);
+ Bundle bundle = msg.getData();
+ bundle.putString("realm", realm);
+ bundle.putString("account", account);
+ bundle.putString("args", args);
+ sendMessage(msg);
+ }
+
//--------------------------------------------------------------------------
// DownloadListener functions.
//--------------------------------------------------------------------------
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 2dac7e9..3cb5e24 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -31,7 +31,7 @@
public static final boolean CACHE_MANAGER = false;
public static final boolean CALLBACK_PROXY = false;
public static final boolean COOKIE_MANAGER = false;
- public static final boolean COOKIE_SYNC_MANAGER = true;
+ public static final boolean COOKIE_SYNC_MANAGER = false;
public static final boolean FRAME_LOADER = false;
public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
public static final boolean LOAD_LISTENER = false;
@@ -41,7 +41,7 @@
public static final boolean URL_UTIL = false;
public static final boolean WEB_BACK_FORWARD_LIST = false;
public static final boolean WEB_SETTINGS = false;
- public static final boolean WEB_SYNC_MANAGER = true;
+ public static final boolean WEB_SYNC_MANAGER = false;
public static final boolean WEB_TEXT_VIEW = false;
public static final boolean WEB_VIEW = false;
public static final boolean WEB_VIEW_CORE = false;
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
new file mode 100644
index 0000000..2312160
--- /dev/null
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -0,0 +1,211 @@
+
+package android.webkit;
+
+import android.graphics.SurfaceTexture;
+import android.media.MediaPlayer;
+import android.util.Log;
+import android.webkit.HTML5VideoViewProxy;
+import android.widget.MediaController;
+import android.opengl.GLES20;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @hide This is only used by the browser
+ */
+public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
+ // Due to the fact that SurfaceTexture consume a lot of memory, we make it
+ // as static. m_textureNames is the texture bound with this SurfaceTexture.
+ private static SurfaceTexture mSurfaceTexture = null;
+ private static int[] mTextureNames;
+
+ // Only when the video is prepared, we render using SurfaceTexture.
+ // This in fact is used to avoid showing the obsolete content when
+ // switching videos.
+ private static boolean mReadyToUseSurfTex = false;
+
+ // For handling the seekTo before prepared, we need to know whether or not
+ // the video is prepared. Therefore, we differentiate the state between
+ // prepared and not prepared.
+ // When the video is not prepared, we will have to save the seekTo time,
+ // and use it when prepared to play.
+ private static final int STATE_NOTPREPARED = 0;
+ private static final int STATE_PREPARED = 1;
+
+ // We only need state for handling seekTo
+ private int mCurrentState;
+
+ // Basically for calling back the OnPrepared in the proxy
+ private HTML5VideoViewProxy mProxy;
+
+ // Save the seek time when not prepared. This can happen when switching
+ // video besides initial load.
+ private int mSaveSeekTime;
+
+ // This is used to find the VideoLayer on the native side.
+ private int mVideoLayerId;
+
+ // Every video will have one MediaPlayer. Given the fact we only have one
+ // SurfaceTexture, there is only one MediaPlayer in action. Every time we
+ // switch videos, a new instance of MediaPlayer will be created in reset().
+ private MediaPlayer mPlayer;
+
+ private static HTML5VideoView mInstance = new HTML5VideoView();
+
+ // Video control FUNCTIONS:
+ public void start() {
+ if (mCurrentState == STATE_PREPARED) {
+ mPlayer.start();
+ mReadyToUseSurfTex = true;
+ }
+ }
+
+ public void pause() {
+ mPlayer.pause();
+ }
+
+ public int getDuration() {
+ return mPlayer.getDuration();
+ }
+
+ public int getCurrentPosition() {
+ return mPlayer.getCurrentPosition();
+ }
+
+ public void seekTo(int pos) {
+ if (mCurrentState == STATE_PREPARED)
+ mPlayer.seekTo(pos);
+ else
+ mSaveSeekTime = pos;
+ }
+
+ public boolean isPlaying() {
+ return mPlayer.isPlaying();
+ }
+
+ public void release() {
+ mPlayer.release();
+ }
+
+ public void stopPlayback() {
+ mPlayer.stop();
+ }
+
+ private void reset(int videoLayerId) {
+ mPlayer = new MediaPlayer();
+ mCurrentState = STATE_NOTPREPARED;
+ mProxy = null;
+ mVideoLayerId = videoLayerId;
+ mReadyToUseSurfTex = false;
+ }
+
+ public static HTML5VideoView getInstance(int videoLayerId) {
+ // Every time we switch between the videos, a new MediaPlayer will be
+ // created. Make sure we call the m_player.release() when it is done.
+ mInstance.reset(videoLayerId);
+ return mInstance;
+ }
+
+ private HTML5VideoView() {
+ // This is a singleton across WebViews (i.e. Tabs).
+ // HTML5VideoViewProxy will reset the internal state every time a new
+ // video start.
+ }
+
+ public void setMediaController(MediaController m) {
+ this.setMediaController(m);
+ }
+
+ public void setVideoURI(String uri, Map<String, String> headers) {
+ // When switching players, surface texture will be reused.
+ mPlayer.setTexture(getSurfaceTextureInstance());
+
+ // When there is exception, we could just bail out silently.
+ // No Video will be played though. Write the stack for debug
+ try {
+ mPlayer.setDataSource(uri, headers);
+ mPlayer.prepareAsync();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // TODO [FULL SCREEN SUPPORT]
+
+ // Listeners setup FUNCTIONS:
+ public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
+ mPlayer.setOnCompletionListener(proxy);
+ }
+
+ public void setOnErrorListener(HTML5VideoViewProxy proxy) {
+ mPlayer.setOnErrorListener(proxy);
+ }
+
+ public void setOnPreparedListener(HTML5VideoViewProxy proxy) {
+ mProxy = proxy;
+ mPlayer.setOnPreparedListener(this);
+ }
+
+ // Inline Video specific FUNCTIONS:
+
+ public SurfaceTexture getSurfaceTexture() {
+ return mSurfaceTexture;
+ }
+
+ public void deleteSurfaceTexture() {
+ mSurfaceTexture = null;
+ return;
+ }
+
+ // SurfaceTexture is a singleton here , too
+ private SurfaceTexture getSurfaceTextureInstance() {
+ // Create the surface texture.
+ if (mSurfaceTexture == null)
+ {
+ mTextureNames = new int[1];
+ GLES20.glGenTextures(1, mTextureNames, 0);
+ mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
+ }
+ return mSurfaceTexture;
+ }
+
+ public int getTextureName() {
+ return mTextureNames[0];
+ }
+
+ public int getVideoLayerId() {
+ return mVideoLayerId;
+ }
+
+ public boolean getReadyToUseSurfTex() {
+ return mReadyToUseSurfTex;
+ }
+
+ public void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
+ mSurfaceTexture.setOnFrameAvailableListener(l);
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ mCurrentState = STATE_PREPARED;
+ seekTo(mSaveSeekTime);
+ if (mProxy != null)
+ mProxy.onPrepared(mp);
+ }
+
+ // Pause the play and update the play/pause button
+ public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
+ if (isPlaying()) {
+ pause();
+ if (proxy != null) {
+ proxy.dispatchOnPaused();
+ }
+ }
+ mReadyToUseSurfTex = false;
+ }
+
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 85763da..b614d8f 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnCompletionListener;
@@ -59,7 +60,8 @@
class HTML5VideoViewProxy extends Handler
implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener,
- MediaPlayer.OnErrorListener {
+ MediaPlayer.OnErrorListener,
+ SurfaceTexture.OnFrameAvailableListener {
// Logging tag.
private static final String LOGTAG = "HTML5VideoViewProxy";
@@ -101,7 +103,7 @@
private static HTML5VideoViewProxy mCurrentProxy;
// The VideoView instance. This is a singleton for now, at least until
// http://b/issue?id=1973663 is fixed.
- private static VideoView mVideoView;
+ private static HTML5VideoView mHTML5VideoView;
// The progress view.
private static View mProgressView;
// The container for the progress view and video view
@@ -122,131 +124,149 @@
}
// The spec says the timer should fire every 250 ms or less.
private static final int TIMEUPDATE_PERIOD = 250; // ms
- static boolean isVideoSelfEnded = false;
+ private static boolean isVideoSelfEnded = false;
+ // By using the baseLayer and the current video Layer ID, we can
+ // identify the exact layer on the UI thread to use the SurfaceTexture.
+ private static int mBaseLayer = 0;
- private static final WebChromeClient.CustomViewCallback mCallback =
- new WebChromeClient.CustomViewCallback() {
- public void onCustomViewHidden() {
- // At this point the videoview is pretty much destroyed.
- // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
- // which happens when the video view is detached from its parent
- // view. This happens in the WebChromeClient before this method
- // is invoked.
- mTimer.cancel();
- mTimer = null;
- if (mVideoView.isPlaying()) {
- mVideoView.stopPlayback();
+ // TODO: [FULL SCREEN SUPPORT]
+
+ // Every time webView setBaseLayer, this will be called.
+ // When we found the Video layer, then we set the Surface Texture to it.
+ // Otherwise, we may want to delete the Surface Texture to save memory.
+ public static void setBaseLayer(int layer) {
+ if (mHTML5VideoView != null) {
+ mBaseLayer = layer;
+ SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture();
+ int textureName = mHTML5VideoView.getTextureName();
+
+ int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
+ if (layer != 0 && surfTexture != null && currentVideoLayerId != -1) {
+ boolean readyToUseSurfTex =
+ mHTML5VideoView.getReadyToUseSurfTex();
+ boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
+ layer, currentVideoLayerId, textureName,
+ readyToUseSurfTex);
+ if (readyToUseSurfTex && !foundInTree) {
+ mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+ mHTML5VideoView.deleteSurfaceTexture();
}
- if (isVideoSelfEnded)
- mCurrentProxy.dispatchOnEnded();
- else
- mCurrentProxy.dispatchOnPaused();
-
- // Re enable plugin views.
- mCurrentProxy.getWebView().getViewManager().showAll();
-
- isVideoSelfEnded = false;
- mCurrentProxy = null;
- mLayout.removeView(mVideoView);
- mVideoView = null;
- if (mProgressView != null) {
- mLayout.removeView(mProgressView);
- mProgressView = null;
- }
- mLayout = null;
}
- };
-
- public static void play(String url, int time, HTML5VideoViewProxy proxy,
- WebChromeClient client) {
- if (mCurrentProxy == proxy) {
- if (!mVideoView.isPlaying()) {
- mVideoView.start();
- }
- return;
}
+ }
- if (mCurrentProxy != null) {
+ // When a WebView is paused, we also want to pause the video in it.
+ public static void pauseAndDispatch() {
+ if (mHTML5VideoView != null) {
+ mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+ // When switching out, clean the video content on the old page
+ // by telling the layer not readyToUseSurfTex.
+ setBaseLayer(mBaseLayer);
+ }
+ }
+
+ // This is on the UI thread.
+ // When native tell Java to play, we need to check whether or not it is
+ // still the same video by using videoLayerId and treat it differently.
+ public static void play(String url, int time, HTML5VideoViewProxy proxy,
+ WebChromeClient client, int videoLayerId) {
+ int currentVideoLayerId = -1;
+ if (mHTML5VideoView != null)
+ currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
+
+ if (currentVideoLayerId != videoLayerId
+ || mHTML5VideoView.getSurfaceTexture() == null) {
+ // Here, we handle the case when switching to a new video,
+ // either inside a WebView or across WebViews
+ // For switching videos within a WebView or across the WebView,
+ // we need to pause the old one and re-create a new media player
+ // inside the HTML5VideoView.
+ if (mHTML5VideoView != null) {
+ mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
+ // release the media player to avoid finalize error
+ mHTML5VideoView.release();
+ }
+ // HTML5VideoView is singleton, however, the internal state will
+ // be reset since we are switching from one video to another.
+ // Then we need to set up all the source/listener etc...
+ mHTML5VideoView = HTML5VideoView.getInstance(videoLayerId);
+
+ mCurrentProxy = proxy;
+
+ // TODO: [FULL SCREEN SUPPORT]
+
+ boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
+ String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
+ Map<String, String> headers = new HashMap<String, String>();
+ if (cookieValue != null) {
+ headers.put(COOKIE, cookieValue);
+ }
+ if (isPrivate) {
+ headers.put(HIDE_URL_LOGS, "true");
+ }
+
+ mHTML5VideoView.setVideoURI(url, headers);
+ mHTML5VideoView.setOnCompletionListener(proxy);
+ mHTML5VideoView.setOnPreparedListener(proxy);
+ mHTML5VideoView.setOnErrorListener(proxy);
+ mHTML5VideoView.setFrameAvailableListener(proxy);
+
+ mHTML5VideoView.seekTo(time);
+
+ mTimer = new Timer();
+
+ } else if (mCurrentProxy == proxy) {
+ // Here, we handle the case when we keep playing with one video
+ if (!mHTML5VideoView.isPlaying()) {
+ mHTML5VideoView.seekTo(time);
+ mHTML5VideoView.start();
+ }
+ } else if (mCurrentProxy != null) {
// Some other video is already playing. Notify the caller that its playback ended.
proxy.dispatchOnEnded();
- return;
}
-
- mCurrentProxy = proxy;
- // Create a FrameLayout that will contain the VideoView and the
- // progress view (if any).
- mLayout = new FrameLayout(proxy.getContext());
- FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER);
- mVideoView = new VideoView(proxy.getContext());
- mVideoView.setWillNotDraw(false);
- mVideoView.setMediaController(new MediaController(proxy.getContext()));
-
- boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
- String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
- Map<String, String> headers = new HashMap<String, String>();
- if (cookieValue != null) {
- headers.put(COOKIE, cookieValue);
- }
- if (isPrivate) {
- headers.put(HIDE_URL_LOGS, "true");
- }
-
- mVideoView.setVideoURI(Uri.parse(url), headers);
- mVideoView.setOnCompletionListener(proxy);
- mVideoView.setOnPreparedListener(proxy);
- mVideoView.setOnErrorListener(proxy);
- mVideoView.seekTo(time);
- mLayout.addView(mVideoView, layoutParams);
- mProgressView = client.getVideoLoadingProgressView();
- if (mProgressView != null) {
- mLayout.addView(mProgressView, layoutParams);
- mProgressView.setVisibility(View.VISIBLE);
- }
- mLayout.setVisibility(View.VISIBLE);
- mTimer = new Timer();
- mVideoView.start();
- client.onShowCustomView(mLayout, mCallback);
- // Plugins like Flash will draw over the video so hide
- // them while we're playing.
- mCurrentProxy.getWebView().getViewManager().hideAll();
}
public static boolean isPlaying(HTML5VideoViewProxy proxy) {
- return (mCurrentProxy == proxy && mVideoView != null && mVideoView.isPlaying());
+ return (mCurrentProxy == proxy && mHTML5VideoView != null
+ && mHTML5VideoView.isPlaying());
}
public static int getCurrentPosition() {
int currentPosMs = 0;
- if (mVideoView != null) {
- currentPosMs = mVideoView.getCurrentPosition();
+ if (mHTML5VideoView != null) {
+ currentPosMs = mHTML5VideoView.getCurrentPosition();
}
return currentPosMs;
}
public static void seek(int time, HTML5VideoViewProxy proxy) {
- if (mCurrentProxy == proxy && time >= 0 && mVideoView != null) {
- mVideoView.seekTo(time);
+ if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) {
+ mHTML5VideoView.seekTo(time);
}
}
public static void pause(HTML5VideoViewProxy proxy) {
- if (mCurrentProxy == proxy && mVideoView != null) {
- mVideoView.pause();
+ if (mCurrentProxy == proxy && mHTML5VideoView != null) {
+ mHTML5VideoView.pause();
mTimer.purge();
}
}
public static void onPrepared() {
- if (mProgressView == null || mLayout == null) {
- return;
- }
+ mHTML5VideoView.start();
mTimer.schedule(new TimeupdateTask(mCurrentProxy), TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
- mProgressView.setVisibility(View.GONE);
- mLayout.removeView(mProgressView);
- mProgressView = null;
+ // TODO: [FULL SCREEN SUPPORT]
+ }
+
+ public static void end() {
+ if (mCurrentProxy != null) {
+ if (isVideoSelfEnded)
+ mCurrentProxy.dispatchOnEnded();
+ else
+ mCurrentProxy.dispatchOnPaused();
+ }
+ isVideoSelfEnded = false;
}
}
@@ -292,6 +312,14 @@
sendMessage(obtainMessage(TIMEUPDATE));
}
+ // When there is a frame ready from surface texture, we should tell WebView
+ // to refresh.
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ // TODO: This should support partial invalidation too.
+ mWebView.invalidate();
+ }
+
// Handler for the messages from WebCore or Timer thread to the UI thread.
@Override
public void handleMessage(Message msg) {
@@ -300,8 +328,9 @@
case PLAY: {
String url = (String) msg.obj;
WebChromeClient client = mWebView.getWebChromeClient();
+ int videoLayerID = msg.arg1;
if (client != null) {
- VideoPlayer.play(url, mSeekPosition, this, client);
+ VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID);
}
break;
}
@@ -318,6 +347,10 @@
case ENDED:
if (msg.arg1 == 1)
VideoPlayer.isVideoSelfEnded = true;
+ VideoPlayer.end();
+ break;
+ // TODO: [FULL SCREEN SUPPORT]
+ // For full screen case, end may need hide the view.
case ERROR: {
WebChromeClient client = mWebView.getWebChromeClient();
if (client != null) {
@@ -500,6 +533,10 @@
super(Looper.getMainLooper());
// Save the WebView object.
mWebView = webView;
+ // Pass Proxy into webview, such that every time we have a setBaseLayer
+ // call, we tell this Proxy to call the native to update the layer tree
+ // for the Video Layer's surface texture info
+ mWebView.setHTML5VideoViewProxy(this);
// Save the native ptr
mNativePointer = nativePtr;
// create the message handler for this thread
@@ -565,7 +602,7 @@
* Play a video stream.
* @param url is the URL of the video stream.
*/
- public void play(String url, int position) {
+ public void play(String url, int position, int videoLayerID) {
if (url == null) {
return;
}
@@ -573,8 +610,8 @@
if (position > 0) {
seek(position);
}
-
Message message = obtainMessage(PLAY);
+ message.arg1 = videoLayerID;
message.obj = url;
sendMessage(message);
}
@@ -628,6 +665,14 @@
mPosterDownloader.start();
}
+ // These two function are called from UI thread only by WebView.
+ public void setBaseLayer(int layer) {
+ VideoPlayer.setBaseLayer(layer);
+ }
+
+ public void pauseAndDispatch() {
+ VideoPlayer.pauseAndDispatch();
+ }
/**
* The factory for HTML5VideoViewProxy instances.
* @param webViewCore is the WebViewCore that is requesting the proxy.
@@ -647,4 +692,7 @@
private native void nativeOnPaused(int nativePointer);
private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
private native void nativeOnTimeupdate(int position, int nativePointer);
+ private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture,
+ int baseLayer, int videoLayerId, int textureName,
+ boolean updateTexture);
}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 28b09519..0f24edc 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -26,14 +26,15 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.ResultReceiver;
import android.text.BoringLayout.Metrics;
import android.text.DynamicLayout;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Layout;
-import android.text.Layout.Alignment;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextPaint;
@@ -136,6 +137,23 @@
// Used to determine whether onFocusChanged was called as a result of
// calling remove().
private boolean mInsideRemove;
+ private class MyResultReceiver extends ResultReceiver {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == InputMethodManager.RESULT_SHOWN
+ && mWebView != null) {
+ mWebView.revealSelection();
+ }
+ }
+
+ /**
+ * @param handler
+ */
+ public MyResultReceiver(Handler handler) {
+ super(handler);
+ }
+ }
+ private MyResultReceiver mReceiver;
// Types used with setType. Keep in sync with CachedInput.h
private static final int NORMAL_TEXT_FIELD = 0;
@@ -184,7 +202,7 @@
}
}
};
-
+ mReceiver = new MyResultReceiver(mHandler);
}
public void setAutoFillable(int queryId) {
@@ -362,6 +380,8 @@
}
}
+ /* package */ ResultReceiver getResultReceiver() { return mReceiver; }
+
/**
* Determine whether this WebTextView currently represents the node
* represented by ptr.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1316235..4aa1f5e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -43,6 +43,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.graphics.SurfaceTexture;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.net.Proxy;
@@ -497,15 +498,6 @@
// default is not set, the UI will continue handle them.
private boolean mDeferTouchProcess;
- // Currently, multi-touch events are sent to WebKit first then back to
- // WebView while single-touch events are handled in WebView first.
- // So there is a chance that a single-touch move event is handled in WebView
- // before multi-touch events are finished.
- // if mIsHandlingMultiTouch is true, which means multi-touch event handling
- // is not finished, then any single-touch move event will be skipped.
- // FIXME: send single-touch events to WebKit first then back to WebView.
- private boolean mIsHandlingMultiTouch = false;
-
// to avoid interfering with the current touch events, track them
// separately. Currently no snapping or fling in the deferred process mode
private int mDeferTouchMode = TOUCH_DONE_MODE;
@@ -617,6 +609,10 @@
private int mTouchHighlightX;
private int mTouchHighlightY;
+ // Basically this proxy is used to tell the Video to update layer tree at
+ // SetBaseLayer time and to pause when WebView paused.
+ private HTML5VideoViewProxy mHTML5VideoViewProxy;
+
/*
* Private message ids
*/
@@ -675,6 +671,7 @@
static final int SELECT_AT = 135;
static final int SCREEN_ON = 136;
+ static final int ENTER_FULLSCREEN_VIDEO = 137;
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
@@ -729,7 +726,8 @@
"SET_AUTOFILLABLE", // = 133;
"AUTOFILL_COMPLETE", // = 134;
"SELECT_AT", // = 135;
- "SCREEN_ON" // = 136;
+ "SCREEN_ON", // = 136;
+ "ENTER_FULLSCREEN_VIDEO" // = 137;
};
// If the site doesn't use the viewport meta tag to specify the viewport,
@@ -1136,10 +1134,13 @@
protected Set<String> doInBackground(Void... unused) {
Set<String> installedPackages = new HashSet<String>();
PackageManager pm = mContext.getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackages(0);
- for (PackageInfo p : packages) {
- if (sGoogleApps.contains(p.packageName)) {
- installedPackages.add(p.packageName);
+ for (String name : sGoogleApps) {
+ try {
+ PackageInfo pInfo = pm.getPackageInfo(name,
+ PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
+ installedPackages.add(name);
+ } catch(PackageManager.NameNotFoundException e) {
+ // package not found
}
}
return installedPackages;
@@ -1190,6 +1191,7 @@
// Initially use a size of two, since the user is likely to only hold
// down two keys at a time (shift + another key)
mKeysPressed = new Vector<Integer>(2);
+ mHTML5VideoViewProxy = null ;
}
/**
@@ -2906,6 +2908,11 @@
if (!mIsPaused) {
mIsPaused = true;
mWebViewCore.sendMessage(EventHub.ON_PAUSE);
+ // We want to pause the current playing video when switching out
+ // from the current WebView/tab.
+ if (mHTML5VideoViewProxy != null) {
+ mHTML5VideoViewProxy.pauseAndDispatch();
+ }
}
}
@@ -4036,14 +4043,12 @@
}
}
- void setBaseLayer(int layer, Rect invalRect, boolean showVisualIndciator) {
+ void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator) {
if (mNativeClass == 0)
return;
- if (invalRect == null) {
- Rect rect = new Rect(0, 0, mContentWidth, mContentHeight);
- nativeSetBaseLayer(layer, rect, showVisualIndciator);
- } else {
- nativeSetBaseLayer(layer, invalRect, showVisualIndciator);
+ nativeSetBaseLayer(layer, invalRegion, showVisualIndicator);
+ if (mHTML5VideoViewProxy != null) {
+ mHTML5VideoViewProxy.setBaseLayer(layer);
}
}
@@ -4284,7 +4289,7 @@
if (isTextView) {
rebuildWebTextView();
if (inEditingMode()) {
- imm.showSoftInput(mWebTextView, 0);
+ imm.showSoftInput(mWebTextView, 0, mWebTextView.getResultReceiver());
if (zoom) {
didUpdateWebTextViewDimensions(INTERSECTS_SCREEN);
}
@@ -5479,7 +5484,6 @@
case MotionEvent.ACTION_DOWN: {
mPreventDefault = PREVENT_DEFAULT_NO;
mConfirmMove = false;
- mIsHandlingMultiTouch = false;
mInitialHitTestResult = null;
if (!mScroller.isFinished()) {
// stop the current scroll animation, but if this is
@@ -5571,7 +5575,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = nativeScrollableLayer(
contentX, contentY, ted.mNativeLayerRect, null);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
@@ -5618,7 +5622,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
@@ -5800,7 +5804,7 @@
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
@@ -5823,7 +5827,7 @@
ted.mNativeLayer = nativeScrollableLayer(
contentX, contentY,
ted.mNativeLayerRect, null);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES){
mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
@@ -5960,6 +5964,10 @@
int y = viewToContentY((int) ev.getY(c) + mScrollY);
ted.mPoints[c] = new Point(x, y);
}
+ if (ted.mAction == MotionEvent.ACTION_POINTER_DOWN
+ || ted.mAction == MotionEvent.ACTION_POINTER_UP) {
+ ted.mActionIndex = ev.getActionIndex();
+ }
ted.mMetaState = ev.getMetaState();
ted.mReprocess = true;
ted.mMotionEvent = MotionEvent.obtain(ev);
@@ -5967,10 +5975,9 @@
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
cancelLongPress();
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPreventDefault = PREVENT_DEFAULT_IGNORE;
}
- private void handleMultiTouchInWebView(MotionEvent ev) {
+ void handleMultiTouchInWebView(MotionEvent ev) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
+ " mTouchMode=" + mTouchMode
@@ -5988,24 +5995,26 @@
float x = ev.getX();
float y = ev.getY();
- detector.onTouchEvent(ev);
+ if (mPreventDefault != PREVENT_DEFAULT_YES) {
+ detector.onTouchEvent(ev);
- if (detector.isInProgress()) {
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "detector is in progress");
- }
- mLastTouchTime = ev.getEventTime();
- x = detector.getFocusX();
- y = detector.getFocusY();
+ if (detector.isInProgress()) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "detector is in progress");
+ }
+ mLastTouchTime = ev.getEventTime();
+ x = detector.getFocusX();
+ y = detector.getFocusY();
- cancelLongPress();
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- if (!mZoomManager.supportsPanDuringZoom()) {
- return;
- }
- mTouchMode = TOUCH_DRAG_MODE;
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
+ cancelLongPress();
+ mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+ if (!mZoomManager.supportsPanDuringZoom()) {
+ return;
+ }
+ mTouchMode = TOUCH_DRAG_MODE;
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
}
}
@@ -6017,7 +6026,6 @@
// set mLastTouchX/Y to the remaining point
mLastTouchX = Math.round(x);
mLastTouchY = Math.round(y);
- mIsHandlingMultiTouch = false;
} else if (action == MotionEvent.ACTION_MOVE) {
// negative x or y indicate it is on the edge, skip it.
if (x < 0 || y < 0) {
@@ -6032,6 +6040,7 @@
if (shouldForwardTouchEvent()) {
if (removeEvents) {
mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
+ mTouchEventQueue.ignoreCurrentlyMissingEvents();
}
TouchEventData ted = new TouchEventData();
ted.mIds = new int[1];
@@ -6041,7 +6050,7 @@
ted.mAction = MotionEvent.ACTION_CANCEL;
ted.mNativeLayer = nativeScrollableLayer(
x, y, ted.mNativeLayerRect, null);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mPreventDefault = PREVENT_DEFAULT_IGNORE;
}
@@ -7170,11 +7179,15 @@
private class TouchEventQueue {
private long mNextTouchSequence = Long.MIN_VALUE + 1;
private long mLastHandledTouchSequence = Long.MIN_VALUE;
+ private long mIgnoreUntilSequence = Long.MIN_VALUE;
private QueuedTouch mTouchEventQueue;
private QueuedTouch mQueuedTouchRecycleBin;
private int mQueuedTouchRecycleCount;
private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
+ // milliseconds until we abandon hope of getting all of a previous gesture
+ private static final int QUEUED_GESTURE_TIMEOUT = 2000;
+
private QueuedTouch obtainQueuedTouch() {
if (mQueuedTouchRecycleBin != null) {
QueuedTouch result = mQueuedTouchRecycleBin;
@@ -7185,6 +7198,13 @@
return new QueuedTouch();
}
+ /**
+ * Allow events with any currently missing sequence numbers to be skipped in processing.
+ */
+ public void ignoreCurrentlyMissingEvents() {
+ mIgnoreUntilSequence = mNextTouchSequence;
+ }
+
private void recycleQueuedTouch(QueuedTouch qd) {
if (mQueuedTouchRecycleCount < MAX_RECYCLED_QUEUED_TOUCH) {
qd.mNext = mQueuedTouchRecycleBin;
@@ -7200,6 +7220,7 @@
public void reset() {
mNextTouchSequence = Long.MIN_VALUE + 1;
mLastHandledTouchSequence = Long.MIN_VALUE;
+ mIgnoreUntilSequence = Long.MIN_VALUE;
while (mTouchEventQueue != null) {
QueuedTouch recycleMe = mTouchEventQueue;
mTouchEventQueue = mTouchEventQueue.mNext;
@@ -7226,6 +7247,15 @@
* @param ted Touch data to be processed in order.
*/
public void enqueueTouchEvent(TouchEventData ted) {
+ if (ted.mSequence < mLastHandledTouchSequence) {
+ // Stale event and we already moved on; drop it. (Should not be common.)
+ Log.w(LOGTAG, "Stale touch event " + MotionEvent.actionToString(ted.mAction) +
+ " received from webcore; ignoring");
+ return;
+ }
+
+ dropStaleGestures(ted.mMotionEvent, ted.mSequence);
+
if (mLastHandledTouchSequence + 1 == ted.mSequence) {
handleQueuedTouchEventData(ted);
@@ -7258,6 +7288,9 @@
*/
public void enqueueTouchEvent(MotionEvent ev) {
final long sequence = nextTouchSequence();
+
+ dropStaleGestures(ev, sequence);
+
if (mLastHandledTouchSequence + 1 == sequence) {
handleQueuedMotionEvent(ev);
@@ -7279,6 +7312,42 @@
}
}
+ private void dropStaleGestures(MotionEvent ev, long sequence) {
+ if (mTouchEventQueue == null) return;
+
+ MotionEvent nextQueueEvent = mTouchEventQueue.mTed != null ?
+ mTouchEventQueue.mTed.mMotionEvent : mTouchEventQueue.mEvent;
+
+ if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && nextQueueEvent != null) {
+ long eventTime = ev.getEventTime();
+ long nextQueueTime = nextQueueEvent.getEventTime();
+ if (eventTime > nextQueueTime + QUEUED_GESTURE_TIMEOUT) {
+ Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
+ "Ignoring previous queued events.");
+ QueuedTouch qd = mTouchEventQueue;
+ while (qd != null && qd.mSequence < sequence) {
+ QueuedTouch recycleMe = qd;
+ qd = qd.mNext;
+ recycleQueuedTouch(recycleMe);
+ }
+ mTouchEventQueue = qd;
+ mLastHandledTouchSequence = sequence - 1;
+ }
+ }
+
+ if (mIgnoreUntilSequence > mLastHandledTouchSequence) {
+ QueuedTouch qd = mTouchEventQueue;
+ while (qd != null && qd.mSequence < mIgnoreUntilSequence &&
+ qd.mSequence < sequence) {
+ mLastHandledTouchSequence = qd.mSequence;
+ QueuedTouch recycleMe = qd;
+ qd = qd.mNext;
+ recycleQueuedTouch(recycleMe);
+ }
+ mTouchEventQueue = qd;
+ }
+ }
+
private void handleQueuedTouch(QueuedTouch qt) {
if (qt.mTed != null) {
handleQueuedTouchEventData(qt.mTed);
@@ -7291,12 +7360,10 @@
private void handleQueuedMotionEvent(MotionEvent ev) {
int action = ev.getActionMasked();
if (ev.getPointerCount() > 1) { // Multi-touch
- mIsHandlingMultiTouch = true;
-
handleMultiTouchInWebView(ev);
} else {
final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
- if (detector != null) {
+ if (detector != null && mPreventDefault != PREVENT_DEFAULT_YES) {
// ScaleGestureDetector needs a consistent event stream to operate properly.
// It won't take any action with fewer than two pointers, but it needs to
// update internal bookkeeping state.
@@ -7329,11 +7396,7 @@
}
} else {
if (ted.mPoints.length > 1) { // multi-touch
- if (ted.mAction == MotionEvent.ACTION_POINTER_UP &&
- ted.mMotionEvent.getPointerCount() == 2) {
- mIsHandlingMultiTouch = false;
- }
- if (!ted.mNativeResult) {
+ if (!ted.mNativeResult && mPreventDefault != PREVENT_DEFAULT_YES) {
mPreventDefault = PREVENT_DEFAULT_NO;
handleMultiTouchInWebView(ted.mMotionEvent);
} else {
@@ -7525,7 +7588,7 @@
ted.mNativeLayer = nativeScrollableLayer(
ted.mPoints[0].x, ted.mPoints[0].y,
ted.mNativeLayerRect, null);
- ted.mDontEnqueueResult = true;
+ ted.mSequence = mTouchEventQueue.nextTouchSequence();
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mTouchMode = TOUCH_DONE_MODE;
@@ -7571,7 +7634,7 @@
case NEW_PICTURE_MSG_ID: {
// called for new content
final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj;
- setBaseLayer(draw.mBaseLayer, draw.mInvalRegion.getBounds(),
+ setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
getSettings().getShowVisualIndicator());
final Point viewSize = draw.mViewSize;
WebViewCore.ViewState viewState = draw.mViewState;
@@ -7741,9 +7804,12 @@
break;
}
TouchEventData ted = (TouchEventData) msg.obj;
- if (!ted.mDontEnqueueResult) {
- mTouchEventQueue.enqueueTouchEvent(ted);
- }
+
+ // WebCore is responding to us; remove pending timeout.
+ // It will be re-posted when needed.
+ removeMessages(PREVENT_DEFAULT_TIMEOUT);
+
+ mTouchEventQueue.enqueueTouchEvent(ted);
break;
case REQUEST_KEYBOARD:
@@ -7785,6 +7851,11 @@
setKeepScreenOn(msg.arg1 == 1);
break;
+ case ENTER_FULLSCREEN_VIDEO:
+ int layerId = msg.arg1;
+ Log.v(LOGTAG, "Display the video layer " + layerId + " fullscreen");
+ break;
+
case SHOW_FULLSCREEN: {
View view = (View) msg.obj;
int npp = msg.arg1;
@@ -8467,6 +8538,15 @@
}
/**
+ * Enable the communication b/t the webView and VideoViewProxy
+ *
+ * @hide only used by the Browser
+ */
+ public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
+ mHTML5VideoViewProxy = proxy;
+ }
+
+ /**
* Enable expanded tiles bound for smoother scrolling.
*
* @hide only used by the Browser
@@ -8613,7 +8693,7 @@
private native void nativeSetFindIsEmpty();
private native void nativeSetFindIsUp(boolean isUp);
private native void nativeSetHeightCanMeasure(boolean measure);
- private native void nativeSetBaseLayer(int layer, Rect invalRect,
+ private native void nativeSetBaseLayer(int layer, Region invalRegion,
boolean showVisualIndicator);
private native void nativeShowCursorTimed();
private native void nativeReplaceBaseContent(int content);
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index db605de..65026a5 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -256,4 +256,18 @@
*/
public void onScaleChanged(WebView view, float oldScale, float newScale) {
}
+
+ /**
+ * Notify the host application that a request to automatically log in the
+ * user has been processed.
+ * @param view The WebView requesting the login.
+ * @param realm The account realm used to look up accounts.
+ * @param account An optional account. If not null, the account should be
+ * checked against accounts on the device. If it is a valid
+ * account, it should be used to log in the user.
+ * @param args Authenticator specific arguments used to log in the user.
+ */
+ public void onReceivedLoginRequest(WebView view, String realm,
+ String account, String args) {
+ }
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index f367b93..bed77ef 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -480,6 +480,15 @@
mCallbackProxy.setInstallableWebApp();
}
+ /**
+ * Notify the webview that we want to display the video layer fullscreen.
+ */
+ protected void enterFullscreenForVideoLayer(int layerId) {
+ if (mWebView == null) return;
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.ENTER_FULLSCREEN_VIDEO, layerId, 0).sendToTarget();
+ }
+
//-------------------------------------------------------------------------
// JNI methods
//-------------------------------------------------------------------------
@@ -563,7 +572,7 @@
int framePtr, int nodePtr, int x, int y);
private native boolean nativeHandleTouchEvent(int action, int[] idArray,
- int[] xArray, int[] yArray, int count, int metaState);
+ int[] xArray, int[] yArray, int count, int actionIndex, int metaState);
private native void nativeUpdateFrameCache();
@@ -820,6 +829,7 @@
int mAction;
int[] mIds; // Ids of the touch points
Point[] mPoints;
+ int mActionIndex; // Associated pointer index for ACTION_POINTER_DOWN/UP
int mMetaState;
boolean mReprocess;
MotionEvent mMotionEvent;
@@ -827,7 +837,6 @@
Rect mNativeLayerRect = new Rect();
long mSequence;
boolean mNativeResult;
- boolean mDontEnqueueResult;
}
static class GeolocationPermissionsData {
@@ -1336,7 +1345,7 @@
ted.mNativeLayerRect);
}
ted.mNativeResult = nativeHandleTouchEvent(ted.mAction, ted.mIds,
- xArray, yArray, count, ted.mMetaState);
+ xArray, yArray, count, ted.mActionIndex, ted.mMetaState);
Message.obtain(
mWebView.mPrivateHandler,
WebView.PREVENT_TOUCH_ID,
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index f27ced8..72052a6 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -23,6 +23,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.SystemClock;
+import android.util.FloatMath;
import android.util.Log;
import android.view.ScaleGestureDetector;
import android.view.View;
@@ -112,6 +113,22 @@
private float mZoomCenterY;
/*
+ * Similar to mZoomCenterX(Y), these track the focus point of the scale
+ * gesture. The difference is these get updated every time when onScale is
+ * invoked no matter if a zooming really happens.
+ */
+ private float mFocusX;
+ private float mFocusY;
+
+ /*
+ * mFocusMovementQueue keeps track of the previous focus point movement
+ * has been through. Comparing to the difference of the gesture's previous
+ * span and current span, it determines if the gesture is for panning or
+ * zooming or both.
+ */
+ private FocusMovementQueue mFocusMovementQueue;
+
+ /*
* These values represent the point around which the screen should be
* centered after zooming. In other words it is used to determine the center
* point of the visible document after the page has finished zooming. This
@@ -196,6 +213,8 @@
* viewport size is.
*/
setZoomOverviewWidth(WebView.DEFAULT_VIEWPORT_WIDTH);
+
+ mFocusMovementQueue = new FocusMovementQueue();
}
/**
@@ -336,6 +355,10 @@
return scale;
}
+ public final boolean isScaleOverLimits(float scale) {
+ return scale <= mMinZoomScale || scale >= mMaxZoomScale;
+ }
+
public final boolean isZoomScaleFixed() {
return mMinZoomScale >= mMaxZoomScale;
}
@@ -507,7 +530,7 @@
mTextWrapScale = scale;
}
- if (exceedsMinScaleIncrement(scale, mActualScale) || force) {
+ if (scale != mActualScale || force) {
float oldScale = mActualScale;
float oldInvScale = mInvActualScale;
@@ -714,21 +737,91 @@
return mScaleDetector;
}
+ private class FocusMovementQueue {
+ private static final int QUEUE_CAPACITY = 5;
+ private float[] mQueue;
+ private float mSum;
+ private int mSize;
+ private int mIndex;
+
+ FocusMovementQueue() {
+ mQueue = new float[QUEUE_CAPACITY];
+ mSize = 0;
+ mSum = 0;
+ mIndex = 0;
+ }
+
+ private void clear() {
+ mSize = 0;
+ mSum = 0;
+ mIndex = 0;
+ for (int i = 0; i < QUEUE_CAPACITY; ++i) {
+ mQueue[i] = 0;
+ }
+ }
+
+ private void add(float focusDelta) {
+ mSum += focusDelta;
+ if (mSize < QUEUE_CAPACITY) { // fill up the queue.
+ mSize++;
+ } else { // circulate the queue.
+ mSum -= mQueue[mIndex];
+ }
+ mQueue[mIndex] = focusDelta;
+ mIndex = (mIndex + 1) % QUEUE_CAPACITY;
+ }
+
+ private float getSum() {
+ return mSum;
+ }
+ }
+
private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener {
+ private float mAccumulatedSpan;
public boolean onScaleBegin(ScaleGestureDetector detector) {
mInitialZoomOverview = false;
dismissZoomPicker();
+ mFocusMovementQueue.clear();
mWebView.mViewManager.startZoom();
mWebView.onPinchToZoomAnimationStart();
+ mAccumulatedSpan = 0;
return true;
}
- public boolean onScale(ScaleGestureDetector detector) {
+ // If the user moves the fingers but keeps the same distance between them,
+ // we should do panning only.
+ public boolean isPanningOnly(ScaleGestureDetector detector) {
+ float prevFocusX = mFocusX;
+ float prevFocusY = mFocusY;
+ mFocusX = detector.getFocusX();
+ mFocusY = detector.getFocusY();
+ float focusDelta = (prevFocusX == 0 && prevFocusY == 0) ? 0 :
+ FloatMath.sqrt((mFocusX - prevFocusX) * (mFocusX - prevFocusX)
+ + (mFocusY - prevFocusY) * (mFocusY - prevFocusY));
+ mFocusMovementQueue.add(focusDelta);
+ float deltaSpan = detector.getCurrentSpan() - detector.getPreviousSpan() +
+ mAccumulatedSpan;
+ final boolean result = mFocusMovementQueue.getSum() > Math.abs(deltaSpan);
+ if (result) {
+ mAccumulatedSpan += deltaSpan;
+ } else {
+ mAccumulatedSpan = 0;
+ }
+ return result;
+ }
+
+ public boolean handleScale(ScaleGestureDetector detector) {
+ float scale = detector.getScaleFactor() * mActualScale;
+
+ // if scale is limited by any reason, don't zoom but do ask
+ // the detector to update the event.
+ boolean isScaleLimited =
+ isScaleOverLimits(scale) || scale < getZoomOverviewScale();
+
// Prevent scaling beyond overview scale.
- float scale = Math.max(
- computeScaleWithLimits(detector.getScaleFactor() * mActualScale),
- getZoomOverviewScale());
+ scale = Math.max(computeScaleWithLimits(scale), getZoomOverviewScale());
+
if (mPinchToZoomAnimating || willScaleTriggerZoom(scale)) {
mPinchToZoomAnimating = true;
// limit the scale change per step
@@ -740,13 +833,21 @@
scale = computeScaleWithLimits(scale);
// if the scale change is too small, regard it as jitter and skip it.
if (Math.abs(scale - mActualScale) < MINIMUM_SCALE_WITHOUT_JITTER) {
- return false;
+ return isScaleLimited;
}
setZoomCenter(detector.getFocusX(), detector.getFocusY());
setZoomScale(scale, false);
mWebView.invalidate();
return true;
}
+ return isScaleLimited;
+ }
+
+ public boolean onScale(ScaleGestureDetector detector) {
+ if (isPanningOnly(detector) || handleScale(detector)) {
+ mFocusMovementQueue.clear();
+ return true;
+ }
return false;
}
@@ -960,14 +1061,15 @@
final Point viewSize = drawData.mViewSize;
updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth);
setupZoomOverviewWidth(drawData, mWebView.getViewWidth());
+ final float overviewScale = getZoomOverviewScale();
if (!mMinZoomScaleFixed) {
- mMinZoomScale = getZoomOverviewScale();
+ mMinZoomScale = (mInitialScale > 0) ?
+ Math.min(mInitialScale, overviewScale) : overviewScale;
mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
}
if (!mWebView.drawHistory()) {
float scale;
- final float overviewScale = getZoomOverviewScale();
WebSettings settings = mWebView.getSettings();
if (mInitialScale > 0) {
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 200c870..fb57ce0 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -564,6 +564,9 @@
}
} else {
int index = (int) (position * count);
+ // Don't overflow
+ if (index > count - 1) index = count - 1;
+
if (mList instanceof ExpandableListView) {
ExpandableListView expList = (ExpandableListView) mList;
expList.setSelectionFromTop(expList.getFlatListPosition(
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index d92588cb..17b3bda 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -477,8 +477,7 @@
break;
case MotionEvent.ACTION_POINTER_DOWN: {
final int index = ev.getActionIndex();
- final float x = ev.getX(index);
- mLastMotionX = x;
+ mLastMotionX = ev.getX(index);
mActivePointerId = ev.getPointerId(index);
break;
}
@@ -1446,6 +1445,7 @@
super.setOverScrollMode(mode);
}
+ @SuppressWarnings({"SuspiciousNameCombination"})
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 2d164fd..9933d68 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -54,18 +54,16 @@
import java.util.WeakHashMap;
/**
- * Provides the user interface elements for the user to enter a search query and submit a
+ * A widget that provides a user interface for the user to enter a search query and submit a
* request to a search provider. Shows a list of query suggestions or results, if
- * available and allows the user to pick a suggestion or result to launch into.
+ * available, and allows the user to pick a suggestion or result to launch into.
*
- * <p>
- * <b>XML attributes</b>
- * <p>
- * See {@link android.R.styleable#SearchView SearchView Attributes},
- * {@link android.R.styleable#View View Attributes}
+ * <p>For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a>
+ * documentation.<p>
*
* @attr ref android.R.styleable#SearchView_iconifiedByDefault
* @attr ref android.R.styleable#SearchView_maxWidth
+ * @attr ref android.R.styleable#SearchView_queryHint
*/
public class SearchView extends LinearLayout {
@@ -83,6 +81,7 @@
private CursorAdapter mSuggestionsAdapter;
private View mSearchButton;
private View mSubmitButton;
+ private View mSearchPlate;
private View mSubmitArea;
private ImageView mCloseButton;
private View mSearchEditFrame;
@@ -190,6 +189,7 @@
mQueryTextView.setSearchView(this);
mSearchEditFrame = findViewById(R.id.search_edit_frame);
+ mSearchPlate = findViewById(R.id.search_plate);
mSubmitArea = findViewById(R.id.submit_area);
mSubmitButton = findViewById(R.id.search_go_btn);
mCloseButton = (ImageView) findViewById(R.id.search_close_btn);
@@ -258,6 +258,7 @@
mSearchable = searchable;
if (mSearchable != null) {
updateSearchAutoComplete();
+ updateQueryHint();
}
// Cache the voice search capability
mVoiceButtonEnabled = hasVoiceSearch();
@@ -384,6 +385,8 @@
* in the SearchableInfo.
*
* @param hint the hint text to display
+ *
+ * @attr ref android.R.styleable#SearchView_queryHint
*/
public void setQueryHint(CharSequence hint) {
mQueryHint = hint;
@@ -399,6 +402,8 @@
* <p>The default value is true.</p>
*
* @param iconified whether the search field should be iconified by default
+ *
+ * @attr ref android.R.styleable#SearchView_iconifiedByDefault
*/
public void setIconifiedByDefault(boolean iconified) {
if (mIconifiedByDefault == iconified) return;
@@ -575,19 +580,19 @@
}
private void updateSubmitButton(boolean hasText) {
- mSubmitButton.setVisibility(
- isSubmitAreaEnabled() ? (hasText ? VISIBLE : INVISIBLE) : GONE);
+ int visibility = GONE;
+ if (isSubmitAreaEnabled() && hasFocus() && (hasText || !mVoiceButtonEnabled)) {
+ visibility = VISIBLE;
+ }
+ mSubmitButton.setVisibility(visibility);
}
private void updateSubmitArea() {
int visibility = GONE;
- if (isSubmitAreaEnabled()) {
- if (mSubmitButton.getVisibility() == VISIBLE
- || mVoiceButton.getVisibility() == VISIBLE) {
- visibility = VISIBLE;
- } else {
- visibility = INVISIBLE;
- }
+ if (isSubmitAreaEnabled()
+ && (mSubmitButton.getVisibility() == VISIBLE
+ || mVoiceButton.getVisibility() == VISIBLE)) {
+ visibility = VISIBLE;
}
mSubmitArea.setVisibility(visibility);
}
@@ -601,6 +606,11 @@
mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET);
}
+ private void updateFocusedState(boolean focused) {
+ mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+ mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET);
+ }
+
private void setImeVisibility(boolean visible) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -851,16 +861,11 @@
* Update the visibility of the voice button. There are actually two voice search modes,
* either of which will activate the button.
* @param empty whether the search query text field is empty. If it is, then the other
- * criteria apply to make the voice button visible. Otherwise the voice button will not
- * be visible - i.e., if the user has typed a query, remove the voice button.
+ * criteria apply to make the voice button visible.
*/
private void updateVoiceButton(boolean empty) {
- // If the voice button is to be visible, show it
- // Else, make it gone if the submit button is enabled, otherwise invisible to
- // avoid losing the real-estate
- int visibility = mSubmitButtonEnabled ? GONE : INVISIBLE;
-
- if (mVoiceButtonEnabled && !isIconified() && empty) {
+ int visibility = GONE;
+ if (mVoiceButtonEnabled && !isIconified() && (empty || !mSubmitButtonEnabled)) {
visibility = VISIBLE;
mSubmitButton.setVisibility(GONE);
}
@@ -958,7 +963,8 @@
}
void onTextFocusChanged() {
- updateCloseButton();
+ updateViewsVisibility(isIconified());
+ updateFocusedState(mQueryTextView.hasFocus());
}
private boolean onItemClicked(int position, int actionKey, String actionMsg) {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index bab469b..21c61bd 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -531,6 +531,8 @@
@Override
protected void dispatchDraw(Canvas canvas) {
+ boolean expandClipRegion = false;
+
canvas.getClipBounds(stackInvalidateRect);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -540,12 +542,22 @@
child.getAlpha() == 0f || child.getVisibility() != VISIBLE) {
lp.resetInvalidateRect();
}
- stackInvalidateRect.union(lp.getInvalidateRect());
+ Rect childInvalidateRect = lp.getInvalidateRect();
+ if (!childInvalidateRect.isEmpty()) {
+ expandClipRegion = true;
+ stackInvalidateRect.union(childInvalidateRect);
+ }
}
- canvas.save(Canvas.CLIP_SAVE_FLAG);
- canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
- super.dispatchDraw(canvas);
- canvas.restore();
+
+ // We only expand the clip bounds if necessary.
+ if (expandClipRegion) {
+ canvas.save(Canvas.CLIP_SAVE_FLAG);
+ canvas.clipRect(stackInvalidateRect, Region.Op.UNION);
+ super.dispatchDraw(canvas);
+ canvas.restore();
+ } else {
+ super.dispatchDraw(canvas);
+ }
}
private void onLayout() {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index fb2a72b..2e56996 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -68,7 +68,7 @@
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean alwaysUseOption, boolean alwaysChoose) {
+ boolean alwaysUseOption) {
super.onCreate(savedInstanceState);
mPm = getPackageManager();
intent.setComponent(null);
@@ -91,7 +91,7 @@
}
mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
int count = mAdapter.getCount();
- if (count > 1 || (count == 1 && alwaysChoose)) {
+ if (count > 1) {
ap.mAdapter = mAdapter;
} else if (count == 1) {
startActivity(mAdapter.intentForPosition(0));
@@ -104,12 +104,6 @@
setupAlert();
}
- protected void onCreate(Bundle savedInstanceState, Intent intent,
- CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean alwaysUseOption) {
- onCreate(savedInstanceState, intent, title, initialIntents, rList, alwaysUseOption, false);
- }
-
public void onClick(DialogInterface dialog, int which) {
ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
Intent intent = mAdapter.intentForPosition(which);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1cca21d..d86504d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1581,7 +1581,7 @@
// Update discharge amounts.
if (mOnBatteryInternal) {
- updateDischargeScreenLevels(false, true);
+ updateDischargeScreenLevelsLocked(false, true);
}
}
}
@@ -1602,7 +1602,7 @@
// Update discharge amounts.
if (mOnBatteryInternal) {
- updateDischargeScreenLevels(true, false);
+ updateDischargeScreenLevelsLocked(true, false);
}
}
}
@@ -4030,7 +4030,7 @@
clearHistoryLocked();
}
- void updateDischargeScreenLevels(boolean oldScreenOn, boolean newScreenOn) {
+ void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
if (oldScreenOn) {
int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
@@ -4055,69 +4055,73 @@
void setOnBattery(boolean onBattery, int oldStatus, int level) {
synchronized(this) {
- boolean doWrite = false;
- Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
- m.arg1 = onBattery ? 1 : 0;
- mHandler.sendMessage(m);
- mOnBattery = mOnBatteryInternal = onBattery;
+ setOnBatteryLocked(onBattery, oldStatus, level);
+ }
+ }
- long uptime = SystemClock.uptimeMillis() * 1000;
- long mSecRealtime = SystemClock.elapsedRealtime();
- long realtime = mSecRealtime * 1000;
- if (onBattery) {
- // We will reset our status if we are unplugging after the
- // battery was last full, or the level is at 100, or
- // we have gone through a significant charge (from a very low
- // level to a now very high level).
- if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
- || level >= 90
- || (mDischargeCurrentLevel < 20 && level >= 80)) {
- doWrite = true;
- resetAllStatsLocked();
- mDischargeStartLevel = level;
- }
- updateKernelWakelocksLocked();
- mHistoryCur.batteryLevel = (byte)level;
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(mSecRealtime);
- mTrackBatteryUptimeStart = uptime;
- mTrackBatteryRealtimeStart = realtime;
- mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
- mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
- mDischargeCurrentLevel = mDischargeUnplugLevel = level;
- if (mScreenOn) {
- mDischargeScreenOnUnplugLevel = level;
- mDischargeScreenOffUnplugLevel = 0;
- } else {
- mDischargeScreenOnUnplugLevel = 0;
- mDischargeScreenOffUnplugLevel = level;
- }
- mDischargeAmountScreenOn = 0;
- mDischargeAmountScreenOff = 0;
- doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
- } else {
- updateKernelWakelocksLocked();
- mHistoryCur.batteryLevel = (byte)level;
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(mSecRealtime);
- mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
- mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
- mDischargeCurrentLevel = level;
- if (level < mDischargeUnplugLevel) {
- mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
- mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
- }
- updateDischargeScreenLevels(mScreenOn, mScreenOn);
- doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
+ void setOnBatteryLocked(boolean onBattery, int oldStatus, int level) {
+ boolean doWrite = false;
+ Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
+ m.arg1 = onBattery ? 1 : 0;
+ mHandler.sendMessage(m);
+ mOnBattery = mOnBatteryInternal = onBattery;
+
+ long uptime = SystemClock.uptimeMillis() * 1000;
+ long mSecRealtime = SystemClock.elapsedRealtime();
+ long realtime = mSecRealtime * 1000;
+ if (onBattery) {
+ // We will reset our status if we are unplugging after the
+ // battery was last full, or the level is at 100, or
+ // we have gone through a significant charge (from a very low
+ // level to a now very high level).
+ if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+ || level >= 90
+ || (mDischargeCurrentLevel < 20 && level >= 80)) {
+ doWrite = true;
+ resetAllStatsLocked();
+ mDischargeStartLevel = level;
}
- if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
- if (mFile != null) {
- writeAsyncLocked();
- }
+ updateKernelWakelocksLocked();
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(mSecRealtime);
+ mTrackBatteryUptimeStart = uptime;
+ mTrackBatteryRealtimeStart = realtime;
+ mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+ mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+ mDischargeCurrentLevel = mDischargeUnplugLevel = level;
+ if (mScreenOn) {
+ mDischargeScreenOnUnplugLevel = level;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = level;
+ }
+ mDischargeAmountScreenOn = 0;
+ mDischargeAmountScreenOff = 0;
+ doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
+ } else {
+ updateKernelWakelocksLocked();
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(mSecRealtime);
+ mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
+ mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
+ mDischargeCurrentLevel = level;
+ if (level < mDischargeUnplugLevel) {
+ mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
+ mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
+ }
+ updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+ doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
+ }
+ if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
+ if (mFile != null) {
+ writeAsyncLocked();
}
}
}
@@ -4127,71 +4131,73 @@
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
- boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
- int oldStatus = mHistoryCur.batteryStatus;
- if (!mHaveBatteryLevel) {
- mHaveBatteryLevel = true;
- // We start out assuming that the device is plugged in (not
- // on battery). If our first report is now that we are indeed
- // plugged in, then twiddle our state to correctly reflect that
- // since we won't be going through the full setOnBattery().
- if (onBattery == mOnBattery) {
- if (onBattery) {
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- } else {
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ synchronized(this) {
+ boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
+ int oldStatus = mHistoryCur.batteryStatus;
+ if (!mHaveBatteryLevel) {
+ mHaveBatteryLevel = true;
+ // We start out assuming that the device is plugged in (not
+ // on battery). If our first report is now that we are indeed
+ // plugged in, then twiddle our state to correctly reflect that
+ // since we won't be going through the full setOnBattery().
+ if (onBattery == mOnBattery) {
+ if (onBattery) {
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ } else {
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ }
+ }
+ oldStatus = status;
+ }
+ if (onBattery) {
+ mDischargeCurrentLevel = level;
+ mRecordingHistory = true;
+ }
+ if (onBattery != mOnBattery) {
+ mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.batteryStatus = (byte)status;
+ mHistoryCur.batteryHealth = (byte)health;
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ mHistoryCur.batteryTemperature = (char)temp;
+ mHistoryCur.batteryVoltage = (char)volt;
+ setOnBatteryLocked(onBattery, oldStatus, level);
+ } else {
+ boolean changed = false;
+ if (mHistoryCur.batteryLevel != level) {
+ mHistoryCur.batteryLevel = (byte)level;
+ changed = true;
+ }
+ if (mHistoryCur.batteryStatus != status) {
+ mHistoryCur.batteryStatus = (byte)status;
+ changed = true;
+ }
+ if (mHistoryCur.batteryHealth != health) {
+ mHistoryCur.batteryHealth = (byte)health;
+ changed = true;
+ }
+ if (mHistoryCur.batteryPlugType != plugType) {
+ mHistoryCur.batteryPlugType = (byte)plugType;
+ changed = true;
+ }
+ if (temp >= (mHistoryCur.batteryTemperature+10)
+ || temp <= (mHistoryCur.batteryTemperature-10)) {
+ mHistoryCur.batteryTemperature = (char)temp;
+ changed = true;
+ }
+ if (volt > (mHistoryCur.batteryVoltage+20)
+ || volt < (mHistoryCur.batteryVoltage-20)) {
+ mHistoryCur.batteryVoltage = (char)volt;
+ changed = true;
+ }
+ if (changed) {
+ addHistoryRecordLocked(SystemClock.elapsedRealtime());
}
}
- oldStatus = status;
- }
- if (onBattery) {
- mDischargeCurrentLevel = level;
- mRecordingHistory = true;
- }
- if (onBattery != mOnBattery) {
- mHistoryCur.batteryLevel = (byte)level;
- mHistoryCur.batteryStatus = (byte)status;
- mHistoryCur.batteryHealth = (byte)health;
- mHistoryCur.batteryPlugType = (byte)plugType;
- mHistoryCur.batteryTemperature = (char)temp;
- mHistoryCur.batteryVoltage = (char)volt;
- setOnBattery(onBattery, oldStatus, level);
- } else {
- boolean changed = false;
- if (mHistoryCur.batteryLevel != level) {
- mHistoryCur.batteryLevel = (byte)level;
- changed = true;
+ if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
+ // We don't record history while we are plugged in and fully charged.
+ // The next time we are unplugged, history will be cleared.
+ mRecordingHistory = false;
}
- if (mHistoryCur.batteryStatus != status) {
- mHistoryCur.batteryStatus = (byte)status;
- changed = true;
- }
- if (mHistoryCur.batteryHealth != health) {
- mHistoryCur.batteryHealth = (byte)health;
- changed = true;
- }
- if (mHistoryCur.batteryPlugType != plugType) {
- mHistoryCur.batteryPlugType = (byte)plugType;
- changed = true;
- }
- if (temp >= (mHistoryCur.batteryTemperature+10)
- || temp <= (mHistoryCur.batteryTemperature-10)) {
- mHistoryCur.batteryTemperature = (char)temp;
- changed = true;
- }
- if (volt > (mHistoryCur.batteryVoltage+20)
- || volt < (mHistoryCur.batteryVoltage-20)) {
- mHistoryCur.batteryVoltage = (char)volt;
- changed = true;
- }
- if (changed) {
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
- }
- }
- if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
- // We don't record history while we are plugged in and fully charged.
- // The next time we are unplugged, history will be cleared.
- mRecordingHistory = false;
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index a41b348..586ba87 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -43,6 +43,7 @@
import android.view.ViewParent;
import android.view.Window;
import android.widget.AdapterView;
+import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -957,4 +958,60 @@
}
}
}
+
+ private static class HomeView extends FrameLayout {
+ private View mUpView;
+ private View mIconView;
+
+ public HomeView(Context context) {
+ this(context, null);
+ }
+
+ public HomeView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mUpView = findViewById(com.android.internal.R.id.up);
+ mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+ int width = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+ int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
+ measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+ final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+ width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+ height = Math.max(height,
+ iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int vCenter = (b - t) / 2;
+ int width = r - l;
+ if (mUpView.getVisibility() != GONE) {
+ final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+ final int upHeight = mUpView.getMeasuredHeight();
+ final int upWidth = mUpView.getMeasuredWidth();
+ final int upTop = t + vCenter - upHeight / 2;
+ mUpView.layout(l, upTop, l + upWidth, upTop + upHeight);
+ final int upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
+ width -= upOffset;
+ l += upOffset;
+ }
+ final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+ final int iconHeight = mIconView.getMeasuredHeight();
+ final int iconWidth = mIconView.getMeasuredWidth();
+ final int hCenter = (r - l) / 2;
+ final int iconLeft = l + iconLp.leftMargin + hCenter - iconWidth / 2;
+ final int iconTop = t + iconLp.topMargin + vCenter - iconHeight / 2;
+ mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 5ac903d..076a1cb 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -23,6 +23,7 @@
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
import android.view.InputDevice;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -97,7 +98,8 @@
public PointerLocationView(Context c) {
super(c);
- setFocusable(true);
+ setFocusableInTouchMode(true);
+
mVC = ViewConfiguration.get(c);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
@@ -505,22 +507,69 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
addPointerEvent(event);
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) {
+ requestFocus();
+ }
return true;
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
- if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ final int source = event.getSource();
+ if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
addPointerEvent(event);
+ } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+ Log.i(TAG, "Joystick: " + event);
+ } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) {
+ Log.i(TAG, "Position: " + event);
+ } else {
+ Log.i(TAG, "Generic: " + event);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (shouldLogKey(keyCode)) {
+ final int repeatCount = event.getRepeatCount();
+ if (repeatCount == 0) {
+ Log.i(TAG, "Key Down: " + event);
+ } else {
+ Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event);
+ }
return true;
}
- return super.onGenericMotionEvent(event);
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (shouldLogKey(keyCode)) {
+ Log.i(TAG, "Key Up: " + event);
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ private static boolean shouldLogKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ return true;
+ default:
+ return KeyEvent.isGamepadButton(keyCode)
+ || KeyEvent.isModifierKey(keyCode);
+ }
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
Log.i(TAG, "Trackball: " + event);
- return super.onTrackballEvent(event);
+ return true;
}
// HACK
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
index d6f2e1a..288865f 100644
--- a/core/java/com/android/internal/widget/WaveView.java
+++ b/core/java/com/android/internal/widget/WaveView.java
@@ -40,7 +40,7 @@
public class WaveView extends View implements ValueAnimator.AnimatorUpdateListener {
private static final String TAG = "WaveView";
private static final boolean DBG = false;
- private static final int WAVE_COUNT = 5; // default wave count
+ private static final int WAVE_COUNT = 20; // default wave count
private static final long VIBRATE_SHORT = 20; // msec
private static final long VIBRATE_LONG = 20; // msec
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2ed938a..1c4dc29 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -124,6 +124,7 @@
android_hardware_Camera.cpp \
android_hardware_SensorManager.cpp \
android_hardware_UsbDevice.cpp \
+ android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
android_debug_JNITest.cpp \
android_util_FileObserver.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 878af3d..0e071a4 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -78,6 +78,7 @@
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
+extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
extern int register_android_media_AudioRecord(JNIEnv *env);
@@ -1274,6 +1275,7 @@
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_SensorManager),
REG_JNI(register_android_hardware_UsbDevice),
+ REG_JNI(register_android_hardware_UsbDeviceConnection),
REG_JNI(register_android_hardware_UsbRequest),
REG_JNI(register_android_media_AudioRecord),
REG_JNI(register_android_media_AudioSystem),
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index f89967b..ee3e209 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -91,7 +91,7 @@
return nullObjectReturn("decoder->buildTileIndex returned false");
}
- SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
+ SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, stream, width, height);
return GraphicsJNI::createBitmapRegionDecoder(env, bm);
}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 88de94f..c4e5878 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
#include <android_runtime/AndroidRuntime.h>
@@ -64,6 +65,15 @@
return surfaceTexture;
}
+sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
+ JNIEnv* env, jobject thiz)
+{
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+ sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ?
+ new SurfaceTextureClient(surfaceTexture) : NULL);
+ return surfaceTextureClient;
+}
+
// ----------------------------------------------------------------------------
class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index b01820c..c2950ea 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -24,190 +24,8 @@
#include <usbhost/usbhost.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
using namespace android;
-static jfieldID field_context;
-
-struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice)
-{
- return (struct usb_device*)env->GetIntField(javaDevice, field_context);
-}
-
-// in android_hardware_UsbEndpoint.cpp
-extern struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint);
-
-static jboolean
-android_hardware_UsbDevice_open(JNIEnv *env, jobject thiz, jstring deviceName,
- jobject fileDescriptor)
-{
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
- // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
- fd = dup(fd);
- if (fd < 0)
- return false;
-
- const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
- struct usb_device* device = usb_device_new(deviceNameStr, fd);
- if (device) {
- env->SetIntField(thiz, field_context, (int)device);
- } else {
- LOGE("usb_device_open failed for %s", deviceNameStr);
- close(fd);
- }
-
- env->ReleaseStringUTFChars(deviceName, deviceNameStr);
- return (device != NULL);
-}
-
-static void
-android_hardware_UsbDevice_close(JNIEnv *env, jobject thiz)
-{
- LOGD("close\n");
- struct usb_device* device = get_device_from_object(env, thiz);
- if (device) {
- usb_device_close(device);
- env->SetIntField(thiz, field_context, 0);
- }
-}
-
-static jint
-android_hardware_UsbDevice_get_fd(JNIEnv *env, jobject thiz)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_get_fd");
- return -1;
- }
- return usb_device_get_fd(device);
-}
-
-static jboolean
-android_hardware_UsbDevice_claim_interface(JNIEnv *env, jobject thiz, int interfaceID, jboolean force)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_claim_interface");
- return -1;
- }
-
- int ret = usb_device_claim_interface(device, interfaceID);
- if (ret && force && errno == EBUSY) {
- // disconnect kernel driver and try again
- usb_device_connect_kernel_driver(device, interfaceID, false);
- ret = usb_device_claim_interface(device, interfaceID);
- }
- return ret == 0;
-}
-
-static jint
-android_hardware_UsbDevice_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_release_interface");
- return -1;
- }
- int ret = usb_device_release_interface(device, interfaceID);
- if (ret == 0) {
- // allow kernel to reconnect its driver
- usb_device_connect_kernel_driver(device, interfaceID, true);
- }
- return ret;
-}
-
-static jint
-android_hardware_UsbDevice_control_request(JNIEnv *env, jobject thiz,
- jint requestType, jint request, jint value, jint index,
- jbyteArray buffer, jint length, jint timeout)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_control_request");
- return -1;
- }
-
- jbyte* bufferBytes = NULL;
- if (buffer) {
- if (env->GetArrayLength(buffer) < length) {
- env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
- return -1;
- }
- bufferBytes = env->GetByteArrayElements(buffer, 0);
- }
-
- jint result = usb_device_control_transfer(device, requestType, request,
- value, index, bufferBytes, length, timeout);
-
- if (bufferBytes)
- env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
-
- return result;
-}
-
-static jint
-android_hardware_UsbDevice_bulk_request(JNIEnv *env, jobject thiz,
- jint endpoint, jbyteArray buffer, jint length, jint timeout)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_control_request");
- return -1;
- }
-
- jbyte* bufferBytes = NULL;
- if (buffer) {
- if (env->GetArrayLength(buffer) < length) {
- env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
- return -1;
- }
- bufferBytes = env->GetByteArrayElements(buffer, 0);
- }
-
- jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
-
- if (bufferBytes)
- env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
-
- return result;
-}
-
-static jobject
-android_hardware_UsbDevice_request_wait(JNIEnv *env, jobject thiz)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_request_wait");
- return NULL;
- }
-
- struct usb_request* request = usb_request_wait(device);
- if (request)
- return (jobject)request->client_data;
- else
- return NULL;
-}
-
-static jstring
-android_hardware_UsbDevice_get_serial(JNIEnv *env, jobject thiz)
-{
- struct usb_device* device = get_device_from_object(env, thiz);
- if (!device) {
- LOGE("device is closed in native_request_wait");
- return NULL;
- }
- char* serial = usb_device_get_serial(device);
- if (!serial)
- return NULL;
- jstring result = env->NewStringUTF(serial);
- free(serial);
- return result;
-}
-
static jint
android_hardware_UsbDevice_get_device_id(JNIEnv *env, jobject clazz, jstring name)
{
@@ -227,21 +45,6 @@
}
static JNINativeMethod method_table[] = {
- {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
- (void *)android_hardware_UsbDevice_open},
- {"native_close", "()V", (void *)android_hardware_UsbDevice_close},
- {"native_get_fd", "()I", (void *)android_hardware_UsbDevice_get_fd},
- {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDevice_claim_interface},
- {"native_release_interface","(I)Z", (void *)android_hardware_UsbDevice_release_interface},
- {"native_control_request", "(IIII[BII)I",
- (void *)android_hardware_UsbDevice_control_request},
- {"native_bulk_request", "(I[BII)I",
- (void *)android_hardware_UsbDevice_bulk_request},
- {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;",
- (void *)android_hardware_UsbDevice_request_wait},
- { "native_get_serial", "()Ljava/lang/String;",
- (void*)android_hardware_UsbDevice_get_serial },
-
// static methods
{ "native_get_device_id", "(Ljava/lang/String;)I",
(void*)android_hardware_UsbDevice_get_device_id },
@@ -256,11 +59,6 @@
LOGE("Can't find android/hardware/usb/UsbDevice");
return -1;
}
- field_context = env->GetFieldID(clazz, "mNativeContext", "I");
- if (field_context == NULL) {
- LOGE("Can't find UsbDevice.mNativeContext");
- return -1;
- }
return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
method_table, NELEM(method_table));
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
new file mode 100644
index 0000000..ec36a38
--- /dev/null
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define LOG_TAG "UsbDeviceConnectionJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <usbhost/usbhost.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+struct usb_device* get_device_from_object(JNIEnv* env, jobject connection)
+{
+ return (struct usb_device*)env->GetIntField(connection, field_context);
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
+ jobject fileDescriptor)
+{
+ int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+ fd = dup(fd);
+ if (fd < 0)
+ return false;
+
+ const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
+ struct usb_device* device = usb_device_new(deviceNameStr, fd);
+ if (device) {
+ env->SetIntField(thiz, field_context, (int)device);
+ } else {
+ LOGE("usb_device_open failed for %s", deviceNameStr);
+ close(fd);
+ }
+
+ env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+ return (device != NULL);
+}
+
+static void
+android_hardware_UsbDeviceConnection_close(JNIEnv *env, jobject thiz)
+{
+ LOGD("close\n");
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (device) {
+ usb_device_close(device);
+ env->SetIntField(thiz, field_context, 0);
+ }
+}
+
+static jint
+android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_get_fd");
+ return -1;
+ }
+ return usb_device_get_fd(device);
+}
+
+static jboolean
+android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
+ int interfaceID, jboolean force)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_claim_interface");
+ return -1;
+ }
+
+ int ret = usb_device_claim_interface(device, interfaceID);
+ if (ret && force && errno == EBUSY) {
+ // disconnect kernel driver and try again
+ usb_device_connect_kernel_driver(device, interfaceID, false);
+ ret = usb_device_claim_interface(device, interfaceID);
+ }
+ return ret == 0;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_release_interface");
+ return -1;
+ }
+ int ret = usb_device_release_interface(device, interfaceID);
+ if (ret == 0) {
+ // allow kernel to reconnect its driver
+ usb_device_connect_kernel_driver(device, interfaceID, true);
+ }
+ return ret;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
+ jint requestType, jint request, jint value, jint index,
+ jbyteArray buffer, jint length, jint timeout)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_control_request");
+ return -1;
+ }
+
+ jbyte* bufferBytes = NULL;
+ if (buffer) {
+ if (env->GetArrayLength(buffer) < length) {
+ env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
+ return -1;
+ }
+ bufferBytes = env->GetByteArrayElements(buffer, 0);
+ }
+
+ jint result = usb_device_control_transfer(device, requestType, request,
+ value, index, bufferBytes, length, timeout);
+
+ if (bufferBytes)
+ env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+
+ return result;
+}
+
+static jint
+android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
+ jint endpoint, jbyteArray buffer, jint length, jint timeout)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_control_request");
+ return -1;
+ }
+
+ jbyte* bufferBytes = NULL;
+ if (buffer) {
+ if (env->GetArrayLength(buffer) < length) {
+ env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL);
+ return -1;
+ }
+ bufferBytes = env->GetByteArrayElements(buffer, 0);
+ }
+
+ jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
+
+ if (bufferBytes)
+ env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+
+ return result;
+}
+
+static jobject
+android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_request_wait");
+ return NULL;
+ }
+
+ struct usb_request* request = usb_request_wait(device);
+ if (request)
+ return (jobject)request->client_data;
+ else
+ return NULL;
+}
+
+static jstring
+android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
+{
+ struct usb_device* device = get_device_from_object(env, thiz);
+ if (!device) {
+ LOGE("device is closed in native_request_wait");
+ return NULL;
+ }
+ char* serial = usb_device_get_serial(device);
+ if (!serial)
+ return NULL;
+ jstring result = env->NewStringUTF(serial);
+ free(serial);
+ return result;
+}
+
+static JNINativeMethod method_table[] = {
+ {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
+ (void *)android_hardware_UsbDeviceConnection_open},
+ {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close},
+ {"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd},
+ {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
+ {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
+ {"native_control_request", "(IIII[BII)I",
+ (void *)android_hardware_UsbDeviceConnection_control_request},
+ {"native_bulk_request", "(I[BII)I",
+ (void *)android_hardware_UsbDeviceConnection_bulk_request},
+ {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;",
+ (void *)android_hardware_UsbDeviceConnection_request_wait},
+ { "native_get_serial", "()Ljava/lang/String;",
+ (void*)android_hardware_UsbDeviceConnection_get_serial },
+};
+
+int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection");
+ if (clazz == NULL) {
+ LOGE("Can't find android/hardware/usb/UsbDeviceConnection");
+ return -1;
+ }
+ field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_context == NULL) {
+ LOGE("Can't find UsbDeviceConnection.mNativeContext");
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection",
+ method_table, NELEM(method_table));
+}
+
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index b497adb..6bd67d1 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -35,8 +35,8 @@
return (struct usb_request*)env->GetIntField(java_request, field_context);
}
-// in android_hardware_UsbDevice.cpp
-extern struct usb_device* get_device_from_object(JNIEnv* env, jobject java_device);
+// in android_hardware_UsbDeviceConnection.cpp
+extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection);
static jboolean
android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device,
@@ -107,7 +107,7 @@
}
return false;
} else {
- // save a reference to ourselves so UsbDevice.waitRequest() can find us
+ // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
request->client_data = (void *)env->NewGlobalRef(thiz);
return true;
}
@@ -155,7 +155,7 @@
request->buffer = NULL;
return false;
} else {
- // save a reference to ourselves so UsbDevice.waitRequest() can find us
+ // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
// we also need this to make sure our native buffer is not deallocated
// while IO is active
request->client_data = (void *)env->NewGlobalRef(thiz);
@@ -187,7 +187,7 @@
}
static JNINativeMethod method_table[] = {
- {"native_init", "(Landroid/hardware/usb/UsbDevice;IIII)Z",
+ {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
(void *)android_hardware_UsbRequest_init},
{"native_close", "()V", (void *)android_hardware_UsbRequest_close},
{"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f78f83c..b6619ab 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -315,7 +315,11 @@
}
// get the pointer to where we'll record the audio
- recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
if (recordBuff == NULL) {
LOGE("Error retrieving destination for recorded audio data, can't record");
@@ -327,7 +331,7 @@
ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes,
sizeInBytes > (jint)recorderBuffSize ?
(jint)recorderBuffSize : sizeInBytes );
- env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
+ env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
return (jint) readSize;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 8409adc..44d2a52 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -530,8 +530,12 @@
}
// get the pointer for the audio data from the java array
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
if (javaAudioData) {
- cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+ cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
if (cAudioData == NULL) {
LOGE("Error retrieving source of audio data to play, can't play");
return 0; // out of memory or no data to load
@@ -543,7 +547,7 @@
jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
- env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
+ env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
//LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
// (int)written, (int)(sizeInBytes), (int)offsetInBytes);
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index a46c2dd..5cfb9b1 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -20,7 +20,7 @@
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <hardware_legacy/power.h>
-#include <sys/reboot.h>
+#include <cutils/android_reboot.h>
namespace android
{
@@ -77,25 +77,26 @@
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
{
- sync();
#ifdef HAVE_ANDROID_OS
- reboot(RB_POWER_OFF);
+ android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+#else
+ sync();
#endif
}
static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
{
- sync();
#ifdef HAVE_ANDROID_OS
if (reason == NULL) {
- reboot(RB_AUTOBOOT);
+ android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
const char *chars = env->GetStringUTFChars(reason, NULL);
- __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, (char*) chars);
+ android_reboot(ANDROID_RB_RESTART2, 0, (char *) chars);
env->ReleaseStringUTFChars(reason, chars); // In case it fails.
}
jniThrowIOException(env, errno);
+#else
+ sync();
#endif
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0ad174f..c684e7e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1379,12 +1379,6 @@
android:excludeFromRecents="true">
</activity>
- <activity android:name="com.android.server.usb.UsbResolverActivity"
- android:theme="@style/Theme.Holo.Dialog.Alert"
- android:finishOnCloseSystemDialogs="true"
- android:excludeFromRecents="true">
- </activity>
-
<service android:name="com.android.server.LoadAverageService"
android:exported="true" />
diff --git a/core/res/res/drawable-hdpi/ic_media_embed_play.png b/core/res/res/drawable-hdpi/ic_media_embed_play.png
new file mode 100644
index 0000000..e67ec80
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_fullscreen.png b/core/res/res/drawable-hdpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..3f26e45
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_paste_bubble_holo_disabled.png b/core/res/res/drawable-hdpi/ic_paste_bubble_holo_disabled.png
new file mode 100644
index 0000000..15bd8b2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_paste_bubble_holo_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
index 9646e63..62e3274 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
index 8c8e56a..b7512fa 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
index b9407ba..bfc6f83 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
index 0090124..708ba90 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
index 16b75c6..0da1e9c 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
index 472c564..2e93557 100644
--- a/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
index d097577..7aeaad6 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
index f36cad8..cf46f32 100644
--- a/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_embed_play.png b/core/res/res/drawable-ldpi/ic_media_embed_play.png
new file mode 100644
index 0000000..e7c1972
--- /dev/null
+++ b/core/res/res/drawable-ldpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_fullscreen.png b/core/res/res/drawable-ldpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..1a38c38
--- /dev/null
+++ b/core/res/res/drawable-ldpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_embed_play.png b/core/res/res/drawable-mdpi/ic_media_embed_play.png
new file mode 100644
index 0000000..41cd65f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_embed_play.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_fullscreen.png b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
new file mode 100644
index 0000000..24fb6d6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_media_fullscreen.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_paste_bubble_holo_disabled.png b/core/res/res/drawable-mdpi/ic_paste_bubble_holo_disabled.png
new file mode 100644
index 0000000..e483e84
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_paste_bubble_holo_disabled.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
index b9435b6..ae77fa0 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
index 477d820..c6bdfcc 100644
--- a/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/text_cursor_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
index 9646e63..b7413b3 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
index 8c8e56a..82e7a03 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
index b9407ba..4b0ea21 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
index 0090124..e87591c 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
index 16b75c6..14f69b1 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
index 472c564..85329ca 100644
--- a/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_right_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
index d097577..7e130d9 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
index f36cad8..050d1c0 100644
--- a/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/layout/action_bar_home.xml b/core/res/res/layout/action_bar_home.xml
index 7867577..c82f91d 100644
--- a/core/res/res/layout/action_bar_home.xml
+++ b/core/res/res/layout/action_bar_home.xml
@@ -14,14 +14,14 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="?android:attr/selectableItemBackground"
- android:orientation="horizontal">
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.internal.widget.ActionBarView$HomeView"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground" >
<ImageView android:id="@android:id/up"
android:src="?android:attr/homeAsUpIndicator"
- android:layout_gravity="top|left"
+ android:layout_gravity="center_vertical|left"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -33,4 +33,4 @@
android:paddingRight="16dip"
android:layout_gravity="center"
android:scaleType="center" />
-</LinearLayout>
+</view>
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 93b6deb..c52b73f 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -54,6 +54,10 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
+ android:layout_marginLeft="4dip"
+ android:layout_marginRight="4dip"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
android:orientation="horizontal">
<!-- Inner layout contains the app icon, button(s) and EditText -->
diff --git a/core/res/res/layout/text_edit_no_paste_window.xml b/core/res/res/layout/text_edit_no_paste_window.xml
index fa50275..f804986 100644
--- a/core/res/res/layout/text_edit_no_paste_window.xml
+++ b/core/res/res/layout/text_edit_no_paste_window.xml
@@ -25,7 +25,7 @@
android:paddingRight="16dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:drawableLeft="@android:drawable/ic_menu_paste_dark"
+ android:drawableLeft="@android:drawable/ic_paste_bubble_holo_disabled"
android:drawablePadding="8dip"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/layout/text_edit_side_no_paste_window.xml b/core/res/res/layout/text_edit_side_no_paste_window.xml
index 0ed3849..903bcb6 100644
--- a/core/res/res/layout/text_edit_side_no_paste_window.xml
+++ b/core/res/res/layout/text_edit_side_no_paste_window.xml
@@ -25,7 +25,7 @@
android:paddingRight="16dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:drawableLeft="@android:drawable/ic_menu_paste_dark"
+ android:drawableLeft="@android:drawable/ic_paste_bubble_holo_disabled"
android:drawablePadding="8dip"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..002be41
--- /dev/null
+++ b/core/res/res/raw-ar-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>نافذة جديدة للتصفح المتخفي</title>
+ </head>
+ <body>
+ <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
+
+ <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
+
+ <ul>
+ <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
+ <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
+ <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
+ <li>المراقبة من قبل العملاء السريين</li>
+ <li>الأشخاص الذين يقفون خلفك</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ar/incognito_mode_start_page.html b/core/res/res/raw-ar/incognito_mode_start_page.html
new file mode 100644
index 0000000..002be41
--- /dev/null
+++ b/core/res/res/raw-ar/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>نافذة جديدة للتصفح المتخفي</title>
+ </head>
+ <body>
+ <p><strong>أنت الآن في وضع التصفح المتخفي</strong> الصفحات التي تشاهدها في هذه النافذة لن تظهر في سجل المتصفح أو سجلّ البحث، ولن تترك آثارًا أخرى للتتبع، مثل ملفات تعريف الارتباط على جهازك بعد أن تغلق نافذة التصفح المتخفي. ورغم ذلك، سيتم الاحتفاظ بأي ملفات تنزلها أو أية إشارات مرجعية تقوم بإنشائها.</p>
+
+ <p><strong>العمل في وضع التصفح المخفي لا يؤثر على طريقة عمل الأشخاص الآخرين أو الخوادم أو البرامج الأخرى. كن على حذر مما يلي:</strong></p>
+
+ <ul>
+ <li>مواقع الويب التي تجمع معلومات عنك أو تشارك الآخرين فيها</li>
+ <li>مزوّدو خدمة الإنترنت أو الموظفون الذين يتتبعون الصفحات التي تزورها</li>
+ <li>البرامج الضارة التي تتبع ضغطات المفاتيح التي تقوم بها مقابل تنزيل وجوه رمزية مجانًا</li>
+ <li>المراقبة من قبل العملاء السريين</li>
+ <li>الأشخاص الذين يقفون خلفك</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html b/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..ee25ae4
--- /dev/null
+++ b/core/res/res/raw-bg-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нов прозорец „инкогнито“</title>
+ </head>
+ <body>
+ <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
+
+ <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
+
+ <ul>
+ <li>уебсайтове, които събират или споделят информация за вас;</li>
+ <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
+ <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
+ <li>наблюдение от тайните служби;</li>
+ <li>хора, които стоят зад вас.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-bg/incognito_mode_start_page.html b/core/res/res/raw-bg/incognito_mode_start_page.html
new file mode 100644
index 0000000..ee25ae4
--- /dev/null
+++ b/core/res/res/raw-bg/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нов прозорец „инкогнито“</title>
+ </head>
+ <body>
+ <p><strong>Влязохте в режим „инкогнито“</strong>. Страниците, които разглеждате в този прозорец, няма да се показват в историята на браузъра ви, нито в историята на търсенията ви. Те също няма да оставят други следи като „бисквитки“ в устройството ви, след като затворите прозореца в режим „инкогнито“. Ще се съхранят обаче всички файлове, които изтеглите, или отметки, които създадете.</p>
+
+ <p><strong>Преминаването в режим „инкогнито“ не засяга поведението на други хора, сървъри или софтуер. </strong>Внимавайте за:</p>
+
+ <ul>
+ <li>уебсайтове, които събират или споделят информация за вас;</li>
+ <li>доставчици на интернет услуги или служители, които проследяват посещаваните от вас страници;</li>
+ <li>злонамерен софтуер, който ви дава безплатни емотикони, но в замяна проследява натисканията на клавишите от вас;</li>
+ <li>наблюдение от тайните служби;</li>
+ <li>хора, които стоят зад вас.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..bec3dac
--- /dev/null
+++ b/core/res/res/raw-ca-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova finestra d'incògnit</title>
+ </head>
+ <body>
+ <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
+
+ <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
+
+ <ul>
+ <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
+ <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
+ <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
+ <li>vigilància per part d'agents secrets,</li>
+ <li>persones que estan darrere teu.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ca/incognito_mode_start_page.html b/core/res/res/raw-ca/incognito_mode_start_page.html
new file mode 100644
index 0000000..bec3dac
--- /dev/null
+++ b/core/res/res/raw-ca/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova finestra d'incògnit</title>
+ </head>
+ <body>
+ <p><strong>Has passat a l'estat d'incògnit</strong>. Les pàgines que visualitzis en aquesta finestra no apareixeran a l'historial del navegador ni a l'historial de cerques, i no deixaran cap pista, com ara galetes, al dispositiu després de tancar la finestra d'incògnit. Tanmateix, es conservaran tots els fitxers que baixis o les adreces d'interès que creïs.</p>
+
+ <p><strong>Utilitzar el mode d'incògnit no afecta el comportament d'altres usuaris, servidors ni programari. Vés amb compte amb:</strong></p>
+
+ <ul>
+ <li>llocs web que recopilen o comparteixen informació sobre la teva identitat,</li>
+ <li>proveïdors de serveis d'Internet o treballadors que segueixen les pàgines que visites,</li>
+ <li>programari maliciós que segueix les teves pulsacions del teclat a canvi d'emoticones,</li>
+ <li>vigilància per part d'agents secrets,</li>
+ <li>persones que estan darrere teu.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html b/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..7420393
--- /dev/null
+++ b/core/res/res/raw-cs-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nové anonymní okno</title>
+ </head>
+ <body>
+ <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
+
+ <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
+
+ <ul>
+ <li>Weby, které sbírají nebo sdílejí informace o vás</li>
+ <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
+ <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
+ <li>Tajné agenty</li>
+ <li>Lidi, kteří vám koukají přes rameno</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-cs/incognito_mode_start_page.html b/core/res/res/raw-cs/incognito_mode_start_page.html
new file mode 100644
index 0000000..7420393
--- /dev/null
+++ b/core/res/res/raw-cs/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nové anonymní okno</title>
+ </head>
+ <body>
+ <p><strong>Spustili jste anonymní režim</strong>. Stránky, které zobrazíte v tomto okně, se nezahrnou do historie prohlížeče ani historie vyhledávání a dokonce po zavření tohoto anonymního okna ve vašem zařízení nezanechají ani žádné jiné stopy například v podobě souborů cookie. Veškeré stažené soubory nebo vytvořené záložky však budou zachovány.</p>
+
+ <p><strong>Použití anonymního režimu nemá vliv na chování jiných osob, serverů nebo softwaru. Dejte si pozor na:</strong></p>
+
+ <ul>
+ <li>Weby, které sbírají nebo sdílejí informace o vás</li>
+ <li>Poskytovatele internetových služeb nebo zaměstnavatele, kteří sledují stránky, které navštěvujete</li>
+ <li>Škodlivý software, který sleduje stisknuté klávesy a výměnou nabízí nové emotikony</li>
+ <li>Tajné agenty</li>
+ <li>Lidi, kteří vám koukají přes rameno</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-da-xlarge/incognito_mode_start_page.html b/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..eae989f
--- /dev/null
+++ b/core/res/res/raw-da-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nyt inkognitovindue</title>
+ </head>
+ <body>
+ <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
+
+ <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
+
+ <ul>
+ <li>Websider, der indsamler eller deler oplysninger om dig</li>
+ <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
+ <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
+ <li>Overvågning af hemmelige agenter</li>
+ <li>Folk, der kigger dig over skulderen</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-da/incognito_mode_start_page.html b/core/res/res/raw-da/incognito_mode_start_page.html
new file mode 100644
index 0000000..eae989f
--- /dev/null
+++ b/core/res/res/raw-da/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nyt inkognitovindue</title>
+ </head>
+ <body>
+ <p><strong>Nu er du inkognito</strong>. De sider, du besøger i dette vindue, vises ikke i din browser- eller søgeoversigt, og de efterlader ikke andre spor, såsom cookies, på din enhed, når du lukker incognitovinduet. Filer, som du downloader eller bogmærker, som du opretter, gemmes dog.</p>
+
+ <p><strong>At være inkognito er ikke noget, der påvirker andre folk, servere eller software. Vær opmærksom på:</strong></p>
+
+ <ul>
+ <li>Websider, der indsamler eller deler oplysninger om dig</li>
+ <li>Internetserviceudbydere eller arbejdsgivere, der registrerer de sider, du besøger</li>
+ <li>Ondsindet software, der registrerer dine tasteslag til gengæld for gratis smileys</li>
+ <li>Overvågning af hemmelige agenter</li>
+ <li>Folk, der kigger dig over skulderen</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-de-xlarge/incognito_mode_start_page.html b/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..1d2cb69
--- /dev/null
+++ b/core/res/res/raw-de-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Neues Inkognito-Fenster</title>
+ </head>
+ <body>
+ <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
+
+ <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
+
+ <ul>
+ <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
+ <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
+ <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
+ <li>Geheimagenten</li>
+ <li>Personen, die hinter Ihnen stehen</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-de/incognito_mode_start_page.html b/core/res/res/raw-de/incognito_mode_start_page.html
new file mode 100644
index 0000000..1d2cb69
--- /dev/null
+++ b/core/res/res/raw-de/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Neues Inkognito-Fenster</title>
+ </head>
+ <body>
+ <p><strong>Sie haben den Modus für anonymes Browsen aktiviert</strong>. In diesem Fenster aufgerufene Seiten erscheinen nicht in Ihrem Browser- oder Suchverlauf. Zudem werden nach dem Schließen des Inkognito-Fensters keine anderen Spuren wie etwa Cookies auf Ihrem Gerät gespeichert. Heruntergeladene Dateien oder hinzugefügte Lesezeichen werden jedoch beibehalten.</p>
+
+ <p><strong>Das anonyme Browsen wirkt sich nicht auf das Verhalten von Menschen, Servern oder Software aus. </strong>Vorsicht ist geboten bei:</p>
+
+ <ul>
+ <li>Websites, auf denen Informationen über Sie gesammelt oder weitergegeben werden</li>
+ <li>Internetanbietern oder Arbeitgebern, die die von Ihnen aufgerufenen Seiten protokollieren</li>
+ <li>Bösartiger Software, die Ihnen kostenlose Smileys bietet, dafür aber Ihre Tastatureingaben speichert</li>
+ <li>Geheimagenten</li>
+ <li>Personen, die hinter Ihnen stehen</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-el-xlarge/incognito_mode_start_page.html b/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5641650
--- /dev/null
+++ b/core/res/res/raw-el-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
+ </head>
+ <body>
+ <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
+
+ <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
+
+ <ul>
+ <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
+ <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
+ <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
+ <li>Παρακολούθηση από μυστικούς πράκτορες</li>
+ <li>Άτομα που στέκονται πίσω σας</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-el/incognito_mode_start_page.html b/core/res/res/raw-el/incognito_mode_start_page.html
new file mode 100644
index 0000000..5641650
--- /dev/null
+++ b/core/res/res/raw-el/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Νέο παράθυρο για ανώνυμη περιήγηση</title>
+ </head>
+ <body>
+ <p><strong>Είστε σε κατάσταση ανώνυμης περιήγησης</strong>. Οι σελίδες που θα προβάλλετε σε αυτό το παράθυρο δεν θα εμφανιστούν στο ιστορικό του πρόγράμματος περιήγησης ή στο ιστορικό αναζήτησης. Επίσης, δεν θα αφήσουν ίχνη, όπως cookie, στη συσκευή σας αφού κλείσετε το παράθυρο ανώνυμης περιήγησης. Ωστόσο, τα αρχεία και οι σελιδοδείκτες που θα δημιουργήσετε θα διατηρηθούν.</p>
+
+ <p><strong>Η κατάσταση ανώνυμης περιήγησης δεν επηρεάζει την συμπεριφορά άλλων, διακομιστών ή λογισμικού. Αλλά προσοχή σε:</strong></p>
+
+ <ul>
+ <li>Ιστοτόπους που συλλέγουν ή μοιράζονται πληροφορίες για εσάς</li>
+ <li>Πάροχους υπηρεσιών διαδικτύου ή εργοδότες που παρακολουθούν τις ιστοσελίδες που επισκέπτεστε</li>
+ <li>Κακόβουλο λογισμικό που καταγράφει ότι πληκτρολογείτε με αντάλλαγμα δωρεάν "φατσούλες"</li>
+ <li>Παρακολούθηση από μυστικούς πράκτορες</li>
+ <li>Άτομα που στέκονται πίσω σας</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html b/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..7436f98
--- /dev/null
+++ b/core/res/res/raw-en-rGB-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>New incognito window</title>
+ </head>
+ <body>
+ <p><strong>You've gone incognito</strong>. Pages that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
+
+ <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
+
+ <ul>
+ <li>Websites that collect or share information about you</li>
+ <li>Internet service providers or employers that track the pages that you visit</li>
+ <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+ <li>Surveillance by secret agents</li>
+ <li>People standing behind you</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-en-rGB/incognito_mode_start_page.html b/core/res/res/raw-en-rGB/incognito_mode_start_page.html
new file mode 100644
index 0000000..7436f98
--- /dev/null
+++ b/core/res/res/raw-en-rGB/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>New incognito window</title>
+ </head>
+ <body>
+ <p><strong>You've gone incognito</strong>. Pages that you view in this window won't appear in your browser history or search history, and they won't leave other traces, such as cookies, on your device after you close the incognito window. However, any files that you download or bookmarks that you create will be preserved.</p>
+
+ <p><strong>Going incognito doesn't affect the behaviour of other people, servers or software. Be cautious of:</strong></p>
+
+ <ul>
+ <li>Websites that collect or share information about you</li>
+ <li>Internet service providers or employers that track the pages that you visit</li>
+ <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+ <li>Surveillance by secret agents</li>
+ <li>People standing behind you</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..d283df5
--- /dev/null
+++ b/core/res/res/raw-es-rUS-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nueva ventana de incógnito</title>
+ </head>
+ <body>
+ <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
+
+ <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
+
+ <ul>
+ <li>Sitios web que recaban o comparten tu información</li>
+ <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
+ <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
+ <li>Vigilancia a cargo de agentes secretos</li>
+ <li>Personas paradas atrás tuyo</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-es-rUS/incognito_mode_start_page.html b/core/res/res/raw-es-rUS/incognito_mode_start_page.html
new file mode 100644
index 0000000..d283df5
--- /dev/null
+++ b/core/res/res/raw-es-rUS/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nueva ventana de incógnito</title>
+ </head>
+ <body>
+ <p><strong>Estás de incógnito</strong>. Las páginas que veas en esta ventana no aparecerán en el historial de tu navegador ni en el historial de búsquedas, y cuando cierres la ventana de incógnito, tampoco quedará ningún otro rastro, como cookies, en tu dispositivo. Sin embargo, sí se preservarán los archivos que descargues o los favoritos que marques.</p>
+
+ <p><strong>Estar de incógnito no afecta el comportamiento de otras personas, servidores o programas. Ten cuidado con:</strong></p>
+
+ <ul>
+ <li>Sitios web que recaban o comparten tu información</li>
+ <li>Proveedores de servicio de Internet o empleadores que hacen un seguimiento de las páginas que visitas</li>
+ <li>Programas de software maliciosos que hacen un seguimiento de la actividad de tu teclado a cambio de emoticones gratuitos</li>
+ <li>Vigilancia a cargo de agentes secretos</li>
+ <li>Personas paradas atrás tuyo</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-es-xlarge/incognito_mode_start_page.html b/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6d9b501
--- /dev/null
+++ b/core/res/res/raw-es-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nueva ventana de incógnito</title>
+ </head>
+ <body>
+ <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
+
+ <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
+
+ <ul>
+ <li>sitios web que recopilan o comparten información personal</li>
+ <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
+ <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
+ <li>actividades de seguimiento por parte de terceros</li>
+ <li>personas merodeando cerca de tu ordenador</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-es/incognito_mode_start_page.html b/core/res/res/raw-es/incognito_mode_start_page.html
index 43fd37f..6d9b501 100644
--- a/core/res/res/raw-es/incognito_mode_start_page.html
+++ b/core/res/res/raw-es/incognito_mode_start_page.html
@@ -1,26 +1,19 @@
-<html>
+<html DIR="LTR">
<head>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<title>Nueva ventana de incógnito</title>
</head>
<body>
- <p><strong>Has entrado en el modo "Navegar de incógnito"</strong>. Las páginas
- que consultes a través de esta ventana no quedarán registradas en el historial del navegador
- ni en el historial de búsquedas, y tampoco dejarán otros rastros en el equipo (como cookies)
- una vez cerrada. Aunque sí quedarán almacenados los archivos que descargues y los marcadores
- que guardes durante la sesión.</p>
+ <p><strong>Estás navegando de incógnito</strong>. Las páginas que consultes a través de esta ventana no quedarán registradas en el historial del navegador ni en el historial de búsquedas, y tampoco dejarán otros rastros en el ordenador (como cookies) una vez cerrada. Los archivos que descargues y los marcadores que guardes sí se almacenarán. </p>
- <p><strong>La función "Navegar de incógnito" no afecta al comportamiento de
- otros usuarios, servidores o programas. Atención con:</strong></p>
+ <p><strong>La función de navegación de incógnito no afecta al comportamiento de los servidores o programas de software. Ten cuidado con:</strong></p>
<ul>
- <li>sitios web que recopilan o comparten información personal,</li>
- <li>proveedores de servicios de Internet o trabajadores de estas empresas que
- supervisan las páginas que visita el usuario,</li>
- <li>software malicioso que realiza un seguimiento de las teclas que pulsa el usuario a
- cambio de unos emoticones gratuitos,</li>
- <li>el seguimiento por parte de detectives privados,</li>
- <li>personas merodeando cerca de tu equipo.</li>
+ <li>sitios web que recopilan o comparten información personal</li>
+ <li>proveedores de servicios de Internet o trabajadores de estas empresas que supervisan las páginas que visitas</li>
+ <li>software malicioso que realiza un seguimiento de las teclas que pulsas a cambio de emoticonos gratuitos</li>
+ <li>actividades de seguimiento por parte de terceros</li>
+ <li>personas merodeando cerca de tu ordenador</li>
</ul>
</body>
</html>
diff --git a/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f004120
--- /dev/null
+++ b/core/res/res/raw-fa-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>پنجره ناشناس جدید</title>
+ </head>
+ <body>
+ <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
+
+ <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
+
+ <ul>
+ <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
+ <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
+ <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
+ <li>نظارت توسط نمایندگان سری</li>
+ <li>افرادی که پشت سرتان ایستاده اند</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-fa/incognito_mode_start_page.html b/core/res/res/raw-fa/incognito_mode_start_page.html
new file mode 100644
index 0000000..f004120
--- /dev/null
+++ b/core/res/res/raw-fa/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>پنجره ناشناس جدید</title>
+ </head>
+ <body>
+ <p><strong>شما به صورت ناشناس وارد شده اید</strong> صفحاتی که شما در این پنجره مشاهده میکنید در سابقه مرورگر یا سابقه جستجوی شما ظاهر نمیشوند، و پس از بستن پنجره ناشناس، دنباله ای از خود مانند کوکی ها روی دستگاه شما بر جای نمیگذارند. به هر حال، فایل های دانلود شده و نشانکهای صفحه ای که ایجاد کرده اید باقی خواهند ماند.</p>
+
+ <p><strong>وارد شدن به صورت ناشناس، تاثیری بر روی رفتار افراد دیگر، سرورها و یا نرم افزارها ندارد. در خصوص موارد زیر هشیار باشید:</strong></p>
+
+ <ul>
+ <li>وبسایت هایی که اطلاعاتی را در مورد شما جمع آوری کرده و به اشتراک میگذارند</li>
+ <li>تامین کننده های خدمات اینترنتی شما یا کارمندانی که صفحاتی که شما بازدید کرده اید را پیگیری میکنند</li>
+ <li>نرم افزارهای مخربی که در ازای نشانک های رایگان، ضربات کلیدهای شما را ذخیره میکنند</li>
+ <li>نظارت توسط نمایندگان سری</li>
+ <li>افرادی که پشت سرتان ایستاده اند</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..feb9f4f
--- /dev/null
+++ b/core/res/res/raw-fi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Uusi incognito-ikkuna</title>
+ </head>
+ <body>
+ <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
+
+ <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
+
+ <ul>
+ <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
+ <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
+ <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
+ <li>Salaisten agenttien seurantaa</li>
+ <li>Ihmisiä jotka seisovat takanasi</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-fi/incognito_mode_start_page.html b/core/res/res/raw-fi/incognito_mode_start_page.html
new file mode 100644
index 0000000..feb9f4f
--- /dev/null
+++ b/core/res/res/raw-fi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Uusi incognito-ikkuna</title>
+ </head>
+ <body>
+ <p><strong>Olet nyt incognito-tilassa</strong>. Incognito-tilassa katsellut sivut eivät näy selainhistoriassa eikä hakuhistoriassa. Ne eivät myöskään jätä muita jälkiä, kuten evästeitä, sivun sulkemisen jälkeen. Lataamasi tiedostot tai luomasi kirjanmerkit tosin tallentuvat.</p>
+
+ <p><strong>Incognito-tilaan siirtyminen ei vaikuta muiden ihmisten, palvelimien tai tietokoneohjelmien toimintaan. Varo:</strong></p>
+
+ <ul>
+ <li>Verkkosivustoja jotka keräävät sinusta tietoa ja/tai jakavat sitä eteenpäin</li>
+ <li>Internet-palveluntarjoajia ja työnantajia jotka seuraavat sivuja, joilla käyt</li>
+ <li>Haittaohjelmia jotka seuraavat näppäimistön toimintaa ja tarjoavat vastineeksi ilmaisia hymiöitä</li>
+ <li>Salaisten agenttien seurantaa</li>
+ <li>Ihmisiä jotka seisovat takanasi</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..8962cdf
--- /dev/null
+++ b/core/res/res/raw-fr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nouvelle fenêtre de navigation privée</title>
+ </head>
+ <body>
+ <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
+
+ <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
+
+ <ul>
+ <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
+ <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
+ <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
+ <li>Des personnes qui pourraient surveiller vos activités</li>
+ <li>Des personnes qui se tiennent derrière vous</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-fr/incognito_mode_start_page.html b/core/res/res/raw-fr/incognito_mode_start_page.html
new file mode 100644
index 0000000..8962cdf
--- /dev/null
+++ b/core/res/res/raw-fr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nouvelle fenêtre de navigation privée</title>
+ </head>
+ <body>
+ <p><strong>Vous êtes passé en navigation privée</strong>. Les pages que vous consultez dans cette fenêtre n'apparaîtront ni dans l'historique de votre navigateur, ni dans l'historique des recherches, et ne laisseront aucune trace (comme les cookies) sur votre appareil une fois que vous aurez fermé la fenêtre de navigation privée. Tous les fichiers téléchargés et les favoris créés seront toutefois conservés.</p>
+
+ <p><strong>Passer en navigation privée n'a aucun effet sur les autres utilisateurs, serveurs ou logiciels. Méfiez-vous :</strong></p>
+
+ <ul>
+ <li>Des sites Web qui collectent ou partagent des informations vous concernant</li>
+ <li>Des fournisseurs d'accès Internet ou des employeurs qui conservent une trace des pages que vous visitez</li>
+ <li>Des programmes indésirables qui enregistrent vos frappes en échange d'émoticônes gratuites</li>
+ <li>Des personnes qui pourraient surveiller vos activités</li>
+ <li>Des personnes qui se tiennent derrière vous</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f73c41d
--- /dev/null
+++ b/core/res/res/raw-hi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>नई गुप्त विंडो</title>
+ </head>
+ <body>
+ <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
+
+ <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
+
+ <ul>
+ <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
+ <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
+ <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
+ <li>गुप्तचरों द्वारा निगरानी</li>
+ <li>आपके पीछे खड़े लोग</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hi/incognito_mode_start_page.html b/core/res/res/raw-hi/incognito_mode_start_page.html
new file mode 100644
index 0000000..f73c41d
--- /dev/null
+++ b/core/res/res/raw-hi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>नई गुप्त विंडो</title>
+ </head>
+ <body>
+ <p><strong>आप गुप्त मोड में हैं</strong>. इस विंडो में देखे गए पृष्ठ आपके ब्राउज़र इतिहास या खोज इतिहास में प्रकट नहीं होंगे, और वे आपके डिवाइस पर गुप्त विंडो बंद करने के बाद और कोई चिह्न जैसे कुकीज़, नहीं छोड़ते. हालांकि डाउनलोड की गई या बुकमार्क की गई कोई भी फ़ाइल संरक्षित रखी जाएगी.</p>
+
+ <p><strong>गुप्त मोड में होने से दूसरे लोगों, सर्वर. या सॉफ़्टवेयर पर कोई प्रभाव नहीं होता. इनका ध्यान रखें</strong></p>
+
+ <ul>
+ <li>वे वेबसाइट जो आपके बारे में जानकारी एकत्र या शेयर करती हैं</li>
+ <li>इंटरनेट सेवा प्रदाता या नियोक्ता जो आपके द्वारा विज़िट किए गए पृष्ठों पर नज़र रखते हैं</li>
+ <li>दुर्भावनापूर्ण सॉफ़्टवेयर जो मुफ़्त स्माइली के बदले आपके कीस्ट्रोक पर नज़र रखते हैं.</li>
+ <li>गुप्तचरों द्वारा निगरानी</li>
+ <li>आपके पीछे खड़े लोग</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6f20fe0
--- /dev/null
+++ b/core/res/res/raw-hr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Novi anonimni prozor</title>
+ </head>
+ <body>
+ <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
+
+ <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
+
+ <ul>
+ <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
+ <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
+ <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
+ <li>Nadzor tajnih službi</li>
+ <li>Osobe koje stoje iza vas</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hr/incognito_mode_start_page.html b/core/res/res/raw-hr/incognito_mode_start_page.html
new file mode 100644
index 0000000..6f20fe0
--- /dev/null
+++ b/core/res/res/raw-hr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Novi anonimni prozor</title>
+ </head>
+ <body>
+ <p><strong>Sada ste anonimni</strong>. Stranice koje pregledavate u ovom prozoru neće se pojaviti u povijesti preglednika ili povijesti pretraživanja, neće ostaviti tragove, poput kolačića, na vašem uređaju nakon što zatvorite anonimni prozor. Međutim, sve datoteke koje preuzmete ili oznake koje stvorite bit će sačuvane.</p>
+
+ <p><strong>Anonimno pregledavanje neće utjecati na ponašanje drugih osoba, poslužitelja ili softvera. Pazite na sljedeće:</strong></p>
+
+ <ul>
+ <li>Web-lokacije koje prikupljaju ili dijele informacije o vama</li>
+ <li>Davatelje internetskih usluga ili poslodavce koji prate stranice koje posjećujete</li>
+ <li>Zlonamjerni softver koji prati koje tipke pritišćete u zamjenu za besplatne emotikone</li>
+ <li>Nadzor tajnih službi</li>
+ <li>Osobe koje stoje iza vas</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html b/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..38b0806
--- /dev/null
+++ b/core/res/res/raw-hu-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Új inkognitóablak</title>
+ </head>
+ <body>
+ <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
+
+ <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
+
+ <ul>
+ <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
+ <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
+ <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
+ <li>Titkos ügynökök megfigyelése</li>
+ <li>Az Ön mögött álló emberek</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-hu/incognito_mode_start_page.html b/core/res/res/raw-hu/incognito_mode_start_page.html
new file mode 100644
index 0000000..38b0806
--- /dev/null
+++ b/core/res/res/raw-hu/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Új inkognitóablak</title>
+ </head>
+ <body>
+ <p><strong>Ön inkognitó módra váltott</strong>. Az inkognitóablakban megtekintett oldalak nem jelennek meg böngészője előzményeiben, illetve keresési előzményeiben, és nem hagynak más nyomot pl. cookie-t sem a számítógépén az inkognitóablak bezárását követően. A letöltött fájlok, valamint a létrehozott könyvjelzők azonban megmaradnak.</p>
+
+ <p><strong>Az inkognitó üzemmód nem befolyásolja a többi felhasználó, szerver vagy szoftver viselkedését. Ügyeljen a következőkre:</strong></p>
+
+ <ul>
+ <li>Olyan webhelyek, amelyek információt gyűjtenek vagy osztanak meg Önről</li>
+ <li>Olyan internetszolgáltatók vagy alkalmazottaik, akik nyomon követik az Ön által látogatott oldalakat</li>
+ <li>Olyan kártékony szoftverek, amelyek ingyenes hangulatjelekért cserébe nyomon követik billentyűbeviteleit</li>
+ <li>Titkos ügynökök megfigyelése</li>
+ <li>Az Ön mögött álló emberek</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-id-xlarge/incognito_mode_start_page.html b/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..788c088
--- /dev/null
+++ b/core/res/res/raw-id-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Jendela penyamaran baru</title>
+ </head>
+ <body>
+ <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
+
+ <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
+
+ <ul>
+ <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
+ <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
+ <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
+ <li>Pemantauan oleh agen rahasia</li>
+ <li>Orang yang berdiri di belakang Anda</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-id/incognito_mode_start_page.html b/core/res/res/raw-id/incognito_mode_start_page.html
new file mode 100644
index 0000000..788c088
--- /dev/null
+++ b/core/res/res/raw-id/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Jendela penyamaran baru</title>
+ </head>
+ <body>
+ <p><strong>Anda menggunakan penyamaran</strong>. Laman yang Anda lihat di jendela ini tidak akan ditampilkan dalam riwayat peramban atau riwayat penelusuran, dan tidak akan meninggalkan jejak, seperti kuki, di perangkat setelah jendela penyamaran ditutup. Namun, berkas yang diunduh atau bookmark yang dibuat akan disimpan.</p>
+
+ <p><strong>Menggunakan penyamaran tidak mempengaruhi perilaku orang lain, server, atau perangkat lunak. Waspadai:</strong></p>
+
+ <ul>
+ <li>Situs web yang mengumpulkan atau berbagi informasi tentang Anda</li>
+ <li>Penyedia layanan internet atau tempat kerja yang melacak laman yang Anda kunjungi</li>
+ <li>Perangkat lunak jahat yang melacak penekanan tombol dengan imbalan smiley gratis</li>
+ <li>Pemantauan oleh agen rahasia</li>
+ <li>Orang yang berdiri di belakang Anda</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-it-xlarge/incognito_mode_start_page.html b/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..4a34874
--- /dev/null
+++ b/core/res/res/raw-it-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nuova finestra di navigazione in incognito</title>
+ </head>
+ <body>
+ <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
+
+ <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
+
+ <ul>
+ <li>Siti web che raccolgono o condividono informazioni su di te</li>
+ <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
+ <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
+ <li>Agenti segreti</li>
+ <li>Persone che ti stanno alle spalle</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-it/incognito_mode_start_page.html b/core/res/res/raw-it/incognito_mode_start_page.html
new file mode 100644
index 0000000..4a34874
--- /dev/null
+++ b/core/res/res/raw-it/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nuova finestra di navigazione in incognito</title>
+ </head>
+ <body>
+ <p><strong>Sei passato alla navigazione in incognito</strong>. Le pagine aperte in questa finestra non vengono registrate nella cronologia di navigazione o di ricerca, e non lasciano traccia sul tuo computer, ad esempio sotto forma di cookie, una volta chiusa la finestra. Tuttavia, qualsiasi file scaricato o preferito creato verrà conservato.</p>
+
+ <p><strong>La navigazione in incognito non influisce sul comportamento di altri utenti, server o software. Diffida di:</strong></p>
+
+ <ul>
+ <li>Siti web che raccolgono o condividono informazioni su di te</li>
+ <li>Provider di servizi Internet o datori di lavoro che registrano le pagine da te visitate</li>
+ <li>Software dannosi che registrano le sequenze di tasti da te utilizzate in cambio di smiley gratuiti</li>
+ <li>Agenti segreti</li>
+ <li>Persone che ti stanno alle spalle</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..368dea0
--- /dev/null
+++ b/core/res/res/raw-iw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>חלון חדש של גלישה בסתר</title>
+ </head>
+ <body>
+ <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
+
+ <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים אחרים או תוכנות אחרות. היזהר מ:</strong></p>
+
+ <ul>
+ <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
+ <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
+ <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
+ <li>מעקב של סוכנים חשאיים</li>
+ <li>אנשים שעומדים מאחוריך</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-iw/incognito_mode_start_page.html b/core/res/res/raw-iw/incognito_mode_start_page.html
new file mode 100644
index 0000000..368dea0
--- /dev/null
+++ b/core/res/res/raw-iw/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="RTL">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>חלון חדש של גלישה בסתר</title>
+ </head>
+ <body>
+ <p><strong>עברת למצב של גלישה בסתר</strong>. דפים שאתה רואה בחלון זה לא יופיעו בהיסטוריית הדפדפן או בהיסטוריית החיפושים שלך, והם לא ישאירו עקבות אחרים, כמו קובצי cookie, לאחר שתסגור את חלון הגלישה בסתר. עם זאת, כל קובץ שאתה מוריד או כוכביות שאתה יוצר יישמרו.</p>
+
+ <p><strong> גלישה בסתר לא משפיעה על התנהגותם של אנשים אחרים, שרתים אחרים או תוכנות אחרות. היזהר מ:</strong></p>
+
+ <ul>
+ <li>אתרים שאוספים נתונים או משתפים מידע לגביך</li>
+ <li>ספקי שירות אינטרנט או עובדים שעוקבים אחר הדפים שבהם אתה מבקר</li>
+ <li>תוכנה זדונית שעוקבת אחר ההקשות שלך על המקשים בתמורה לסימני סמיילי בחינם</li>
+ <li>מעקב של סוכנים חשאיים</li>
+ <li>אנשים שעומדים מאחוריך</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..a58ad05
--- /dev/null
+++ b/core/res/res/raw-ja-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新しいシークレットウィンドウ</title>
+ </head>
+ <body>
+ <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
+
+ <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
+
+ <ul>
+ <li>ユーザーの情報を収集、共有するウェブサイト</li>
+ <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
+ <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
+ <li>スパイ、諜報活動</li>
+ <li>背後にいる人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ja/incognito_mode_start_page.html b/core/res/res/raw-ja/incognito_mode_start_page.html
new file mode 100644
index 0000000..a58ad05
--- /dev/null
+++ b/core/res/res/raw-ja/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新しいシークレットウィンドウ</title>
+ </head>
+ <body>
+ <p><strong>シークレットモードを使用中です</strong>。このウィンドウで開いたページはブラウザの履歴や検索履歴に残りません。このウィンドウを閉じるとCookieなどの記録も端末から消去されます。ただし、ダウンロードしたファイルやブックマークしたページは保存されます。</p>
+
+ <p><strong>シークレットモードが他のユーザーやサーバー、ソフトウェアの動作に影響することはありません。なお、下記のようなケースにご注意ください。</strong></p>
+
+ <ul>
+ <li>ユーザーの情報を収集、共有するウェブサイト</li>
+ <li>アクセスしたページをトラッキングするインターネットサービスプロバイダや雇用主</li>
+ <li>無料ダウンロードなどと一緒にインストールされ、キーストロークを記録するマルウェア</li>
+ <li>スパイ、諜報活動</li>
+ <li>背後にいる人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..0e703b1
--- /dev/null
+++ b/core/res/res/raw-ko-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>새 시크릿 창</title>
+ </head>
+ <body>
+ <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
+
+ <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
+
+ <ul>
+ <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
+ <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
+ <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
+ <li>비밀 개체를 통한 감시</li>
+ <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ko/incognito_mode_start_page.html b/core/res/res/raw-ko/incognito_mode_start_page.html
new file mode 100644
index 0000000..0e703b1
--- /dev/null
+++ b/core/res/res/raw-ko/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>새 시크릿 창</title>
+ </head>
+ <body>
+ <p><strong>시크릿 모드로 들어오셨습니다.</strong> 이 창에서 보는 페이지는 브라우저 기록이나 검색기록에 남지 않으며, 시크릿 창을 닫은 뒤 기기에 쿠기와 같은 흔적도 남기지 않습니다. 다운로드한 파일이나 생성한 북마크는 보관됩니다. </p>
+
+ <p><strong>시크릿 모드를 이용해도 다른 사용자, 서버, 소프트웨어에 영향을 주지는 않습니다. 다음을 주의하세요.</strong></p>
+
+ <ul>
+ <li>사용자에 대한 정보를 모으고 공유하는 웹사이트</li>
+ <li>방문 페이지를 추적하는 인터넷 서비스 제공업체나 직원 </li>
+ <li>스마일 이모티콘을 제공한다는 명목으로 입력 내용을 추적하는 악성 소프트웨어</li>
+ <li>비밀 개체를 통한 감시</li>
+ <li>뒤에서 사용자의 작업내용을 지켜보는 사람</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9244ae4
--- /dev/null
+++ b/core/res/res/raw-lt-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Naujas inkognito langas</title>
+ </head>
+ <body>
+ <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
+
+ <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
+
+ <ul>
+ <li>svetainių, kurios renka ar platina informaciją apie jus</li>
+ <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
+ <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
+ <li>jus galinčių sekti slaptųjų agentų</li>
+ <li>už nugaros stovinčių asmenų</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-lt/incognito_mode_start_page.html b/core/res/res/raw-lt/incognito_mode_start_page.html
new file mode 100644
index 0000000..9244ae4
--- /dev/null
+++ b/core/res/res/raw-lt/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Naujas inkognito langas</title>
+ </head>
+ <body>
+ <p><strong>Naršote inkognito režimu</strong>. Šiame lange peržiūrimi puslapiai nebus išsaugomi naršyklės istorijoje ar paieškos istorijoje ir uždarius inkognito langą nepaliks jokių kitų žymių, pvz., slapukų. Tačiau bus išsaugoti atsisiųsti failai ar sukurtos žymos.</p>
+
+ <p><strong>Naršymas inkognito režimu nedaro jokios įtakos kitiems asmenims, serveriams ar programinei įrangai. Saugokitės:</strong></p>
+
+ <ul>
+ <li>svetainių, kurios renka ar platina informaciją apie jus</li>
+ <li>interneto paslaugos teikėjų ar darbdavių, kurie stebi, kuriuos puslapius peržiūrite</li>
+ <li>kenkėjiškos programinės įrangos, kuri siūlydama nemokamų šypsniukų fiksuoja klavišų paspaudimus</li>
+ <li>jus galinčių sekti slaptųjų agentų</li>
+ <li>už nugaros stovinčių asmenų</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..f325ef5
--- /dev/null
+++ b/core/res/res/raw-lv-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Jauns inkognito logs</title>
+ </head>
+ <body>
+ <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
+
+ <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
+
+ <ul>
+ <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
+ <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
+ <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
+ <li>slepeno aģentu veiktas izmeklēšanas;</li>
+ <li>personām, kas stāv aiz jums.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-lv/incognito_mode_start_page.html b/core/res/res/raw-lv/incognito_mode_start_page.html
new file mode 100644
index 0000000..f325ef5
--- /dev/null
+++ b/core/res/res/raw-lv/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Jauns inkognito logs</title>
+ </head>
+ <body>
+ <p><strong>Jūs esat ieslēdzis inkognito režīmu</strong>. Šajā logā aplūkotās lapas neparādīsies jūsu pārlūkprogrammas vēsturē vai meklēšanas vēsturē, tās arī neatstās citas pēdas, piemēram, sīkfailus, jūsu ierīcē pēc inkognito režīma loga aizvēršanas. Tomēr visi jūsu lejupielādētie faili vai izveidotās grāmatzīmes tiks saglabātas.</p>
+
+ <p><strong>Inkognito režīma ieslēgšana neietekmēs citu personu, serveru vai programmatūras darbību. Uzmanieties no</strong></p>
+
+ <ul>
+ <li>vietnēm, kas apkopo vai koplieto informāciju par jums;</li>
+ <li>interneta pakalpojumu sniedzējiem vai darba devējiem, kas izseko jūsu apmeklētajām lapām;</li>
+ <li>maldprogrammatūras, kas izseko jūsu taustiņsitieniem apmaiņā par bezmaksas smaidiņiem;</li>
+ <li>slepeno aģentu veiktas izmeklēšanas;</li>
+ <li>personām, kas stāv aiz jums.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..724e734
--- /dev/null
+++ b/core/res/res/raw-nb-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nytt inkognitovindu</title>
+ </head>
+ <body>
+ <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
+
+ <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
+
+ <ul>
+ <li>Nettsider som samler eller deler informasjon om deg</li>
+ <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
+ <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
+ <li>Hemmelige agenter som spionerer på deg</li>
+ <li>Folk som titter over skulderen din</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-nb/incognito_mode_start_page.html b/core/res/res/raw-nb/incognito_mode_start_page.html
new file mode 100644
index 0000000..724e734
--- /dev/null
+++ b/core/res/res/raw-nb/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nytt inkognitovindu</title>
+ </head>
+ <body>
+ <p><strong></strong>Du er nå inkognito Sider du besøker i dette vinduet blir ikke lagret i nettleser- eller søkelogg, og etterlater ikke andre spor, f. eks. informasjonskapsler, på enheten din etter at du har lukket vinduet. Filer du laster ned eller bokmerker du lager blir derimot lagret.</p>
+
+ <p><strong>Det at du er inkognito endrer ikke hvordan andre mennesker, tjenere eller programmer oppfører seg. Pass deg for:</strong></p>
+
+ <ul>
+ <li>Nettsider som samler eller deler informasjon om deg</li>
+ <li>Nettleverandører eller arbeidsgivere som overvåker hvilke sider du besøker</li>
+ <li>Skadelige programmer som følger med på tastetrykk i bytte mot smilefjes</li>
+ <li>Hemmelige agenter som spionerer på deg</li>
+ <li>Folk som titter over skulderen din</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..92fedd7
--- /dev/null
+++ b/core/res/res/raw-nl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nieuw incognitovenster</title>
+ </head>
+ <body>
+ <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
+
+ <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
+
+ <ul>
+ <li>Websites die informatie over u verzamelen of delen</li>
+ <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
+ <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
+ <li>Spionage door geheim agenten</li>
+ <li>Mensen die achter u staan</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-nl/incognito_mode_start_page.html b/core/res/res/raw-nl/incognito_mode_start_page.html
new file mode 100644
index 0000000..92fedd7
--- /dev/null
+++ b/core/res/res/raw-nl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nieuw incognitovenster</title>
+ </head>
+ <body>
+ <p><strong>U bent nu incognito</strong> De pagina's die u in dit venster bekijkt worden niet opgenomen in de browsergeschiedenis en de zoekgeschiedenis en laten geen cookies of andere sporen na op uw apparaat nadat u het incognitovenster hebt gesloten. Alle bestanden die u downloadt en bladwijzers die u maakt, blijven echter behouden.</p>
+
+ <p><strong>Incognito zijn heeft geen invloed op het gedrag van andere personen, servers of software. Wees op uw hoede voor:</strong></p>
+
+ <ul>
+ <li>Websites die informatie over u verzamelen of delen</li>
+ <li>Internetproviders of werkgevers die bijhouden welke pagina's u bezoekt</li>
+ <li>Schadelijke software die uw toetsaanslagen registreert in ruil voor gratis emoticons</li>
+ <li>Spionage door geheim agenten</li>
+ <li>Mensen die achter u staan</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9748ead
--- /dev/null
+++ b/core/res/res/raw-pl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nowe okno incognito</title>
+ </head>
+ <body>
+ <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
+
+ <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
+
+ <ul>
+ <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
+ <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
+ <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
+ <li>aktywność wywiadowczą tajnych agentów</li>
+ <li>osoby stojące za plecami</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pl/incognito_mode_start_page.html b/core/res/res/raw-pl/incognito_mode_start_page.html
new file mode 100644
index 0000000..9748ead
--- /dev/null
+++ b/core/res/res/raw-pl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nowe okno incognito</title>
+ </head>
+ <body>
+ <p><strong>Jesteś teraz incognito</strong> Strony przeglądane w tym oknie nie będą wyświetlane w historii przeglądarki ani w historii wyszukiwania. Po zamknięciu okna incognito na komputerze nie zostanie po nich żaden ślad np. w postaci plików cookie. Zachowane zostaną jednak pobrane pliki lub utworzone zakładki.</p>
+
+ <p><strong>Przejście do trybu incognito nie ma wpływu na działania innych osób, serwery ani oprogramowanie. Należy uważać na:</strong></p>
+
+ <ul>
+ <li>witryny zbierające lub udostępniające dane na temat użytkowników</li>
+ <li>dostawców usług internetowych oraz pracowników monitorujących strony odwiedzane przez użytkowników</li>
+ <li>złośliwe oprogramowanie śledzące naciśnięcia klawiszy (np. w zamian za darmowe emotikony)</li>
+ <li>aktywność wywiadowczą tajnych agentów</li>
+ <li>osoby stojące za plecami</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..89a5ab0
--- /dev/null
+++ b/core/res/res/raw-pt-rPT-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova janela de navegação anónima</title>
+ </head>
+ <body>
+ <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
+
+ <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
+
+ <ul>
+ <li>Web sites que recolhem ou partilham informações sobre si</li>
+ <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
+ <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
+ <li>Vigilância de agentes secretos</li>
+ <li>Pessoas que estejam perto de si</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pt-rPT/incognito_mode_start_page.html b/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
new file mode 100644
index 0000000..89a5ab0
--- /dev/null
+++ b/core/res/res/raw-pt-rPT/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova janela de navegação anónima</title>
+ </head>
+ <body>
+ <p><strong>Está no modo de navegação anónima</strong>. As páginas que visualizar nesta janela não vão aparecer nos históricos de pesquisa ou de navegação e não deixarão quaisquer vestígios (por exemplo cookies) no computador depois de fechar a janela. No entanto se transferir ficheiros ou criar marcadores, estes serão preservados.</p>
+
+ <p><strong>Navegar no modo de navegação anónima não afecta o comportamento de outras pessoas, nem o comportamento de servidores ou programas. Tenha cuidado com:</strong></p>
+
+ <ul>
+ <li>Web sites que recolhem ou partilham informações sobre si</li>
+ <li>Serviços de fornecimento de internet ou empregadores que monitorizam as páginas que você visita</li>
+ <li>Programas maliciosos que monitorizam as teclas em que carrega em troca de ícones expressivos ("smileys")</li>
+ <li>Vigilância de agentes secretos</li>
+ <li>Pessoas que estejam perto de si</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html b/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..b301eda
--- /dev/null
+++ b/core/res/res/raw-pt-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova janela anônima</title>
+ </head>
+ <body>
+ <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
+
+ <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
+
+ <ul>
+ <li>Websites que coletam ou compartilham informações sobre você</li>
+ <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
+ <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
+ <li>Vigilância por agentes secretos</li>
+ <li>Pessoas paradas detrás de você</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-pt/incognito_mode_start_page.html b/core/res/res/raw-pt/incognito_mode_start_page.html
new file mode 100644
index 0000000..b301eda
--- /dev/null
+++ b/core/res/res/raw-pt/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nova janela anônima</title>
+ </head>
+ <body>
+ <p><strong>Você ficou anônimo</strong>. As páginas que você vê nesta janela não aparecerão no histórico do seu navegador ou da sua pesquisa e não deixarão rastros, como cookies, no seu dispositivo depois que você fechar a janela anônima. Quaisquer arquivos que você fizer o download ou favoritos que criar serão preservados.</p>
+
+ <p><strong>Tornar-se anônimo não afeta o comportamento de outras pessoas, servidores ou software. Esteja atento a:</strong></p>
+
+ <ul>
+ <li>Websites que coletam ou compartilham informações sobre você</li>
+ <li>Provedores de serviços de internet ou funcionários que rastreiam as páginas que você visita</li>
+ <li>Softwares maliciosos que rastreiam os seus toques de teclado em troca de ícones gratuitos</li>
+ <li>Vigilância por agentes secretos</li>
+ <li>Pessoas paradas detrás de você</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..3e499d3
--- /dev/null
+++ b/core/res/res/raw-ro-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Fereastră incognito nouă</title>
+ </head>
+ <body>
+ <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
+
+ <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
+
+ <ul>
+ <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
+ <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
+ <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
+ <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
+ <li>persoanele din spatele dvs.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ro/incognito_mode_start_page.html b/core/res/res/raw-ro/incognito_mode_start_page.html
new file mode 100644
index 0000000..3e499d3
--- /dev/null
+++ b/core/res/res/raw-ro/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Fereastră incognito nouă</title>
+ </head>
+ <body>
+ <p><strong>Navigaţi incognito</strong>. Paginile pe care le afişaţi în această fereastră nu vor apărea în istoricul browserului sau al căutărilor şi nu vor lăsa alte urme, precum cookie-uri, pe dispozitivul dvs. după ce închideţi fereastra incognito. Dar fişierele descărcate şi marcajele create vor fi păstrate.</p>
+
+ <p><strong>Navigarea incognito nu influenţează comportamentul altor persoane, servere sau aplicaţii software. Fiţi atent(ă) la:</strong></p>
+
+ <ul>
+ <li>site-urile web care colectează sau distribuie informaţii despre dvs.;</li>
+ <li>furnizorii de servicii de internet sau angajatorii care urmăresc paginile pe care le accesaţi;</li>
+ <li>aplicaţiile software rău intenţionate care vă urmăresc apăsările pe taste promiţându-vă că vă oferă emoticonuri gratuite;</li>
+ <li>acţiunile de monitorizare efectuate de agenţi secreţi;</li>
+ <li>persoanele din spatele dvs.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html b/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..ae7b59c
--- /dev/null
+++ b/core/res/res/raw-ru-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Новое окно в режиме инкогнито</title>
+ </head>
+ <body>
+ <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
+
+ <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
+
+ <ul>
+ <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
+ <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
+ <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
+ <li>Слежки тайными агентами</li>
+ <li>Людей, которые стоят у вас за спиной</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-ru/incognito_mode_start_page.html b/core/res/res/raw-ru/incognito_mode_start_page.html
new file mode 100644
index 0000000..ae7b59c
--- /dev/null
+++ b/core/res/res/raw-ru/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Новое окно в режиме инкогнито</title>
+ </head>
+ <body>
+ <p><strong>Вы перешли в режим инкогнито</strong>. Страницы, которые вы просматриваете в окне в режиме инкогнито, не появятся в истории вашего браузера или истории поиска, а также не оставят на вашем компьютере других следов, таких как файлы cookie, когда вы закроете это окно. Тем не менее, все файлы, которые вы загружаете, или закладки, которые вы создаете, останутся в целости и сохранности. </p>
+
+ <p><strong>Переход в режим инкогнито не влияет на поведение других пользователей, серверов или программ. Опасайтесь:</strong></p>
+
+ <ul>
+ <li>Веб-сайтов, которые собирают информацию о вас или передают ее другим</li>
+ <li>Поставщиков услуг Интернета или их сотрудников, которые отслеживают, какие страницы вы посещаете</li>
+ <li>Вредоносного ПО, которое отслеживает нажатие клавиш клавиатуры в обмен на бесплатные смайлики</li>
+ <li>Слежки тайными агентами</li>
+ <li>Людей, которые стоят у вас за спиной</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5b138f1
--- /dev/null
+++ b/core/res/res/raw-sk-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nové okno inkognito</title>
+ </head>
+ <body>
+ <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
+
+ <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
+
+ <ul>
+ <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
+ <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
+ <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
+ <li>sledovanie tajnými agentmi;</li>
+ <li>ľudí, ktorí stoja za vami.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sk/incognito_mode_start_page.html b/core/res/res/raw-sk/incognito_mode_start_page.html
new file mode 100644
index 0000000..5b138f1
--- /dev/null
+++ b/core/res/res/raw-sk/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nové okno inkognito</title>
+ </head>
+ <body>
+ <p><strong>Ste v režime inkognito</strong> Stránky, ktoré si pozriete v tomto okne, sa nezobrazia v histórii prehliadača ani v histórii vyhľadávania. Po zavretí okna inkognito na zariadení nezostanú ani žiadne iné stopy, ako sú napr. súbory cookie. Napriek tomu však zostanú zachované všetky prevzaté súbory aj záložky, ktoré ste vytvorili.</p>
+
+ <p><strong>Režim inkognito neovplyvňuje správanie iných ľudí, serverov ani softvéru. Dávajte si pozor na:</strong></p>
+
+ <ul>
+ <li>webové stránky, ktoré zbierajú alebo zdieľajú vaše informácie;</li>
+ <li>poskytovateľov internetových služieb alebo zamestnancov, ktorí sledujú vaše navštívené stránky;</li>
+ <li>škodlivý softvér, ktorý sleduje ktoré klávesy stláčate výmenou za smajlíkov zadarmo;</li>
+ <li>sledovanie tajnými agentmi;</li>
+ <li>ľudí, ktorí stoja za vami.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..33a8b08
--- /dev/null
+++ b/core/res/res/raw-sl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Novo okno brez beleženja zgodovine</title>
+ </head>
+ <body>
+ <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
+
+ <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
+
+ <ul>
+ <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
+ <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
+ <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
+ <li>Nadzor tajnih agentov.</li>
+ <li>Osebe, ki stojijo za vašim hrbtom.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sl/incognito_mode_start_page.html b/core/res/res/raw-sl/incognito_mode_start_page.html
new file mode 100644
index 0000000..33a8b08
--- /dev/null
+++ b/core/res/res/raw-sl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Novo okno brez beleženja zgodovine</title>
+ </head>
+ <body>
+ <p><strong>Ste v načinu brez beleženja zgodovine.</strong> Strani, ki si jih ogledate v tem oknu, ne bodo prikazane v zgodovini brskalnika ali zgodovini iskanja, prav tako v vaši napravi ne bodo pustile sledi, kot npr. piškotkov, ko zaprete stran, ki jo imate odprto v tem načinu. Datoteke, ki jih prenesete ali zaznamki, ki jih ustvarite, bodo ohranjeni.</p>
+
+ <p><strong>Funkcije brez beleženja zgodovine ne vplivajo na obnašanje drugih oseb, strežnikov ali programske opreme. Pazite na:</strong></p>
+
+ <ul>
+ <li>Spletna mesta, ki zbirajo informacije o vas ali jih dajejo v skupno rabo.</li>
+ <li>Ponudnike internetnih storitev ali zaposlene, ki spremljajo spletna mesta, ki ste jih obiskali.</li>
+ <li>Zlonamerno programsko opremo, ki spremlja vaše tipkanje, v zameno pa vam ponuja brezplačne čustvene simbole.</li>
+ <li>Nadzor tajnih agentov.</li>
+ <li>Osebe, ki stojijo za vašim hrbtom.</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..b1fbcb1
--- /dev/null
+++ b/core/res/res/raw-sr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нов прозор без архивирања</title>
+ </head>
+ <body>
+ <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
+
+ <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
+
+ <ul>
+ <li>Веб сајтова који прикупљају и деле податке о вама</li>
+ <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
+ <li>Злонамерног софтвера који прати шта куцате</li>
+ <li>Надзора тајних агената</li>
+ <li>Људи који вам стоје иза леђа</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sr/incognito_mode_start_page.html b/core/res/res/raw-sr/incognito_mode_start_page.html
new file mode 100644
index 0000000..b1fbcb1
--- /dev/null
+++ b/core/res/res/raw-sr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нов прозор без архивирања</title>
+ </head>
+ <body>
+ <p><strong>Ушли сте у режим без архивирања</strong> Странице које гледате у овом прозору се неће појавити у историји прегледања ни историји претраге, нити ће оставити друге трагове, попут колачића, на вашем уређају када затворите овај прозор. Међутим, ако преузмете датотеке или направите обележиваче, они ће бити сачувани.</p>
+
+ <p><strong>Режим без архивирања не утиче на понашање других људи, сервера нити софтвера. Чувајте се:</strong></p>
+
+ <ul>
+ <li>Веб сајтова који прикупљају и деле податке о вама</li>
+ <li>Добављача интернет услуга или запослених који прате странице које посетите</li>
+ <li>Злонамерног софтвера који прати шта куцате</li>
+ <li>Надзора тајних агената</li>
+ <li>Људи који вам стоје иза леђа</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html b/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..5ebbb22
--- /dev/null
+++ b/core/res/res/raw-sv-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nytt inkognitofönster</title>
+ </head>
+ <body>
+ <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
+
+ <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
+
+ <ul>
+ <li>Webbplatser som samlar eller delar information om dig</li>
+ <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
+ <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
+ <li>Övervakning av hemliga agenter</li>
+ <li>Personer som står bakom dig</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-sv/incognito_mode_start_page.html b/core/res/res/raw-sv/incognito_mode_start_page.html
new file mode 100644
index 0000000..5ebbb22
--- /dev/null
+++ b/core/res/res/raw-sv/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Nytt inkognitofönster</title>
+ </head>
+ <body>
+ <p><strong>Du använder inkognitoläget</strong>. Sidor som du har läst i detta fönster visas inte i din webbläsarhistorik eller sökhistorik. De lämnar inga spår efter sig, till exempel cookies, i din enhet efter att du stängt inkognitofönstret. Alla filer som du hämtar eller bokmärken du skapar sparas dock.</p>
+
+ <p><strong>Att använda datorn inkognito påverkar inte användare, servrar eller program. Se upp för:</strong></p>
+
+ <ul>
+ <li>Webbplatser som samlar eller delar information om dig</li>
+ <li>Internetleverantörer eller arbetsgivare som spårar var du surfar</li>
+ <li>Skadlig programvara som spårar dina tangenttryckningar som nyckelloggare</li>
+ <li>Övervakning av hemliga agenter</li>
+ <li>Personer som står bakom dig</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-th-xlarge/incognito_mode_start_page.html b/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..29c64eb
--- /dev/null
+++ b/core/res/res/raw-th-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
+ </head>
+ <body>
+ <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
+
+ <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
+
+ <ul>
+ <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
+ <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
+ <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
+ <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
+ <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-th/incognito_mode_start_page.html b/core/res/res/raw-th/incognito_mode_start_page.html
new file mode 100644
index 0000000..29c64eb
--- /dev/null
+++ b/core/res/res/raw-th/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>หน้าต่างใหม่ที่ไม่ระบุตัวตน</title>
+ </head>
+ <body>
+ <p><strong>คุณได้เข้าสู่โหมดไม่ระบุตัวตนแล้ว</strong> หน้าเว็บที่คุณดูในหน้าต่างนี้จะไม่ปรากฏในประวัติของเบราว์เซอร์หรือประวัติการค้นหาของคุณ และจะไม่ทิ้งร่องรอยอื่นๆ เช่น คุกกี้ ไว้บนอุปกรณ์หลังจากที่คุณปิดหน้าต่างที่ไม่ระบุตัวตนนี้แล้ว อย่างไรก็ตาม ไฟล์ที่คุณดาวน์โหลดหรือบุ๊กมาร์กที่สร้างขึ้นจะถูกเก็บไว้</p>
+
+ <p><strong>การเข้าสู่โหมดไม่ระบุตัวตนจะไม่กระทบต่อการทำงานของบุคคล เซิร์ฟเวอร์ หรือซอฟต์แวร์อื่น โปรดระวัง:</strong></p>
+
+ <ul>
+ <li>เว็บไซต์ที่เก็บหรือแบ่งปันข้อมูลเกี่ยวกับคุณ</li>
+ <li>ผู้ให้บริการอินเทอร์เน็ตหรือนายจ้างที่ติดตามหน้าเว็บที่คุณเข้าชม</li>
+ <li>ซอฟต์แวร์มุ่งร้ายที่ติดตามการกดแป้นพิมพ์โดยมากับของฟรี</li>
+ <li>การตรวจสอบของหน่วยสืบราชการลับ</li>
+ <li>บุคคลที่ยืนอยู่ข้างหลังคุณ</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..6ce5853
--- /dev/null
+++ b/core/res/res/raw-tl-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Bagong incognito window</title>
+ </head>
+ <body>
+ <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
+
+ <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
+
+ <ul>
+ <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
+ <li>Mga internet service provider o mga employer na sinusubaybayan ang mga pahinang binibisita mo</li>
+ <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
+ <li>Pagmamasid ng mga secret agent</li>
+ <li>Mga tao na nakatayo sa likuran mo</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-tl/incognito_mode_start_page.html b/core/res/res/raw-tl/incognito_mode_start_page.html
new file mode 100644
index 0000000..6ce5853
--- /dev/null
+++ b/core/res/res/raw-tl/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Bagong incognito window</title>
+ </head>
+ <body>
+ <p><strong>Nag-incognito ka</strong>. Hindi lalabas sa iyong kasaysayan ng pag-browse at kasaysayan ng paghahanap ang mga pahinang tiningnan mo sa window na ito, at hindi sila mag-iiwan ng ibang bakas, gaya ng cookies, sa iyong device matapos mong isara ang window na incognito. Gayunpaman, pananatiliin ang anumang mga file na iyong na-download o ang iyong mga ginawang bookmark.</p>
+
+ <p><strong>Hindi nakakaapekto ang pagiging incognito sa gawi ng ibang mga tao, server, o software. Maging maingat sa:</strong></p>
+
+ <ul>
+ <li>Mga website na kumokolekta o nagbabahagi ng impormasyong tungkol sa iyo</li>
+ <li>Mga internet service provider o mga employer na sinusubaybayan ang mga pahinang binibisita mo</li>
+ <li>Malicious software na sinusubaybayan ang iyong mga keystroke kapalit ng mga libreng smiley</li>
+ <li>Pagmamasid ng mga secret agent</li>
+ <li>Mga tao na nakatayo sa likuran mo</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html b/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..c570cc7
--- /dev/null
+++ b/core/res/res/raw-tr-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Yeni gizli pencere</title>
+ </head>
+ <body>
+ <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
+
+ <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
+
+ <ul>
+ <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
+ <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
+ <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
+ <li>Gizli ajanlar tarafından takip edilme</li>
+ <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-tr/incognito_mode_start_page.html b/core/res/res/raw-tr/incognito_mode_start_page.html
new file mode 100644
index 0000000..c570cc7
--- /dev/null
+++ b/core/res/res/raw-tr/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Yeni gizli pencere</title>
+ </head>
+ <body>
+ <p><strong>Gizli moda geçtiniz</strong> Bu pencerede görüntülediğiniz sayfalar tarayıcı geçmişinizde veya arama geçmişinizde görünmez ve gizli pencereyi kapatmanızın ardından cihazınızda çerezler gibi izler bırakmaz. Ancak, indirdiğiniz dosyalar ve oluşturduğunuz favoriler korunur.</p>
+
+ <p><strong>Gizli moda geçmeniz diğer kişilerin, sunucuların veya yazılımların davranışlarını etkilemez. Şu konularda dikkatli olun:</strong></p>
+
+ <ul>
+ <li>Hakkınızda bilgi toplayan veya paylaşan web siteleri</li>
+ <li>Ziyaret ettiğiniz sayfaları izleyen şirket çalışanları veya servis sağlayıcıları</li>
+ <li>Ücretsiz ifade simgeleri karşılığında tuş vuruşlarınızı takip eden kötü niyetli yazılımlar</li>
+ <li>Gizli ajanlar tarafından takip edilme</li>
+ <li>Arkanızda dikilip ne yaptığınıza bakan kişiler</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html b/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..8852854
--- /dev/null
+++ b/core/res/res/raw-uk-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нове анонімне вікно</title>
+ </head>
+ <body>
+ <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
+
+ <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
+
+ <ul>
+ <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
+ <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
+ <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
+ <li>нагляду збоку секретних служб</li>
+ <li>людей за вашою спиною</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-uk/incognito_mode_start_page.html b/core/res/res/raw-uk/incognito_mode_start_page.html
new file mode 100644
index 0000000..8852854
--- /dev/null
+++ b/core/res/res/raw-uk/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Нове анонімне вікно</title>
+ </head>
+ <body>
+ <p><strong>Ви в анонімному режимі</strong>. Сторінки, які ви переглядаєте в цьому вікні, не з’являться в історії веб-переглядача чи в історії пошуку. Вони також не залишать жодних слідів, як-от файлів cookie, у вашому пристрої після того, як ви закриєте анонімне вікно. Однак, завантажені файли та збережені закладки залишаться.</p>
+
+ <p><strong>Анонімний режим не впливає на поведінку інших людей, серверів чи програмного забезпечення. Остерігайтеся:</strong></p>
+
+ <ul>
+ <li>веб-сайтів, які збирають чи поширюють інформацію про вас</li>
+ <li>постачальників інтернет-послуг або роботодавців, які відстежують сторінки, які ви відвідуєте</li>
+ <li>зловмисного програмного забезпечення, яке пропонує безкоштовні смайли, натомість реєструючи клавіші, які ви натискаєте</li>
+ <li>нагляду збоку секретних служб</li>
+ <li>людей за вашою спиною</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html b/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..9902cde
--- /dev/null
+++ b/core/res/res/raw-vi-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Cửa sổ ẩn danh mới</title>
+ </head>
+ <body>
+ <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
+
+ <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
+
+ <ul>
+ <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
+ <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
+ <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
+ <li>Sự theo dõi của các cơ quan tình báo</li>
+ <li>Những người đứng đằng sau bạn</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-vi/incognito_mode_start_page.html b/core/res/res/raw-vi/incognito_mode_start_page.html
new file mode 100644
index 0000000..9902cde
--- /dev/null
+++ b/core/res/res/raw-vi/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>Cửa sổ ẩn danh mới</title>
+ </head>
+ <body>
+ <p><strong>Bạn đã sử dụng cửa sổ ẩn danh</strong>. Các trang bạn xem trong cửa sổ này sẽ không xuất hiện trong lịch sử của trình duyệt hoặc lịch sử tìm kiếm và chúng cũng không để lại dấu vết như cookie trên thiết bị sau khi bạn đóng cửa sổ ẩn danh. Tuy nhiên, mọi tệp bạn tải xuống hoặc mọi dấu trang bạn tạo sẽ được giữ nguyên.</p>
+
+ <p><strong>Sử dụng cửa sổ ẩn danh không ảnh hưởng đến hành vi của người khác, của máy chủ hoặc phần mềm. Hãy cảnh giác với:</strong></p>
+
+ <ul>
+ <li>Các trang web thu thập hoặc chia sẻ thông tin về bạn</li>
+ <li>Nhà cung cấp dịch vụ Internet hoặc ông chủ muốn theo dõi những trang bạn đã truy cập</li>
+ <li>Phần mềm độc hại theo dõi thao tác gõ phím khi nhập các mặt cười</li>
+ <li>Sự theo dõi của các cơ quan tình báo</li>
+ <li>Những người đứng đằng sau bạn</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-xlarge/incognito_mode_start_page.html b/core/res/res/raw-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..492658d
--- /dev/null
+++ b/core/res/res/raw-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
+ <title>New incognito tab</title>
+ </head>
+ <body>
+ <p><strong>You've gone incognito</strong>. Pages you view in this tab
+ won't appear in your browser history or search history, and they won't
+ leave other traces, like cookies, on your device after you close the
+ incognito tab. Any files you download or bookmarks you create will be
+ preserved, however.</p>
+
+ <p><strong>Going incognito doesn't affect the behavior of other people,
+ servers, or software. Be wary of:</strong></p>
+
+ <ul>
+ <li>Websites that collect or share information about you</li>
+ <li>Internet service providers or employers that track the pages you visit</li>
+ <li>Malicious software that tracks your keystrokes in exchange for free smileys</li>
+ <li>Surveillance by secret agents</li>
+ <li>People standing behind you</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..2caf8f8b
--- /dev/null
+++ b/core/res/res/raw-zh-rCN-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新建隐身窗口</title>
+ </head>
+ <body>
+ <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
+
+ <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
+
+ <ul>
+ <li>搜集并分享有关您的信息的网站</li>
+ <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
+ <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
+ <li>对您进行监视的秘密代理</li>
+ <li>站在您身后的人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-zh-rCN/incognito_mode_start_page.html b/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
new file mode 100644
index 0000000..2caf8f8b
--- /dev/null
+++ b/core/res/res/raw-zh-rCN/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新建隐身窗口</title>
+ </head>
+ <body>
+ <p><strong>您已进入隐身模式</strong>。当关闭隐身窗口后,您在此窗口中查看的网页将不会出现在您的浏览器历史记录或搜索记录中,也不会在您的设备留下任何踪迹(如 cookie)。但是,您下载的任何文件或您创建的书签会予以保留。</p>
+
+ <p><strong>进入隐身模式不会影响他人、其他服务器或软件的行为。敬请提防:</strong></p>
+
+ <ul>
+ <li>搜集并分享有关您的信息的网站</li>
+ <li>跟踪您所访问的网页的互联网服务提供商或雇主</li>
+ <li>跟踪您的键盘输入内容以换取免费表情符号的恶意软件</li>
+ <li>对您进行监视的秘密代理</li>
+ <li>站在您身后的人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
new file mode 100644
index 0000000..54eb40b
--- /dev/null
+++ b/core/res/res/raw-zh-rTW-xlarge/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新的無痕式視窗</title>
+ </head>
+ <body>
+ <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
+
+ <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
+
+ <ul>
+ <li>會收集或分享您的相關資訊的網站</li>
+ <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
+ <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
+ <li>情報特務的監控</li>
+ <li>站在您身後的人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/raw-zh-rTW/incognito_mode_start_page.html b/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
new file mode 100644
index 0000000..54eb40b
--- /dev/null
+++ b/core/res/res/raw-zh-rTW/incognito_mode_start_page.html
@@ -0,0 +1,19 @@
+<html DIR="LTR">
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
+ <title>新的無痕式視窗</title>
+ </head>
+ <body>
+ <p><strong>您已開啟無痕式視窗</strong>。透過這個視窗開啟的網頁都不會出現在瀏覽器記錄和搜尋記錄中,而且您關閉此類視窗之後,裝置上並不會保留任何相關記錄 (例如 cookie)。不過系統會保存您的下載檔案和書籤。</p>
+
+ <p><strong>無痕式視窗無法掌控人、伺服器和軟體的行為,所以請小心下列的人事物:</strong></p>
+
+ <ul>
+ <li>會收集或分享您的相關資訊的網站</li>
+ <li>會追蹤您造訪網頁的網路服務供應商或雇主</li>
+ <li>以免費下載為誘因引誘您點擊的連結,其中通常隱藏鍵盤記錄惡意軟體</li>
+ <li>情報特務的監控</li>
+ <li>站在您身後的人</li>
+ </ul>
+ </body>
+</html>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e778340..e9261d9 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"محو بيانات الهاتف بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تعيين الخادم الوكيل العمومي للجهاز"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"تعيين الخادم الوكيل العمومي للجهاز لكي يتم استخدامه أثناء تمكين السياسة. يعين مشرف الجهاز الأول فقط الخادم الوكيل العمومي الفعال."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"تعيين انتهاء صلاحية كلمة المرور"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"التحكم في الوقت المستغرق قبل الحاجة إلى تغيير كلمة مرور شاشة التوقف"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"ضبط انتهاء كلمة مرور تأمين شاشة"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"التحكم في عدد مرات تغيير كلمة مرور تأمين الشاشة"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تعيين تشفير التخزين"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"طلب تشفير بيانات التطبيق المخزنة"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0e95bfba..d15baa9 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Изтриване на данните в телефона без предупреждение чрез възстановяване на фабричните настройки"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Задаване на глобален прокси сървър за устройството"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Задаване на глобалния прокси сървър, който да се използва, когато правилото е активирано. Само първият администратор на устройството задава действителния глобален прокси сървър."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Задаване на срок на валидност на паролата"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролирайте след колко време трябва да се променя паролата за заключване на екрана"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Изтичане на паролата"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролирайте колко често трябва да се променя паролата за заключен екран"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Шифроване за хранилището"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Изисква съхраняваните данни за приложенията да бъдат шифровани"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index daf0e37..263f1c4 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Esborra les dades del telèfon sense advertiment mitjançant un restabliment de les dades de fàbrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Defineix el servidor intermediari global del dispositiu"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Defineix el servidor intermediari global del dispositiu que cal utilitzar mentre la política estigui activada. Només el primer administrador del dispositiu pot definir el servidor intermediari global efectiu."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Defineix la caducitat de la contrasenya"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controla quant de temps abans de la pantalla de bloqueig cal canviar la contrasenya"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Defineix la caducitat de la contrasenya de bloqueig de pantalla"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controla la freqüència amb què cal canviar la contrasenya de bloqueig de pantalla"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptació d’emmagatzematge"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 58c7678..b93989f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez upozornění smazat všechna data telefonu obnovením továrních dat"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavit globální proxy server zařízení"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit konec platnosti hesla"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavit vypršení hesla zámku"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Určuje, jak často je třeba měnit heslo pro uzamčení obrazovky"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavit šifrování úložiště"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Požadovat šifrování ukládaných dat"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8dfc384..25246f6 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Slet telefonens data uden varsel ved at gendanne fabriksindstillinger"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angiv enhedens globale proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for adgangskode"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Angiv udløb for skærmlåskoden"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Administrer, hvor tit skærmlåsens adgangskode skal skiftes"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angiv kryptering af lager"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kræv, at gemte programdata krypteres"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 881bf13..98e0ef3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -155,7 +155,7 @@
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+ <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
<string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
@@ -164,7 +164,7 @@
<string name="permgrouplab_location" msgid="635149742436692049">"Ihren Standort"</string>
<string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+ <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen"</string>
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Ihre Konten"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Zugriff auf verfügbare Konten"</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string>
@@ -179,11 +179,11 @@
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Zugriff auf USB-Speicher"</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Zugriff auf SD-Karte"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+ <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"Statusleiste"</string>
- <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden."</string>
+ <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden"</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"Statusleiste ein-/ausblenden"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
+ <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden"</string>
<string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Ausgehende Anrufe abfangen"</string>
<string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"SMS empfangen"</string>
@@ -207,13 +207,13 @@
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+ <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße"</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"Automodus aktivieren"</string>
- <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren."</string>
+ <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren"</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"Hintergrundprozesse beenden"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Ermöglicht einer Anwendung, Hintergrundprozesse anderer Anwendungen auch bei ausreichendem Speicher zu beenden."</string>
<string name="permlab_forceStopPackages" msgid="1447830113260156236">"Beenden anderer Anwendungen erzwingen"</string>
- <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen."</string>
+ <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen"</string>
<string name="permlab_forceBack" msgid="1804196839880393631">"Schließen von Anwendung erzwingen"</string>
<string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string>
@@ -243,7 +243,7 @@
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
<string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so die Kontrolle über das gesamte Display übernehmen."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+ <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen"</string>
<string name="permlab_manageAppTokens" msgid="17124341698093865">"Anwendungs-Tokens verwalten"</string>
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"Tasten und Steuerungstasten drücken"</string>
@@ -262,24 +262,24 @@
<string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+ <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann"</string>
<string name="permlab_deletePackages" msgid="3343439331576348805">"Anwendungen löschen"</string>
<string name="permdesc_deletePackages" msgid="3634943677518723314">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"Daten anderer Anwendungen löschen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+ <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten"</string>
<string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Caches anderer Anwendungen löschen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen"</string>
<string name="permlab_getPackageSize" msgid="4799785352306641460">"Speicherplatz der Anwendung abrufen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+ <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen"</string>
<string name="permlab_installPackages" msgid="335800214119051089">"Anwendungen direkt installieren"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"Alle Cache-Daten der Anwendung löschen"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="3097119797652477973">"Ermöglicht einer Anwendung, Tablet-Speicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
<string name="permdesc_clearAppCache" product="default" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string>
- <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von internen auf externe Medien zu verschieben und umgekehrt."</string>
+ <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von internen auf externe Medien zu verschieben und umgekehrt"</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"Lesen vertraulicher Protokolldaten"</string>
<string name="permdesc_readLogs" product="tablet" msgid="4077356893924755294">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Tablet durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
<string name="permdesc_readLogs" product="default" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
@@ -326,13 +326,13 @@
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes zu, um falls möglich den ungefähren Standort des Tablets zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes zu, um falls möglich den ungefähren Standort des Tablets festzustellen. Schädliche Anwendungen können damit herausfinden, wo Sie sich ungefähr befinden"</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
- <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen."</string>
+ <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen"</string>
<string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"Ermöglicht der Anwendung, Fotos und Videos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder aus dem Sichtfeld der Kamera erfassen."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Tablet dauerhaft deaktivieren"</string>
@@ -342,11 +342,11 @@
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"Tablet-Neustart erzwingen"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"Neustart des Telefons erzwingen"</string>
<string name="permdesc_reboot" product="tablet" msgid="4555793623560701557">"Ermöglicht der Anwendung, einen Neustart des Tablets zu erzwingen."</string>
- <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+ <string name="permdesc_reboot" product="default" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen"</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben"</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Externen Speicher formatieren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren"</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"Informationen zum internen Speicher abrufen"</string>
<string name="permdesc_asec_access" msgid="8820326551687285439">"Ermöglicht der Anwendung, Informationen zum internen Speicher abzurufen."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"Internen Speicher erstellen"</string>
@@ -358,9 +358,9 @@
<string name="permlab_asec_rename" msgid="7496633954080472417">"Internen Speicher umbenennen"</string>
<string name="permdesc_asec_rename" msgid="2152829985238876790">"Ermöglicht der Anwendung, den internen Speicher umzubenennen."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"Vibrationsalarm steuern"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+ <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
+ <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern"</string>
<!-- no translation found for permlab_manageUsb (1113453430645402723) -->
<skip />
<!-- no translation found for permdesc_manageUsb (6148489202092166164) -->
@@ -368,7 +368,7 @@
<string name="permlab_accessMtp" msgid="4953468676795917042">"MTP-Protokoll implementieren"</string>
<string name="permdesc_accessMtp" msgid="6532961200486791570">"Erlaubt den Zugriff auf den Kernel-MTP-Treiber zur Implementierung des MTP-USB-Protokolls."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"Hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+ <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
<string name="permdesc_callPhone" msgid="3369867353692722456">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"Alle Telefonnummern direkt anrufen"</string>
@@ -389,79 +389,79 @@
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Standby-Modus des Tablets deaktivieren"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="4032181488045338551">"Ermöglicht einer Anwendung, den Standby-Modus des Tablets zu deaktivieren."</string>
- <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren"</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Tablet ein- oder ausschalten"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
<string name="permdesc_devicePower" product="tablet" msgid="3853773100100451905">"Ermöglicht der Anwendung, das Tablet ein- oder auszuschalten."</string>
- <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+ <string name="permdesc_devicePower" product="default" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten"</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"In Werkstestmodus ausführen"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Tablet-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Tablet im Herstellertestmodus ausgeführt wird."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefon-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Herstellertestmodus ausgeführt wird."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"Hintergrund festlegen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen."</string>
+ <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen"</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Größenhinweise für Hintergrund festlegen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen"</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"System auf Werkseinstellung zurücksetzen"</string>
<string name="permdesc_masterClear" msgid="5033465107545174514">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"Zeit einstellen"</string>
- <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Ermöglicht einer Anwendung, die Uhrzeit des Tablets zu ändern."</string>
- <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="209693136361006073">"Ermöglicht einer Anwendung, die Uhrzeit des Tablets zu ändern"</string>
+ <string name="permdesc_setTime" product="default" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern"</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"Zeitzone festlegen"</string>
<string name="permdesc_setTimeZone" product="tablet" msgid="2522877107613885139">"Ermöglicht einer Anwendung, die Zeitzone des Tablets zu ändern."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern"</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"Als Konto-Manager fungieren"</string>
- <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen."</string>
+ <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen"</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"bekannte Konten suchen"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="857622793935544694">"Ermöglicht einer Anwendung, eine Liste der dem Tablet bekannten Konten abzurufen."</string>
- <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen"</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"Als Kontoauthentifizierer fungieren"</string>
- <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter."</string>
+ <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter"</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"Kontoliste verwalten"</string>
- <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen."</string>
+ <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen"</string>
<string name="permlab_useCredentials" msgid="6401886092818819856">"Authentifizierungsinformationen eines Kontos verwenden"</string>
- <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern."</string>
+ <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern"</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+ <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen"</string>
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"uneingeschränkter Internetzugriff"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+ <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten"</string>
<string name="permlab_writeApnSettings" msgid="7823599210086622545">"Einstellungen für Zugriffspunktname schreiben"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+ <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern"</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"Netzwerkkonnektivität ändern"</string>
- <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+ <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern"</string>
<string name="permlab_changeTetherState" msgid="2702121155761140799">"Tethering-Konnektivität ändern"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern."</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern"</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern"</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"WLAN-Status anzeigen"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+ <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen"</string>
<string name="permlab_changeWifiState" msgid="7280632711057112137">"WLAN-Status ändern"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+ <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-Verwaltung"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="3511795757324345837">"Ermöglicht einer Anwendung, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-Verbindungen herstellen"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="4191941825910543803">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Tablets einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
- <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für Nahfeldkommunikation, Karten und Lesegeräte"</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Synchronisierungseinstellungen schreiben"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+ <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen"</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abonnierte Feeds lesen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen"</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abonnierte Feeds schreiben"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
<string name="permlab_readDictionary" msgid="432535716804748781">"nutzerdefiniertes Wörterbuch lesen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+ <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat"</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"in nutzerdefiniertes Wörterbuch schreiben"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen."</string>
+ <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen"</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"USB-Speicherinhalt ändern/löschen"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"SD-Karten-Inhalt ändern/löschen"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Ermöglicht der Anwendung Schreiben in USB-Speicher"</string>
@@ -471,7 +471,7 @@
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
<string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Gewährt einer Anwendung Lese- und Schreibzugriff auf das Cache-Dateisystem."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
- <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen."</string>
+ <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Displays festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf des Passworts festlegen"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Legen Sie fest, wie häufig das Passwort zum Sperren des Bildschirms geändert werden muss."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Speicherverschlüsselung"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Anforderung, dass gespeicherte Anwendungsdaten verschlüsselt werden"</string>
<string-array name="phoneTypes">
@@ -674,7 +674,7 @@
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Ermöglicht einer Anwendung, den auf Ihrem Tablet gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
@@ -811,7 +811,7 @@
<string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
<string name="loading" msgid="1760724998928255250">"Wird geladen..."</string>
<string name="capital_on" msgid="1544682755514494298">"EIN"</string>
- <string name="capital_off" msgid="6815870386972805832">"Aus"</string>
+ <string name="capital_off" msgid="6815870386972805832">"AUS"</string>
<string name="whichApplication" msgid="4533185947064773386">"Aktion durchführen mit"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Standardeinstellung zurücksetzen unter \"Einstellungen > Anwendungen > Anwendungen verwalten\""</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ccd1c4c..8b9a8df 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Διαγραφή των δεδομένων του τηλεφώνου χωρίς προειδοποίηση με επαναφορά των εργοστασιακών δεδομένων"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ρύθμιση του γενικού διακομιστή μεσολάβησης της συσκευής"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδικού πρόσβασης"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ορισμός λήξης κωδ. κλειδ. οθ."</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Επιλέξτε πόσο συχνά θα πρέπει να αλλάζει ο κωδικός πρόσβασης κλειδώματος οθόνης"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ορισμός κρυπτογρ. αποθ. χώρου"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Να απαιτείται η κρυπτογράφηση των αποθηκευμένων δεδομένων εφαρμογής"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 90c52fc..0a511eb 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Erase the phone\'s data without warning by performing a factory data reset"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Set the device global proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Set the device\'s global proxy to be used while policy is enabled. Only the first device admin sets the effective global proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Set password expiry"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Control how long before lock-screen password needs to be changed"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Set lock-screen password expiry"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Control how frequently the lock-screen password must be changed"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Set storage encryption"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Require that stored application data be encrypted"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ae29e83..688565b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad de la contraseña"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad del bloqueo de pantalla"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar cuán a menudo se debe cambiar la contraseña de bloqueo de pantalla"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Establecer la encriptación del almacenamiento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requiere que los datos almacenados de la aplicación estén encriptados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 82b774b..9ab0169 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrado de los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor proxy global"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad de contraseña"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Definir caducidad bloqueo pantalla"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar la frecuencia con la que se debe cambiar el bloqueo de pantalla"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptación de almacenamiento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exige que se encripten los datos de la aplicación almacenados."</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d8451e0..655f250 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"پاک کردن داده های گوشی بدون هشدار با انجام یک عملکرد بازنشانی داده های کارخانه"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"تنظیم پروکسی جهانی دستگاه"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"پروکسی جهانی دستگاه مورد نظر را جهت استفاده هنگام فعال بودن خط مشی تنظیم کنید. فقط اولین سرپرست دستگاه پروکسی جهانی مفید را تنظیم می کند."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"کنترل مدت زمانی که رمز ورود صفحه قفل قبل از تغییر یافتن لازم دارد"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"کنترل تعداد دفعات تغییر رمز ورود قفل صفحه"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"نیاز به رمزگذاری داده های برنامه کاربردی ذخیره شده دارد"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index eab76b3..28312a1 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tyhjennä puhelimen tiedot varoituksetta palauttamalla tehdasasetukset."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Aseta laitteen yleinen välityspalvelin"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Aseta laitteen yleinen välityspalvelin käyttöön, kun käytäntö on käytössä. Vain ensimmäinen laitteen järjestelmänhallitsija voi asettaa käytettävän yleisen välityspalvelimen."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta salasanan voimassaoloaika"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valitse, kuinka pian ruudunlukituksen poiston salasana tulee vaihtaa"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Aseta ruudunlukituksen salasanan voimassaoloaika"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Määritä, miten usein ruudunlukituksen salasana tulee vaihtaa"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Aseta tallennustilan salaus"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pakota tallennettujen sovellustietojen salaus"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 44cefa3..7a6c43a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant la configuration usine"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquer le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Définir la date d\'expiration du mot de passe"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Définir exp. mot passe verr."</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Contrôler la fréquence de modification du mot de passe de verrouillage de l\'écran"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Définir cryptage du stockage"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exiger que les données d\'application stockées soient cryptées"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cd69188..860bec9 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Izbriši podatke telefona bez upozorenja vraćanjem u tvorničko stanje"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"postavi globalni proxy uređaja"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Postavi globalni proxy uređaja za upotrebu dok su pravila omogućena. Samo prvi administrator uređaja postavlja djelotvoran globalni proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Postavi istek zaporke"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nadzirite za koliko vremena zaporka za zaključani zaslon treba biti promijenjena"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Post. istek zap. zaklj. zasl."</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nadzirite koliko se često mora mijenjati zaporka za zaključavanje zaslona"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Postavi enkripciju za pohranu"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Zahtijevaj da pohranjeni podaci aplikacije budu kriptirani"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index c2a976f..f962f35 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Figyelmeztetés nélkül törli a telefon összes adatát, visszaállítva a gyári adatokat"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Az eszköz globális proxyjának beállítása"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Az eszköz globális proxyja lesz használatban, amíg az irányelv engedélyezve van. Csak az eszköz első rendszergazdája állíthatja be a tényleges globális proxyt."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Jelszó lejáratának beállítása"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Azt vezérli, mennyi időnként kell módosítani a képernyőt zároló jelszót"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Képernyőjelszó érvényessége"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Adja meg, hogy milyen gyakran kell módosítani a képernyőzár jelszavát"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Tárhelytitkosítás beállítása"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Megköveteli a tárolt alkalmazásadatok titkosítását"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 19a5cc4..7b10651 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Hapus data ponsel tanpa peringatan, dengan menyetel ulang data pabrik"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setel proxy global perangkat"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setel proxy global perangkat yang akandigunakan ketika kebijakan diaktifkan. Hanya admin perangkat pertama yang menyetel procy global yang berlaku."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Setel waktu kedaluwarsa sandi"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrol berapa lama sebelum sandi penguncian layar perlu diubah"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Setel kedaluwarsa sandi pengunci layar"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrol seberapa sering sandi pengunci layar harus diganti"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setel enkripsi penyimpanan"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Mengharuskan data aplikasi yang disimpan untuk dienkripsi"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 83da3be..76b6d1d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Cancella i dati del telefono senza preavviso eseguendo un ripristino dati di fabbrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Imposta il proxy globale del dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Imposta scadenza password"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabilisci la scadenza della password di blocco dello schermo"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Imposta scadenza password blocco schermo"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabilisci la frequenza di modifica della password di blocco dello schermo"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Imposta crittografia archivio"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Richiede la crittografia dei dati applicazione memorizzati"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2ee3b7c..1b597c8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"מחק את נתוני הטלפון ללא אזהרה, על ידי ביצוע איפוס נתוני יצרן"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"הגדר את שרת ה-proxy הגלובלי של ההתקן"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"הגדר את שרת proxy הגלובלי של ההתקן לשימוש כאשר המדיניות מופעלת. רק מנהל ההתקן הראשון מגדיר את שרת ה-proxy הגלובלי הפעיל."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תפוגת תוקף של סיסמה"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"שלוט בפרק הזמן הדרוש לשינוי הסיסמה של נעילת המסך"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"הגדר תאריך תפוגה לסיסמה של נעילת המסך"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"שלוט בתדירות שבה הסיסמה של נעילת המסך חייבת להשתנות"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"הגדר הצפנת אחסון"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"דורש שנתוני היישום המאוחסנים יהיו מוצפנים"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 04ee3a5..7594744 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"警告せずにデータの初期化を実行して端末内のデータを消去します。"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"端末のグローバルプロキシを設定"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"パスワードの有効期限の設定"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"解除パスワードの有効期限の設定"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"ロック解除パスワードの変更が必要になる頻度を指定します"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"ストレージ暗号化の設定"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"保存したアプリケーションデータが暗号化されるようにする"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 71c1b90..a718344 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"공장 초기화를 수행하여 경고 없이 휴대전화 데이터를 지웁니다."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"비밀번호 만료 설정"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"화면 잠금 비밀번호 만료 설정"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"화면 잠금 비밀번호 변경 빈도 설정"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"저장소 암호화 설정"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 32f2bf7..2580af9 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Be įspėjimo ištrinti telefono duomenis iš naujo nustatant gamyklinius duomenis"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nustatyti įrenginio bendrąjį tarpinį serverį"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nustatyti įrenginio bendrąjį tarpinį serverį, kad būtų naudojamas, kol įgalinta politika. Tik pirmasis įrenginio administratorius nustato efektyvų bendrąjį tarpinį serverį."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nustatyti slaptažodžio galiojimo pabaigą"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valdyti, per kiek laiko iki ekrano užrakinimo turi būti pakeistas slaptažodis"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Nust. ekr. užr. slapt. gal. pab."</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Valdykite, kaip dažnai reikia keisti ekrano užrakto slaptažodį"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nustatyti atmintinės šifruotę"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Saugomos programos duomenys turi būti šifruoti"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 77fb533..b7adf2d 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Dzēš tālruņa datus bez brīdinājuma, veicot rūpnīcas datu atiestatīšanu"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Iestatīt ierīces globālo starpniekserveri"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Iestatiet izmantojamo ierīces globālo starpniekserveri, kad ir iespējota politika. Spēkā esošo globālo starpniekserveri iestata tikai pirmās ierīces administrators."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Paroles beigu termiņa iestatīšana"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolē ekrāna bloķēšanas paroles maiņas intervālu"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ekr. bloķ. paroles term. iest."</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolē, cik bieži ir jāmaina ekrāna bloķēšanas parole."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Skatīt atmiņas šifrējumu"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Pieprasīt, lai saglabātie lietojumprogrammas dati tiktu šifrēti"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e010d7a..d3463fd 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tilbakestill telefonens data uten advarsel ved å utføre tilbakestilling til fabrikkstandard"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angi enhetens globale mellomtjener"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for passordet"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Angi utløpsdato for skjermlåspassordet"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Velg hvor lenge det skal gå før passordet til skjermlåsen må byttes"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Angi lagringskryptering"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Krever at lagrede programdata krypteres"</string>
<string-array name="phoneTypes">
@@ -924,7 +924,7 @@
<string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Minnekortet er skadet. Du må kanskje formatere det."</string>
<string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-lagring fjernet uventet"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Minnekortet ble tatt ut uventet"</string>
- <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-lagring før enheten tas ut av maskinen for å unngå tap av data."</string>
+ <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-enheten før du tar den ut for å unngå tap av data."</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
<string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-lagring kan trygt fjernes"</string>
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Trygt å ta ut minnekort"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cc24b00..68ab40c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"De gegevens van de telefoon zonder waarschuwing wissen door de fabrieksinstellingen te herstellen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Algemene proxy voor het apparaat instellen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Verval wachtwoord instellen"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Beheren hoe vaak het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Codering voor opslag instellen"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vereisen dat opgeslagen toepassingsgegevens kunnen worden gecodeerd"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 5ee4216..4c5f062 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Wymazywanie danych z telefonu bez ostrzeżenia, przez przywrócenie danych fabrycznych"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ustaw globalny serwer proxy urządzenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ustaw wygasanie hasła blokady"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrola częstości zmian hasła ekranu blokady"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ustaw szyfrowanie pamięci"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Wymaga szyfrowania danych zapisanych aplikacji"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 855b966..014bf88 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apagar os dados do telefone sem avisar, ao efectuar uma reposição de dados de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do aparelho"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do aparelho a ser utilizado quando a política estiver activada. Só o primeiro administrador do aparelho define o proxy global efectivo."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir tempo de validade da palavra-passe"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Def. valid. palavra-passe bloq. ecrã"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar a frequência com que a palavra-passe deve ser alterada"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Def. encriptação armazenamento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Requerer encriptação dos dados da aplicação armazenados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ba3600e..07907fb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apaga os dados do telefone sem aviso, executando uma redefinição da configuração original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Definir validade da senha"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Definir val. da senha de bloqueio"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlar a frequência com que a senha da tela de bloqueio deve ser alterada"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Definir criptografia de armazenamento"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Exigir que os dados do aplicativo armazenado sejam criptografados"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d29c25..59fc5c9 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ştergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setaţi serverul proxy global pentru dispozitiv"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Setaţi expirarea parolei"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Controlarea duratei până când parola de blocare a ecranului trebuie modificată"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Expirare parolă blocare ecran"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Stabiliţi frecvenţa de schimbare a parolei de blocare a ecranului"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Setaţi criptarea stocării"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Necesită ca datele aplicaţiei stocate să fie criptate"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 541f414f..ff67961 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Уничтожить все данные на телефоне без предупреждения путем сброса настроек"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Глобальный прокси-сервер"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Задать время действия пароля"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Задать время действия пароля перед появлением экрана блокировки"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Задать срок действия пароля"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Укажите, как часто следует менять пароль блокировки экрана"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Настроить шифрование хранилища"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Требует шифровать данные приложений, находящиеся в хранилище."</string>
<string-array name="phoneTypes">
@@ -621,7 +621,7 @@
<string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Повторите попытку"</string>
<string name="lockscreen_password_wrong" msgid="6237443657358168819">"Повторите попытку"</string>
<string name="lockscreen_plugged_in" msgid="613343852842944435">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Заряжена."</string>
+ <string name="lockscreen_charged" msgid="4938930459620989972">"Батарея заряжена"</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарядное устройство."</string>
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Нет SIM-карты."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index a97876d..5d10d27 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia telefónu"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastaviť globálny server proxy zariadenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastaviť dátum vypršania platnosti hesla"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ovládanie doby, po uplynutí ktorej treba zmeniť heslo na odomknutie obrazovky"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Nastav. koniec platnosti hesla"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifr. ukl. priestoru"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Vyžaduje šifrovanie uložených údajov aplikácií"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4e9a739..3d003fb 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Brisanje (s tovarniško ponastavitvijo) vseh podatkov v telefonu brez opozorila"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavitev globalnega strežnika proxy za napravo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Nastavite globalni strežnik proxy naprave, ki bo v uporabi, ko je pravilnik omogočen. Samo skrbnik prve naprave lahko nastavi veljaven globalni strežnik proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Nastavite, koliko časa prej je treba spremeniti geslo za odklepanje zaslona"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Nastavitev poteka gesla za zaklepanje zaslona"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Določite, kako pogosto je treba spremeniti geslo za zaklepanje zaslona"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastavitev šifriranja shrambe"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Shranjeni podatki programa morajo biti šifrirani"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7377cd9..a8d9e29 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Брисање података на телефону без упозорења враћањем фабричких података"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подесите глобални прокси сервер уређаја"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Подеси време истека лозинке"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролишите време када лозинка за закључавање екрана треба да се промени"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Подешавање истека лозинке екрана"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролишите колико често лозинка за закључавање екрана мора да се мења"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Подешавање шифровања складишта"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Захтева да сачувани подаци апликације буду шифровани"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5c1c3d8..9b93047 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ta bort data från telefonen utan förvarning genom att återställa standardinställningarna"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ange global proxyserver"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ange lösenordets utgångsdatum"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Styr hur ofta lösenordet till skärmlåset måste ändras"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Ange krypterad lagring"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Kräv att sparade applikationsdata krypteras."</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index cebae1c..62dfc29 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"ลบข้อมูลของโทรศัพท์โดยไม่มีการเตือน ด้วยการดำเนินการรีเซ็ตข้อมูลเป็นค่าเริ่มต้น"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ตั้งค่าพร็อกซีส่วนกลางของอุปกรณ์ที่จะใช้ขณะเปิดการใช้งานนโยบาย เฉพาะผู้ดูแลอุปกรณ์คนแรกเท่านั้นที่ตั้งค่าพร็อกซีส่วนกลางที่มีผลบังคับ"</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าการหมดอายุของรหัสผ่าน"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"ควบคุมระยะเวลาก่อนที่จะต้องเปลี่ยนรหัสผ่านการล็อกหน้าจอ"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"ตั้งค่าวันหมดอายุของรหัสผ่านล็อกหน้าจอ"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"ควบคุมความถี่ในการเปลี่ยนรหัสผ่านล็อกหน้าจอ"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"ตั้งค่าการเข้ารหัสที่เก็บข้อมูล"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"กำหนดว่าแอปพลิเคชันที่จัดเก็บต้องมีการเข้ารหัส"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a9a90ee..08c3ff7 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Burahin ang data ng telepono nang walang babala, sa pamamagitan ng pagsasagawa ng pag-reset sa data ng factory"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Itakda ang pandaigdigang proxy ng device"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Itakda ang pandaigdigang proxy ng device na gagamitin habang pinagana ang patakaran. Tanging ang unang admin ng device ang magtatakda sa may bisang pandaigdigang proxy."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda pag-expire ng password"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolin kung gaano katagal bago kailangang palitan ang password sa pag-lock ng screen"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Itakda expire password pag-lock scr"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kontrolin kung gaano kadalas dapat na mapalitan ang password sa pag-lock ng screen"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Itakda pag-encrypt ng imbakan"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Hinging naka-encrypt ang nakaimbak na data ng application"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index af0074b..0b0ef01 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silin"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Cihaz genelinde geçerli proxy\'i ayarla"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Şifre süre sonu tarihi ayarla"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Ekr kilt şifr süre sonu ayarla"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Ekran kilitleme şifresinin hangi sıklıkla değiştirilmesi gerektiğini denetleyin"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Deplm şifrelemesini ayarla"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Depolanan uygulama verisinin şifrelenmiş olmasını gerektir"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bdfb444..eabbea1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Видаляє дані телефону без попередження, відновлюючи заводські налаштування"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Установ. глоб. проксі пристрою"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Устан. використ. глоб. проксі, коли ввімкнено політику. Лише адміністратор першого пристрою встановлює активний глоб. проксі."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Регулює, за скільки часу перед блокуванням екрана треба змінювати пароль"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Установити термін дії пароля блокування екрана"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Контролювати частоту зміни пароля блокування екрана"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Установити шифрування носія"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Потрібно, щоб дані збереженої програми були зашифровані"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8019069..812004b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Xóa dữ liệu trên điện thoại mà không cần cảnh báo, bằng cách thực hiện đặt lại về dữ liệu gốc"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Đặt proxy chung của điện thoại"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Đặt proxy chung của điện thoại được sử dụng trong khi chính sách được bật. Chỉ quản trị viên đầu tiên của điện thoại mới có thể đặt proxy chung hiệu quả."</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kiểm soát thời lượng trước khi mật khẩu khóa màn hình cần được thay đổi"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Đặt hết hạn mật khẩu khóa màn hình"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"Kiểm soát tần suất bắt buộc phải thay đổi mật khẩu khóa màn hình"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Đặt mã hóa dung lượng lưu trữ"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"Yêu cầu dữ liệu ứng dụng được lưu trữ phải được mã hóa"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 072dcc1..3b70dd7 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"恢复出厂设置时,将擦除手机上的数据而不发送警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"设置设备全局代理"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用政策的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"设置密码有效期"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制屏幕锁定密码的使用期限"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"设置锁定屏幕密码的有效期"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制锁定屏幕密码的更改频率"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"设置存储设备加密"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"需要对存储的应用程序数据进行加密"</string>
<string-array name="phoneTypes">
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ec515bc..e72b28e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -486,8 +486,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"執行重設為原廠設定時,系統會直接清除手機資料而不提出警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
- <!-- outdated translation 4740941403188940274 --> <string name="policylab_expirePassword" msgid="885279151847254056">"設定密碼到期日"</string>
- <!-- outdated translation 6626724939177185949 --> <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制螢幕鎖定密碼的使用期限"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"設定螢幕上鎖密碼到期日"</string>
+ <string name="policydesc_expirePassword" msgid="4844430354224822074">"控制螢幕上鎖密碼的變更頻率"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"設定儲存裝置加密"</string>
<string name="policydesc_encryptedStorage" msgid="2504984732631479399">"必須為儲存的應用程式資料加密"</string>
<string-array name="phoneTypes">
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 3f78ce0..d23dfd3 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -49,13 +49,8 @@
suite.addTestSuite(WifiApStress.class);
suite.addTestSuite(WifiStressTest.class);
} else {
- // create a new test suite
- suite.setName("WifiOnlyStressTests");
- String[] methodNames = {"testWifiScanning"};
- Class<WifiStressTest> testClass = WifiStressTest.class;
- for (String method: methodNames) {
- suite.addTest(TestSuite.createTest(testClass, method));
- }
+ // only the wifi stress tests
+ suite.addTestSuite(WifiStressTest.class);
}
return suite;
}
@@ -68,11 +63,13 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- String valueStr = (String) icicle.get("softap_iterations");
- if (valueStr != null) {
- int iteration = Integer.parseInt(valueStr);
- if (iteration > 0) {
- mSoftapIterations = iteration;
+ if (!UtilHelper.isWifiOnly()) {
+ String valueStr = (String) icicle.get("softap_iterations");
+ if (valueStr != null) {
+ int iteration = Integer.parseInt(valueStr);
+ if (iteration > 0) {
+ mSoftapIterations = iteration;
+ }
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 2f2a283..7578e67 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -18,6 +18,7 @@
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -264,18 +265,22 @@
assertTrue("Wait for Wi-Fi to idle timeout",
mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
- // use long timeout as the pppd startup may take several retries.
- assertTrue("Wait for cellular connection timeout",
- mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
- ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ if (!UtilHelper.isWifiOnly()) {
+ // use long timeout as the pppd startup may take several retries.
+ assertTrue("Wait for cellular connection timeout",
+ mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ }
sleep(mWifiSleepTime + WIFI_IDLE_DELAY, "Interrupted while device is in sleep mode");
// Verify the wi-fi is still off and data connection is on
assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
- assertEquals("Cellular connection is down", State.CONNECTED,
- mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
- assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+ if (!UtilHelper.isWifiOnly()) {
+ assertEquals("Cellular connection is down", State.CONNECTED,
+ mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+ assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+ }
// Turn screen on again
mAct.turnScreenOn();
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 1428b63..68a158e 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -261,6 +261,23 @@
# key 239 "KEY_KBDILLUMUP"
# key 240 "KEY_UNKNOWN"
+key 256 BUTTON_1
+key 257 BUTTON_2
+key 258 BUTTON_3
+key 259 BUTTON_4
+key 260 BUTTON_5
+key 261 BUTTON_6
+key 262 BUTTON_7
+key 263 BUTTON_8
+key 264 BUTTON_9
+key 265 BUTTON_10
+key 266 BUTTON_11
+key 267 BUTTON_12
+key 268 BUTTON_13
+key 269 BUTTON_14
+key 270 BUTTON_15
+key 271 BUTTON_16
+
key 288 BUTTON_1
key 289 BUTTON_2
key 290 BUTTON_3
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 4747379..b0c96b1 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -1,821 +1,8 @@
-page.title=Common Tasks and How to Do Them in Android
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
@jd:body
-<ul>
- <li><a href="#neweclipseandroidproject">Creating an Android Application using
- the Eclipse plugin</a></li>
- <li><a href="#newandroidprojectnoeclipse">Creating an Android Application without
- the Eclipse plugin</a></li>
- <li><a href="#addexternallibrary">Adding an External Library (.jar) using Eclipse</a></li>
- <li><a href="#implementcallbacks">Implementing Activity callbacks</a> (Android
- calls your activity at various key moments in its life cycle. You must know
- how to handle each of these to draw your screen, initialize class members,
- and acquire data.)</li>
- <li><a href="#opennewscreen">Opening a new screen</a></li>
- <li><a href="#listening">Listening for button clicks </a></li>
- <li><a href="#configurewindowproperties">Configuring general window properties </a></li>
- <li><a href="#localhostalias">Referring to localhost from the emulated environment</a></li>
- <li><a href="#appstate">Storing and retrieving state</a></li>
- <li><a href="{@docRoot}guide/topics/data/data-storage.html#preferences">Storing and retrieving preferences</a></li>
- <li><a href="#storingandretrieving">Storing and retrieving larger or more complex
- persistent data</a> (files and data) </li>
- <li><a href="#playback">Playing audio, video, still, or other media files</a></li>
- <li><a href="#broadcastreceivers">Listening for and broadcasting global messages
- and setting alarms</a></li>
- <li><a href="#alerts">Displaying alerts </a></li>
- <li><a href="#progressbar">Displaying a progress bar</a> </li>
- <li><a href="#addmenuitems">Adding items to the screen menu</a> </li>
- <li><a href="#webpage">Display a web page</a> </li>
- <li><a href="#binding">Binding to data</a></li>
- <li><a href="#handle">Getting a Handle to a Screen Element</a></li>
- <li><a href="#captureimages">Capture images from the phone camera </a></li>
- <li><a href="#threading">Handling expensive operations in the UI thread</a></li>
- <li><a href="#selectingtext">Selecting, highlighting, or styling portions of
- text</a></li>
- <li><a href="#querymap">Utilizing attributes in a Map query</a></li>
- <li><a href="#filelist">List of files for an Android application</a></li>
- <li><a href="#logging">Print messages to a log file</a></li>
-</ul>
-<p>The ApiDemos sample application includes many, many examples of common
-tasks and UI features. See the code inside
-<code><sdk>samples/ApiDemos</code> and the other sample applications
-under the <code>samples/</code> folder in the SDK.</p>
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/commontasks.html"
+</script>
-
-<h2 id="neweclipseandroidproject">Creating an Android Application using the Eclipse Plugin</h2>
-
-<p>Using the Android Eclipse plugin is the fastest and easiest way
-to start creating a new Android application. The plugin automatically generates
-the correct project structure for your application, and keeps the resources
-compiled for you automatically.</p>
-
-<p>It is still a good idea to know what is going on though. Take a look at <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
-to understand the basics of how an Android application works.</p>
-
-<p>You should also take a look at the ApiDemos application and the other sample
-applications included in the SDK, in the <code><sdk>/samples/</code>
-folder in the SDK.</p>
-
-<p>Finally, a great way to started with Android development in Eclipse is to
-follow both the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello,
-World</a> and <a
-href="{@docRoot}resources/tutorials/notepad/index.html">Notepad</a> code
-tutorials. In particular, the start of the Hello Android tutorial is an
-excellent introduction to creating a new Android application in Eclipse.</p>
-
-<h2 id="newandroidprojectnoeclipse">Creating an Android Application without the Eclipse Plugin</h2>
-
-<p>This topic describes the manual steps in creating an Android application.
-Before reading this, you should read <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
-to understand the basics of how an Android application works. You might also
-want to look at the sample code included with the Android SDK, in the
-<code><sdk>/samples/</code> directory. </p>
-
-<p>Here is a list of the basic steps in building an application.</p>
-<ol>
- <li><strong>Create your required resource files</strong> This includes
- the AndroidManifest.xml global description file, string files that your application
- needs, and layout files describing your user interface. A full list of optional
- and required files and syntax details for each is given in <a href="#filelist">File
- List for an Android Application</a>. </li>
- <li><strong>Design your user interface</strong> See <a
- href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for
- details on elements of the Android screen. </li>
- <li><strong>Implement your Activity </strong>(this page)<strong> </strong> You
- will create one class/file for each screen in your application. Screens will
- inherit from an {@link android.app android.app} class, typically {@link android.app.Activity
- android.app.Activity} for basic screens, {@link android.app.ListActivity
- android.app.ListActivity} for list screens, or {@link android.app.Dialog
- android.app.Dialog} for dialog boxes. You will implement the required callbacks
- that let you draw your screen, query data, and commit changes, and also perform
- any required tasks such as opening additional screens or reading data from
- the device. Common tasks, such as opening a new screen or reading data from
- the device, are described below.
- The list of files you'll need for your application are described in <a href="#filelist">List
- of Files for an Android Application</a>. </li>
- <li><strong><a href="{@docRoot}guide/developing/other-ide.html#buildingwithant">Build and install your
- package</a>.</strong> The Android SDK has some nice tools for generating
- projects and debugging code. </li>
-</ol>
-
-<h2 id="addexternallibrary">Adding an External Library (.jar) using Eclipse</h2>
-<p>
-You can use a third party JAR in your application by adding it to your Eclipse project as follows:
-</p>
-<ol>
-<li>
-In the <strong>Package Explorer</strong> panel, right-click on your project and select <strong>Properties</strong>.
-<li>
-Select <strong>Java Build Path</strong>, then the tab <strong>Libraries</strong>.
-<li>
-Press the <strong>Add External JARs...</strong> button and select the JAR file.
-</ol>
-<p>
-Alternatively, if you want to include third party JARs with your package, create a new directory for them within your project and select <strong>Add Library...</strong> instead.</p>
-<p>
-It is not necessary to put external JARs in the assets folder.
-</p>
-
-<a name="implementcallbacks" id="implementcallbacks"></a>
-<h2>Implementing Activity Callbacks</h2>
-<p>Android calls a number of callbacks to let you draw your screen, store data before
- pausing, and refresh data after closing. You must implement at least some of
- these methods. See the <a
-href="{@docRoot}guide/topics/fundamentals/activites.html#Lifecycle">Activities</a>
- document to learn when and in what order these methods
- are called. Here are some of the standard types of screen classes that Android provides:</p>
-<ul>
- <li>{@link android.app.Activity android.app.Activity} - This is a standard screen,
- with no specialization.</li>
- <li>{@link android.app.ListActivity android.app.ListActivity} - This is a screen
- that is used to display a list of something. It hosts a ListView object,
- and exposes methods to let you identify the selected item, receive callbacks
- when the selected item changes, and perform other list-related actions. </li>
- <li>{@link android.app.Dialog android.app.Dialog} - This is a small, popup dialog-style
- window that isn't intended to remain in the history stack. (It is not resizeable
- or moveable by the user.)</li>
-</ul>
-
-<a name="opennewscreen" id="opennewscreen"></a><h2>Opening a New Screen</h2>
-<p>Your Activity will often need to open another Activity screen as it progresses.
- This new screen can be part of the same application or part of another application,
- the new screen can be floating or full screen, it can return a result, and you
- can decide whether to close this screen and remove it from the history stack
- when you are done with it, or to keep the screen open in history. These next
- sections describe all these options. </p>
-<h3>Floating or full?<a name="floatingorfull" id="floatingorfull"></a></h3>
-<p>When you open a new screen you can decide whether to make it transparent or floating,
- or full-screen. The choice of new screen affects the event sequence of events
- in the old screen (if the new screen obscures the old screen, a different
- series of events is called in the old screen). See the <a
- href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a> document for
-details. </p>
-<p>Transparent or floating windows are implemented in three
- standard ways: </p>
-<ul>
- <li>Create an {@link android.app.Dialog app.Dialog} class </li>
- <li>Create an {@link android.app.AlertDialog app.AlertDialog} class </li>
- <li>Set the {@link android.R.style#Theme_Dialog} <em>theme</em> attribute to <code>@android:style/Theme.Dialog</code>
- in your AndroidManifest.xml file. For example:
- <pre><activity class="AddRssItem" android:label="Add an item" android:theme="@android:style/Theme.Dialog"/>
-</pre></li>
-</ul>
-<p>Calling startActivity() or startActivityForResult() will open a new screen in whatever
- way it defines itself (if it uses a floating theme it will be floating,
- otherwise it will be full screen). </p>
-<h3>Opening a Screen </h3>
-<p>When you want to open a new screen, you can either explicitly specify the activity
- class to open, or you can let the operating system decide which screen to open,
- based upon the data and various parameters you pass in. A screen is opened by
- calling {@link android.app.Activity#startActivity(android.content.Intent) startActivity}
- and passing in an {@link android.content.Intent Intent} object, which specifies
- the criteria for the handling screen. To specify a specific screen, call Intent.setClass
- or setClassName with the exact activity class to open. Otherwise, set a variety
- of values and data, and let Android decide which screen is appropriate to open.
- Android will find one or zero Activities that match the specified requirements;
- it will never open multiple activities for a single request. More information
- on Intents and how Android resolves them to a specific class is given in the
- {@link android.content.Intent Intent} topic. </p>
-<a name="intentexamples" id="intentexamples"></a><h3>Some Intent examples </h3>
-<p>The following snippet loads the com.android.samples.Animation1 class, and
- passes it some arbitrary data.:</p>
-<pre>Intent myIntent = new Intent();
-myIntent.setClassName("com.android.samples", "com.android.samples.Animation1");
-myIntent.putExtra("com.android.samples.SpecialValue", "Hello, Joe!"); // key/value pair, where key needs current package prefix.
-startActivity(myIntent); </pre>
-<p>The next snippet requests that a Web page be opened by specifying the VIEW action,
- and a URI data string starting with "http://" schema:</p>
-<pre>Intent myIntent = new Intent(Intent.VIEW_ACTION, Uri.parse("http://www.google.com"));</pre>
-<p>Here is the intent filter from the AndroidManifest.xml file for com.android.browser:</p>
-<pre><intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <scheme android:name="http" />
- <scheme android:name="https" />
- <scheme android:name="file" />
-</intent-filter> </pre>
-<p>Android defines a number of standard values, for instance the action constants
- defined by {@link android.content.Intent}. You can define custom values, but
- both the caller and handler must use them. See the <intent-filter>
- tag description in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
- File</a> for more information on the manifest syntax for the handling
- application. </p>
-<a name="returningaresult" id="returningaresult"></a><h3>Returning a Result from a Screen</h3>
-<p>A window can return a result after it closes. This result will be passed back
- into the calling Activity's {@link android.app.Activity#onActivityResult(int,int,android.content.Intent)
- onActivityResult()} method, which can supply an Intent containing arbitrary data, along with
- the request code passed to startActivityForResult(). Note that you must call the {@link
- android.app.Activity#startActivityForResult(android.content.Intent,int) startActivityForResult()}
- method that accepts a request code parameter to get this callback. The following
- code demonstrates opening a new screen and retrieving a result. </p>
-<pre>// Open the new screen.
-public void onClick(View v){
- // Start the activity whose result we want to retrieve. The
- // result will come back with request code GET_CODE.
- Intent intent = new Intent(this, com.example.app.ChooseYourBoxer.class);
- startActivityForResult(intent, CHOOSE_FIGHTER);
-}
-
-// Listen for results.
-protected void onActivityResult(int requestCode, int resultCode, Intent data){
- // See which child activity is calling us back.
- switch (resultCode) {
- case CHOOSE_FIGHTER:
- // This is the standard resultCode that is sent back if the
- // activity crashed or didn't doesn't supply an explicit result.
- if (resultCode == RESULT_CANCELED){
- myMessageboxFunction("Fight cancelled");
- }
- else {
- myFightFunction(data);
- }
- default:
- break;
- }
-}
-
-// Class SentResult
-// Temporary screen to let the user choose something.
- private OnClickListener mLincolnListener = new OnClickListener(){
- public void onClick(View v) {
- Bundle stats = new Bundle();
- stats.putString("height","6\'4\"");
- stats.putString("weight", "190 lbs");
- stats.putString("reach", "74\"");
- setResult(RESULT_OK, "Lincoln", stats);
- finish();
- }
- };
-
- private OnClickListener mWashingtonListener = new OnClickListener() {
- public void onClick(View v){
- Bundle stats = new Bundle();
- stats.putString("height","6\'2\"");
- stats.putString("weight", "190 lbs");
- stats.putString("reach", "73\"");
- setResult(RESULT_OK, "Washington", Bundle);
- finish();
- }
- };
- </pre>
-<h3>Lifetime of the new screen </h3>
-<p>An activity can remove itself from the history stack by calling {@link android.app.Activity#finish()
- Activity.finish()} on itself, or the activity that opened the screen can call
- {@link android.app.Activity#finishActivity(int) Activity.finishActivity()}
- on any screens that it opens to close them. </p>
-<a name="listening" id="listening"></a><h2>Listening for Button Clicks</h2>
-<p>Button click and other UI event capturing are covered in <a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a> on the UI Design page.</p>
-<a name="configurewindowproperties" id="configurewindowproperties"></a><h2>Configuring General Window Properties</h2>
-<p>You can set a number of general window properties, such as whether to display
- a title, whether the window is floating, and whether it displays an icon, by
- calling methods on the {@link android.view.Window Window} member
- of the underlying View object for the window. Examples include calling {@link
- android.app.Activity#getWindow() getWindow().requestFeature()} (or the convenience
- method {@link android.app.Activity#requestWindowFeature(int) requestWindowFeature(<em>some_feature</em>)})
- to hide the title. Here is an example of hiding the title bar:</p>
-<pre>//Hide the title bar
-requestWindowFeature(Window.FEATURE_NO_TITLE);
-</pre>
-<p>A better way to achieve the same end is to specify a theme in your Android
-Manifest file:</p>
-<pre><application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
-</pre>
-<p>This is preferable because it tells the system not to show a title bar while
-your application is starting up. With the explicit method call, your application
-will have a title bar visible to the user until <code>onCreate</code> runs.</p>
-<p>(Note that this can be applied to either the <code><application></code>
-tag or to individual <code><activity></code> tags.)</p>
-<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
-<p>
-If you need to refer to your host computer's <em>localhost</em>, such as when you
-want the emulator client to contact a server running on the same host, use the alias
-<code>10.0.2.2</code> to refer to the host computer's loopback interface.
-From the emulator's perspective, localhost (<code>127.0.0.1</code>) refers to its own
-loopback interface.
-</p>
-<a name="appstate" id="appstate"></a><h2>Storing and Retrieving State</h2>
-<p>If your application is dumped from memory because of space concerns, it will lose
- all user interface state information such as checkbox state and text box values
- as well as class member values. Android calls {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)
- Activity.onSaveInstanceState} before it pauses the application. This method hands in a {@link
- android.os.Bundle Bundle} that can be used to store name/value pairs that will
- persist and be handed back to the application even if it is dropped from memory.
- Android will pass this Bundle back to you when it calls {@link android.app.Activity#onCreate(android.os.Bundle)
- onCreate()}. This Bundle only exists while the application is still in the history
- stack (whether or not it has been removed from memory) and will be lost when
- the application is finalized. See the topics for {@link android.app.Activity#onSaveInstanceState} and
- {@link android.app.Activity#onCreate} for
- examples of storing and retrieving state.</p>
-<p>Read more about the lifecycle of an activity in <a
-href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a> document.</p>
-<h3>Storing and Retrieving Larger or More Complex Persistent Data<a name="storingandretrieving" id="storingandretrieving"></a></h3>
-<p>Your application can store files or complex collection objects, and reserve them
- for private use by itself or other activities in the application, or it can expose
- its data to all other applications on the device. See <a href="{@docRoot}guide/topics/data/data-storage.html">Storing,
- Retrieving, and Exposing Data</a> to learn how to store and retrieve private data,
- how to store and retrieve common data from the device, and how to expose your
- private data to other applications.</p>
-<a name="playback" id="playback"></a><h2>Playing Media Files</h2>
-<p>Please see the document <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> for more details.</p>
-<a name="broadcastreceivers" id="broadcastreceivers"></a><h2>Listening For and Broadcasting Global Messages, and Setting Alarms</h2>
-<p>You can create a listening class that can be notified or even instantiated whenever
- a specific type of system message is sent.
-</p>
-<p>The listening classes, called broadcast receivers, extend {@link android.content.BroadcastReceiver
- BroadcastReceiver}. If you want Android to instantiate the object whenever an appropriate
- intent notification is sent, define the receiver with a <code><receiver></code> element
- in the AndroidManifest.xml file. If the caller is expected to instantiate the
- object in preparation to receive a message, this is not required. The receiver
- will get a call to their {@link android.content.BroadcastReceiver#onReceive(android.content.Context,android.content.Intent)
- BroadcastReceiver.onReceive()} method. A receiver can define an <code><intent-filter></code> tag
- that describes the types of messages it will receive. Just as Android's IntentResolver
- will look for appropriate Activity matches for a startActivity() call, it will
- look for any matching Receivers (but it will send the message to all matching
- receivers, not to the "best" match). </p>
-<p>To send a notification, the caller creates an {@link android.content.Intent Intent}
- object and calls {@link android.app.Activity#sendBroadcast(android.content.Intent)
- Context.sendBroadcast()} with that Intent. Multiple recipients can receive
- the same message. You can broadcast an Intent message to an intent receiver in
- any application, not only your own. If the receiving class is not registered
- using <code><receiver></code> in its manifest, you can dynamically instantiate
- and register a receiver by calling {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,android.content.IntentFilter)
- Context.registerReceiver()}. </p>
-<p>Receivers can include intent filters to specify what kinds of intents they are
- listening for. Alternatively, if you expect a single known caller to contact
- a single known receiver, the receiver does not specify an intent filter, and
- the caller specifies the receiver's class name in the Intent by calling {@link
- android.content.Intent#setClassName(java.lang.String, java.lang.String) Intent.setClassName()}
- with the recipient's class name. The recipient receives a {@link android.content.Context
- Context} object that refers to its own package, not to the package of the sender.</p>
-<p><em><strong>Note:</strong></em> If a receiver or broadcaster
- enforces permissions, your application might need to request permission
- to send or receive messages from that object. You can request permission by using
- the <uses-permission> tag in the manifest. </p>
-<p>Here is a code snippet of a sender and receiver. This example does not demonstrate
- registering receivers dynamically. For a full code example, see the AlarmService
- class in the ApiDemos project.</p>
-<h3>Sending the message</h3>
-<pre>// We are sending this to a specific recipient, so we will
-// only specify the recipient class name.
-Intent intent = new Intent(this, AlarmReceiver.class);
-intent.putExtra("message","Wake up.");
-sendBroadcast(intent);
-</pre>
-<h3>Receiving the message</h3>
-<p><strong>Receiver AndroidManifest.xml </strong>(because there is no intent filter
- child, this class will only receive a broadcast when the receiver class is specified
- by name, as is done in this example):</p>
-<pre>
-<receiver class=".AlarmReceiver" /></pre>
-<p><strong>Receiver Java code: </strong></p>
-<pre>
-public class AlarmReceiver extends BroadcastReceiver{
- // Display an alert that we've received a message.
- @Override
- public void onReceive(Context context, Intent intent){
- // Send a text notification to the screen.
- NotificationManager nm = (NotificationManager)
- context.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notifyWithText(R.id.alarm,
- "Alarm!!!",
- NotificationManager.LENGTH_SHORT,
- null);
- }
-} </pre>
-<h3>Other system messages</h3>
-<p>You can listen for other system messages sent by Android as well, such as USB
- connection/removal messages, SMS arrival messages, and timezone changes. See
- {@link android.content.Intent} for a list of broadcast messages to listen for.
- Messages are marked "Broadcast Action" in the documentation. </p>
-<h3>Listening for phone events<a name="phoneevents" id="phoneevents"></a></h3>
-<p>The {@link android.telephony android.telephony} package overview page describes how to
- register to listen for phone events. </p>
-<a name="alarms" id="alarms"></a><h3>Setting Alarms </h3>
-<p>Android provides an {@link android.app.AlarmManager AlarmManager} service that
- will let you specify an Intent to send at a designated time. This intent is typically
- used to start an application at a preset time. (Note: If you want to send
- a notification to a sleeping or running application, use {@link android.os.Handler
- Handler} instead.)</p>
-<a name="alerts" id="alerts"></a><h2>Displaying Alerts</h2>
-<p>There are two major kinds of alerts that you may display to the user:
-(1) Normal alerts are displayed in response to a user action, such as
-trying to perform an action that is not allowed. (2) Out-of-band alerts,
-called notifications, are
-displayed as a result of something happening in the background, such as the
-user receiving new e-mail.</p>
-
-<a name="dialogsandalerts" id="dialogsandalerts"></a><h3>Normal Alerts</h3>
-
-<p>Android provides a number of ways for you to show popup notifications to your
- user as they interact with your application. </p>
-<table width="100%" border="1">
- <tr>
- <th scope="col">Class</th>
- <th scope="col">Description</th>
- </tr>
- <tr>
- <td>{@link android.app.Dialog app.Dialog}</td>
- <td>A generic floating dialog box with a layout that you design. </td>
- </tr>
- <tr>
- <td><p>{@link android.app.AlertDialog app.AlertDialog}</p></td>
- <td>A popup alert dialog with two buttons (typically OK and Cancel) that
- take callback handlers. See the section after this table for more details. </td>
- </tr>
- <tr>
- <td>{@link android.app.ProgressDialog ProgressDialog} </td>
- <td>A dialog box used to indicate progress of an operation with a known progress
- value or an indeterminate length (setProgress(bool)). See <strong>Views</strong> > <strong>Progress Bar</strong> in
- ApiDemos for examples. </td>
- </tr>
- <tr>
- <td>Activity</td>
- <td>By setting the theme of an activity to
- {@link android.R.style#Theme_Dialog
- android:theme="@android:style/Theme.Dialog"},
- your activity will take on
- the appearance of a normal dialog, floating on top of whatever was
- underneath it. You usually set the theme through the
- {@link android.R.attr#theme android:theme} attribute in your AndroidManifest.xml.
- The advantage of this
- over Dialog and AlertDialog is that Application has a much better managed
- life cycle than dialogs: if a dialog goes to the background and is killed,
- you cannot recapture state, whereas Application exposes a {@link android.os.Bundle
- Bundle} of saved values in <code>onCreate()</code> to help you maintain state.</td>
- </tr>
-</table>
-<h3>AlertDialog</h3>
-<p>This is a basic warning dialog box that lets you configure a message, button text,
- and callback. You can create one by calling using the {@link
- android.app.AlertDialog.Builder} class, as shown here. </p>
-<pre>private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case ACCEPT_CALL:
- answer(msg.obj);
- break;
-
- case BOUNCE_TO_VOICEMAIL:
- voicemail(msg.obj);
- break;
-
- }
- }
-};
-
-
-private void IncomingMotherInLawCall(Connection c) {
- String Text;
-
- // "Answer" callback.
- Message acceptMsg = Message.obtain();
- acceptMsg.target = mHandler;
- acceptMsg.what = ACCEPT_CALL;
- acceptMsg.obj = c.getCall();
-
- // "Cancel" callback.
- final Message rejectMsg = Message.obtain();
- rejectMsg.target = mHandler;
- rejectMsg.what = BOUNCE_TO_VOICEMAIL;
- rejectMsg.obj = c.getCall();
-
- new AlertDialog.Builder(this)
- .setMessage("Phyllis is calling")
- .setPositiveButton("Answer", acceptMsg)
- .setOnCancelListener(new OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- rejectMsg.sendToTarget();
- }});
- .show();
-} </pre>
-
-<h3>Notifications</h3>
-
-<p>Out-of-band alerts should always be displayed using the
-{@link android.app.NotificationManager}, which allows you to tell the user
-about something they may be interested in without disrupting what they are
-currently doing. A notification can be anything from a brief pop-up box
-informing the user of the new information, through displaying a persistent
-icon in the status bar, to vibrating, playing sounds, or flashing lights to
-get the user's attention. In all cases, the user must explicitly shift their
-focus to the notification before they can interact with it.</p>
-
-<p>The following code demonstrates using NotificationManager to display a basic text
- popup when a new SMS message arrives in a listening service, and provides the
- current message count. You can see several more examples in the ApiDemos application,
- under app/ (named <em>notification</em>*.java).</p>
-<pre>static void setNewMessageIndicator(Context context, int messageCount){
- // Get the static global NotificationManager object.
- NotificationManager nm = NotificationManager.getDefault();</p>
-
- // If we're being called because a new message has been received,
- // then display an icon and a count. Otherwise, delete the persistent
- // message.
- if (messageCount > 0) {
- nm.notifyWithText(myApp.NOTIFICATION_GUID, // ID for this notification.
- messageCount + " new message" + messageCount > 1 ? "s":"", // Text to display.
- NotificationManager.LENGTH_SHORT); // Show it for a short time only.
- }
-}</pre>
-<p>To display a notification in the status bar and have it launch an intent when
- the user selects it (such as the new text message notification does), call {@link
- android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()},
- and pass in vibration patterns, status bar icons, or Intents to associate with
- the notification. </p>
-<a name="progressbar" id="progressbar"></a><h2>Displaying a Progress Bar</h2>
-<p>An activity can display a progress bar to notify the user that something is happening.
- To display a progress bar in a screen, call {@link android.app.Activity#requestWindowFeature(int)
- Activity.requestWindowFeature(Window.FEATURE_PROGRESS)}. To set the value
- of the progress bar, call {@link android.view.Window#setFeatureInt(int,int)
- Activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, <em>level</em>)}.
- Progress bar values are from 0 to 9,999, or set the value to 10,000 to make the
- progress bar invisible. </p>
-<p>You can also use the {@link android.app.ProgressDialog ProgressDialog} class,
- which enables a dialog box with an embedded progress bar to send a "I'm working
- on it" notification to the user. </p>
-<a name="addmenuitems" id="addmenuitems"></a><h2>Adding Items to the Screen Menu</h2>
-<p>See <a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>.</p>
-
-<a name="webpage" id="webpage"></a><h2>Display a Web Page</h2>
-<p>Use the {@link android.webkit.WebView webkit.WebView} object. </p>
-<a name="binding" id="binding"></a><h2>Binding to Data</h2>
-<p>You can bind a ListView to a set of underlying data by using a shim class called
- {@link android.widget.ListAdapter ListAdapter} (or a subclass). ListAdapter subclasses
- bind to a variety of data sources, and expose a common set of methods such as
- getItem() and getView(), and uses them to pick View items to display in its list.
- You can extend ListAdapter and override getView() to create your own custom list
- items. There are essentially only two steps you need to perform to bind to data: </p>
-<ol>
- <li>Create a ListAdapter object and specify its data source</li>
- <li>Give the ListAdapter to your ListView object.</li>
-</ol>
-<p>That's it!</p>
-<p>Here's an example of binding a ListActivity screen to the results from a cursor
- query. (Note that the setListAdapter() method shown is a convenience method that
- gets the page's ListView object and calls setAdapter() on it.)</p>
-<pre>// Run a query and get a Cursor pointing to the results.
-Cursor c = People.query(this.getContentResolver(), null);
-startManagingCursor(c);
-
-// Create the ListAdapter. A SimpleCursorAdapter lets you specify two interesting things:
-// an XML template for your list item, and
-// The column to map to a specific item, by ID, in your template.
-ListAdapter adapter = new SimpleCursorAdapter(this,
- android.R.layout.simple_list_item_1, // Use a template that displays a text view
- c, // Give the cursor to the list adapter
- new String[] {People.NAME} , // Map the NAME column in the people database to...
- new String[] {"text1"}); // The "text1" view defined in the XML template
-setListAdapter(adapter);</pre>
-<p>See view/List4 in the ApiDemos project for an example of extending ListAdapter
- for a new data type. </p>
-
-<a name="handle"></a>
-
-<h2>Getting a Handle to a Screen Element</h2>
-<p>You can get a handle to a screen element by calling {@link
-android.app.Activity#findViewById(int) Activity.findViewById}. You can then use
-the handle to set or retrieve any values exposed by the object. </p>
-<a name="captureimages" id="captureimages"></a><h2>Capture Images from the Phone Camera</h2>
-<p>You can hook into the device's camera onto your own Canvas object by using the
- {@link android.hardware.Camera Camera} class. See that class's documentation,
- and the ApiDemos project's Camera Preview application (Graphics/Camera Preview)
- for example code. </p>
-
-
-<a name="threading" id="threading"></a><h2>Handling Expensive Operations in the UI Thread</h2>
-<p>Avoid performing long-running operations (such as network I/O) directly in the UI thread —
-the main thread of an application where the UI is run — or your application may be blocked
-and become unresponsive. Here is a brief summary of the recommended approach for handling expensive operations:</p>
-<ol>
-<li>Create a Handler object in your UI thread</li>
-<li>Spawn off worker threads to perform any required expensive operations</li>
-<li>Post results from a worker thread back to the UI thread's handler either through a Runnable or a {@link android.os.Message}</li>
-<li>Update the views on the UI thread as needed</li>
-</ol>
-
-<p>The following outline illustrates a typical implementation:</p>
-
-<pre>
-public class MyActivity extends Activity {
-
- [ . . . ]
- // Need handler for callbacks to the UI thread
- final Handler mHandler = new Handler();
-
- // Create runnable for posting
- final Runnable mUpdateResults = new Runnable() {
- public void run() {
- updateResultsInUi();
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- [ . . . ]
- }
-
- protected void startLongRunningOperation() {
-
- // Fire off a thread to do some work that we shouldn't do directly in the UI thread
- Thread t = new Thread() {
- public void run() {
- mResults = doSomethingExpensive();
- mHandler.post(mUpdateResults);
- }
- };
- t.start();
- }
-
- private void updateResultsInUi() {
-
- // Back in the UI thread -- update our UI elements based on the data in mResults
- [ . . . ]
- }
-}
-</pre>
-
-<p>For further discussions on this topic, see
-<a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a>
-and the {@link android.os.Handler} documentation.</p>
-
-<a name="selectingtext" id="selectingtext"></a><h2>Selecting, Highlighting, or Styling Portions of Text</h2>
-<p>You can highlight or style the formatting of strings or substrings of text in
- a TextView object. There are two ways to do this:</p>
-<ul>
- <li>If you use a <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">string resource</a>,
- you can add some simple styling, such as bold or italic using HTML notation.
- The currently supported tags are: <code>B</code> (bold),
- <code>I</code> (italic), <code>U</code> (underline),
- <code>TT</code> (monospace), <code>BIG</code>, <code>SMALL</code>,
- <code>SUP</code> (superscript), <code>SUB</code> (subscript),
- and <code>STRIKE</code> (strikethrough).
- So, for example, in res/values/strings.xml you could declare this:<br />
- <code><resource><br />
- <string id="@+id/styled_welcome_message">We
- are <b><i>so</i></b> glad to see you.</string><br />
- </resources></code></li>
- <li>To style text on the fly, or to add highlighting or more complex styling,
- you must use the Spannable object as described next. </li>
-</ul>
-<p>To style text on the fly, you must make sure the TextView is using {@link android.text.Spannable}
- storage for the text (this will always be true if the TextView is an EditText),
- retrieve its text with {@link android.widget.TextView#getText}, and call {@link
- android.text.Spannable#setSpan}, passing in a new style class from the {@link
- android.text.style} package and the selection range. </p>
-<p>The following code snippet demonstrates creating a string with a highlighted section,
- italic section, and bold section, and adding it to an EditText object. </p>
-<pre>// Get our EditText object.
-EditText vw = (EditText)findViewById(R.id.text);
-
-// Set the EditText's text.
-vw.setText("Italic, highlighted, bold.");
-
-// If this were just a TextView, we could do:
-// vw.setText("Italic, highlighted, bold.", TextView.BufferType.SPANNABLE);
-// to force it to use Spannable storage so styles can be attached.
-// Or we could specify that in the XML.
-
-// Get the EditText's internal text storage
-Spannable str = vw.getText();
-
-// Create our span sections, and assign a format to each.
-str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new BackgroundColorSpan(0xFFFFFF00), 8, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, str.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-</pre>
-
-<a name="querymap" id="querymap"></a><h2>Utilizing attributes in a Map query</h2>
-<p>
-When using a search intent to ask the Maps activity to search for something, the Maps activity responds to the following attributes in the optional context bundle:
-</p>
-<pre>
- float "centerLatitude" default 0.0f
- float "centerLongitude" default 0.0f
- float "latitudeSpan" default 0.0f
- float "longitudeSpan" default 0.0f
- int "zoomLevel" default 10
-</pre>
-<p>
-This context information is used to center the search result in a particular area, and is equivalent to adjusting the Map activity to the described location and zoom level before issuing the query.
-</p>
-<p>
-If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent, then it is undefined which one takes precedence.
-</p>
-
-<a name="filelist" id="filelist"></a><h2>List of Files for an Android Application</h2>
-<p>The following list describes the structure and files of an Android application.
- Many of these files can be built for you (or stubbed out) by the android tool
- shipped in the tools/ menu of the SDK. </p>
-<table width="100%" border="0">
- <tr>
- <td width="28%" valign="top">MyApp/<br /></td>
- <td width="72%" valign="top"> </td>
- </tr>
- <tr>
- <td valign="top"> AndroidManifest.xml</td>
- <td valign="top">(<em>required</em>) Advertises the screens that this application provides,
- where they can be launched (from the main program menu or elsewhere),
- any content providers it implements and what kind of data they handle,
- where the implementation classes are, and other application-wide
- information. Syntax details for this file are described in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>.</td>
- </tr>
- <tr>
- <td valign="top"> src/<br />
- /<em>myPackagePath</em>/.../<em>MyClass</em>.java</td>
- <td valign="top">(<em>required</em>) This folder holds all the source code files for your
- application, inside the appropriate package subfolders. </td>
- </tr>
- <tr>
- <td valign="top"> res/</td>
- <td valign="top">(<em>required</em>) This folder holds all the <em>resources</em> for
- your application. Resources are external data files or description files
- that are compiled into your code at build time. Files in different folders
- are compiled differently, so you must put the proper resource into the
- proper folder. (See <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a> for details.)</td>
- </tr>
- <tr>
- <td valign="top"> anim/<br />
- <em>animation1</em>.xml<br />
- <em>...</em></td>
- <td valign="top">(<em>optional</em>) Holds any animation XML description files that the
- application uses. The format of these files is described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
- </tr>
- <tr>
- <td valign="top"> drawable/<br />
- <em>some_picture</em>.png<br />
- <em>some_stretchable</em>.9.png<br />
- <em>some_background</em>.xml<br />
- ...</td>
- <td valign="top">(<em>optional</em>) Zero or more files that will be compiled to {@link
- android.graphics.drawable android.graphics.drawable} resources. Files
- can be image files (png, gif, or other) or XML files describing other
- graphics such as bitmaps, stretchable bitmaps, or gradients. Supported
- bitmap file formats are PNG (preferred), JPG, and GIF (discouraged),
- as well as the custom 9-patch stretchable bitmap format. These formats
- are described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
- </tr>
- <tr>
- <td valign="top"> layout/<br />
- <em>screen_1_layout</em>.xml<br />
- ...<br /></td>
- <td valign="top">(<em>optional</em>) Holds all the XML files describing screens or parts
- of screens. Although you could create a screen in Java, defining them
- in XML files is typically easier. A layout file is similar in concept
- to an HTML file that describes the screen layout and components. See <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for more information about designing screens, and <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Available Resource Types</a> for the syntax of these files.</td>
- </tr>
- <tr>
- <td valign="top"> values/<br />
- arrays<br />
- classes.xml<br />
- colors.xml<br />
- dimens.xml<br />
- strings.xml<br />
- styles.xml<br />
- values.xml<br /></td>
- <td valign="top"><p>(<em>optional</em>) XML files describing additional resources
- such as strings, colors, and styles. The naming, quantity, and number
- of these files are not enforced--any XML file is compiled, but these
- are the standard names given to these files. However, the syntax
- of these files is prescribed by Android, and described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </p>
- </td>
- </tr>
- <tr>
- <td valign="top"> xml/</td>
- <td valign="top">(<em>optional</em>) XML files that can be read at run time on the device. </td>
- </tr>
- <tr>
- <td valign="top"> raw/</td>
- <td valign="top">(<em>optional</em>) Any files to be copied directly to the device. </td>
- </tr>
-</table>
-
-
-<a name="logging" ></a>
-<h2>Print Messages to a Log File</h2>
-
-<p>To write log messages from your application:</p>
-<ol><li>Import <code>android.util.Log</code>.</li>
- <li>Use <code>Log.v()</code>, <code>Log.d()</code>, <code>Log.i()</code>,
- <code>Log.w()</code>, or <code>Log.e()</code> to log messages.
- (See the {@link android.util.Log} class.)<br/> E.g.,
- <code>Log.e(this.toString(), "error: " + err.toString())</code></li>
- <li>Launch <a href="{@docRoot}guide/developing/tools/ddms.html">DDMS</a> from a terminal
- by executing <code>ddms</code> in your Android SDK <code>/tools</code> path.</li>
- <li>Run your application in the Android emulator.</li>
- <li>From the DDMS application, select the emulator
- (e.g., "emulator-5554") and click <b>Device > Run logcat...</b>
- to view all the log data.</li>
-</ol>
-<p class="note"><strong>Note:</strong> If you are running Eclipse and
-encounter a warning about the VM debug port when opening DDMS, you can ignore it
-if you're only interested in logs. However, if you want to further inspect and
-control your processes from DDMS, then you should close Eclipse before launching DDMS so that
-it may use the VM debugging port.</p>
-
-
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/commontasks.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/framework.jd b/docs/html/guide/appendix/faq/framework.jd
index 33b69ac..a79686e 100644
--- a/docs/html/guide/appendix/faq/framework.jd
+++ b/docs/html/guide/appendix/faq/framework.jd
@@ -1,197 +1,8 @@
-page.title=Android Application Framework FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
@jd:body
-<ul>
- <li><a href="#1">Do all the Activities and Services of an
- application run in a single process?</a></li>
- <li><a href="#2">Do all Activities run in the main thread of
- an application process?</a></li>
- <li><a href="#3">How do I pass complicated data structures
- from one Activity/Service to another?</a></li>
- <li><a href="#4">How can I check if an Activity is already
- running before starting it?</a></li>
- <li><a href="#5">If an Activity starts a remote service, is
- there any way for the Service to pass a message back to the Activity?</a></li>
- <li><a href="#6">How to avoid getting the Application not
- responding dialog?</a></li>
- <li><a href="#7">How does an application know if a package is
- added or removed?</a></li>
-</ul>
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/framework.html"
+</script>
-
-<a name="1" id="1"></a>
-
-<h2>Do all the Activities and Services of an application run in a
-single process?</h2>
-
-<p>All Activities and Services in an application run in a single process by
-default. If needed, you can declare an <code>android:process</code> attribute
-in your manifest file, to explicitly place a component (Activity/Service) in
-another process.</p>
-
-
-
-<a name="2" id="2"></a>
-
-<h2>Do all Activities run in the main thread of an application
-process?</h2>
-
-<p>By default, all of the application code in a single process runs
-in the main UI thread. This is the same thread
-that also handles UI events. The only exception is the code that handles
-IPC calls coming in from other processes. The system maintains a
-separate pool of transaction threads in each process to dispatch all
-incoming IPC calls. The developer should create separate threads for any
-long-running code, to avoid blocking the main UI thread.</p>
-
-
-
-<a name="3" id="3"></a>
-
-<h2>How do I pass data between Activities/Services within a single
-application?</h2>
-
-<p>It depends on the type of data that you want to share:</p>
-
-<h3>Primitive Data Types</h3>
-
-<p>To share primitive data between Activities/Services in an
-application, use Intent.putExtras(). For passing primitive data that
-needs to persist use the
-<a href="{@docRoot}guide/topics/data/data-storage.html#preferences">
-Preferences</a> storage mechanism.</p>
-
-<h3>Non-Persistent Objects</h3>
-
-<p>For sharing complex non-persistent user-defined objects for short
-duration, the following approaches are recommended:
-</p>
- <h4>The android.app.Application class</h4>
- <p>The android.app.Application is a base class for those who need to
-maintain global application state. It can be accessed via
-getApplication() from any Activity or Service. It has a couple of
-life-cycle methods and will be instantiated by Android automatically if
-your register it in AndroidManifest.xml.</p>
-
- <h4>A public static field/method</h4>
- <p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
-fields and/or methods. You can access these static fields from any other
-class in your application. To share an object, the activity which creates your object sets a
-static field to point to this object and any other activity that wants to use
-this object just accesses this static field.</p>
-
- <h4>A HashMap of WeakReferences to Objects</h4>
- <p>You can also use a HashMap of WeakReferences to Objects with Long
-keys. When an activity wants to pass an object to another activity, it
-simply puts the object in the map and sends the key (which is a unique
-Long based on a counter or time stamp) to the recipient activity via
-intent extras. The recipient activity retrieves the object using this
-key.</p>
-
- <h4>A Singleton class</h4>
- <p>There are advantages to using a static Singleton, such as you can
-refer to them without casting getApplication() to an
-application-specific class, or going to the trouble of hanging an
-interface on all your Application subclasses so that your various
-modules can refer to that interface instead. </p>
-<p>But, the life cycle of a static is not well under your control; so
-to abide by the life-cycle model, the application class should initiate and
-tear down these static objects in the onCreate() and onTerminate() methods
-of the Application Class</p>
-</p>
-
-<h3>Persistent Objects</h3>
-
-<p>Even while an application appears to continue running, the system
-may choose to kill its process and restart it later. If you have data
-that you need to persist from one activity invocation to the next, you
-need to represent that data as state that gets saved by an activity when
-it is informed that it might go away.</p>
-
-<p>For sharing complex persistent user-defined objects, the
-following approaches are recommended:
-<ul>
- <li>Application Preferences</li>
- <li>Files</li>
- <li>contentProviders</li>
- <li>SQLite DB</li>
-</ul>
-</p>
-
-<p>If the shared data needs to be retained across points where the application
-process can be killed, then place that data in persistent storage like
-Application Preferences, SQLite DB, Files or ContentProviders. Please refer to
-the <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>
-for further details on how to use these components.</p>
-
-
-
-
-<a name="4" id="4"></a>
-
-<h2>How can I check if an Activity is already running before starting
-it?</h2>
-
-<p>The general mechanism to start a new activity if its not running—
-or to bring the activity stack to the front if is already running in the
-background— is the to use the NEW_TASK_LAUNCH flag in the startActivity()
-call.</p>
-
-
-
-<a name="5" id="5"></a>
-
-<h2>If an Activity starts a remote service, is there any way for the
-Service to pass a message back to the Activity?</h2>
-
-<p>The remote service can define a callback interface and register it with the
-clients to callback into the clients. The
-{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to
-register and unregister clients with the service, and send and receive
-messages.</p>
-
-<p>The sample code for remote service callbacks is given in <a
-href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">ApiDemos/RemoteService</a></p>
-
-
-
-<a name="6" id="6"></a>
-
-<h2>How to avoid getting the Application not responding dialog?</h2>
-
-<p>Please read the <a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a>
-document.</p>
-
-
-
-
-<a name="7" id="7"></a>
-
-<h2>How does an application know if a package is added or removed?
-</h2>
-
-<p>Whenever a package is added, an intent with PACKAGE_ADDED action
-is broadcast by the system. Similarly when a package is removed, an
-intent with PACKAGE_REMOVED action is broadcast. To receive these
-intents, you should write something like this:
-<pre>
- <receiver android:name ="com.android.samples.app.PackageReceiver">
- <intent-filter>
- <action android:name="android.intent.action.PACKAGE_ADDED"/>
- <action android:name="android.intent.action.PACKAGE_REMOVED"/>
-
- <data android:scheme="package" />
- </intent-filter>
- </receiver>
- </pre>
- <br>
-Here PackageReceiver is a BroadcastReceiver class.Its onReceive()
-method is invoked, every time an application package is installed or
-removed.
-
-</p>
-
-
-
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/framework.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/index.jd b/docs/html/guide/appendix/faq/index.jd
index 90415ae..4194663 100644
--- a/docs/html/guide/appendix/faq/index.jd
+++ b/docs/html/guide/appendix/faq/index.jd
@@ -1,15 +1,8 @@
-page.title=FAQs, Tips, and How-to
@jd:body
-<dl>
- <dt><a href="commontasks.html">Common Development Tasks and How To Do Them</a></dt>
- <dd>Quick and to the point — how-to's for a variety of development tasks you are likely to use.</dd>
- <dt><a href="framework.html">Application Framework FAQ</a></dt>
- <dd>Common questions about the Android Application Framework.</dd>
- <dt><a href="troubleshooting.html">Troubleshooting Tips</a></dt>
- <dd>Answers to help you troubleshoot common problems.</dd>
- <dt><a href="licensingandoss.html">Open Source Licensing FAQ</a></dt>
- <dd>Common topics around licensing and Android Open Source</dd>
- <dt><a href="security.html">Android Security FAQ</a></dt>
- <dd>Answers to common questions about Android security.</dd>
-</dl>
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/index.html"
+</script>
+
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/index.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/licensingandoss.jd b/docs/html/guide/appendix/faq/licensingandoss.jd
index c267fe81..0da97db 100644
--- a/docs/html/guide/appendix/faq/licensingandoss.jd
+++ b/docs/html/guide/appendix/faq/licensingandoss.jd
@@ -1,19 +1,8 @@
-page.title=Android Open Source Licensing FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
@jd:body
-<ul>
- <li><a href="#mirror">Where can I find the open source components of Android?</a></li>
- <li><a href="#timeline">When will we see more code released under open source licenses?</a></li>
- <li><a href="#apache2">Why are you releasing the code under the Apache License instead of GPLv2?</a></li>
-</ul>
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/licensingandoss.html"
+</script>
-<a name="mirror" id="mirror"></a><h2>Where can I find the open source components of Android?</h2>
-<p>The source code for the full Android stack is available from the <a href="http://source.android.com">Android Open Source Project </a> site.
-
-<p>Other mirrored GPL and LGPL'd components are available at <a href="http://code.google.com/p/android/downloads/list"><code>http://code.google.com/p/android/downloads/list</code></a>.</p>
-<p>Notices for other licenses can be found within the SDK.</p>
-
-<a name="apache2" id="apache2"></a><h2>Why are you releasing the code under the Apache License instead of GPLv2?</h2>
-<p>One of the best explanations for the reasoning behind releasing code under Apache2 can be found in a <a href="http://arstechnica.com/news.ars/post/20071106-why-google-chose-the-apache-software-license-over-gplv2.html">ArsTechnica article</a> by Ryan Paul.</p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/licensingandoss.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/security.jd b/docs/html/guide/appendix/faq/security.jd
index b0d832b..88bcd51 100644
--- a/docs/html/guide/appendix/faq/security.jd
+++ b/docs/html/guide/appendix/faq/security.jd
@@ -1,156 +1,8 @@
-page.title=Android Security FAQ
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
@jd:body
-<ul>
- <li><a href="#secure">Is Android Secure?</a></li>
- <li><a href="#issue">I think I found a security flaw. How do I report
- it?</a></li>
- <li><a href="#informed">How can I stay informed of Android security
- announcements?</a></li>
- <li><a href="#use">How do I securely use my Android phone?</a></li>
- <li><a href="#malware">I think I found malicious software being distributed
- for Android. How can I help?</a></li>
- <li><a href="#fixes">How will Android-powered devices receive security fixes?</a>
- </li>
- <li><a href="#directfix">Can I get a fix directly from the Android Platform
- Project?</a></li>
-</ul>
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/security.html"
+</script>
-
-<a name="secure" id="secure"></a><h2>Is Android secure?</h2>
-
-<p>The security and privacy of our users' data is of primary importance to the
-Android Open Source Project. We are dedicated to building and maintaining one
-of the most secure mobile platforms available while still fulfilling our goal
-of opening the mobile device space to innovation and competition.</p>
-
-<p>The Android Platform provides a rich <a
-href="http://code.google.com/android/devel/security.html">security model</a>
-that allows developers to request the capabilities, or access, needed by their
-application and to define new capabilities that other applications can request.
-The Android user can choose to grant or deny an application's request for
-certain capabilities on the handset.</p>
-
-<p>We have made great efforts to secure the Android platform, but it is
-inevitable that security bugs will be found in any system of this complexity.
-Therefore, the Android team works hard to find new bugs internally and responds
-quickly and professionally to vulnerability reports from external researchers.
-</p>
-
-
-<a name="issue" id="issue"></a><h2>I think I found a security flaw. How do I
-report it?</h2>
-
-<p>You can reach the Android security team at <a
-href="mailto:security@android.com">security@android.com</a>. If you like, you
-can protect your message using our <a
-href="http://code.google.com/android/security_at_android_dot_com.txt">PGP
-key</a>.</p>
-
-<p>We appreciate researchers practicing responsible disclosure by emailing us
-with a detailed summary of the issue and keeping the issue confidential while
-users are at risk. In return, we will make sure to keep the researcher informed
-of our progress in issuing a fix and will properly credit the reporter(s) when
-we announce the patch. We will always move swiftly to mitigate or fix an
-externally-reported flaw and will publicly announce the fix once patches are
-available to users.</p>
-
-
-<a name="informed" id="informed"></a><h2>How can I stay informed of Android
-security announcements?</h2>
-
-<p>An important part of sustainably securing a platform, such as, Android is
-keeping the user and security community informed of bugs and fixes. We will
-publicly announce security bugs when the fixes are available via postings to
-the <a
-href="http://groups.google.com/group/android-security-announce">android-security-announce</a>
-group on Google Groups. You can subscribe to this group as you would a mailing
-list and view the archives here.</p>
-
-<p>For more general discussion of Android platform security, or how to use
-security features in your Android application, please subscribe to <a
-href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a>.
-</p>
-
-
-<a name="use" id="use"></a><h2>How do I securely use my Android phone?</h2>
-
-<p>As an open platform, Android allows users to load software from any
-developer onto a device. As with a home PC, the user must be
-aware of who is providing the software they are downloading and must decide
-whether they want to grant the application the capabilities it requests.
-This decision can be informed by the user's judgment of the software
-developer's trustworthiness, and where the software came from.</p>
-
-<p>Despite the security protections in Android, it is important
-for users to only download and install software from developers they trust.
-More details on how Android users can make smart security decisions will be
-released when consumer devices become available.</p>
-
-
-<a name="malware" id="malware"></a><h2>I think I found malicious software being
-distributed for Android. How can I help?</h2>
-
-<p>Like any other open platform, it will be possible for unethical developers
-to create malicious software, known as <a
-href="http://en.wikipedia.org/wiki/Malware">malware</a>, for Android. If you
-think somebody is trying to spread malware, please let us know at <a
-href="mailto:security@android.com">security@android.com</a>. Please include as
-much detail about the application as possible, with the location it is
-being distributed from and why you suspect it of being malicious software.</p>
-
-<p>The term <i>malicious software</i> is subjective, and we cannot make an
-exhaustive definition. Some examples of what the Android Security Team believes
-to be malicious software is any application that:
-<ul>
- <li>drains the device's battery very quickly;</li>
- <li>shows the user unsolicited messages (especially messages urging the
- user to buy something);</li>
- <li>resists (or attempts to resist) the user's effort to uninstall it;</li>
- <li>attempts to automatically spread itself to other devices;</li>
- <li>hides its files and/or processes;</li>
- <li>discloses the user's private information to a third party, without the
- user's knowledge and consent;</li>
- <li>destroys the user's data (or the device itself) without the user's
- knowledge and consent;</li>
- <li>impersonates the user (such as by sending email or buying things from a
- web store) without the user's knowledge and consent; or</li>
- <li>otherwise degrades the user's experience with the device.</li>
-</ul>
-</p>
-
-
-<a name="fixes" id="fixes"></a><h2>How will Android-powered devices receive security
-fixes?</h2>
-
-<p>The manufacturer of each device is responsible for distributing software
-upgrades for it, including security fixes. Many devices will update themselves
-automatically with software downloaded "over the air", while some devices
-require the user to upgrade them manually.</p>
-
-<p>When Android-powered devices are publicly available, this FAQ will provide links how
-Open Handset Alliance members release updates.</p>
-
-<a name="directfix" id="directfix"></a><h2>Can I get a fix directly from the
-Android Platform Project?</h2>
-
-<p>Android is a mobile platform that will be released as open source and
-available for free use by anybody. This means that there will be many
-Android-based products available to consumers, and most of them will be created
-without the knowledge or participation of the Android Open Source Project. Like
-the maintainers of other open source projects, we cannot build and release
-patches for the entire ecosystem of products using Android. Instead, we will
-work diligently to find and fix flaws as quickly as possible and to distribute
-those fixes to the manufacturers of the products.</p>
-
-<p>In addition, We will add security fixes to the open source distribution of
-Android and publicly announce the changes on <a
-href="http://groups.google.com/group/android-security-announce">android-security-announce</a>.
-</p>
-
-<p>If you are making an Android-powered device and would like to know how you can
-properly support your customers by keeping abreast of software updates, please
-contact us at <a
-href="mailto:info@openhandsetalliance.com">info@openhandsetalliance.com</a>.</p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/security.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/appendix/faq/troubleshooting.jd b/docs/html/guide/appendix/faq/troubleshooting.jd
index 86ab187..e3a9e4182 100755
--- a/docs/html/guide/appendix/faq/troubleshooting.jd
+++ b/docs/html/guide/appendix/faq/troubleshooting.jd
@@ -1,335 +1,8 @@
-page.title=Troubleshooting
-parent.title=FAQs, Tips, and How-to
-parent.link=index.html
@jd:body
+<script type="text/javascript">
+ document.location=toRoot+"resources/faq/troubleshooting.html"
+</script>
-<p>Here are some tips and tricks for common Android errors. Don't forget to use the
- ddms logcat capability to get a deeper view when errors occur. See <a href="{@docRoot}guide/developing/debug-tasks.html">Debugging</a> for more debugging tips. </p>
-<ul>
- <li><a href="#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</a></li>
- <li><a href="#nodevice">ADB reports "no device" when an emulator is running</a></li>
- <li><a href="#noapp">My new application/activity isn't showing up in the device application
- list </a></li>
- <li><a href="#noupdate">I updated my app, but the updates don't seem to be showing up on
- the device</a></li>
- <li><a href="#layout_wilih">I'm getting a "Binary XML file line #2: You must supply a layout_wilih
- attribute" error when I start an application</a></li>
- <li><a href="#permission">My request to (<em>make a call, catch an incoming SMS, receive
- a notification, send an intent to an Android application</em>) is being
- ignored</a></li>
- <li><a href="#build">Help! My project won't build in Eclipse</a></li>
- <li><a href="#eclipse">Eclipse isn't talking to the emulator</a></li>
- <li><a href="#majorminor">When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</a></li>
- <li><a href="#apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></li>
- <li><a href="#gesturebuilderinstall">I can't install the GestureBuilder sample
-app in the emulator</a></li>
- <li><a href="#signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</a></li>
- <li><a href="#manifestfiles">Unable to view manifest files from within Eclipse</a></li>
-</ul>
-
-<a name="installeclipsecomponents" id="installeclipsecomponents"></a><h2>ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</h2>
-<p>
-The "Android Editors" feature of the ADT Plugin requires specific Eclipse components, such as WST. If you
-encounter this error message during ADT installation, you need to install the
-required Eclipse components and then try the ADT installation again. Follow the steps below to install the required components for the
-Android Editors feature, based on the version of Eclipse that you are using.</p>
-
-<table style="font-size:100%">
-<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td width="50%">
-<ol>
-<li>From the dialog where you select the <strong>Update sites to visit</strong>, select the checkboxes for both the
-ADT site, and the Callisto/Europa/Ganymede Discovery Site (you may want to
-check <strong>Automatically select mirrors</strong> at the bottom).</li>
-<li>Click <strong>Finish</strong>.</li>
-<li>In the <strong>Next</strong> dialog, select the Android Plugins.</li>
-<li>Now, expand the tree item of the discovery site. It seems that if you
-don't do it, it doesn't load the content of the discovery site.</li>
-<li>On the right, click <strong>Select required</strong>. This will select all the components
-that are required to install the Android plugin (wst, emf, etc...).</li>
-<li>Click <strong>Next</strong>, accept the agreement, click <strong>Install All</strong>, and restart Eclipse.</li>
-</ol>
-</td>
-<td>
-<ol>
- <li>Select <strong>Help</strong> > <strong>Software Updates...</strong></li>
- <li>Select the <strong>Installed Software</strong> tab.</li>
- <li>Click <strong>Update...</strong></li>
- <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
-</ol>
-</td>
-</tr>
-</table>
-
-
-</p>
-<a name="nodevice"></a><h2>ADB reports "no device" when an emulator is running</h2>
- <p>Try restarting adb by stopping it (<code>adb
- kill-server</code>) then any other adb command to restart it.</p>
-
-<a name="noapp"></a><h2>My new application/activity isn't showing up in the
- applications list </h2>
-<ul>
- <li>You often must restart your device or emulator before a new activity shows
- up in the applications list. This is particularly true when it is a completely
- new application with a new AndroidManifest.xml file.</li>
- <li>If this is for a new activity in an existing AndroidManifest.xml file, did
- you include an <code><activity></code> tag for your app (or a <code><service></code> tag
- for a service, or a <code><receiver></code> tag for a receiver, etc.)? </li>
- <li>Make sure that your AndroidManifest.xml file is valid. Errors in attribute
- values, such as the <em>value </em> attribute in <code><action <em>value</em>="<em><something></em>"></code>
- will often not be caught by compilers, but will prevent your application
- from being displayed because the intent filter will not be matched. Extra
- spaces or other characters can often sneak into these strings.</li>
- <li>Did you send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb install</a>)?</li>
- <li>Run logcat on your device (<code>adb logcat</code>)
- and then install your .apk file. Check the logcat output to see whether the
- application is being installed and recognized properly. Here's sample output
- from a successful installation:
-<pre>I/FileObserver( 414): *** onEvent wfd: 3 mask: 8 path: MyRSSReader.apk
-D/PackageManager( 414): Scanning package: /data/app/MyRSSReader.apk
-D/PackageManager( 414): Adding package com.example.codelab.rssexample
-D/PackageManager( 414): Registered content provider: my_rss_item, className = com.example.codelab.rssexample.RssContentProvider, isSyncable = false
-D/PackageManager( 414): Providers: com.example.codelab.rssexample.RssContentProvider
-D/PackageManager( 414): Activities: com.example.codelab.rssexample.MyRssReader com.example.codelab.rssexample.MyRssReader2 </pre>
- </li>
- <li>If logcat shows that the package manager is having problems loading the manifest
- file, force your manifest to be recompiled by adding a space in the file and
- compiling it.</li>
-</ul>
-<a name="noupdate"></a><h2>I updated my app, but the updates don't seem to be showing up on the device</h2>
- <p>Did you remember to send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb
- install</a>)?</p>
-
-<a name="layout_wilih"></a><h2>I'm getting a "Binary XML file line #2: You must supply a layout_wilih
- attribute" error
- when I start an application (but I declare a layout_wilih attribute <em>right
- there!!!</em>)</h2>
-<ul>
- <li>Make sure that the SDK you are building with is the same version as the Android
- OS that you are running on. </li>
- <li>Make sure that you're calling setContentView() early in your onCreate() method.
- Calling other methods, such as setListAdapter() before calling setContentView()
- can sometimes create odd errors when Android tries to access screen elements
- that haven't been set before.</li>
-</ul>
-<a name="permission"></a><h2>My request to (<em>make a call, catch an incoming SMS,
-receive a notification, send an intent to an Android application</em>) is being
-ignored</h2>
- <p>You might not have permission (or might not have requested permission) to
- call this activity or receive this intent. Many standard Android activities,
- such as making a call, have a permission assigned to it to prevent arbitrary
- applications from sending or receiving requests. See <a
- href="{@docRoot}guide/topics/security/security.html">Security and
- Permissions</a> for more information on permissions, and
- {@link android.Manifest.permission Manifest.permission} for a list of
- standard permissions supported by the Android platform.
-</p>
-<a name="build"></a><h2>Help! My project won't build in Eclipse</h2>
-<p>If your project doesn't build, you may notice symptoms such as new
-resources added in the <code>res/</code> sub-folders not showing up in the R class,
-the emulator not being started, not being able to run the application, or even seeming to run an old version of the application.</p>
-<p>To troubleshoot these types of problems, first try:</p>
-<ol>
- <li>Switch to the DDMS view in Eclipse (if you don't already have it open):
- <ol type="a">
- <li>From the menu select <code>Window > Open Perspective > Other</code></li>
- <li>Select DDMS from the list and hit OK</li>
- </ol>
- </li>
- <li>In the Devices panel (top right panel by default), click on the down triangle
- to bring up the panel menu</li>
- <li>Select <code>Reset ADB</code> from the menu, and then try running the
- application again</li>
-</ol>
-<p>If the above still doesn't work, you can try these steps:</p>
-<ol>
- <li>
- Check the console and problems tabs at the bottom of the Eclipse UI
- </li>
- <li>
- If there are problems listed in either place, they should give you a clue
- what is wrong
- </li>
- <li>
- If you aren't sure if the problems are fresh or stale, clear the console
- with a right click > Clear, then clean the project
- </li>
- <li>
- To clean the project (a good idea with any kind of build error), select
- Project > Clean from the eclipse main menu, then select the project you
- are working on (or clean all)
- </li>
-</ol>
-<a name="eclipse"></a><h2>Eclipse isn't talking to the emulator</h2>
-<p>When communication doesn't seem to be happening between Eclipse and the emulator, symptoms can include: nothing happening when you press run, the emulator hanging waiting
-for a debugger to connect, or errors that Eclipse reports about not being able
-to find the emulator or shell. By far the most common symptom is that when you press run, the emulator starts (or
-is already running), but the application doesn't start.</p>
-<p>
-You may find any of these steps will fix the problem and with practice you
-probably can figure out which one you need to do for your particular issue, but
-to start with, the safest option is to run through all of them in order:</p>
-<ol>
- <li>
- Quit the emulator if it is running
- </li>
- <li>
- Check that any emulator processes are killed (sometimes they can hang, use ps on unix or mac, or task manager in the process view on
- windows).
- </li>
- <li>
- Quit Eclipse
- </li>
- <li>
- From the command line, type:
-<pre>adb kill-server </pre>
- </li>
- <li>
- Start Eclipse and try again
- </li>
-</ol>
-
-<a name="majorminor"></a><h2>When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</h2>
-<p>This error is displayed if you are using an older version of the JDK. Please make sure you are using JDK version 5 or 6.</p>
-
-<h2 id="apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></h2>
-
-<p>The Android system requires that all applications be signed, as described in
- <a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. The ApiDemos
-applications included with the SDK are preinstalled on the emulator and for that reason have been
-compiled and signed with a private key.</p>
-
-If you want to modify or run one of the ApiDemos apps from Eclipse/ADT or other IDE, you can do so
-so only after you uninstall the <em>preinstalled</em> version of the app from the emulator. If
-you try to run an ApiDemos app from your IDE without removing the preinstalled version first,
-you will get errors similar to these: </p>
-
-<pre>[2008-08-13 15:14:15 - ApiDemos] Re-installation failed due to different application signatures.
-[2008-08-13 15:14:15 - ApiDemos] You must perform a full uninstall of the application. WARNING: ...This will remove the application data!
-[2008-08-13 15:14:15 - ApiDemos] Please execute 'adb uninstall com.android.samples' in a shell.</pre>
-
-<p>The error occurs because, in this case, you are attempting to install another copy of ApiDemos
-onto the emulator, a copy that is signed with a different certificate. (The Android IDE tools will
-have signed the app with a debug certificate, where the existing version was already signed with
-a private certificate.) The system does not allow this type of reinstallation. </p>
-
-<p>To resolve the issue, you need to fully uninstall the preinstalled and then reinstall it using
-the adb tool. Here's how to do that:</p>
-
-<ol>
- <li>In a terminal, change to the tools directory of the SDK.</li>
- <li>If no emulator instance is running, start an emulator using using the command <code>emulator &</code>.</li>
- <li>Uninstall the preinstalled app using the command <code>adb uninstall com.android.samples</code>.</li>
- <li>Reinstall the app using the command <code>adb install <path to the ApiDemos.apk></code>. If you are
- working in Eclipse/ADT, you can just compile and run the app in the normal way. </li>
-</ol>
-
-<p>Note that if multiple emulator instances are running, you need to direct your uninstall/install
-commands to the emulator instance that you are targeting. To do that you can add the
-<code>-s <serialNumber></code> to the command, for example: </p>
-
-<pre>adb -s emulator-5556 install</pre>
-
-<p>For more information about adb, see the <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>
-documentation.</p>
-
-<h2 id="gesturebuilderinstall">I can't install the GestureBuilder sample
-app in the emulator</a></h2>
-
-<p>This is similar to the ApiDemos problem described above, except that
-you cannot fix it by uninstalling GestureBuilder from the emulator. The
-GestureBuilder app cannot be uninstalled because it is currently installed
-within the system files themselves.</p>
-
-<p><strong>Symptoms</strong></p>
-
-<ul><li><p>You cannot run GestureBuilder in the emulator:</p>
-
-<pre>[2009-12-10 14:57:19 - GestureBuilderActivity]Re-installation failed due to different application signatures.
-[2009-12-10 14:57:19 - GestureBuilderActivity]You must perform a full uninstall of the application. WARNING: This will remove the application data!
-[2009-12-10 14:57:19 - GestureBuilderActivity]Please execute 'adb uninstall com.android.gesture.builder' in a shell.</pre>
-</li>
-
-<li><p>Running <code>adb uninstall com.android.gesture.builder</code> fails:</p>
-<pre>$ adb uninstall com.android.gesture.builder
- Failure</pre>
-</li></ul>
-
-<p>For now, the work-around is to change the sample's package name
-so that the system can install it as a new app rather than as a
-replacement for the existing GestureBuilder app. To change the
-package name, open the manifest file and modify the package attribute
-of the manifest element. Next, update imports and other references to
-the package name, rebuild the app, and run it in an AVD.</p>
-
-<p>For example, here's how you could do this in Eclipse:</p>
-
-<ol>
- <li>Right-click on the package name
-(<code>src/com.android.gesture.builder</code>).</li>
- <li>Select <strong>Refactor > Rename</strong> and change the name, for example to
-<code>com.android.gestureNEW.builder</code>. </li>
- <li>Open the manifest file. Inside the <code><manifest></code>
-tag, change the package name to
-<code>com.android.gestureNEW.builder</code>.</li>
- <li>Open each of the two Activity files and do Ctrl-Shift-O to add
-missing import packages, then save each file.</li>
-<li>Run the GestureBuilder application on the emulator.</li>
-</ol>
-
-<p>If you get an error message such as "Could not load /sdcard/gestures.
-Make sure you have a mounted SD card," be sure that your target AVD has an
-SD card. To create an AVD that has an SD card, use the
-<a href="{@docRoot}guide/developing/tools/avd.html#options"><code>-c</code>
-option</a> in the <code>android create avd</code> command.</p>
-
-<h2 id="signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</h2>
-
-<p>If your development machine uses a locale that has a non-Gregorian calendar, you may encounter problems when first trying to compile and run your application. Specifically, you may find that the Android build tools won't compile your application because the debug key is expired. </p>
-
-<p>The problem occurs because the Keytool utility — included in the JDK and used by the Android build tools — fails to properly handle non-Gregorian locales and may create validity dates that are in the past. That is, it may generate a debug key that is already expired, which results in the compile error.</p>
-
-<p>If you encounter this problem, follow these steps to work around it: </p>
-
-<ol>
-<li>First, delete the debug keystore/key already generated by the Android build tools. Specifically, delete the <code>debug.keystore</code> file. On Linux/Mac OSX, the file is stored in <code>~/.android</code>. On Windows XP, the file is stored in <code>
-C:\Documents and Settings\<user>\.android</code>. On Windows Vista, the file is stored in <code>
-C:\Users\<user>\.android</code></li>
-<li>Next, you can either
-<ul>
-<li>Temporarily change your development machine's locale (date and time) to one that uses a Gregorian calendar, for example, United States. Once the locale is changed, use the Android build tools to compile and install your app. The build tools will regenerate a new keystore and debug key with valid dates. Once the new debug key is generated, you can reset your development machine to the original locale. </li>
-<li>Alternatively, if you do not want to change your machine's locale settings, you can generate the keystore/key on any machine using the Gregorian calendar, then copy the <code>debug.keystore</code> file from that computer to the proper location on your development machine. </li>
-</ul>
-</li>
-</ol>
-
-<p>This problem has been verified on Windows and may apply to other platforms. </p>
-
-<p>For general information about signing Android applications, see
-<a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. </p>
-
-<h2 id="manifestfiles">Unable to view manifest files from within
-Eclipse</a></h2>
-
-<p>When you try to open an application's manifest file from within
-Eclipse, you might get an error such as this one:</p>
-<pre>An error has occurred. See error log for more details.
-org.eclipse.wst.sse.ui.StructuredTextEditor.isBlockSelectionModeEnabled()Z</pre>
-
-<p>Try reverting to the 3.0 version of the Eclipse XML Editors and
-Tools. If this does not work, remove the 3.1 version of the tool. To do
-this in Eclipse 3.4:</p>
-
-<ol>
- <li>Select <strong>Help > Software Updates...</strong></li>
- <li>Select the <strong>Installed Software</strong> tab.</li>
- <li>Select <strong>Eclipse XML Editors and Tools</strong>.</li>
- <li>Click <strong>Uninstall</strong>.</li>
- <li>Click <strong>Finish</strong>.</li>
-</ol>
-
-<p>When you restart Eclipse, you should be able to view the manifest
-files. </p>
+<p>You should have already been redirected by your browser. Please follow
+<a href="{@docRoot}resources/faq/troubleshooting.html">this link</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index abfae5d..3127e10 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -119,7 +119,7 @@
<table>
<tr>
- <th>Manufacturer</th><th>USB Vendor ID</th></tr>
+ <th>Company</th><th>USB Vendor ID</th></tr>
<tr>
<td>Acer</td>
<td><code>0502</code></td></tr>
@@ -133,6 +133,9 @@
<td>Garmin-Asus</td>
<td><code>091E</code></td></tr>
<tr>
+ <td>Google</td>
+ <td><code>18d1</code></td></tr>
+ <tr>
<td>HTC</td>
<td><code>0bb4</code></td></tr>
<tr>
diff --git a/docs/html/guide/developing/index.jd b/docs/html/guide/developing/index.jd
index 3a64dbc..4257bf0 100644
--- a/docs/html/guide/developing/index.jd
+++ b/docs/html/guide/developing/index.jd
@@ -23,7 +23,7 @@
before continuing.</p>
</li>
- <li>Set up Android Virtual Devices or hardware devices</a>.
+ <li>Set up Android Virtual Devices or hardware devices.
<p>You need to create Android Virtual Devices (AVD) or connect hardware devices on which
you will install your applications.</p>
@@ -66,8 +66,8 @@
run tests within an emulator or device.</p>
</li>
</ol>
-
- <h2 id="EssentialTools">Essential command line tools</h2>
+
+<h2 id="EssentialTools">Essential command line tools</h2>
<p>When developing in IDEs or editors other than Eclipse, be familiar with
all of the tools below, because you will have to run them from the command line.</p>
@@ -112,6 +112,43 @@
Eclipse, such as the <code>adb</code> shell commands. You might also need to call Keytool and Jarsigner to
sign your applications, but you can set up Eclipse to do this automatically as well.</p>
- <p>For more information on the tools provided with the Android SDK, see the
+<p>For more information on the tools provided with the Android SDK, see the
<a href="{@docRoot}guide/developing/tools/index.html">Tools</a> section of the documentation.</p>
+
+<h2 id="ThirdParty">Third-Party Development Tools</h2>
+<p>
+ The tools described in this section are not developed by the Android SDK team. The Android Dev Guide
+ does not provide documentation for these tools. Please refer to the linked documents in each
+ section for documentation.
+</p>
+<h3 id="IntelliJ">Developing in IntelliJ IDEA</h3>
+<div style="float: right">
+<img alt="The IntelliJ graphical user interface" height="500px" src="{@docRoot}images/developing/intellijidea_android_ide.png"/>
+</div>
+<p>
+ IntelliJ IDEA is a powerful Java IDE from JetBrains that provides
+ full-cycle Android development support in both the free Community
+ Edition and the Ultimate edition.
+</p>
+<p>
+ The IDE ensures compatibility with the latest Android SDK and offers a
+ smart code editor with completion, quick navigation between code and
+ resources, a graphical debugger, unit testing support using Android
+ Testing Framework, and the ability to run applications in either the
+ emulator or a USB-connected device.
+</p>
+<p>
+ <strong>Links:</strong>
+</p>
+<ul>
+ <li>
+ <a href="http://www.jetbrains.com/idea">IntelliJ IDEA official website</a>
+</li>
+ <li>
+ <a href="http://www.jetbrains.com/idea/features/google_android.html">Android support in IntelliJ IDEA</a>
+</li>
+ <li>
+ <a href="http://wiki.jetbrains.net/intellij/Android">IntelliJ IDEA Android Tutorials</a>
+ </li>
+</ul>
diff --git a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
index 97c7c1f..c0795d7 100644
--- a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
+++ b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
@@ -128,7 +128,7 @@
device.press('KEYCODE_MENU','DOWN_AND_UP')
# Takes a screenshot
-result = device.takeSnapShot()
+result = device.takeSnapshot()
# Writes the screenshot to a file
result.writeToFile('myproject/shot1.png','png')
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index c258949..fa588cb 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -310,7 +310,7 @@
<span class="en">Search</span>
</a></div>
<ul>
- <li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Using the Android Search Dialog</a></li>
+ <li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Creating a Search Interface</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li>
diff --git a/docs/html/guide/practices/optimizing-for-3.0.jd b/docs/html/guide/practices/optimizing-for-3.0.jd
index a22e69a..5cd519b 100644
--- a/docs/html/guide/practices/optimizing-for-3.0.jd
+++ b/docs/html/guide/practices/optimizing-for-3.0.jd
@@ -5,20 +5,32 @@
<div id="qv">
<h2>In this document</h2>
<ol>
-<li><a href="#Setup">Set Up Your SDK with Android 3.0</a></li>
-<li><a href="#SearchableConfiguration">Optimize Your App for Tablets and Similar Devices</a></li>
-<li><a href="#SearchableActivity">Upgrade or Develop a New App for Tablets and Similar
-Devices</a></li>
+<li><a href="#Setup">Setting Up Your SDK with Android 3.0</a></li>
+<li><a href="#Optimizing">Optimizing Your App for Tablets</a></li>
+<li><a href="#Upgrading">Upgrading or Developing a New App for Tablets</a></li>
+<li><a href="#ManagingAppDist">Managing App Distribution Based on Screen Configuration</a>
+ <ol>
+ <li><a href="#FilteringTabletApps">Filtering a tablet app from mobile devices</a></li>
+ <li><a href="#FilteringMobileApps">Filtering a mobile device app from tablets</a></li>
+ </ol>
+</li>
+<li><a href="#Issues">Other Issues</a>
+ <ol>
+ <li><a href="#Landscape">Adding support for landscape screens</a></li>
+ <li><a href="#Telephony">Using telephony or other variable features</a></li>
+ </ol>
+</li>
</ol>
</div>
</div>
-<p>If you're developing an Android application, Android 3.0 introduces several features that allow
+<p>Android 3.0 introduces several features that allow
you to enhance your user's experience on tablets and similar devices. Any application you've already
published is compatible with devices running Android 3.0, by default, because Android applications
-are forward-compatible. However, there are some simple changes you should make to optimize your
-application for tablet-type devices.</p>
+are forward-compatible. However, new tablet devices running Android 3.0 are now available to the
+public and provide users a new Android experience on a larger screen, so you should make sure
+your application looks and works great on the new platform and new device form-factors.</p>
<p>This document shows how you can optimize your existing application for Android 3.0 and
maintain compatibility with older versions or upgrade your application completely with new APIs.</p>
@@ -27,18 +39,28 @@
<p><b>To get started:</b></p>
<ol>
- <li><a href="#Setup">Set up your SDK with Android 3.0</a>.</li>
- <li>Then choose to either optimize or upgrade:
+ <li><a href="#Setup">Set up your SDK with Android 3.0</a>.
+ <p>Install the Android 3.0 platform, new tools, and set up a new AVD.</p></li>
+ <li>Choose to either optimize or upgrade:
<ol type="a">
- <li><a href="#Optimize">Optimize Your App for Tablets and Similar Devices</a>.
- <p>When you have an existing application and want to maintain compatibility with
-older versions of Android.</p>
+ <li><a href="#Optimizing">Optimize your app for tablets and similar devices</a>.
+ <p>Read this section if you have an existing application and want to
+maintain compatibility with older versions of Android. All you need to do is update your
+manifest file to declare support for Android 3.0, test your application on the new platform, and
+add extra resources to support extra large screens, as appropriate.</p>
</li>
- <li><a href="#Upgrade">Upgrade or Develop a New App for Tablets and Similar Devices</a>.
- <p>When you want to upgrade your application to use APIs introduced in Android 3.0 or
- create a new application targeted to tablets and similar devices.</p></li>
+ <li><a href="#Upgrading">Upgrade or develop a new app for tablets and similar devices</a>.
+ <p>Read this section if you want to upgrade your application to use APIs introduced in
+Android 3.0 or create a new application targeted to tablets and similar devices. Compared to
+upgrading to previous versions of Android, there's nothing different about upgrading to Android 3.0.
+This section introduces some of the key features and APIs you should use to make an
+application that's fully enhanced for tablets.</p></li>
</ol>
</li>
+ <li>Consider whether you need to <a href="#ManagingAppDist">manage the distribution of your
+application based on screen configuration</a>.</li>
+ <li>Then review some <a href="#Issue">other issues</a> you might encounter when developing
+for tablets and similar devices.</li>
</ol>
@@ -66,14 +88,16 @@
<p>Set the target to "Android 3.0" and the skin to "WXGA" (the default skin).</p></li>
</ol>
+<p>The best way to test your application on Android 3.0 is to use real hardware running Android 3.0,
+such as the <a href="http://www.motorola.com/staticfiles/Consumers/XOOM/index.html">Motorola
+Xoom</a>. Of course, you can also use the Android emulator on your development machine, but because
+the Android emulator must simulate the ARM instruction set on your computer and the WXGA screen is
+significantly larger than a typical virtual device, emulator performance is much slower than a real
+device.</p>
<h3>About emulator performance</h3>
-<p>Because the Android emulator must simulate the ARM instruction set on your computer
-and the WXGA screen is significantly larger than a typical virtual device, emulator performance is
-much slower than a real device.</p>
-
-<p>In particular, initializing the emulator can be slow and can take several minutes, depending on
+<p>Initializing the emulator can be slow and can take several minutes, depending on
your hardware. When the emulator is booting, there is limited user feedback, so please be patient
and wait until you see the home screen (or lock screen) appear. </p>
@@ -82,9 +106,10 @@
Also see the tip below for information about using a snapshot to drastically reduce startup time
after the first initialization. </p>
-<p>We're working hard to resolve the performance issues and it will improve in future tools
-releases. For the time being, the emulator is still best way to evaluate your application's
-appearance and functionality on Android 3.0 without a real device.</p>
+<p>General performance in the emulator is also slow. We're working hard to resolve the performance
+issues and it will improve in future tools releases. If you don't yet have a real device running
+Android 3.0, the emulator is still best way to evaluate your application's appearance and
+functionality on Android 3.0.</p>
<p class="note"><strong>Tip:</strong> To improve the startup time for the emulator, enable snapshots
for the AVD when you create it with the SDK and AVD Manager (there's a checkbox in the AVD creator
@@ -97,7 +122,7 @@
-<h2 id="Optimize">Optimize Your Application for Tablets and Similar Devices</h2>
+<h2 id="Optimizing">Optimizing Your App for Tablets</h2>
<p>If you've already developed an application for an earlier version of Android, there are a few
things you can do to optimize it for a tablet-style experience on Android 3.0 without changing the
@@ -142,21 +167,24 @@
</pre>
<p>By targeting the Android 3.0 platform, the system automatically applies the holographic theme
to each activity when your application runs on an Android 3.0 device. The holographic theme
-provides a new design for widgets, such as buttons and text boxes, and restyles other
-visual elements. This is the standard theme in applications built for Android 3.0, so your
-application will look more at home by enabling the theme.</p>
- <p>Additionally, the holographic theme enables the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> in your activities when running on an
-Android 3.0 device. The Action Bar replaces the traditional title bar at the top of the activity
-window and provides the user access to the activity's Options Menu.</p>
+provides a new design for widgets, such as buttons and text boxes, and new styles for other
+visual elements. This is the standard theme for applications built for Android 3.0, so your
+application will look and feel consistent with the system and other applications when it is
+enabled.</p>
+ <p>Additionally, when an activity uses the holographic theme, the system enables the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> for the activity. The Action Bar
+replaces the traditional title bar at the top of the activity window and provides the user access to
+the activity's Options Menu.</p>
</li>
- <li>Continue to build your application against the minimum version specified by <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>,
-but install it on the Android 3.0 AVD. Repeat your tests to be sure that your user interface works
-well with the holographic theme.
+ <li>Build your application against the same version of the Android platform you have been
+using previously (such as the version declared in your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>),
+but install it on the Android 3.0 AVD. (You should not build against Android 3.0 unless you are
+using new APIs.) Repeat your tests to be sure that your user interface works well with the
+holographic theme.
<p class="note"><strong>Note:</strong> If you have applied other themes directly to your
activities, they will override the inherited holographic theme. To resolve this, you can use
-the <a href="{@docRoot}guide/topics/resources/providing-resources.html#VersionQualifier">system
+the <a href="{@docRoot}guide/topics/resources/providing-resources.html#VersionQualifier">platform
version qualifier</a> to provide an alternative theme for Android 3.0 devices that's based on the
holographic theme. For more information, read how to <a
href="{@docRoot}guide/topics/ui/themes.html#SelectATheme">select a theme based on platform
@@ -177,15 +205,24 @@
(wide), so you should be sure that your activities offer a layout that's optimized for a wide
viewing area. <p>You can specify landscape resources with the <code>land</code> resource
qualifier, but if you want alternative resources for an extra large landscape screen, you
-should use both <code>xlarge</code> and <code>land</code> qualifiers. For example, {@code
+should use both the <code>xlarge</code> and <code>land</code> qualifiers. For example, {@code
res/layout-xlarge-land/}. The order of the qualifier names is important; see <a
href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
Providing Alternative Resources</a> for more information.</p></li>
- <li>Button position: Consider whether the position of the most common buttons in your UI are
-easily accessible while holding a tablet with two hands.</li>
+ <li>Button position and size: Consider whether the position and size of the most common
+buttons in your UI make them easily accessible while holding a tablet with two hands. In some
+cases, you might need to resize buttons, especially if they use {@code "wrap_content"}
+as the width value. To enlarge the buttons, if necessary, you should either: add
+extra padding to the button; specify dimension values with {@code dp} units; or use {@code
+android:layout_weight} when the button is in a <a
+href="{@docRoot}guide/topics/ui/layout-objects.html#linearlayout">linear layout</a>. Use your
+best judgment of proportions for each screen size—you don't want the buttons to be too big,
+either.</li>
<li>Font sizes: Be sure your application uses {@code sp} units when setting font
-sizes. This alone should ensure a readable experience on tablet-style devices. In some cases,
-however, you might want to consider larger font sizes for <code>xlarge</code> configurations.</li>
+sizes. This alone should ensure a readable experience on tablet-style devices, because it is a
+scale-independent pixel unit, which will resize as appropriate for the current screen configuration.
+In some cases, however, you still might want to consider larger font sizes for <code>xlarge</code>
+configurations.</li>
</ul>
<p>In general, always be sure that your application follows the <a
href="{@docRoot}guide/practices/screens_support.html#screen-independence">Best Practices
@@ -197,7 +234,29 @@
-<h2 id="Upgrade">Upgrade or Develop a New App for Tablets and Similar Devices</h2>
+
+<h2 id="Upgrading">Upgrading or Developing a New App for Tablets</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h3>Use new APIs and remain backward-compatible</h3>
+<p>It is possible for you to upgrade your application with some new
+APIs <em>and</em> remain compatible with older versions of Android. Usually, this requires that you
+use techniques such as reflection to check for the availability of certain APIs at runtime. However,
+to help you add features from Android 3.0 without requiring you to change your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+or build target, we're providing a static library called the "Android Compatibility package"
+(downloadable from the AVD and SDK Manager).</p>
+<p>This library includes APIs for <a
+href="{@docRoot}guide/topics/fundamentals/fragments.html">fragments</a>, <a
+href="{@docRoot}guide/topics/fundamentals/loaders.html">loaders</a>, and some updated classes. By
+simply adding this library to your Android project, you can use these APIs in your application and
+remain compatible with Android 1.6. For more information, see the blog post, <a
+href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">Fragments for
+All</a>.</p>
+</div>
+</div>
+
<p>If you want to develop an application that's fully enhanced for tablet-type devices running
Android 3.0, then you need to use new APIs in Android 3.0. This section introduces some of
@@ -206,9 +265,11 @@
<h3>Declare the minimum system version</h3>
-<p>The first thing to do when you create a project for Android 3.0 is set your manifest's <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
-to {@code "11"}. For example:</p>
+<p>The first thing to do when you upgrade or create a project for Android 3.0 is set your manifest's
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+android:minSdkVersion}</a> to {@code "11"}. This declares that your application uses APIs available
+in Android 3.0 and greater, so it should not be available to devices running an older version of
+Android. For example:</p>
<pre>
<manifest ... >
@@ -218,9 +279,11 @@
<application>
</manifest>
</pre>
-
-<p>By targeting the Android 3.0 platform, the system automatically applies the new holographic theme
-to each of your activities.</p>
+
+<p>Not only is this necessary in order to declare the minimum API level your application requires,
+but it enables the new holographic theme to each of your activities. The holographic theme is the
+standard theme for the Android 3.0 system and all applications designed for it. It includes new
+designs for the system widgets and overall appearance.</p>
<p>Additionally, the holographic theme enables the Action Bar for each activity.</p>
@@ -229,13 +292,14 @@
<p>The Action Bar is a widget for activities that replaces the traditional title bar at the top of
the screen. By default, the Action Bar includes the application logo on the left side, followed by
-the activity title, and any available items from the Options Menu on the right side.</p>
+the activity title, and access to items from the Options Menu in a drop-down list on the right
+side.</p>
-<p>You can enable items from your activity's Options Menu to appear directly in the Action Bar as
-"action items" by adding {@code showAsAction="ifRoom"} to specific items in your <a
+<p>You can enable items from the Options Menu to appear directly in the Action Bar as
+"action items" by adding {@code showAsAction="ifRoom"} to specific menu items in your <a
href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. You can also add
navigation features to the Action Bar, such as tabs, and use the application icon to navigate to
-your application's "home" activity or "up" the activity hierarchy.</p>
+your application's "home" activity or to navigate "up" the application's activity hierarchy.</p>
<p>For more information, read <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the
Action Bar</a>.</p>
@@ -244,11 +308,12 @@
<h3>Divide your activities into fragments</h3>
-<p>A fragment represents a behavior or a portion of user interface in an activity. You can combine
-multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple
-activities. You can think of a fragment as a modular section of an activity, which has its own
-lifecycle, receives its own input events, and which you can add or remove while the activity is
-running.</p>
+<p>A fragment represents a behavior or a portion of user interface in an activity. You can think of
+a fragment as a modular section of an activity, which has its own lifecycle, receives its own input
+events, and which you can add or remove while the activity is running. Fragments are an optional
+component for your activities that allow you to build a multi-pane UI and reuse them in multiple
+activities. If you're building an application for tablets, we recommend that you use fragments to
+create activities that offer a more dynamic and flexible user interface.</p>
<p>For example, a news application can use one fragment to show a list of articles on the left and
another fragment to display an article on the right—both fragments appear in one activity,
@@ -262,8 +327,8 @@
<h3>Use new animation APIs for transitions</h3>
-<p>An all new flexible animation framework allows you to animate arbitrary properties of any object
-(View, Drawable, Fragment, Object, or anything else). You can define several animation aspects
+<p>An all-new animation framework allows you to animate arbitrary properties of any object
+(such as a View, Drawable, Fragment, or anything else). You can define several animation aspects
(such as duration, repeat, interpolation, and more) for an object's int, float, and hexadecimal
color values, by default. That is, when an object has a property field for one of these types, you
can change its value over time to affect an animation.</p>
@@ -279,8 +344,9 @@
<h3>Enable hardware acceleration</h3>
-<p>You can now enable the OpenGL renderer for your application by setting {@code
-android:hardwareAccelerated="true"} in your manifest's <a
+<p>Android 3.0 adds a hardware-accelerated OpenGL renderer that gives a performance boost to most 2D
+graphics operations. You can enable hardware-accelerated rendering in your application by setting
+{@code android:hardwareAccelerated="true"} in your manifest's <a
href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
element or for individual <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
<activity>}</a> elements. Hardware acceleration results in smoother animations, smoother
@@ -314,48 +380,16 @@
href="{@docRoot}sdk/android-3.0.html">Android 3.0 Platform</a> document.</p>
-<h3>Publish your app for extra large screens</h3>
-
-<p>You should also decide whether your application is <em>only</em> for
-tablet-type devices (specifically, <em>xlarge</em> devices) or for all types of screen sizes.</p>
-
-<p>If you want your application to be available to all screen sizes (for example, for all
-phones and tablets), there's nothing you need to do. By default, an application with <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-android:minSdkVersion}</a> set to {@code "4"} or higher will resize to fit any screen size.</p>
-
-<p>If your application is <em>only</em> for <em>xlarge</em> screens, include the <a
-href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
-<supports-screens>}</a> element in your manifest and declare that the application supports
-only <em>xlarge</em> screens, by declaring all other sizes {@code "false"}. For example:</p>
-
-<pre>
-<manifest ... >
- ...
- <supports-screens android:smallScreens="false"
- android:normalScreens="false"
- android:largeScreens="false"
- android:xlargeScreens="true" />
- <application ... >
- ...
- <application>
-</manifest>
-</pre>
-
-<p>With this declaration, you indicate that your application does not support any screen size except
-extra large. External services such as Android Market may then use this information to filter your
-application from devices that do not have an extra large screen.</p>
-
-
<h3>Look at some samples</h3>
-<p>Many of the new features and APIs that are described in the <a
-href="{@docRoot}sdk/android-3.0.html#api">Android 3.0 Platform Preview</a> also have accompanying
-samples that can help you understand how to use them. To get the samples, download them from the SDK
-repository using the Android SDK Manager. After downloading the samples ("Samples for SDK API 11"),
-you can find them in <code><sdk_root>/samples/android-11/</code>. The links below can help you
-find samples for the features you are interested in:</p>
+<p>Many of the new features and APIs that are described above and in the <a
+href="{@docRoot}sdk/android-3.0.html#api">Android 3.0 Platform</a> document also have accompanying
+samples that allow you to preview the effects and can help you understand how to use them. To get
+the samples, download them from the SDK repository <a href="{@docRoot}sdk/adding-components.html"
+>using the Android SDK and AVD Manager</a>. After downloading the samples ("Samples for SDK API
+11"), you can find them in <code><sdk_root>/samples/android-11/</code>. The following list
+provides links to the browsable source code for some of the samples:</p>
<ul>
<li><a href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a>:
@@ -395,3 +429,248 @@
graphics.</li>
</ul>
+
+
+<h2 id="ManagingAppDist">Managing App Distribution Based on Screen Configuration</h2>
+
+<p>If your manifest file has either <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+or <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+android:targetSdkVersion}</a> set to {@code "4"} or higher, then the Android system will scale your
+application's layout and assets to fit the current device screen, whether the device screen is
+smaller or larger than the one for which you originally designed your application. As such, you
+should always test your application on real or <a
+href="{@docRoot}guide/developing/devices/index.html">virtual devices</a> with various screen sizes
+and densities.</p>
+
+<p>Although we recommend that you design your application to function properly on multiple
+configurations of screen size and density, you can instead choose to limit the distribution of your
+application to certain types of screens, such as only tablets or only mobile devices. To do so, you
+can add elements to your Android manifest file that enable filtering based on screen configuration
+by external services such as Android Market.</p>
+
+<p>However, before you decide to restrict your application to certain screen configurations, you
+should understand the techniques for <a
+href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a> and employ
+them to the best of your ability. By supporting multiple screens, your application can be made
+available to the greatest number of users with different devices.</p>
+
+
+<h3 id="FilteringTabletApps">Filtering a tablet application from mobile devices</h3>
+
+<p>If the system scaling adversely affects your application UI when scaling your application down
+for smaller screens, you should add <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
+layouts</a> for smaller screens to adjust your layout. However, sometimes your layout still might
+not fit a smaller screen or you've explicitly designed your application only for tablets and other
+large devices. In this case, you can manage the availability of your application to smaller screens
+by using the <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+<supports-screens>}</a> manifest element.</p>
+
+<p>For example, if you want your application to be available only to extra large
+screens, you can declare the element in your manifest like this:</p>
+
+<pre>
+<manifest ... >
+ ...
+ <supports-screens android:smallScreens="false"
+ android:normalScreens="false"
+ android:largeScreens="false"
+ android:xlargeScreens="true" />
+ <application ... >
+ ...
+ <application>
+</manifest>
+</pre>
+
+<p>External services such as Android Market read this manifest element and use it to ensure that
+your application is available only to devices with an extra large screen.</p>
+
+<p class="note"><strong>Note:</strong> If you use the <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+<supports-screens>}</a> element for the reverse scenario (when your application is not compatible
+with <em>larger</em> screens) and set the larger screen size attributes to {@code "false"}, then
+external services such as Android Market <strong>do not</strong> apply filtering. Your application
+will still be available to larger screens, but when it runs, it will not fill the screen—the
+system will draw it in a "postage stamp" window that's the same relative size as the screen size
+that your application does support. If you want to prevent your application from being downloaded on
+larger screens, see the following section.</p>
+
+
+<h3 id="FilteringMobileApps">Filtering a mobile device application from tablets</h3>
+
+<p>Because Android automatically scales applications to fit larger screens, you shouldn't
+need to filter your application from larger screens. However, you might discover that your
+application can't scale up or perhaps you've decided to publish two versions of your application
+that each deliver different features for different screen configurations, so you don't want
+larger devices to download the version designed for smaller screens. In such a case, you can
+use the <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+<compatible-screens>}</a> element to manage the distribution of your application based on the
+combination of screen size and density. External services such as
+Android Market uses this information to apply filtering to your application, so that only devices
+that have a screen configuration with which you declare compatibility can download your
+application.</p>
+
+<p>The <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+<compatible-screens>}</a> element must contain one or more {@code <screen>} elements,
+which each specify a screen configuration with which your application is compatible, using both
+the {@code android:screenSize} and {@code android:screenDensity} attributes. Each {@code
+<screen>} element <strong>must include both attributes</strong> to specify an individual
+screen configuration—if either attribute is missing, then the element is invalid
+(external services such as Android Market will ignore it).</p>
+
+<p>For example, if your application is compatible with only small and normal screens, regardless
+of screen density, then you must specify eight different {@code <screen>} elements,
+because each screen size has four density configurations. You must declare each one of
+these; any combination of size and density that you do <em>not</em> specify is considered a screen
+configuration with which your application is <em>not</em> compatible. Here's what the manifest
+entry looks like if your application is compatible with only small and normal screens:</p>
+
+<pre>
+<manifest ... >
+ ...
+ <compatible-screens>
+ <!-- all small size screens -->
+ <screen android:screenSize="small" android:screenDensity="ldpi" />
+ <screen android:screenSize="small" android:screenDensity="mdpi" />
+ <screen android:screenSize="small" android:screenDensity="hdpi" />
+ <screen android:screenSize="small" android:screenDensity="xhdpi" />
+ <!-- all normal size screens -->
+ <screen android:screenSize="normal" android:screenDensity="ldpi" />
+ <screen android:screenSize="normal" android:screenDensity="mdpi" />
+ <screen android:screenSize="normal" android:screenDensity="hdpi" />
+ <screen android:screenSize="normal" android:screenDensity="xhdpi" />
+ </compatible-screens>
+ <application ... >
+ ...
+ <application>
+</manifest>
+</pre>
+
+<p class="note"><strong>Note:</strong> Although you can also use the <a
+href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+<compatible-screens>}</a> element for the reverse scenario (when your application is not
+compatible with smaller screens), it's easier if you instead use the <a
+href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code
+<supports-screens>}</a> as discussed in the previous section, because it doesn't require you
+to specify each screen density your application supports.</p>
+
+<p>Remember, you should strive to make your application available to as many devices as possible by
+applying all necessary techniques for <a
+href="{@docRoot}guide/practices/screens_support.html">supporting multiple screens</a>. You should
+then use the <a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html">{@code
+<compatible-screens>}</a> element to filter your application from certain devices only when you
+cannot offer compatibility on all screen configurations or you have decided to provide
+multiple versions of your application, each for a different set of screen configurations.</p>
+
+
+
+<h2 id="Issues">Other Issues</h2>
+
+<p>Whether you decide to optimize or upgrade your application for tablet-type devices, you
+should be aware that the functionality and availability of your application on new devices
+might be affected by the following issues:</p>
+
+<ul>
+ <li><a href="#Landscape">Tablets are often designed for use in the landscape orientation</a>
+ <p>Tablets and similar devices often have a screen that uses the landscape orientation
+by default. If your application assumes a portrait orientation or locks into portrait
+orientation, you should update your application to support landscape.</p></li>
+ <li><a href="#Telephony">Not all devices have telephony or other features</a>
+ <p>If your application declares the {@code "android.hardware.telephony"} feature in the manifest,
+then it will not be available to devices that do not offer telephony (such as tablets), based on
+Android Market filtering. If your application can function properly without telephony, you should
+update your application to gracefully disable the telephony features when not available on a
+device.</p></li>
+</ul>
+
+
+<h3 id="Landscape">Adding support for landscape screens</h3>
+
+<p>Although tablets can rotate to operate in any orientation, they are often designed for
+landscape orientation and that is how most users will use them. So, you should ensure that your
+application can function in landscape. Even if you want to avoid rotating the screen while your
+application is running, you should not assume that portrait is the device's default orientation. You
+should either ensure that your layout is usable in both portrait and landscape orientations or
+provide an <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources"
+>alternative layout resource</a> for landscape orientation.</p>
+
+<p>If you believe your application or game provides its best experience when the screen is tall,
+consider that tablets and similar devices have a screen that's as tall or taller in landscape
+orientation than a phone in portrait orientation. With that in mind, you might be able to add a
+landscape design that adds padding or extra landscape scenery on the left and right sides, so
+the primary screen space still remains taller than it is wide.</p>
+
+<p>Ideally, your application should handle all orientation changes instead of locking into one
+orientation. When the user rotates the screen, the system restarts the current activity by calling
+{@link android.app.Activity#onDestroy onDestroy()} and {@link android.app.Activity#onCreate
+onCreate()}) in immediate succession. You should design your activity to account for these changes
+in the lifecycle, so the activity can save and restore its state. You can learn about the
+necessary lifecycle callback methods and how to save and restore the activity state in the <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
+document. If your activity state is more complex and cannot retain it using the normal
+lifecycle callback methods, you can use alternative techniques described in <a
+href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a>.</p>
+
+<p>In the worst-case scenario, however, you can avoid orientation changes by using the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code
+android:screenOrientation}</a> attribute in the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
+element. Instead of locking the orientation in landscape or portrait, however, you should
+specify a value of {@code "nosensor"}. This way, your activity uses whatever orientation the
+device specifies as its natural orientation and the screen will not rotate. You should still
+avoid using the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code
+android:screenOrientation}</a> attribute, but because it's sometimes necessary to lock the
+screen into one orientation, it's best if you do so in a way that uses the device's natural
+orientation instead of assuming one specific orientation.</p>
+
+<p>If your application uses the orientation sensors, such as the accelerometer (with the {@link
+android.hardware.SensorManager} APIs), also be aware that the landscape screen can also cause
+problems, due to false assumptions about which orientation is the natural position. For more
+information about how you should properly handle rotation changes when using the orientation
+sensors, read the blog post, <a
+href="http://android-developers.blogspot.com/2010/09/one-screen-turn-deserves-another.html">One
+Screen Turn Deserves Another</a>.</p>
+
+
+
+<h3 id="Telephony">Using telephony or other variable features</h3>
+
+<p>Tablets and similar devices might not include support for telephony, so they can't make
+traditional phone calls or handle SMS. Some devices might also omit
+other hardware features, such as Bluetooth. If your application uses these features, then your
+manifest file probably already includes (or should include) a declaration of the feature with the <a
+href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a>
+element. Doing so prevents devices that do not declare support for the feature from downloading
+your applications. For example:</p>
+
+<pre><uses-feature android:name="android.hardware.telephony" /></pre>
+
+<p>By default, this declares that your application <em>requires</em> telephony features. So,
+external services such as Android Market use this information to filter your application from
+devices that do not offer telephony.</p>
+
+<p>If, however, your application uses, but does not require the feature, you should
+add to this element, {@code android:required="false"}. For example:</p>
+
+<pre><uses-feature android:name="android.hardware.telephony" android:required="false" /></pre>
+
+<p>This indicates that your application uses the feature, but is still functional if the feature is
+not available. So, it should still be available to devices that don't provide telephony hardware
+(or telephony features), such as tablets.</p>
+
+<p>Then in your application code, you must gracefully disable the features that use telephony
+when it's not available. You can check whether the feature is available using {@link
+android.content.pm.PackageManager#hasSystemFeature PackageManager.hasSystemFeature()}. For
+example:</p>
+
+<pre>
+PackageManager pm = getPackageManager();
+boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+</pre>
+
+<p>For more information about these
+issues and how to future-proof your application for different hardware, read the blog post <a
+href="http://android-developers.blogspot.com/2010/10/five-steps-to-future-hardware-happiness.html">
+The Five Steps to Future Hardware Happiness</a>.</p>
\ No newline at end of file
diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd
index 93077a0..df240e2 100644
--- a/docs/html/guide/publishing/app-signing.jd
+++ b/docs/html/guide/publishing/app-signing.jd
@@ -260,8 +260,8 @@
<p>To fix this problem, simply delete the <code>debug.keystore</code> file.
The default storage location for AVDs is in <code>~/.android/</code> on OS X and Linux,
-in <code>C:\Documents and Settings\<user>\.android\</code> on Windows XP, and in
-<code>C:\Users\<user>\.android\</code> on Windows Vista.</p>
+in <code>C:\Documents and Settings\<user>\.android\</code> on Windows XP, and in
+<code>C:\Users\<user>\.android\</code> on Windows Vista and Windows 7.</p>
<p>The next time you build, the build tools will regenerate a new keystore and debug key.</p>
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 8669874..5c89869 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -101,6 +101,38 @@
</dd>
</dl>
</dd>
+
+<dt>example</dt>
+<dd>
+<p>If your application is compatible with only small and normal screens, regardless
+of screen density, then you must specify eight different {@code <screen>} elements,
+because each screen size has four different density configurations. You must declare each one of
+these; any combination of size and density that you do <em>not</em> specify is considered a screen
+configuration with which your application is <em>not</em> compatible. Here's what the manifest
+entry looks like if your application is compatible with only small and normal screens:</p>
+
+<pre>
+<manifest ... >
+ ...
+ <compatible-screens>
+ <!-- all small size screens -->
+ <screen android:screenSize="small" android:screenDensity="ldpi" />
+ <screen android:screenSize="small" android:screenDensity="mdpi" />
+ <screen android:screenSize="small" android:screenDensity="hdpi" />
+ <screen android:screenSize="small" android:screenDensity="xhdpi" />
+ <!-- all normal size screens -->
+ <screen android:screenSize="normal" android:screenDensity="ldpi" />
+ <screen android:screenSize="normal" android:screenDensity="mdpi" />
+ <screen android:screenSize="normal" android:screenDensity="hdpi" />
+ <screen android:screenSize="normal" android:screenDensity="xhdpi" />
+ </compatible-screens>
+ <application ... >
+ ...
+ <application>
+</manifest>
+</pre>
+</dd>
+
<dt>introduced in:</dt>
<dd>API Level 9</dd>
<dt>see also:</dt>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index d09790b..5c1eed0 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -250,7 +250,7 @@
android:icon="@drawable/group_item1_icon" />
<item android:id="@+id/group_item2"
android:onClick="onGroupItemClick"
- android:title="G@string/group_item2"
+ android:title="@string/group_item2"
android:icon="@drawable/group_item2_icon" />
</group>
<item android:id="@+id/submenu"
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 60030f0..1583dee 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -596,7 +596,7 @@
</tr>
-->
<tr id="VersionQualifier">
- <td>System Version (API Level)</td>
+ <td>Platform Version (API Level)</td>
<td>Examples:<br/>
<code>v3</code><br/>
<code>v4</code><br/>
@@ -609,7 +609,7 @@
href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a> document for more information
about these values.</p>
<p class="caution"><strong>Caution:</strong> Android 1.5 and 1.6 only match resources
-with this qualifier when it exactly matches the system version. See the section below about <a
+with this qualifier when it exactly matches the platform version. See the section below about <a
href="#KnownIssues">Known Issues</a> for more information.</p>
</td>
</tr>
@@ -975,7 +975,7 @@
<p>The correct behavior is for the system to match resources marked with a <a
href="#VersionQualifier">version qualifier</a> equal
-to or less than the system version on the device, but on Android 1.5 and 1.6, (API Level 3 and 4),
+to or less than the platform version on the device, but on Android 1.5 and 1.6, (API Level 3 and 4),
there is a bug that causes the system to match resources marked with the version qualifier
only when it exactly matches the version on the device.</p>
diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd
index c8f06b9..02ee084 100644
--- a/docs/html/guide/topics/search/adding-custom-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd
@@ -17,8 +17,8 @@
</li>
<li><a href="#IntentForSuggestions">Declaring an Intent for Suggestions</a>
<ol>
- <li><a href="#IntentAction">Declaring the Intent action</a></li>
- <li><a href="#IntentData">Declaring the Intent data</a></li>
+ <li><a href="#IntentAction">Declaring the intent action</a></li>
+ <li><a href="#IntentData">Declaring the intent data</a></li>
</ol>
</li>
<li><a href="#HandlingIntent">Handling the Intent</a></li>
@@ -47,8 +47,8 @@
</div>
</div>
-<p>When using the Android search dialog, you can provide custom search suggestions that are
-created from data in your application. For example, if your application is a word
+<p>When using the Android search dialog or search widget, you can provide custom search suggestions
+that are created from data in your application. For example, if your application is a word
dictionary, you can suggest words from the
dictionary that match the text entered so far. These are the most valuable suggestions, because you
can effectively predict what the user wants and provide instant access to it. Figure 1 shows
@@ -58,9 +58,8 @@
Search Box, providing access to your content from outside your application.</p>
<p>Before you begin with this guide to add custom suggestions, you need to have implemented the
-Android search dialog for searches in your
-application. If you haven't, see <a href="search-dialog.html">Using the Android Search
-Dialog</a>.</p>
+Android search dialog or a search widget for searches in your
+application. If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p>
<h2 id="TheBasics">The Basics</h2>
@@ -71,11 +70,11 @@
search suggestions.</p>
</div>
-<p>When the user selects a custom suggestion, the Search Manager sends an {@link
+<p>When the user selects a custom suggestion, the Android system sends an {@link
android.content.Intent} to
-your searchable Activity. Whereas a normal search query sends an Intent with the {@link
+your searchable activity. Whereas a normal search query sends an intent with the {@link
android.content.Intent#ACTION_SEARCH} action, you can instead define your custom suggestions to use
-{@link android.content.Intent#ACTION_VIEW} (or any other Intent action), and also include data
+{@link android.content.Intent#ACTION_VIEW} (or any other intent action), and also include data
that's relevant to the selected suggestion. Continuing
the dictionary example, when the user selects a suggestion, your application can immediately
open the definition for that word, instead of searching the dictionary for matches.</p>
@@ -83,8 +82,8 @@
<p>To provide custom suggestions, do the following:</p>
<ul>
- <li>Implement a basic searchable Activity, as described in <a
-href="search-dialog.html">Using the Android Search Dialog</a>.</li>
+ <li>Implement a basic searchable activity, as described in <a
+href="search-dialog.html">Creating a Search Interface</a>.</li>
<li>Modify the searchable configuration with information about the content provider that
provides custom suggestions.</li>
<li>Build a table (such as in an {@link android.database.sqlite.SQLiteDatabase}) for your
@@ -96,22 +95,21 @@
suggestion (including a custom action and custom data). </li>
</ul>
-<p>Just like the Search Manager displays the search dialog, it also displays your search
-suggestions. All you need is a content provider from which the Search Manager can retrieve your
+<p>Just as the Android system displays the search dialog, it also displays your search
+suggestions. All you need is a content provider from which the system can retrieve your
suggestions. If you're not familiar with creating content
providers, read the <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
Providers</a> developer guide before you continue.</p>
-<p>When the Search Manager identifies that your Activity is searchable and provides search
-suggestions, the following procedure takes place as soon as the user enters text into the
-search dialog:</p>
+<p>When the system identifies that your activity is searchable and provides search
+suggestions, the following procedure takes place when the user types a query:</p>
<ol>
- <li>Search Manager takes the search query text (whatever has been typed so far) and performs a
+ <li>The system takes the search query text (whatever has been typed so far) and performs a
query to your content provider that manages your suggestions.</li>
<li>Your content provider returns a {@link android.database.Cursor} that points to all
suggestions that are relevant to the search query text.</li>
- <li>Search Manager displays the list of suggestions provided by the Cursor.</li>
+ <li>The system displays the list of suggestions provided by the Cursor.</li>
</ol>
<p>Once the custom suggestions are displayed, the following might happen:</p>
@@ -120,9 +118,9 @@
<li>If the user types another key, or changes the query in any way, the above steps are repeated
and the suggestion list is updated as appropriate. </li>
<li>If the user executes the search, the suggestions are ignored and the search is delivered
-to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
-Intent.</li>
- <li>If the user selects a suggestion, an Intent is sent to your searchable Activity, carrying a
+to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH}
+intent.</li>
+ <li>If the user selects a suggestion, an intent is sent to your searchable activity, carrying a
custom action and custom data so that your application can open the suggested content.</li>
</ul>
@@ -142,7 +140,7 @@
</searchable>
</pre>
-<p>You might need some additional attributes, depending on the type of Intent you attach
+<p>You might need some additional attributes, depending on the type of intent you attach
to each suggestion and how you want to format queries to your content provider. The other optional
attributes are discussed in the following sections.</p>
@@ -155,11 +153,11 @@
href="{@docRoot}guide/topics/providers/content-providers.html">Content Provider</a> developer
guide. For the most part, a content provider for custom suggestions is the
same as any other content provider. However, for each suggestion you provide, the respective row in
-the {@link android.database.Cursor} must include specific columns that the Search Manager
+the {@link android.database.Cursor} must include specific columns that the system
understands and uses to format the suggestions.</p>
-<p>When the user starts typing into the search dialog, the Search Manager queries your content
-provider for suggestions by calling {@link
+<p>When the user starts typing into the search dialog or search widget, the system queries
+your content provider for suggestions by calling {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} each time
a letter is typed. In your implementation of {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()}, your
@@ -170,22 +168,22 @@
two sections:</p>
<dl>
<dt><a href="#HandlingSuggestionQuery">Handling the suggestion query</a></dt>
- <dd>How the Search Manager sends requests to your content provider and how to handle them</dd>
+ <dd>How the system sends requests to your content provider and how to handle them</dd>
<dt><a href="#SuggestionTable">Building a suggestion table</a></dt>
- <dd>How to define the columns that the Search Manager expects in the {@link
+ <dd>How to define the columns that the system expects in the {@link
android.database.Cursor} returned with each query</dd>
</dl>
<h3 id="HandlingSuggestionQuery">Handling the suggestion query</h3>
-<p>When the Search Manager requests suggestions from your content provider, it calls your content
+<p>When the system requests suggestions from your content provider, it calls your content
provider's {@link android.content.ContentProvider#query(Uri,String[],String,String[],String)
query()} method. You must
implement this method to search your suggestion data and return a
{@link android.database.Cursor} pointing to the suggestions you deem relevant.</p>
-<p>Here's a summary of the parameters that the Search Manager passes to your {@link
+<p>Here's a summary of the parameters that the system passes to your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
(listed in order):</p>
@@ -196,7 +194,7 @@
content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
android.app.SearchManager#SUGGEST_URI_PATH_QUERY}</em>
</pre>
-<p>The default behavior is for Search Manager to pass this URI and append it with the query text.
+<p>The default behavior is for system to pass this URI and append it with the query text.
For example:</p>
<pre class="no-pretty-print">
content://<em>your.authority</em>/<em>optional.suggest.path</em>/<em>{@link
@@ -233,7 +231,7 @@
<dd>Always null</dd>
</dl>
-<p>The Search Manager can send you the search query text in two ways. The
+<p>The system can send you the search query text in two ways. The
default manner is for the query text to be included as the last path of the content
URI passed in the {@code uri} parameter. However, if you include a selection value in your
searchable configuration's {@code
@@ -251,8 +249,8 @@
String query = uri.getLastPathSegment().toLowerCase();
</pre>
-<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered in
-the search dialog.</p>
+<p>This returns the last segment of the {@link android.net.Uri}, which is the query text entered
+by the user.</p>
@@ -264,7 +262,7 @@
{@code selection} and {@code selectionArgs} parameters to carry the appropriate values. In such a
case, add the {@code android:searchSuggestSelection} attribute to your searchable configuration with
your SQLite selection string. In the selection string, include a question mark ("?") as
-a placeholder for the actual search query. The Search Manager calls {@link
+a placeholder for the actual search query. The system calls {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} with the
selection string as the {@code selection} parameter and the search query as the first
element in the {@code selectionArgs} array.</p>
@@ -278,15 +276,15 @@
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
- android:searchSuggestIntentAction="android.Intent.action.VIEW"
+ android:searchSuggestIntentAction="android.intent.action.VIEW"
<b>android:searchSuggestSelection="word MATCH ?"</b>>
</searchable>
</pre>
<p>With this configuration, your {@link
android.content.ContentProvider#query(Uri,String[],String,String[],String) query()} method
-delivers the {@code selection} parameter as "word MATCH ?" and the {@code selectionArgs}
-parameter as whatever the user entered in the search dialog. When you pass these to an SQLite
+delivers the {@code selection} parameter as {@code "word MATCH ?"} and the {@code selectionArgs}
+parameter as the search query. When you pass these to an SQLite
{@link android.database.sqlite.SQLiteDatabase#query(String,String[],String,String[],String,String,
String) query()} method, as their respective arguments, they are synthesized together (the
question mark is replaced with the query
@@ -296,9 +294,9 @@
question mark.</p>
<p>Another new attribute in the example above is {@code android:searchSuggestIntentAction}, which
-defines the Intent action sent with each Intent when the user selects a suggestion. It is
+defines the intent action sent with each intent when the user selects a suggestion. It is
discussed further in the section about <a href="#IntentForSuggestions">Declaring an Intent for
-suggestions</a>.</p>
+Suggestions</a>.</p>
<p class="note"><strong>Tip:</strong> If you don't want to define a selection clause in
the {@code android:searchSuggestSelection} attribute, but would still like to receive the query
@@ -317,7 +315,7 @@
<h2>Creating a Cursor without a table</h2>
<p>If your search suggestions are not stored in a table format (such as an SQLite table) using the
columns required by the
-Search Manager, then you can search your suggestion data for matches and then format them
+system, then you can search your suggestion data for matches and then format them
into the necessary table on each request. To do so, create a {@link android.database.MatrixCursor}
using the required column names and then add a row for each suggestion using {@link
android.database.MatrixCursor#addRow(Object[])}. Return the final product from your Content
@@ -326,18 +324,18 @@
</div>
</div>
-<p>When you return suggestions to the Search Manager with a {@link android.database.Cursor}, the
-Search Manager expects specific columns in each row. So, regardless of whether you
+<p>When you return suggestions to the system with a {@link android.database.Cursor}, the
+system expects specific columns in each row. So, regardless of whether you
decide to store
your suggestion data in an SQLite database on the device, a database on a web server, or another
format on the device or web, you must format the suggestions as rows in a table and
-present them with a {@link android.database.Cursor}. The Search
-Manager understands several columns, but only two are required:</p>
+present them with a {@link android.database.Cursor}. The system understands several columns, but
+only two are required:</p>
<dl>
<dt>{@link android.provider.BaseColumns#_ID}</dt>
- <dd>A unique integer row ID for each suggestion. The search dialog requires this in order
-to present suggestions in a ListView.</dd>
+ <dd>A unique integer row ID for each suggestion. The system requires this in order
+to present suggestions in a {@link android.widget.ListView}.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</dt>
<dd>The string that is presented as a suggestion.</dd>
</dl>
@@ -359,35 +357,35 @@
all suggestions are provided in an icon-plus-text format with the icon on the right side. This can
be null or zero to indicate no icon in this row.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}</dt>
- <dd>An Intent action string. If this column exists and contains a value at the given row, the
-action defined here is used when forming the suggestion's Intent. If the element is not
+ <dd>An intent action string. If this column exists and contains a value at the given row, the
+action defined here is used when forming the suggestion's intent. If the element is not
provided, the action is taken from the {@code android:searchSuggestIntentAction} field in your
searchable configuration. If your action is the same for all
suggestions, it is more efficient to specify the action using {@code
android:searchSuggestIntentAction} and omit this column.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA}</dt>
<dd>A data URI string. If this column exists and contains a value at the given row, this is the
-data that is used when forming the suggestion's Intent. If the element is not provided, the data is
+data that is used when forming the suggestion's intent. If the element is not provided, the data is
taken from the {@code android:searchSuggestIntentData} field in your searchable configuration. If
neither source is provided,
-the Intent's data field is null. If your data is the same for all suggestions, or can be
+the intent's data field is null. If your data is the same for all suggestions, or can be
described using a constant part and a specific ID, it is more efficient to specify it using {@code
android:searchSuggestIntentData} and omit this column.
</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}</dt>
<dd>A URI path string. If this column exists and contains a value at the given row, then "/" and
-this value is appended to the data field in the Intent. This should only be used if the data field
+this value is appended to the data field in the intent. This should only be used if the data field
specified
by the {@code android:searchSuggestIntentData} attribute in the searchable configuration has already
been set to an appropriate base string.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}</dt>
<dd>Arbitrary data. If this column exists and contains a value at a given row, this is the
-<em>extra</em> data used when forming the suggestion's Intent. If not provided, the
-Intent's extra data field is null. This column allows suggestions to provide additional data that is
-included as an extra in the Intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
+<em>extra</em> data used when forming the suggestion's intent. If not provided, the
+intent's extra data field is null. This column allows suggestions to provide additional data that is
+included as an extra in the intent's {@link android.app.SearchManager#EXTRA_DATA_KEY} key.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_QUERY}</dt>
<dd>If this column exists and this element exists at the given row, this is the data that is
-used when forming the suggestion's query, included as an extra in the Intent's {@link
+used when forming the suggestion's query, included as an extra in the intent's {@link
android.app.SearchManager#QUERY} key. Required if suggestion's action is {@link
android.content.Intent#ACTION_SEARCH}, optional otherwise.</dd>
<dt>{@link android.app.SearchManager#SUGGEST_COLUMN_SHORTCUT_ID}</dt>
@@ -410,22 +408,22 @@
-<h2 id="IntentForSuggestions">Declaring an Intent for suggestions</h2>
+<h2 id="IntentForSuggestions">Declaring an Intent for Suggestions</h2>
-<p>When the user selects a suggestion from the list that appears below the search dialog, the Search
-Manager sends a custom {@link android.content.Intent} to your searchable Activity. You must define
-the action and data for the Intent.</p>
+<p>When the user selects a suggestion from the list that appears below the search dialog or widget,
+the system sends a custom {@link android.content.Intent} to your searchable activity. You
+must define the action and data for the intent.</p>
-<h3 id="IntentAction">Declaring the Intent action</h3>
+<h3 id="IntentAction">Declaring the intent action</h3>
-<p>The most common Intent action for a custom suggestion is {@link
+<p>The most common intent action for a custom suggestion is {@link
android.content.Intent#ACTION_VIEW}, which is appropriate when
you want to open something, like the definition for a word, a person's contact information, or a web
-page. However, the Intent action can be any other action and can even be different for each
+page. However, the intent action can be any other action and can even be different for each
suggestion.</p>
-<p>Depending on whether you want all suggestions to use the same Intent action, you
+<p>Depending on whether you want all suggestions to use the same intent action, you
can define the action in two ways:</p>
<ol type="a">
@@ -457,34 +455,34 @@
default, then override this action for some suggestions by declaring a different action in the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. If you do not include
a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column, then the
-Intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
+intent provided in the {@code android:searchSuggestIntentAction} attribute is used.</p>
<p class="note"><strong>Note</strong>: If you do not include the
{@code android:searchSuggestIntentAction} attribute in your searchable configuration, then you
<em>must</em> include a value in the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION}
-column for every suggestion, or the Intent will fail.</p>
+column for every suggestion, or the intent will fail.</p>
-<h3 id="IntentData">Declaring Intent data</h3>
+<h3 id="IntentData">Declaring intent data</h3>
-<p>When the user selects a suggestion, your searchable Activity receives the Intent with the
-action you've defined (as discussed in the previous section), but the Intent must also carry
-data in order for your Activity to identify which suggestion was selected. Specifically,
+<p>When the user selects a suggestion, your searchable activity receives the intent with the
+action you've defined (as discussed in the previous section), but the intent must also carry
+data in order for your activity to identify which suggestion was selected. Specifically,
the data should be something unique for each suggestion, such as the row ID for the suggestion in
-your SQLite table. When the Intent is received,
+your SQLite table. When the intent is received,
you can retrieve the attached data with {@link android.content.Intent#getData()} or {@link
android.content.Intent#getDataString()}.</p>
-<p>You can define the data included with the Intent in two ways:</p>
+<p>You can define the data included with the intent in two ways:</p>
<ol type="a">
<li>Define the data for each suggestion inside the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column of your suggestions table.
-<p>Provide all necessary data information for each Intent in the suggestions table by including the
+<p>Provide all necessary data information for each intent in the suggestions table by including the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column and then populating it with
-unique data for each row. The data from this column is attached to the Intent exactly as you
+unique data for each row. The data from this column is attached to the intent exactly as you
define it in this column. You can then retrieve it with with {@link
android.content.Intent#getData()} or {@link android.content.Intent#getDataString()}.</p>
@@ -498,7 +496,7 @@
</li>
<li>Fragment a data URI into two pieces: the portion common to all suggestions and the portion
-unique to each suggestion. Place these parts into the {@code android:searchSuggestIntentData}
+unique to each suggestion. Place these parts into the {@code android:searchSuggestintentData}
attribute of the searchable configuration and the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column of your
suggestions table, respectively.
@@ -512,14 +510,14 @@
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
- android:searchSuggestIntentAction="android.Intent.action.VIEW"
+ android:searchSuggestIntentAction="android.intent.action.VIEW"
<b>android:searchSuggestIntentData="content://com.example/datatable"</b> >
</searchable>
</pre>
<p>Then include the final path for each suggestion (the unique part) in the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID}
-column of your suggestions table. When the user selects a suggestion, the Search Manager takes
+column of your suggestions table. When the user selects a suggestion, the system takes
the string from {@code android:searchSuggestIntentData}, appends a slash ("/") and then adds the
respective value from the {@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column to
form a complete content URI. You can then retrieve the {@link android.net.Uri} with with {@link
@@ -530,20 +528,20 @@
<h4>Add more data</h4>
-<p>If you need to express even more information with your Intent, you can add another table column,
+<p>If you need to express even more information with your intent, you can add another table column,
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_EXTRA_DATA}, which can store additional
information about the suggestion. The data saved in this column is placed in {@link
-android.app.SearchManager#EXTRA_DATA_KEY} of the Intent's extra Bundle.</p>
+android.app.SearchManager#EXTRA_DATA_KEY} of the intent's extra Bundle.</p>
<h2 id="HandlingIntent">Handling the Intent</h2>
-<p>Now that your search dialog provides custom search suggestions with custom Intents, you
-need your searchable Activity to handle these Intents when the user selects a
+<p>Now that you provide custom search suggestions with custom intents, you
+need your searchable activity to handle these intents when the user selects a
suggestion. This is in addition to handling the {@link
-android.content.Intent#ACTION_SEARCH} Intent, which your searchable Activity already does.
-Here's an example of how you can handle the Intents during your Activity {@link
+android.content.Intent#ACTION_SEARCH} intent, which your searchable activity already does.
+Here's an example of how you can handle the intents during your activity {@link
android.app.Activity#onCreate(Bundle) onCreate()} callback:</p>
<pre>
@@ -559,25 +557,25 @@
}
</pre>
-<p>In this example, the Intent action is {@link
+<p>In this example, the intent action is {@link
android.content.Intent#ACTION_VIEW} and the data carries a complete URI pointing to the suggested
item, as synthesized by the {@code android:searchSuggestIntentData} string and {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA_ID} column. The URI is then passed to the local
{@code showResult()} method that queries the content provider for the item specified by the URI.</p>
-<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an Intent filter to your
-Android manifest file for the Intent action you defined with the {@code
+<p class="note"><strong>Note:</strong> You do <em>not</em> need to add an intent filter to your
+Android manifest file for the intent action you defined with the {@code
android:searchSuggestIntentAction} attribute or {@link
-android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The Search Manager opens your
-searchable Activity by name to deliver the suggestion's Intent, so the Activity does not need to
+android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column. The system opens your
+searchable activity by name to deliver the suggestion's intent, so the activity does not need to
declare the accepted action.</p>
<h2 id="RewritingQueryText">Rewriting the query text</h2>
-<p>If the user navigates through the suggestions list using the directional controls (trackball or
-d-pad), the text in the search dialog won't change, by default. However, you can temporarily rewrite
-the user's query text as it appears in the text box with
+<p>If the user navigates through the suggestions list using the directional controls (such
+as with a trackball or d-pad), the query text does not update, by default. However, you
+can temporarily rewrite the user's query text as it appears in the text box with
a query that matches the suggestion currently in focus. This enables the user to see what query is
being suggested (if appropriate) and then select the search box and edit the query before
dispatching it as a search.</p>
@@ -654,7 +652,7 @@
android:label="@string/app_label"
android:hint="@string/search_hint"
android:searchSuggestAuthority="com.example.MyCustomSuggestionProvider"
- android:searchSuggestIntentAction="android.Intent.action.VIEW"
+ android:searchSuggestIntentAction="android.intent.action.VIEW"
android:includeInGlobalSearch="true"
<b>android:searchSettingsDescription="@string/search_description"</b> >
</searchable>
@@ -676,7 +674,7 @@
<h3 id="ManagingShortcuts">Managing Quick Search Box suggestion shortcuts</h3>
<p>Suggestions that the user selects from Quick Search Box can be automatically made into shortcuts.
-These are suggestions that the Search Manager has copied from your content provider so it can
+These are suggestions that the system has copied from your content provider so it can
quickly access the suggestion without the need to re-query your content provider. </p>
<p>By default, this is enabled for all suggestions retrieved by Quick Search Box, but if your
diff --git a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
index cb063a1..2c9a461 100644
--- a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
@@ -28,13 +28,15 @@
</div>
</div>
-<p>When using the Android search dialog, you can provide search suggestions based on recent search
+<p>When using the Android search dialog or search widget, you can provide search suggestions based
+on recent search
queries. For example, if a user previously searched for "puppies," then that query appears as a
suggestion once he or she begins typing the same query. Figure 1 shows an example of a search dialog
with recent query suggestions.</p>
-<p>Before you begin, you need to implement the search dialog for basic searches in your application.
-If you haven't, see <a href="search-dialog.html">Using the Android Search Dialog</a>.</p>
+<p>Before you begin, you need to implement the search dialog or a search widget for basic searches
+in your application.
+If you haven't, see <a href="search-dialog.html">Creating a Search Interface</a>.</p>
@@ -47,16 +49,16 @@
</div>
<p>Recent query suggestions are simply saved searches. When the user selects one of
-the suggestions, your searchable Activity receives a {@link
-android.content.Intent#ACTION_SEARCH} Intent with the suggestion as the search query, which your
-searchable Activity already handles (as described in <a href="search-dialog.html">Using the Android
-Search Dialog</a>).</p>
+the suggestions, your searchable activity receives a {@link
+android.content.Intent#ACTION_SEARCH} intent with the suggestion as the search query, which your
+searchable activity already handles (as described in <a href="search-dialog.html">Creating a Search
+Interface</a>).</p>
<p>To provide recent queries suggestions, you need to:</p>
<ul>
- <li>Implement a searchable Activity, <a
-href="{@docRoot}guide/topics/search/search-dialog.html">using the Android Search Dialog</a>.</li>
+ <li>Implement a searchable activity, as described in <a
+href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.</li>
<li>Create a content provider that extends {@link
android.content.SearchRecentSuggestionsProvider} and declare it in your application manifest.</li>
<li>Modify the searchable configuration with information about the content provider that
@@ -64,20 +66,19 @@
<li>Save queries to your content provider each time a search is executed.</li>
</ul>
-<p>Just as the Search Manager displays the search dialog, it also displays the
-search suggestions. All you need to do is provide a source from which the suggestions can be
-retrieved.</p>
+<p>Just as the Android system displays the search dialog, it also displays the
+search suggestions below the dialog or search widget. All you need to do is provide a source from
+which the system can retrieve suggestions.</p>
-<p>When the Search Manager identifies that your Activity is searchable and provides search
-suggestions, the following procedure takes place as soon as the user types into the search
-dialog:</p>
+<p>When the system identifies that your activity is searchable and provides search
+suggestions, the following procedure takes place as soon as the user begins typing a query:</p>
<ol>
- <li>Search Manager takes the search query text (whatever has been typed so far) and performs a
+ <li>The system takes the search query text (whatever has been typed so far) and performs a
query to the content provider that contains your suggestions.</li>
<li>Your content provider returns a {@link android.database.Cursor} that points to all
suggestions that match the search query text.</li>
- <li>Search Manager displays the list of suggestions provided by the Cursor.</li>
+ <li>The system displays the list of suggestions provided by the Cursor.</li>
</ol>
<p>Once the recent query suggestions are displayed, the following might happen:</p>
@@ -86,10 +87,10 @@
<li>If the user types another key, or changes the query in any way, the aforementioned steps are
repeated and the suggestion list is updated.</li>
<li>If the user executes the search, the suggestions are ignored and the search is delivered
-to your searchable Activity using the normal {@link android.content.Intent#ACTION_SEARCH}
-Intent.</li>
+to your searchable activity using the normal {@link android.content.Intent#ACTION_SEARCH}
+intent.</li>
<li>If the user selects a suggestion, an
-{@link android.content.Intent#ACTION_SEARCH} Intent is delivered to your searchable Activity using
+{@link android.content.Intent#ACTION_SEARCH} intent is delivered to your searchable activity using
the suggested text as the query.</li>
</ul>
@@ -151,7 +152,7 @@
<h2 id="RecentQuerySearchableConfiguration">Modifying the Searchable Configuration</h2>
-<p>To configure your search dialog to use your suggestions provider, you need to add
+<p>To configure the system to use your suggestions provider, you need to add
the {@code android:searchSuggestAuthority} and {@code android:searchSuggestSelection} attributes to
the {@code <searchable>} element in your searchable configuration file. For example:</p>
@@ -179,12 +180,12 @@
<h2 id="SavingQueries">Saving Queries</h2>
<p>To populate your collection of recent queries, add each query
-received by your searchable Activity to your {@link
+received by your searchable activity to your {@link
android.content.SearchRecentSuggestionsProvider}. To do this, create an instance of {@link
android.provider.SearchRecentSuggestions} and call {@link
android.provider.SearchRecentSuggestions#saveRecentQuery(String,String) saveRecentQuery()} each time
-your searchable Activity receives a query. For example, here's how you can save the query during
-your Activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
+your searchable activity receives a query. For example, here's how you can save the query during
+your activity's {@link android.app.Activity#onCreate(Bundle) onCreate()} method:</p>
<pre>
@Override
@@ -192,10 +193,10 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
- Intent Intent = getIntent();
+ Intent intent = getIntent();
- if (Intent.ACTION_SEARCH.equals(Intent .getAction())) {
- String query = Intent .getStringExtra(SearchManager.QUERY);
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ String query = intent.getStringExtra(SearchManager.QUERY);
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);
@@ -212,7 +213,7 @@
second line of the suggestion (or null). The second parameter is only used if you've enabled
two-line mode for the search suggestions with {@link
android.content.SearchRecentSuggestionsProvider#DATABASE_MODE_2LINES}. If you have enabled
-two-line mode, then the query text is also matched against this second line when the Search Manager
+two-line mode, then the query text is also matched against this second line when the system
looks for matching suggestions.</p>
diff --git a/docs/html/guide/topics/search/index.jd b/docs/html/guide/topics/search/index.jd
index f563715..7ac5ff1 100644
--- a/docs/html/guide/topics/search/index.jd
+++ b/docs/html/guide/topics/search/index.jd
@@ -5,7 +5,7 @@
<div id="qv">
<h2>Topics</h2>
<ol>
-<li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
+<li><a href="search-dialog.html">Creating a Search Interface</a></li>
<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
</ol>
@@ -24,9 +24,8 @@
<p>Search is a core user feature on Android. Users should be able
to search any data that is available to them, whether the content is located on the device or
-the Internet. The search experience should be seamless and consistent across the entire
-system, which is why Android provides a search framework to help you provide users with
-a familiar search dialog and a great search experience.</p>
+the Internet. To help create a consistent search experience for users, Android provides a
+search framework that helps you implement search for your application.</p>
<div class="figure" style="width:250px">
<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
@@ -34,16 +33,14 @@
search suggestions.</p>
</div>
-<p>Android's search framework provides a user interface in which users can perform a search and
-an interaction layer that communicates with your application, so you don't have to build
-your own search Activity. Instead, a search dialog appears at the top of the screen at the user's
-command without interrupting the current Activity.</p>
+<p>The search framework offers two modes of search input: a search dialog at the top of the
+screen or a search widget ({@link android.widget.SearchView}) that you can embed in your activity
+layout. In either case, the Android system will assist your search implementation by
+delivering search queries to a specific activity that performs searchs. You can also enable either
+the search dialog or widget to provide search suggestions as the user types. Figure 1 shows an
+example of the search dialog with optional search suggestions.</p>
-<p>The search framework manages the life of the search dialog. When users execute a search, the
-search framework passes the query text to your application so your application can perform a
-search. Figure 1 shows an example of the search dialog with optional search suggestions.</p>
-
-<p>Once your application is set up to use the search dialog, you can:</p>
+<p>Once you've set up either the search dialog or the search widget, you can:</p>
<ul>
<li>Enable voice search</li>
@@ -57,19 +54,19 @@
if your data is stored in an SQLite database, you should use the {@link android.database.sqlite}
APIs to perform searches.</p>
-<p>The following documents show you how to use the search dialog in your application:</p>
+<p>The following documents show you how to use Android's framework to implement search:</p>
<dl>
- <dt><strong><a href="search-dialog.html">Using the Android Search Dialog</a></strong></dt>
- <dd>How to set up your application to use the search dialog. </dd>
+ <dt><strong><a href="search-dialog.html">Creating a Search Interface</a></strong></dt>
+ <dd>How to set up your application to use the search dialog or search widget. </dd>
<dt><strong><a href="adding-recent-query-suggestions.html">Adding Recent Query
Suggestions</a></strong></dt>
- <dd>How to show suggestions based on queries previously used in the search dialog.</dd>
+ <dd>How to provide suggestions based on queries previously used.</dd>
<dt><strong><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></strong></dt>
- <dd>How to show suggestions based on custom data from your application and offer your suggestions
+ <dd>How to provide suggestions based on custom data from your application and also offer them
in the system-wide Quick Search Box.</dd>
<dt><strong><a href="searchable-config.html">Searchable Configuration</a></strong></dt>
- <dd>A reference for the searchable configuration file (though the other
+ <dd>A reference document for the searchable configuration file (though the other
documents also discuss the configuration file in terms of specific behaviors).</dd>
</dl>
@@ -92,17 +89,17 @@
send the personal information, you should not log it. If you must log it, protect that data
very carefully and erase it as soon as possible.</p>
</li>
-<li><strong>Provide the user with a way to clear their search history.</strong>
+<li><strong>Provide users with a way to clear their search history.</strong>
<p>The search framework helps your application provide context-specific suggestions while the user
types. Sometimes these
suggestions are based on previous searches or other actions taken by the user in an earlier
session. A user might not wish for previous searches to be revealed to other device users, for
-instance, if they share their phone with a friend. If your application provides suggestions that can
-reveal previous activities, you should implement the ability for the user to clear the search
-history. If you are using {@link android.provider.SearchRecentSuggestions}, you can simply call the
-{@link android.provider.SearchRecentSuggestions#clearHistory()} method. If you are implementing
-custom suggestions, you'll need to provide a similar "clear history" method in your provider that
-the user can execute.</p>
+instance, if the user shares the device with a friend. If your application provides suggestions that
+can reveal previous search activities, you should implement the ability for the user to clear the
+search history. If you are using {@link android.provider.SearchRecentSuggestions}, you can simply
+call the {@link android.provider.SearchRecentSuggestions#clearHistory()} method. If you are
+implementing custom suggestions, you'll need to provide a similar "clear history" method in your
+content provider that the user can execute.</p>
</li>
</ul>
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index 6699fe1..af6c8f2 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -1,38 +1,61 @@
-page.title=Using the Android Search Dialog
+page.title=Creating a Search Interface
parent.title=Search
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
+
+ <h2>Quickview</h2>
+ <ul>
+ <li>The Android system sends search queries from the search dialog or widget to an activity you
+specify to perform searches and present results</li>
+ <li>You can put the search widget in the Action Bar, as an "action view," for quick
+access</li>
+ </ul>
+
+
<h2>In this document</h2>
<ol>
<li><a href="#TheBasics">The Basics</a></li>
<li><a href="#SearchableConfiguration">Creating a Searchable Configuration</a></li>
<li><a href="#SearchableActivity">Creating a Searchable Activity</a>
<ol>
- <li><a href="#DeclaringSearchableActivity">Declaring a searchable Activity</a></li>
+ <li><a href="#DeclaringSearchableActivity">Declaring a searchable activity</a></li>
+ <li><a href="#EnableSearch">Enabling the search dialog and search widget</a></li>
<li><a href="#PerformingSearch">Performing a search</a></li>
</ol>
</li>
-<li><a href="#InvokingTheSearchDialog">Invoking the Search Dialog</a>
+<li><a href="#UsingTheSearchDialog">Using the Search Dialog</a>
<ol>
- <li><a href="#LifeCycle">The impact of the search dialog on your Activity life-cycle</a></li>
+ <li><a href="#LifeCycle">The impact of the search dialog on your activity lifecycle</a></li>
+ <li><a href="#SearchContextData">Passing search context data</a></li>
</ol>
</li>
-<li><a href="#SearchContextData">Passing Search Context Data</a></li>
+<li><a href="#UsingSearchWidget">Using the Search Widget</a>
+ <ol>
+ <li><a href="#ConfiguringWidget">Configuring the search widget</a></li>
+ <li><a href="#WidgetFeatures">Other search widget features</a></li>
+ </ol>
+</li>
<li><a href="#VoiceSearch">Adding Voice Search</a></li>
+<li><a href="#SearchSuggestions">Adding Search Suggestions</a></li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.app.SearchManager}</li>
+<li>{@link android.widget.SearchView}</li>
</ol>
<h2>Related samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable
Dictionary</a></li>
+<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/SearchViewActionBar.html">SearchView
+ in the Action Bar</a></li>
+<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/SearchViewFilterMode.html">SearchView
+ filter mode</a></li>
</ol>
<h2>Downloads</h2>
@@ -50,16 +73,24 @@
</div>
</div>
-<p>When you want to implement search in your application, the last thing you should have to worry
-about is where to put the search box. When you implement search with the Android search framework,
-you don't have to. When the user invokes search, a search dialog appears at the top of the screen
-with your application icon to the left of the search box. When the user executes the search, your
-application receives the query so it can search your application's data. An example of the search
-dialog is shown in figure 1.</p>
+<p>When you're ready to add search functionality to your application, Android helps you implement
+the user interface with either a search dialog that appears at the top of the activity window or a
+search widget that you can insert in your layout. Both the search dialog and the widget can deliver
+the user's search query to a specific activity in your application. This way, the user can initiate
+a search from any activity where the search dialog or widget is available, and the system starts the
+appropriate activity to perform the search and present results.</p>
-<p>This guide shows you how to set up your application to provide search in the search
-dialog. When you use the search dialog, you provide a standardized search
-experience and can add features such as voice search and search suggestions.</p>
+<p>Other features available for the search dialog and widget include:</p>
+
+<ul>
+ <li>Voice search</li>
+ <li>Search suggestions based on recent queries</li>
+ <li>Search suggestions that match actual results in your application data</li>
+</ul>
+
+<p>This guide shows you how to set up your application to provide a search interface
+that's assisted by the Android system to deliver search queries, using either the
+search dialog or the search widget.</p>
<h2 id="TheBasics">The Basics</h2>
@@ -69,40 +100,78 @@
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of an application's search dialog.</p>
</div>
-<p>The Android search framework manages the search dialog for your application. You never need
-to draw it or worry about where it is, and your Activity is not interrupted when the search dialog
-appears. The Search Manager ({@link android.app.SearchManager}) is the component that does this work
-for you. It manages the life of the search dialog and sends your application the user's search
-query.</p>
+<p>Before you begin, you should decide whether you'll implement your search interface using the
+search dialog or the search widget. Both provide the same search features, but in slightly different
+ways:</p>
-<p>When the user executes a search, the Search Manager creates an {@link android.content.Intent} to
-pass the search query to the Activity that you've declared to handle searches. Basically, all you
-need is an Activity that receives the search Intent, performs the search, and presents the results.
-Specifically, you need the following:</p>
+<ul>
+ <li>The <strong>search dialog</strong> is a UI component that's controlled by the Android system.
+When activated by the user, the search dialog appears at the top of the activity, as shown in figure
+1.
+ <p>The Android system controls all events in the search dialog. When the user
+submits a query, the system delivers the query to the activity that you specify to
+handle searches. The dialog can also provide search suggestions while the user types.</p></li>
-<dl>
- <dt>A searchable configuration</dt>
- <dd>An XML file that configures the search dialog and includes settings for features such as voice
-search, search suggestion, and the hint text.</dd>
- <dt>A searchable Activity</dt>
- <dd>The {@link android.app.Activity} that receives the search query, then searches your data and
-displays the search results.</dd>
- <dt>A mechanism by which the user can invoke search</dt>
- <dd>The device search key invokes the search dialog, by default. However, a dedicated search key
-is not guaranteed on all devices, so provide another means by which the user can invoke a search,
-such as a search button in the Options Menu or elsewhere in the Activity UI.</dd>
-</dl>
+ <li>The <strong>search widget</strong> is an instance of {@link android.widget.SearchView} that
+you can place anywhere in your layout. By default, the search widget behaves like a standard {@link
+android.widget.EditText} widget and doesn't do anything, but you can configure it so that the
+Android system handles all input events, delivers queries to the appropriate activity, and provides
+search suggestions (just like the search dialog). However, the search widget is available only in
+Android 3.0 (API Level 11) and higher.
+<p class="note"><strong>Note:</strong> If you want, you can handle all user input into the
+search widget yourself, using various callback methods and listeners. This document, however,
+focuses on how to integrate the search widget with the system for an assisted search
+implementation. If you want to handle all user input yourself, read the reference documentation for
+{@link android.widget.SearchView} and its nested interfaces. </p></li>
+</ul>
+
+<p>When the user executes a search from the search dialog or a search widget, the system creates an
+{@link android.content.Intent} and stores the user query in it. The system then starts the activity
+that you've declared to handle searches (the "searchable activity") and delivers it the intent. To
+set up your application for this kind of assisted search, you need the following:</p>
+
+<ul>
+ <li>A searchable configuration
+ <p>An XML file that configures some settings for the search dialog or widget. It includes settings
+for features such as voice search, search suggestion, and hint text for the search box.</p></li>
+ <li>A searchable activity
+ <p>The {@link android.app.Activity} that receives the search query, searches your
+data, and displays the search results.</p></li>
+ <li>A search interface, provided by either:
+ <ul>
+ <li>The search dialog
+ <p>By default, the search dialog is hidden, but appears at the top of the screen when the
+user presses the device SEARCH button (when available) or another button in your user interface.</p>
+ </li>
+ <li>Or, a {@link android.widget.SearchView} widget
+ <p>Using the search widget allows you to put the search box anywhere in your activity.
+Instead of putting it in your activity layout, however, it's usually more convenient for users as an
+<a href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view in the Action Bar</a>.</p>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<p>The rest of this document shows you how to create the searchable configuration, searchable
+activity, and implement a search interface with either the search dialog or search widget.</p>
<h2 id="SearchableConfiguration">Creating a Searchable Configuration</h2>
-<p>The searchable configuration is an XML file that defines several settings for the search
-dialog in your application. This file is traditionally named {@code searchable.xml} and must be
-saved in the {@code res/xml/} project directory.</p>
+<p>The first thing you need is an XML file called the searchable configuration. It configures
+certain UI aspects of the search dialog or widget and defines how features such as suggestions and
+voice search behave. This file is traditionally named {@code searchable.xml} and must be saved in
+the {@code res/xml/} project directory.</p>
-<p>The file must consist of the {@code <searchable>} element as the root node and specify one
-or more attributes that configure your search dialog. For example:</p>
+<p class="note"><strong>Note:</strong> The system uses this file to instantiate a {@link
+android.app.SearchableInfo} object, but you cannot create this object yourself at
+runtime—you must declare the searchable configuration in XML.</p>
+
+<p>The searchable configuration file must include the <a
+href="{@docRoot}guide/topics/search/searchable-config.html#searchable-element">{@code
+<searchable>}</a> element as the root node and specify one
+or more attributes. For example:</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
@@ -112,51 +181,61 @@
</searchable>
</pre>
-<p>The {@code android:label} attribute is the only required attribute and points to a string
-resource, which should be the same as the application name. This label isn't actually visible to the
-user until you enable suggestions for Quick Search Box, at which point, this label is visible in the
-list of Searchable items in the system Settings.</p>
+<p>The {@code android:label} attribute is the only required attribute. It points to a string
+resource, which should be the application name. This label isn't actually visible to the
+user until you enable search suggestions for Quick Search Box. At that point, this label is visible
+in the list of Searchable items in the system Settings.</p>
<p>Though it's not required, we recommend that you always include the {@code android:hint}
-attribute, which provides a hint string in the search dialog's text box before the user
-enters their query. The hint is important because it provides important clues to users about what
+attribute, which provides a hint string in the search box before users
+enters a query. The hint is important because it provides important clues to users about what
they can search.</p>
<p class="note"><strong>Tip:</strong> For consistency among other
Android applications, you should format the string for {@code android:hint} as "Search
-<em><content-or-product></em>". For example, "Search songs and artists" or "Search
+<content-or-product>". For example, "Search songs and artists" or "Search
YouTube".</p>
-<p>The {@code <searchable>} element accepts several other attributes. Most attributes apply
-only when configuring features such as search suggestions and voice search.</p>
-
-<p>For more details about the searchable configuration file, see the <a
-href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a>
-reference.</p>
+<p>The <a
+href="{@docRoot}guide/topics/search/searchable-config.html#searchable-element">{@code
+<searchable>}</a> element accepts several other attributes. However, you don't need
+most attributes until you add features such as <a href="#SearchSuggestions">search suggestions</a>
+and <a href="#VoiceSearch">voice search</a>. For detailed information about the searchable
+configuration file, see the <a
+href="{@docRoot}guide/topics/search/searchable-config.html">Searchable Configuration</a> reference
+document.</p>
<h2 id="SearchableActivity">Creating a Searchable Activity</h2>
-<p>When the user executes a search from the search dialog, the Search Manager takes the query
-and sends it to your searchable {@link android.app.Activity} in the {@link
-android.content.Intent#ACTION_SEARCH} {@link android.content.Intent}. Your searchable Activity
-then searches your data using the query and presents the results to the user.</p>
+<p>A searchable activity is the {@link android.app.Activity} in your application that performs
+searches based on a query string and presents the search results.</p>
-<p>In order for the Search Manager to know where to deliver the search query, you must declare your
-searchable Activity in the Android manifest file.</p>
+<p>When the user executes a search in the search dialog or widget, the system starts your
+searchable activity and delivers it the search query in an {@link
+android.content.Intent} with the {@link android.content.Intent#ACTION_SEARCH} action. Your
+searchable activity retrieves the query from the intent's {@link android.app.SearchManager#QUERY
+QUERY} extra, then searches your data and presents the results.</p>
+
+<p>Because you may include the search dialog or widget in any other activity in your application,
+the system must know which activity is your searchable activity, so it can properly deliver the
+search query. So, you must first declare your searchable activity in the Android manifest file.</p>
-<h3 id="DeclaringSearchableActivity">Declaring a searchable Activity</h3>
+<h3 id="DeclaringSearchableActivity">Declaring a searchable activity</h3>
-<p>If you don't have one already, create an {@link android.app.Activity} that performs
-searches and present search results. To set up this Activity as your searchable Activity:</p>
+<p>If you don't have one already, create an {@link android.app.Activity} that will perform
+searches and present results. You don't need to implement the search functionality yet—just
+create an activity that you can declare in the manifest. Inside the manifest's <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
+element:</p>
<ol>
- <li>Declare the Activity to accept the {@link android.content.Intent#ACTION_SEARCH} {@link
-android.content.Intent}, in an <a
-href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code <intent-filter>}</a>
+ <li>Declare the activity to accept the {@link android.content.Intent#ACTION_SEARCH} intent, in an
+<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+<intent-filter>}</a>
element.</li>
- <li>Apply the searchable configuration, in a <a
+ <li>Specify the searchable configuration to use, in a <a
href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
element.</li>
</ol>
@@ -165,7 +244,7 @@
<pre>
<application ... >
- <activity android:name=".MySearchableActivity" >
+ <activity android:name=".SearchableActivity" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
@@ -181,71 +260,22 @@
reference to the searchable configuration file (in this example, it
refers to the {@code res/xml/searchable.xml} file).</p>
-<p class="note"><strong>Note:</strong> The {@code <intent-filter>} does not need a <a
+<p class="note"><strong>Note:</strong> The <a
+href="{@docRoot}guide/topics/manifest/intent-filter-element.html">{@code
+<intent-filter>}</a> does not need a <a
href="{@docRoot}guide/topics/manifest/category-element.html">{@code <category>}</a> with the
-{@code DEFAULT} value, because the Search Manager delivers the {@link
-android.content.Intent#ACTION_SEARCH} Intent explicitly to your searchable Activity by name.</p>
+{@code DEFAULT} value (which you usually see in <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> elements),
+because the system delivers the {@link android.content.Intent#ACTION_SEARCH} intent explicitly to
+your searchable activity, using its component name.</p>
-<p>The search dialog is not, by default, available from every Activity of your
-application. Rather, the search dialog is presented to users only when they
-invoke search from a searchable context of your application. A searchable context is any Activity
-for which you have
-declared searchable meta-data in the manifest file. For example, the searchable Activity itself
-(declared in the manifest snippet above) is
-a searchable context because it includes meta-data that defines the
-searchable configuration. Any other Activity in your application is not a searchable context, by
-default, and thus, does not reveal the search dialog. However, you probably do want the search
-dialog available from your other activities (and to launch the searchable Activity when the user
-executes a search). You can do exactly that.</p>
-
-<p>If you want all of your activities to provide the search dialog, add another {@code
-<meta-data>} element inside the {@code
-<application>} element. Use this element to declare the existing searchable Activity as the
-default searchable Activity. For example:</p>
-
-<pre>
-<application ... >
- <activity android:name=".MySearchableActivity" >
- <intent-filter>
- <action android:name="android.intent.action.SEARCH" />
- </intent-filter>
- <meta-data android:name="android.app.searchable"
- android:resource="@xml/searchable"/>
- </activity>
- <activity android:name=".AnotherActivity" ... >
- </activity>
- <!-- declare the default searchable Activity for the whole app -->
- <b><meta-data android:name="android.app.default_searchable"
- android:value=".MySearchableActivity" /></b>
- ...
-</application>
-</pre>
-
-<p>The {@code <meta-data>} element with the {@code android:name} attribute value of
-{@code "android.app.default_searchable"} specifies a default searchable Activity for the context in
-which it is placed (which, in this case, is the entire application). The searchable Activity to
-use is specified with the {@code android:value} attribute. All other activities in the
-application, such as {@code AnotherActivity}, are now considered a searchable context and can invoke
-the search dialog. When a search is executed, {@code MySearchableActivity} is launched to handle
-the search query.</p>
-
-<p>You can also control which activities provide search at a more granular level.
-To specify only an individual Activity as a searchable context, place the {@code
-<meta-data>} with the {@code
-"android.app.default_searchable"} name inside the respective {@code <activity>}
-element (rather than inside the {@code <application>} element). While uncommon, you
-can also create more than one searchable Activity and provide each one in different contexts of your
-application, either by declaring a different searchable Activity in each {@code <activity>}
-element, or by declaring a default searchable Activity for the entire application and then
-overriding it with a {@code <meta-data>} element inside certain activities. (You might do
-this if you want to search different sets of data that cannot be handled by the same
-searchable Activity, depending on the currently open Activity.)</p>
<h3 id="PerformingSearch">Performing a search</h3>
-<p>Once you have declared your searchable Activity, performing a search for the user involves
-three steps:</p>
+<p>Once you have declared your searchable activity in the manifest, performing a search in your
+searchable activity involves three steps:</p>
+
<ol>
<li><a href="#ReceivingTheQuery">Receiving the query</a></li>
<li><a href="#SearchingYourData">Searching your data</a></li>
@@ -253,20 +283,19 @@
</ol>
<p>Traditionally, your search results should be presented in a {@link android.widget.ListView}, so
-you might want your searchable Activity to extend {@link android.app.ListActivity}, which
-provides easy access to {@link android.widget.ListView} APIs. (See the <a
-href="{@docRoot}resources/tutorials/views/hello-listview.html">List View Tutorial</a> for a simple
-{@link android.app.ListActivity} sample.)</p>
+you might want your searchable activity to extend {@link android.app.ListActivity}. It includes
+a default layout with a single {@link android.widget.ListView} and provides several
+convenience methods for working with the {@link android.widget.ListView}.</p>
<h4 id="ReceivingTheQuery">Receiving the query</h4>
-<p>When a user executes a search from the search dialog, the Search Manager sends the {@link
-android.content.Intent#ACTION_SEARCH} {@link android.content.Intent} to your searchable Activity.
-This Intent carries the search query in the
+<p>When a user executes a search from the search dialog or widget, the system starts your
+searchable activity and sends it a {@link android.content.Intent#ACTION_SEARCH} intent. This intent
+carries the search query in the
{@link android.app.SearchManager#QUERY QUERY} string extra. You must check for
-this Intent when the Activity starts and extract the string. For example, here's how you can get the
-query when your Activity starts:</p>
+this intent when the activity starts and extract the string. For example, here's how you can get the
+search query when your searchable activity starts:</p>
<pre>
@Override
@@ -274,8 +303,8 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
+ // Get the intent, verify the action and get the query
Intent intent = getIntent();
-
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doMySearch(query);
@@ -284,7 +313,7 @@
</pre>
<p>The {@link android.app.SearchManager#QUERY QUERY} string is always included with
-the {@link android.content.Intent#ACTION_SEARCH} Intent. In this example, the query is
+the {@link android.content.Intent#ACTION_SEARCH} intent. In this example, the query is
retrieved and passed to a local {@code doMySearch()} method where the actual search operation
is done.</p>
@@ -294,12 +323,13 @@
<p>The process of storing and searching your data is unique to your application.
You can store and search your data in many ways, but this guide does not show you how to store your
data and search it. Storing and searching your data is something you should carefully consider in
-terms of your needs and your data. However, here are some tips you might be able to apply:</p>
+terms of your needs and your data format. However, here are some tips you might be able to
+apply:</p>
<ul>
<li>If your data is stored in a SQLite database on the device, performing a full-text search
-(using FTS3, rather than a LIKE query) can provide a more robust search across text data and can
-produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
+(using FTS3, rather than a {@code LIKE} query) can provide a more robust search across text data and
+can produce results significantly faster. See <a href="http://sqlite.org/fts3.html">sqlite.org</a>
for information about FTS3 and the {@link android.database.sqlite.SQLiteDatabase} class for
information about SQLite on Android. Also look at the <a
href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> sample
@@ -307,43 +337,45 @@
<li>If your data is stored online, then the perceived search performance might be
inhibited by the user's data connection. You might want to display a spinning progress wheel until
your search returns. See {@link android.net} for a reference of network APIs and <a
-href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a> to see
-how you can display a progress wheel.</li>
+href="{@docRoot}guide/topics/ui/dialogs.html#ProgressDialog">Creating a Progress Dialog</a>
+for information about how to display a progress wheel.</li>
</ul>
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>About Adapters</h2>
-<p>An Adapter binds individual items from a set of data into individual {@link
-android.view.View} objects. When the Adapter
-is applied to a {@link android.widget.ListView}, the Views are injected as individual items of the
-list. {@link
-android.widget.Adapter} is simply an interface, so implementations such as {@link
+<p>An {@link android.widget.Adapter} binds each item from a set of data into a
+{@link android.view.View} object. When the {@link android.widget.Adapter}
+is applied to a {@link android.widget.ListView}, each piece of data is inserted as an individual
+view into the list. {@link
+android.widget.Adapter} is just an interface, so implementations such as {@link
android.widget.CursorAdapter} (for binding data from a {@link android.database.Cursor}) are needed.
-If none of the existing implementations work for your data, then you should implement your own from
+If none of the existing implementations work for your data, then you can implement your own from
{@link android.widget.BaseAdapter}. Install the SDK Samples package for API Level 4 to see the
-original version of the Searchable Dictionary, which creates a custom BaseAdapter.</p>
+original version of the Searchable Dictionary, which creates a custom adapter to read data from
+a file.</p>
</div>
</div>
<p>Regardless of where your data lives and how you search it, we recommend that you return search
-results to your searchable Activity with an {@link android.widget.Adapter}. This way, you can easily
+results to your searchable activity with an {@link android.widget.Adapter}. This way, you can easily
present all the search results in a {@link android.widget.ListView}. If your data comes from a
-SQLite database query, then you can apply your results to a {@link android.widget.ListView}
+SQLite database query, you can apply your results to a {@link android.widget.ListView}
using a {@link android.widget.CursorAdapter}. If your data comes in some other type of format, then
-you can create an extension of the {@link android.widget.BaseAdapter}.</p>
+you can create an extension of {@link android.widget.BaseAdapter}.</p>
+
<h4 id="PresentingTheResults">Presenting the results</h4>
-<p>Presenting your search results is mostly a UI detail that is not handled by the search APIs.
-However, one option is to create your searchable Activity to extend {@link
-android.app.ListActivity} and call {@link
-android.app.ListActivity#setListAdapter(ListAdapter)}, passing it an {@link
+<p>As discussed above, the recommended UI for your search results is a {@link
+android.widget.ListView}, so you might want your searchable activity to extend {@link
+android.app.ListActivity}. You can then call {@link
+android.app.ListActivity#setListAdapter(ListAdapter) setListAdapter()}, passing it an {@link
android.widget.Adapter} that is bound to your data. This injects all the
-results into the Activity {@link android.widget.ListView}.</p>
+search results into the activity {@link android.widget.ListView}.</p>
-<p>For more help presenting your results, see the {@link android.app.ListActivity}
+<p>For more help presenting your results in a list, see the {@link android.app.ListActivity}
documentation.</p>
<p>Also see the <a
@@ -353,22 +385,130 @@
-<h2 id="InvokingTheSearchDialog">Invoking the Search Dialog</h2>
-<p>Once you have a searchable Activity, invoking the search dialog is easy. Many Android
-devices provide a dedicated SEARCH key, which reveals the search dialog when the user presses it
-from a searchable context of your application. However, you should not assume that a SEARCH
-key is available on the user's device and should always provide a search button in your UI that
-invokes search.</p>
-<p>To invoke search from your Activity, call {@link android.app.Activity#onSearchRequested()}.</p>
+<h2 id="SearchDialog">Using the Search Dialog</h2>
-<p>For instance, you should provide a menu item in your <a
-href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your UI to
-invoke search with this method. The <a
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h2>Should I use the search dialog or the widget?</h2>
+ <p>The answer depends mostly on whether you are developing for Android 3.0 (API Level 11 or
+higher), because the {@link android.widget.SearchView} widget was introduced in Android 3.0. So,
+if you are developing your application for a version of Android lower than 3.0, the search widget is
+not an option and you should use the search dialog to implement your search interface.</p>
+ <p>If you <em>are</em> developing for Android 3.0 or higher, then the decision depends more on
+your needs. In most cases, we recommend that you use the search widget as an "action view" in the
+Action Bar. However, it might not be an option for you to put the search
+widget in the Action Bar for some reason (perhaps there's not enough space or you don't use the
+Action Bar). So, you might instead want to put the search widget somewhere in your activity layout.
+And if all else fails, you can still use the search dialog if you prefer to keep the search box
+hidden. In fact, you might want to offer both the dialog and the widget in some cases. For more
+information about the widget, skip to <a href="#UsingSearchWidget">Using the Search Widget</a>.</p>
+</div>
+</div>
+
+<p>The search dialog provides a floating search box at the top of the screen, with the application
+icon on the left. The search dialog can provide search suggestions as the user types and, when
+the user executes a search, the system sends the search query to a
+searchable activity that performs the search. However, if you are developing
+your application for devices running Android 3.0, you should consider using the search widget
+instead (see the side box).</p>
+
+<p>The search dialog is always hidden by default, until the user activates it. If the user's device
+includes a SEARCH button, pressing it will activate the search dialog by default. Your application
+can also activate the search dialog on demand by calling {@link
+android.app.Activity#onSearchRequested onSearchRequested()}. However, neither of these work
+until you enable the search dialog for the activity.</p>
+
+<p>To enable the search dialog, you must indicate to the system which searchable activity should
+receive search queries from the search dialog, in order to perform searches. For example, in the
+previous section about <a href="#SearchableActivity">Creating a Searchable Activity</a>, a
+searchable activity named {@code SearchableActivity} was created. If you want a separate activity,
+named {@code OtherActivity}, to show the search dialog and deliver searches to {@code
+SearchableActivity}, you must declare in the manifest that {@code SearchableActivity} is the
+searchable activity to use for the search dialog in {@code OtherActivity}.</p>
+
+<p>To declare the searchable activity for an activity's search dialog,
+add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element inside the respective activity's <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> element.
+The <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element must include the {@code android:value} attribute that specifies the searchable activity's
+class name and the {@code android:name} attribute with a value of {@code
+"android.app.default_searchable"}.</p>
+
+<p>For example, here is the declaration for
+both a searchable activity, {@code SearchableActivity}, and another activity, {@code
+OtherActivity}, which uses {@code SearchableActivity} to perform searches executed from its
+search dialog:</p>
+
+<pre>
+<application ... >
+ <!-- this is the searchable activity; it performs searches -->
+ <activity android:name=".SearchableActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.SEARCH" />
+ </intent-filter>
+ <meta-data android:name="android.app.searchable"
+ android:resource="@xml/searchable"/>
+ </activity>
+
+ <!-- this activity enables the search dialog to initiate searches
+ in the SearchableActivity -->
+ <activity android:name=".OtherActivity" ... >
+ <!-- enable the search dialog to send searches to SearchableActivity -->
+ <b><meta-data android:name="android.app.default_searchable"
+ android:value=".SearchableActivity" /></b>
+ </activity>
+ ...
+</application>
+</pre>
+
+<p>Because the {@code OtherActivity} now includes a <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element to declare which searchable activity to use for searches, the activity has enabled the
+search dialog.
+While the user is in this activity, the device SEARCH button (if available) and the {@link
+android.app.Activity#onSearchRequested onSearchRequested()} method will activate the search dialog.
+When the user executes the search, the system starts {@code SearchableActivity} and delivers it
+the {@link android.content.Intent#ACTION_SEARCH} intent.</p>
+
+<p class="note"><strong>Note:</strong> The searchable activity itself provides the search dialog
+by default, so you don't need to add this declaration to {@code SearchableActivity}.</p>
+
+<p>If you want every activity in your application to provide the search dialog, insert the above <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element as a child of the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
+element, instead of each <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>. This
+way, every activity inherits the value, provides the search dialog, and delivers searches to
+the same searchable activity. (If you have multiple searchable activities, you can override the
+default searchable activity by placing a different <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+declaration inside individual activities.)</p>
+
+<p>With the search dialog now enabled for your activities, your application is ready to perform
+searches.</p>
+
+
+<h3 id="InvokingTheSearchDialog">Invoking the search dialog</h3>
+
+<p>As mentioned above, the device SEARCH button and {@link android.app.Activity#onSearchRequested
+onSearchRequested()} method will open the search dialog, as long as the current activity
+has declared the searchable activity to use, as shown in the previous section.</p>
+
+<p>However, you should not assume that a SEARCH button is available on the user's device. You
+should always provide another search button in your UI that activates the search dialog by calling
+{@link android.app.Activity#onSearchRequested()}.</p>
+
+<p>For instance, you should either provide a menu item in your <a
+href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your
+activity layout that
+activates search by calling {@link android.app.Activity#onSearchRequested()}. The <a
href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a> file includes icons for
-medium and high density screens, which you can use for your search menu item or button (low density
-screens automatically scale-down the hdpi image by one half). </p>
+medium and high density screens, which you can use for your search menu item or button (low-density
+screens scale-down the hdpi image by one half). </p>
<!-- ... maybe this should go into the Creating Menus document ....
<p>If you chose to provide a shortcut key for the menu item, using {@link
@@ -376,27 +516,28 @@
key character, representing the default search key.</p>
-->
-<p>You can also enable "type-to-search" functionality, which reveals the search dialog when the
-user starts typing on the keyboard and the keystrokes are inserted into the search dialog. You can
-enable type-to-search in your Activity by calling
+<p>You can also enable "type-to-search" functionality, which activates the search dialog when the
+user starts typing on the keyboard—the keystrokes are inserted into the search dialog. You can
+enable type-to-search in your activity by calling
{@link android.app.Activity#setDefaultKeyMode(int) setDefaultKeyMode}({@link
-android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your Activity's
+android.app.Activity#DEFAULT_KEYS_SEARCH_LOCAL}) during your activity's
{@link android.app.Activity#onCreate(Bundle) onCreate()} method.</p>
-<h3 id="LifeCycle">The impact of the search dialog on your Activity lifecycle</h3>
+<h3 id="LifeCycle">The impact of the search dialog on your activity lifecycle</h3>
<p>The search dialog is a {@link android.app.Dialog} that floats at the top of the
-screen. It does not cause any change in the Activity stack, so when the search dialog appears, no
-lifecycle methods for the currently open Activity (such as {@link
-android.app.Activity#onPause()}) are called. Your Activity just loses input focus as it is given to
-the search dialog.
+screen. It does not cause any change in the activity stack, so when the search dialog appears, no
+lifecycle methods (such as {@link android.app.Activity#onPause()}) are called. Your activity just
+loses input focus, as input focus is given to the search dialog.
</p>
-<p>If you want to be notified when search is invoked, override the {@link
-android.app.Activity#onSearchRequested()} method. When the system calls this method, you can do any
-work you want to when your Activity looses input focus to the search dialog (such as pause
-animations). Unless you are <a href="#SearchContextData">passing search context data</a>
+<p>If you want to be notified when the search dialog is activated, override the {@link
+android.app.Activity#onSearchRequested()} method. When the system calls this method, it is an
+indication that your activity has lost input focus to the search dialog, so you can do any
+work appropriate for the event (such as pause
+a game). Unless you are <a
+href="#SearchContextData">passing search context data</a>
(discussed below), you should end the method by calling the super class implementation. For
example:</p>
@@ -408,8 +549,8 @@
}
</pre>
-<p>If the user cancels search by pressing the BACK key, the Activity in which search was
-invoked re-gains input focus. You can register to be notified when the search dialog is
+<p>If the user cancels search by pressing the BACK button, the search dialog closes and the activity
+regains input focus. You can register to be notified when the search dialog is
closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)
setOnDismissListener()}
and/or {@link android.app.SearchManager#setOnCancelListener(SearchManager.OnCancelListener)
@@ -420,25 +561,26 @@
user explicitly exited the search dialog, so it is not called when a search is executed (in which
case, the search dialog naturally disappears).</p>
-<p>If the current Activity is not the searchable Activity, then the normal Activity lifecycle
-events are triggered once the user executes a search (the current Activity receives {@link
+<p>If the current activity is not the searchable activity, then the normal activity lifecycle
+events are triggered once the user executes a search (the current activity receives {@link
android.app.Activity#onPause()} and so forth, as
-described in <a href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
-document). If, however, the current Activity is the searchable Activity, then one of two
+described in the <a
+href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
+document). If, however, the current activity is the searchable activity, then one of two
things happens:</p>
<ol type="a">
- <li>By default, the searchable Activity receives the {@link
-android.content.Intent#ACTION_SEARCH} Intent with a call to {@link
+ <li>By default, the searchable activity receives the {@link
+android.content.Intent#ACTION_SEARCH} intent with a call to {@link
android.app.Activity#onCreate(Bundle) onCreate()} and a new instance of the
-Activity is brought to the top of the Activity stack. There are now two instances of your
-searchable Activity in the Activity stack (so pressing the BACK key goes back to the previous
-instance of the searchable Activity, rather than exiting the searchable Activity).</li>
- <li>If you set {@code android:launchMode} to "singleTop", then the
-searchable Activity receives the {@link android.content.Intent#ACTION_SEARCH} Intent with a call
+activity is brought to the top of the activity stack. There are now two instances of your
+searchable activity in the activity stack (so pressing the BACK button goes back to the previous
+instance of the searchable activity, rather than exiting the searchable activity).</li>
+ <li>If you set {@code android:launchMode} to <code>"singleTop"</code>, then the
+searchable activity receives the {@link android.content.Intent#ACTION_SEARCH} intent with a call
to {@link android.app.Activity#onNewIntent(Intent)}, passing the new {@link
-android.content.Intent#ACTION_SEARCH} Intent here. For example, here's how you might handle
-this case, in which the searchable Activity's launch mode is "singleTop":
+android.content.Intent#ACTION_SEARCH} intent here. For example, here's how you might handle
+this case, in which the searchable activity's launch mode is <code>"singleTop"</code>:
<pre>
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -463,29 +605,29 @@
<p>Compared to the example code in the section about <a href="#PerformingSearch">Performing a
Search</a>, all the code to handle the
-search Intent is now in the {@code handleIntent()} method, so that both {@link
+search intent is now in the {@code handleIntent()} method, so that both {@link
android.app.Activity#onCreate(Bundle)
onCreate()} and {@link android.app.Activity#onNewIntent(Intent) onNewIntent()} can execute it.</p>
-<p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the Activity has
+<p>When the system calls {@link android.app.Activity#onNewIntent(Intent)}, the activity has
not been restarted, so the {@link android.app.Activity#getIntent()} method
-returns the same Intent that was received with {@link
+returns the same intent that was received with {@link
android.app.Activity#onCreate(Bundle) onCreate()}. This is why you should call {@link
android.app.Activity#setIntent(Intent)} inside {@link
-android.app.Activity#onNewIntent(Intent)} (so that the Intent saved by the Activity is updated in
+android.app.Activity#onNewIntent(Intent)} (so that the intent saved by the activity is updated in
case you call {@link android.app.Activity#getIntent()} in the future).</p>
</li>
</ol>
-<p>The second scenario using "singleTop" launch mode is usually ideal, because chances are good that
-once a search is done, the user will perform additional searches and it's a bad experience if your
-application creates multiple instances of the searchable Activity. So, we recommend that you set
-your searchable Activity to "singleTop" launch mode in the application
-manifest. For example:</p>
+<p>The second scenario using <code>"singleTop"</code> launch mode is usually ideal, because chances
+are good that once a search is done, the user will perform additional searches and it's a bad
+experience if your application creates multiple instances of the searchable activity. So, we
+recommend that you set your searchable activity to <code>"singleTop"</code> launch mode in the
+application manifest. For example:</p>
<pre>
-<activity android:name=".MySearchableActivity"
+<activity android:name=".SearchableActivity"
<b>android:launchMode="singleTop"</b> >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
@@ -497,57 +639,192 @@
-<h2 id="SearchContextData">Passing Search Context Data</h2>
+<h3 id="SearchContextData">Passing search context data</h3>
-<p>To refine your search criteria from the current Activity instead of depending only on the user's
-search query, you can provide additional data in the Intent that the Search Manager sends to your
-searchable Activity. In a simple case, you can make your refinements inside the searchable
-Activity, for every search made, but if your
-search criteria varies from one searchable context to another, then you can pass whatever data
-is necessary to refine your search in the {@link android.app.SearchManager#APP_DATA} {@link
-android.os.Bundle}, which is included in the {@link android.content.Intent#ACTION_SEARCH}
-Intent.</p>
+<p>In some cases, you can make necessary refinements to the search query inside the searchable
+activity, for every search made. However, if you want to refine your search criteria based on the
+activity from which the user is performing a search, you can provide additional data in the intent
+that the system sends to your searchable activity. You can pass the additional data in the {@link
+android.app.SearchManager#APP_DATA} {@link android.os.Bundle}, which is included in the {@link
+android.content.Intent#ACTION_SEARCH} intent.</p>
-<p>To pass this kind of data to your searchable Activity, override {@link
-android.app.Activity#onSearchRequested()} method for the Activity in which search can be invoked.
+<p>To pass this kind of data to your searchable activity, override the {@link
+android.app.Activity#onSearchRequested()} method for the activity from which the user can perform a
+search, create a {@link android.os.Bundle} with the additional data, and call {@link
+android.app.Activity#startSearch startSearch()} to activate the search dialog.
For example:</p>
<pre>
@Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
- appData.putBoolean(MySearchableActivity.JARGON, true);
+ appData.putBoolean(SearchableActivity.JARGON, true);
startSearch(null, false, appData, false);
return true;
}
</pre>
-<p>Returning "true" indicates that you have successfully handled this callback event. Then in your
-searchable Activity, you can extract the data placed inside {@code appdata} from the {@link
+<p>Returning "true" indicates that you have successfully handled this callback event and
+called {@link android.app.Activity#startSearch startSearch()} to activate
+the search dialog. Once the user submits a query, it's delivered to your
+searchable activity along with the data you've added. You can extract the extra data from the {@link
android.app.SearchManager#APP_DATA} {@link android.os.Bundle} to refine the search. For example:</p>
<pre>
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
- boolean jargon = appData.getBoolean(MySearchableActivity.JARGON);
+ boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
}
</pre>
<p class="caution"><strong>Caution:</strong> Never call the {@link
android.app.Activity#startSearch(String,boolean,Bundle,boolean) startSearch()} method from outside
-the {@link android.app.Activity#onSearchRequested()} callback method. To invoke the search dialog
-in your Activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
+the {@link android.app.Activity#onSearchRequested()} callback method. To activate the search dialog
+in your activity, always call {@link android.app.Activity#onSearchRequested()}. Otherwise, {@link
android.app.Activity#onSearchRequested()} is not called and customizations (such as the addition of
{@code appData} in the above example) are missed.</p>
+
+<h2 id="UsingSearchWidget">Using the Search Widget</h2>
+
+<div class="figure" style="width:429px;margin:0">
+ <img src="{@docRoot}images/ui/actionbar-actionview.png" alt="" />
+ <p class="img-caption"><strong>Figure 2.</strong> The {@link
+android.widget.SearchView} widget as an "action view" in the Action Bar.</p>
+</div>
+
+<p>The {@link android.widget.SearchView} widget is available in Android 3.0 and higher. If
+you're developing your application for Android 3.0 and have decided to use the search widget, we
+recommend that you insert the search widget as an <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view in the Action Bar</a>,
+instead of using the search dialog (and instead of placing the search widget in your activity
+layout). For example, figure 2 shows the search widget in the Action Bar.</p>
+
+<p>The search widget provides the same functionality as the search dialog. It starts the appropriate
+activity when the user executes a search, and it can provide search suggestions and perform voice
+search.</p>
+
+<p class="note"><strong>Note:</strong> When you use the search widget as an action view, you
+still might need to support using the search dialog, for cases in which the search widget does
+not fit in the Action Bar. See the following section about <a href="#UsingBoth">Using both
+the widget and the dialog</a>.</p>
+
+
+<h3 id="ConfiguringWidget">Configuring the search widget</h3>
+
+<p>After you've created a <a href="#SearchableConfiguration">searchable configuration</a> and a <a
+href="#SearchableActivity">searchable activity</a>, as discussed above, you need to enable assisted
+search for each {@link android.widget.SearchView}. You can do so by calling {@link
+android.widget.SearchView#setSearchableInfo setSearchableInfo()} and passing it the {@link
+android.app.SearchableInfo} object that represents your searchable configuration.</p>
+
+<p>You can get a reference to the {@link android.app.SearchableInfo} by calling {@link
+android.app.SearchManager#getSearchableInfo getSearchableInfo()} on {@link
+android.app.SearchManager}.</p>
+
+<p>For example, if you're using a {@link android.widget.SearchView} as an action view in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, you should enable the widget
+during the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback:</p>
+
+<pre>
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the options menu from XML
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.options_menu, menu);
+
+ // Get the SearchView and set the searchable configuration
+ SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
+ SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+ searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
+ searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
+
+ return true;
+}
+</pre>
+
+<p>That's all you need. The search widget is now configured and the system will deliver search
+queries to your searchable activity. You can also enable <a href="#SearchSuggestions">search
+suggestions</a> for the search widget.</p>
+
+<p class="note"><strong>Note:</strong> If you want to handle all user input yourself, you can do so
+with some callback methods and event listeners. For more information, see the reference
+documentation for {@link android.widget.SearchView} and its nested interfaces for the
+appropriate event listeners.</p>
+
+<p>For more information about action views in the Action Bar, read <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">Using the Action Bar</a> (which
+includes sample code for adding a search widget as an action view).</p>
+
+
+<h3 id="WidgetFeatures">Other search widget features</h3>
+
+<p>The {@link android.widget.SearchView} widget allows for a few additional features you might
+want:</p>
+
+<dl>
+ <dt>A submit button</dt>
+ <dd>By default, there's no button to submit a search query, so the user must press the
+"Return" key on the keyboard to initiate a search. You can add a "submit" button by calling
+{@link android.widget.SearchView#setSubmitButtonEnabled setSubmitButtonEnabled(true)}.</dd>
+ <dt>Query refinement for search suggestions</dt>
+ <dd>When you've enabled search suggestions, you usually expect users to simply select a
+suggestion, but they might also want to refine the suggested search query. You can add a button
+alongside each suggestion that inserts the suggestion in the search box for refinement by the
+user, by calling {@link android.widget.SearchView#setQueryRefinementEnabled
+setQueryRefinementEnabled(true)}.</dd>
+ <dt>The ability to toggle the search box visibility</dt>
+ <dd>By default, the search widget is "iconified," meaning that it is represented only by a
+search icon (a magnifying glass), and expands to show the search box when the user touches it.
+As shown above, you can show the search box by default, by calling {@link
+android.widget.SearchView#setIconifiedByDefault setIconifiedByDefault(false)}. You can also
+toggle the search widget appearance by calling {@link android.widget.SearchView#setIconified
+setIconified()}.</dd>
+</dl>
+
+<p>There are several other APIs in the {@link android.widget.SearchView} class that allow you to
+customize the search widget. However, most of them are used only when you handle all
+user input yourself, instead of using the Android system to deliver search queries and display
+search suggestions.</p>
+
+
+<h3 id="UsingBoth">Using both the widget and the dialog</h3>
+
+<p>If you insert the search widget in the Action Bar as an <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view</a>, and you enable it to
+appear in the Action Bar "if there is room" (by setting {@code
+android:showAsAction="ifRoom"}), then there is a chance that the search widget will not appear
+as an action view, but the menu item will appear in the overflow menu. For example, when your
+application runs on a smaller screen, there might not be enough room in the Action Bar to display
+the search widget along with other action items or navigation elements, so the menu item will
+instead appear in the overflow menu. When placed in the overflow menu, the item works like an
+ordinary menu item and does not display the action view (the search widget).</p>
+
+<p>To handle this situation, the menu item to which you've attached the search widget should
+activate the search dialog when the user selects it from the overflow menu. In order for it to do
+so, you must implement {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} to
+handle the "Search" menu item and open the search dialog by calling {@link
+android.app.Activity#onSearchRequested onSearchRequested()}.</p>
+
+<p>For more information about how items in the Action Bar work and how to handle this situation, see
+the documentation for <a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action
+Bar</a>.</p>
+
+<p>Also see the <a
+href="{@docRoot}resources/samples/SearchableDictionary/src/com/example/android/searchabledict/
+SearchableDictionary.html">Searchable Dictionary</a> for an example implementation using
+both the dialog and the widget.</p>
+
+
+
<h2 id="VoiceSearch">Adding Voice Search</h2>
-<p>You can add voice search functionality to your search dialog by adding the {@code
+<p>You can add voice search functionality to your search dialog or widget by adding the {@code
android:voiceSearchMode} attribute to your searchable configuration. This adds a voice search
-button in the search dialog that launches a voice prompt. When the user
+button that launches a voice prompt. When the user
has finished speaking, the transcribed search query is sent to your searchable
-Activity.</p>
+activity.</p>
<p>For example:</p>
@@ -562,7 +839,7 @@
<p>The value {@code showVoiceSearchButton} is required to enable voice
search, while the second value, {@code launchRecognizer}, specifies that the voice search button
-should launch a recognizer that returns the transcribed text to the searchable Activity.</p>
+should launch a recognizer that returns the transcribed text to the searchable activity.</p>
<p>You can provide additional attributes to specify the voice search behavior, such
as the language to be expected and the maximum number of results to return. See the <a
@@ -571,6 +848,38 @@
<p class="note"><strong>Note:</strong> Carefully consider whether voice search is appropriate for
your application. All searches performed with the voice search button are immediately sent to
-your searchable Activity without a chance for the user to review the transcribed query. Sufficiently
+your searchable activity without a chance for the user to review the transcribed query. Sufficiently
test the voice recognition and ensure that it understands the types of queries that
the user might submit inside your application.</p>
+
+
+
+<h2 id="SearchSuggestions">Adding Search Suggestions</h2>
+
+<div class="figure" style="width:250px;margin:0">
+<img src="{@docRoot}images/search/search-suggest-custom.png" alt="" height="417" />
+<p class="img-caption"><strong>Figure 3.</strong> Screenshot of a search dialog with custom
+search suggestions.</p>
+</div>
+
+<p>Both the search dialog and the search widget can provide search suggestions as the user
+types, with assistance from the Android system. The system manages the list of suggestions and
+handles the event when the user selects a suggestion.</p>
+
+<p>You can provide two kinds of search suggestions:</p>
+
+<dl>
+ <dt>Recent query search suggestions</dt>
+ <dd>These suggestions are simply words that the user previously used as search queries in
+your application.
+ <p>See <a href="adding-recent-query-suggestions.html">Adding Recent Query
+Suggestions</a>.</p></dd>
+ <dt>Custom search suggestions</dt>
+ <dd>These are search suggestions that you provide from your own data source, to help users
+immediately select the correct spelling or item they are searching for. Figure 3 shows an
+example of custom suggestions for a dictionary application—the user can select a suggestion
+to instantly go to the definition.
+ <p>See <a href="adding-custom-suggestions.html">Adding Custom
+Suggestions</a></p></dd>
+</dl>
+
diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
index 2aa2db6..fb689f9 100644
--- a/docs/html/guide/topics/search/searchable-config.jd
+++ b/docs/html/guide/topics/search/searchable-config.jd
@@ -7,19 +7,20 @@
<div id="qv">
<h2>See also</h2>
<ol>
- <li><a href="search-dialog.html">Using the Android Search Dialog</a></li>
+ <li><a href="search-dialog.html">Creating a Search Interface</a></li>
<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
</ol>
</div>
</div>
-<p>To utilize the Android search framework and provide a custom search dialog, your
-application must provide a search
-configuration in the form of an XML resource. This document describes the search configuration XML
-in terms of its syntax and usage. For more information about how to implement search
-features for your application, see the developer guide about <a
-href="index.html">Search</a>.</p>
+<p>In order to implement search with assistance from the Android system (to deliver search queries
+to an activity and provide search suggestions), your application must provide a search configuration
+in the form of an XML file.</p>
+
+<p>This page describes the search configuration file in terms of its syntax and usage. For more
+information about how to implement search features for your application, begin with the developer
+guide about <a href="search-dialog.html">Creating a Search Interface</a>.</p>
<dl class="xml">
@@ -66,7 +67,7 @@
<dd>
<dl class="tag-list">
<dt id="searchable-element"><code><searchable></code></dt>
- <dd>Defines all search configurations used with the search dialog.
+ <dd>Defines all search configurations used by the Android system to provide assisted search.
<p class="caps">attributes:</p>
<dl class="atn-list">
<dt><code>android:label</code></dt>
@@ -86,21 +87,21 @@
"Search songs and artists" or "Search YouTube".</dd>
<dt><code>android:searchMode</code></dt>
- <dd><em>Keyword</em>. Sets additional modes that control the search dialog presentation.
-Currently available modes define how the query text that appears in the search dialog
-should be rewritten when a custom suggestion receives focus. The following mode values are accepted:
+ <dd><em>Keyword</em>. Sets additional modes that control the search presentation.
+Currently available modes define how the query text should be rewritten when a custom suggestion
+receives focus. The following mode values are accepted:
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr>
<td><code>"queryRewriteFromText"</code></td>
<td>Use the value from the {@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}
-colum to rewrite the query text in the search dialog.</td>
+column to rewrite the query text.</td>
</tr>
<tr>
<td><code>"queryRewriteFromData"</code></td>
<td>Use the value from the
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column to rewrite the
-query text in the search dialog. This should only be used when the values in
+query text. This should only be used when the values in
{@link android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} are suitable for user
inspection and editing, typically HTTP URI's.</td>
</tr>
@@ -117,7 +118,7 @@
<dt><code>android:inputType</code></dt>
<dd><em>Keyword</em>. Defines the type of input method (such as the type of soft keyboard)
-to use with the search dialog. For most searches, in which free-form text is expected, you don't
+to use. For most searches, in which free-form text is expected, you don't
need this attribute. See {@link android.R.attr#inputType} for a list of suitable values for this
attribute.</dd>
@@ -161,14 +162,14 @@
selectionArgs} parameter (and then ignore the {@code selection} parameter).</dd>
<dt><code>android:searchSuggestIntentAction</code></dt>
- <dd><em>String</em>. The default Intent action to be used when a user
+ <dd><em>String</em>. The default intent action to be used when a user
clicks on a custom search suggestion (such as {@code "android.intent.action.VIEW"}).
If this is not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_ACTION} column), this value is placed in the action
field of the {@link android.content.Intent} when the user clicks a suggestion.</dd>
<dt><code>android:searchSuggestIntentData</code></dt>
- <dd><em>String</em>. The default Intent data to be used when a user
+ <dd><em>String</em>. The default intent data to be used when a user
clicks on a custom search suggestion.
If not overridden by the selected suggestion (via the {@link
android.app.SearchManager#SUGGEST_COLUMN_INTENT_DATA} column), this value is
@@ -177,7 +178,7 @@
<dt><code>android:searchSuggestThreshold</code></dt>
<dd><em>Integer</em>. The minimum number of characters needed to
- trigger a suggestion look-up. Only guarantees that the Search Manager will not query your
+ trigger a suggestion look-up. Only guarantees that the system will not query your
content provider for anything shorter than the threshold. The default value is 0.</dd>
</dl>
@@ -210,20 +211,21 @@
supersets of queries that have returned zero results in the past. For example, if
your content provider returned zero results for "bo", it should be requiried for "bob". If set to
"false", supersets are ignored for a single session ("bob" does not invoke a requery). This lasts
-only for the life of the search dialog (when the search dialog is reopened, "bo" queries your
+only for the life of the search dialog or the life of the activity when using the search widget
+(when the search dialog or activity is reopened, "bo" queries your
content provider again). The default value is false.</dd>
</dl>
<h4>Voice search attributes</h4>
- <p>To enable voice search for your search dialog, you'll need some of the
+ <p>To enable voice search, you'll need some of the
following {@code <searchable>} attributes:</p><br/>
<dl class="atn-list">
<dt><code>android:voiceSearchMode</code></dt>
<dd><em>Keyword</em>. (Required to provide voice search capabilities.)
- Enables voice search for the search dialog, with a specific mode for voice search.
+ Enables voice search, with a specific mode for voice search.
(Voice search may not be provided by the device, in which case these flags
have no effect.) The following mode values are accepted:
<table>
@@ -238,14 +240,14 @@
<td><code>"launchWebSearch"</code></td>
<td>The voice search button takes the user directly
to a built-in voice web search activity. Most applications don't need this flag, as
- it takes the user away from the Activity in which search was invoked.</td>
+ it takes the user away from the activity in which search was invoked.</td>
</tr>
<tr>
<td><code>"launchRecognizer"</code></td>
<td>The voice search button takes
- the user directly to a built-in voice recording activity. This Activity
+ the user directly to a built-in voice recording activity. This activity
prompts the user to speak, transcribes the spoken text, and forwards the resulting
- query text to the searchable Activity, just as if the user typed it into the
+ query text to the searchable activity, just as if the user typed it into the
search UI and clicked the search button.</td>
</tr>
</table>
@@ -283,9 +285,9 @@
<dt><code>android:voiceMaxResults</code></dt>
<dd><em>Integer</em>. Forces the maximum number of results to return,
including the "best" result which is always provided as the {@link
-android.content.Intent#ACTION_SEARCH} Intent's primary
+android.content.Intent#ACTION_SEARCH} intent's primary
query. Must be 1 or greater. Use {@link android.speech.RecognizerIntent#EXTRA_RESULTS} to
-get the results from the Intent.
+get the results from the intent.
If not provided, the recognizer chooses how many results to return.</dd>
</dl>
</dd> <!-- end searchable element -->
@@ -311,8 +313,8 @@
<dd><em>String</em>. (Required.) A key code from {@link
android.view.KeyEvent} that represents the action key
you wish to respond to (for example {@code "KEYCODE_CALL"}). This is added to the
- {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is passed to your
- searchable Activity. To examine the key code, use
+ {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that is passed to your
+ searchable activity. To examine the key code, use
{@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}. Not all
keys are supported for a search action, as many of them are used for typing, navigation, or system
functions.</dd>
@@ -320,15 +322,15 @@
<dt><code>android:queryActionMsg</code></dt>
<dd><em>String</em>. An action message to be sent if the action key is pressed while the
user is entering query text. This is added to the
- {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that the Search Manager
- passes to your searchable Activity. To examine the string, use
+ {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} intent that the system
+ passes to your searchable activity. To examine the string, use
{@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}.</dd>
<dt><code>android:suggestActionMsg</code></dt>
<dd><em>String</em>. An action message to be sent if the action key is pressed while a
suggestion is in focus. This is added to the
- Intent that that the Search Manager passes to your searchable Activity (using the action
+ intent that that the system passes to your searchable activity (using the action
you've defined for the suggestion). To examine the string,
use {@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your
@@ -344,10 +346,10 @@
your content provider provides its own action message.
<p>First, you must define a column in your
content provider for each suggestion to provide an action message, then provide the name of that
-column in this attribute. The Search Manager looks at your suggestion cursor,
+column in this attribute. The system looks at your suggestion cursor,
using the string provided here to select your action message column, and
then select the action message string from the Cursor. That string is added to the
- Intent that the Search Manager passes to your searchable Activity (using the action you've
+ intent that the system passes to your searchable activity (using the action you've
defined for suggestions). To examine the string, use {@link
android.content.Intent#getStringExtra getStringExtra(SearchManager.ACTION_MSG)}. If the data
does not exist for the selected suggestion, the action key is ignored.</dd>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 065f95a..d8898ae3e 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -323,8 +323,7 @@
<p>When adding an action view for a menu item, it's important that you still allow the item to
behave as a normal menu item when it does not appear in the Action Bar. For example, a menu item to
-perform a search should, by default, bring up the <a
-href="{@docRoot}guide/topics/search/search-dialog.html">search dialog</a>, but if the item is
+perform a search should, by default, bring up the Android search dialog, but if the item is
placed in the Action Bar, the action view appears with a {@link android.widget.SearchView}
widget. Figure 4 shows an example of the {@link android.widget.SearchView} widget in an action
view.</p>
@@ -369,9 +368,7 @@
<p>Now, when the menu item is displayed as an action item, it's action view appears instead of
the icon and/or title text. However, if there's not enough room in the Action Bar, the item appears
in the overflow menu as a normal menu item and you must respond to it from the {@link
-android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method. (For a
-guide to providing search functionality, see the <a
-href="{@docRoot}guide/topics/search/index.html">Search</a> documentation.)</p>
+android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method.</p>
<p>When the activity first starts, the system populates the Action Bar and overflow menu by calling
{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}.
@@ -392,8 +389,8 @@
}
</pre>
-<p>For more information about enabling search in the Action Bar, see the <a
-href="{@docRoot}guide/topics/search/index.html">Search</a> developer guide.</p>
+<p>For more information about using the search widget, see <a
+href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.</p>
diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd
index b3c76871..ae078b9 100644
--- a/docs/html/guide/topics/wireless/bluetooth.jd
+++ b/docs/html/guide/topics/wireless/bluetooth.jd
@@ -554,7 +554,7 @@
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
- tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
+ tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
@@ -690,7 +690,7 @@
public void run() {
// Cancel discovery because it will slow down the connection
- mAdapter.cancelDiscovery();
+ mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
diff --git a/docs/html/images/avd-manager.png b/docs/html/images/avd-manager.png
index 69ce972..c33d8a8 100644
--- a/docs/html/images/avd-manager.png
+++ b/docs/html/images/avd-manager.png
Binary files differ
diff --git a/docs/html/images/billing_package.png b/docs/html/images/billing_package.png
old mode 100755
new mode 100644
index ec04c2d..951e117
--- a/docs/html/images/billing_package.png
+++ b/docs/html/images/billing_package.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-isLib.png b/docs/html/images/developing/adt-props-isLib.png
index 18bdb33..49c9111 100644
--- a/docs/html/images/developing/adt-props-isLib.png
+++ b/docs/html/images/developing/adt-props-isLib.png
Binary files differ
diff --git a/docs/html/images/developing/adt-props-libRef.png b/docs/html/images/developing/adt-props-libRef.png
index e61df51..73bccbd 100644
--- a/docs/html/images/developing/adt-props-libRef.png
+++ b/docs/html/images/developing/adt-props-libRef.png
Binary files differ
diff --git a/docs/html/images/developing/intellijidea_android_ide.png b/docs/html/images/developing/intellijidea_android_ide.png
new file mode 100644
index 0000000..b73a4e9
--- /dev/null
+++ b/docs/html/images/developing/intellijidea_android_ide.png
Binary files differ
diff --git a/docs/html/images/licensing_add_library.png b/docs/html/images/licensing_add_library.png
index 90b4435..3bbe6d5 100644
--- a/docs/html/images/licensing_add_library.png
+++ b/docs/html/images/licensing_add_library.png
Binary files differ
diff --git a/docs/html/images/licensing_gapis_8.png b/docs/html/images/licensing_gapis_8.png
index 43ad262..480d989 100644
--- a/docs/html/images/licensing_gapis_8.png
+++ b/docs/html/images/licensing_gapis_8.png
Binary files differ
diff --git a/docs/html/images/licensing_package.png b/docs/html/images/licensing_package.png
index 5da5632..eb2c5cf 100644
--- a/docs/html/images/licensing_package.png
+++ b/docs/html/images/licensing_package.png
Binary files differ
diff --git a/docs/html/resources/faq/commontasks.jd b/docs/html/resources/faq/commontasks.jd
index a5f5177..b211db0 100644
--- a/docs/html/resources/faq/commontasks.jd
+++ b/docs/html/resources/faq/commontasks.jd
@@ -223,7 +223,7 @@
// Listen for results.
protected void onActivityResult(int requestCode, int resultCode, Intent data){
// See which child activity is calling us back.
- switch (resultCode) {
+ switch (requestCode) {
case CHOOSE_FIGHTER:
// This is the standard resultCode that is sent back if the
// activity crashed or didn't doesn't supply an explicit result.
@@ -257,7 +257,7 @@
stats.putString("height","6\'2\"");
stats.putString("weight", "190 lbs");
stats.putString("reach", "73\"");
- setResult(RESULT_OK, "Washington", Bundle);
+ setResult(RESULT_OK, "Washington", stats);
finish();
}
};
@@ -289,7 +289,12 @@
will have a title bar visible to the user until <code>onCreate</code> runs.</p>
<p>(Note that this can be applied to either the <code><application></code>
tag or to individual <code><activity></code> tags.)</p>
-<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated environment</h2>
+<p class="caution"><strong>Caution:</strong> This theme will also hide the Action Bar on Android
+3.0 and higher. If you want to keep the Action Bar, but hide the title bar, see how you can <a
+href="{@docRoot}guide/topics/ui/themes.html#SelectATheme">select a theme based on platform
+version</a>.</p>
+<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated
+environment</h2>
<p>
If you need to refer to your host computer's <em>localhost</em>, such as when you
want the emulator client to contact a server running on the same host, use the alias
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 020c738..b11770f 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -433,7 +433,7 @@
</pre>
</li>
-<li>Now open and modify your <code>HelloAndroid</code> class use the
+<li>Now open and modify your <code>HelloAndroid</code> class and use the
XML layout. Edit the file to look like this:
<pre>
package com.example.helloandroid;
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 6c087bb..f88c3a6 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -556,11 +556,10 @@
menu.</p></li>
<li>{@link android.widget.SearchView}
- <p>Provides a search box that works in conjunction with the Search Manager (in the same manner
-as the traditional <a href="{@docRoot}guide/topics/search/search-dialog.html">search dialog</a>). It
-can also display recent query suggestions or custom suggestions as configured by the search
-provider. This widget is particularly useful for offering search in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>.</p></li>
+ <p>Provides a search box that you can configure to deliver search queries to a specified
+activity and display search suggestions (in the same manner as the traditional search dialog). This
+widget is particularly useful for offering a search widget in the Action Bar. For more information,
+see <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</p>.</li>
<li>{@link android.widget.StackView}
<p>A view that displays its children in a 3D stack and allows users to swipe through
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 3a7b39f..ece9d4a 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -1,8 +1,8 @@
page.title=ADT Plugin for Eclipse
-adt.zip.version=10.0.0
-adt.zip.download=ADT-10.0.0.zip
-adt.zip.bytes=4243777
-adt.zip.checksum=bf88bff62bc45c3b6d062e2beed67765
+adt.zip.version=10.0.1
+adt.zip.download=ADT-10.0.1.zip
+adt.zip.bytes=5096182
+adt.zip.checksum=e26a77db08377bdd2e62edeb9a3e3701
@jd:body
@@ -33,7 +33,7 @@
<p>ADT extends the capabilities of Eclipse to let you quickly set up new Android
projects, create an application UI, add components based on the Android
Framework API, debug your applications using the Android SDK tools, and even
-export signed (or unsigned) APKs in order to distribute your application.</p>
+export signed (or unsigned) {@code .apk} files in order to distribute your application.</p>
<p>Developing in Eclipse with ADT is highly recommended and is the fastest way
to get started. With the guided project setup it provides, as well as tools
@@ -100,6 +100,36 @@
<a href="#" onclick="return toggleDiv(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
width="9px" />
+ADT 10.0.1</a> <em>(March 2011)</em>
+ <div class="toggleme">
+
+<dl>
+
+<dt>Dependencies:</dt>
+
+<dd>ADT 10.0.1 is designed for use with SDK Tools r10. If you haven't
+already installed SDK Tools r10 into your SDK, use the Android SDK and AVD Manager to do
+so.</dd>
+
+<dt>General notes:</dt>
+<dd>
+ <ul>
+ <li>Temporary work-around to resolve the rare cases in which the layout editor will
+not open.</li>
+ <li>Fix issue in which ADT 10.0.0 would install on Eclipse 3.4 and lower, even though ADT
+requires Eclipse 3.5 or higher (as of 10.0.0).</li>
+ </ul>
+</dd>
+</dl>
+</div>
+</div>
+
+
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
+width="9px" />
ADT 10.0.0</a> <em>(February 2011)</em>
<div class="toggleme">
@@ -594,13 +624,14 @@
<p>ADT is a plugin for the Eclipse IDE. Before you can install or use ADT,
you must have a compatible version of Eclipse installed on your development
-computer. </p>
+computer. Check the <a
+href="requirements.html">System Requirements</a> document for
+a list of Eclipse versions that are compatible with the Android SDK.</li></p>
<ul>
<li>If Eclipse is already installed on your computer, make sure that it is
-a version that is compatible with ADT and the Android SDK. Check the <a
-href="requirements.html">System Requirements</a> document for
-a list of Eclipse versions that are compatible with the Android SDK.</li>
+a version that is compatible with ADT and the Android SDK.
+
<li>If you need to install or update Eclipse, you can download it from this
location:
@@ -608,7 +639,7 @@
"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>
</p>
-<p>For Eclipse 3.5 or newer, the "Eclipse Classic" version is recommended. Otherwise, a Java or RCP
+<p>The "Eclipse Classic" version is recommended. Otherwise, a Java or RCP
version of Eclipse is recommended.</p></li>
</ul>
@@ -624,19 +655,15 @@
<h3 id="downloading">Downloading the ADT Plugin</h3>
-<p>Use Update Manager feature of your Eclipse installation to install the latest
+<p>Use the Update Manager feature of your Eclipse installation to install the latest
revision of ADT on your development computer.<p>
<p>Assuming that you have a compatible version of the Eclipse IDE installed, as
described in <a href="#preparing">Preparing for Installation</a>, above, follow
these steps to download the ADT plugin and install it in your Eclipse
-environment. </p>
+environment.</p>
-<table style="font-size:100%">
-<tr><th>Eclipse 3.5 (Galileo) and 3.6 (Helios)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td width="45%">
-<!-- 3.5+ steps -->
+
<ol>
<li>Start Eclipse, then select <strong>Help</strong> > <strong>Install New
Software...</strong>.</li>
@@ -655,35 +682,6 @@
<li>When the installation completes, restart Eclipse. </li>
</ol>
-</td>
-<td width="50%">
-
-<!-- 3.4 steps -->
-<ol>
- <li>Start Eclipse, then select <strong>Help</strong> > <strong>Software Updates...</strong>.
-In the dialog that appears, click the <strong>Available Software</strong> tab.</li>
- <li>Click <strong>Add Site</strong>.</li>
- <li>In the Add Site dialog that appears, enter this URL in the "Location" field:
- <pre>https://dl-ssl.google.com/android/eclipse/</pre>
- <p>Note: If you have trouble acquiring the plugin, you can try
- using "http" in the URL, instead of "https" (https is preferred for
- security reasons).</p>
- <p>Click <strong>OK</strong>.</p>
- </li>
- <li>Back in the Available Software view, you should see the plugin listed by the URL,
- with "Developer Tools" nested within it. Select the checkbox next to Developer Tools,
- which will automatically select the nested tools. Then click
- <strong>Install</strong></li>
- <li>On the subsequent Install window, all of the included tools
- should be checked. Click <strong>Next</strong>. </li>
- <li>Read and accept the license agreements, then click <strong>Finish</strong>.</li>
- <li>When the installation completes, restart Eclipse. </li>
-
-</ol>
-</td>
-</tr>
-</table>
-
<h3 id="configuring">Configuring the ADT Plugin</h3>
<p>Once you've successfully downloaded ADT as described above, the next step
@@ -807,11 +805,6 @@
<p>Follow the steps below to check whether an update is available and, if so,
to install it. </p>
-<table style="font-size:100%">
-<tr><th>Eclipse 3.5 (Galileo) and 3.6 (Helios)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td>
-<!-- 3.5+ steps -->
<ol>
<li>Select <strong>Help</strong> > <strong>Check for Updates</strong>.
<p>If there are no updates available, a dialog will say so and you're done.</p></li>
@@ -823,25 +816,6 @@
Android Development Tools.</li>
<li>Restart Eclipse.</li>
</ol>
-</td>
-
-<td width="50%">
-<!-- 3.4 steps -->
-<ol>
- <li>Select <strong>Help</strong> > <strong>Software Updates</strong>.</li>
- <li>Select the <strong>Available Software</strong> tab.</li>
- <li>If there are updates available, select Android DDMS, Android Development Tools,
- and Android Hierarchy Viewer, then click <strong>Update</strong>.</li>
- <li>In the resulting Available Updates dialog, ensure that each of the listed tools
- are selected, then click <strong>Next</strong>.</li>
- <li>Read and accept the license agreement and then click <strong>Finish</strong>.
- This will download and install the latest version of Android DDMS and
- Android Development Tools.</li>
- <li>Restart Eclipse.</li>
-</ol>
-</td>
-</tr>
-</table>
<p>If you encounter problems during the update, remove the existing ADT plugin from Eclipse, then
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index b0fd761..a1080c2 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -96,13 +96,14 @@
<p>If you will be developing in Eclipse with the Android Development
Tools (ADT) Plugin—the recommended path if you are new to
Android—make sure that you have a suitable version of Eclipse
-installed on your computer (3.4 or newer is recommended). If you need
-to install Eclipse, you can download it from this location: </p>
+installed on your computer as described in the
+<a href="requirements.html">System Requirements</a> document.
+If you need to install Eclipse, you can download it from this location: </p>
<p style="margin-left:2em;"><a href=
"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p>
-<p>For Eclipse 3.5 or newer, the "Eclipse Classic" version is recommended. Otherwise, a Java or
+<p>The "Eclipse Classic" version is recommended. Otherwise, a Java or
RCP version of Eclipse is recommended.</p>
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index 3d62dd9..f12d0aa 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -24,7 +24,9 @@
<h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
<ul>
- <li>Eclipse 3.4 (Ganymede) or greater</li>
+ <li>Eclipse 3.5 (Galileo) or greater
+<p class="note"><strong>Note:</strong> Eclipse 3.4 (Ganymede) is no longer
+supported with the latest version of ADT.</p></li>
<li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
in most Eclipse IDE packages) </li>
<li>If you need to install or update Eclipse, you can download it from <a
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index a1c26db..6b9a5ce 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -129,7 +129,7 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.0
+ <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 10.0.1
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
<span style="display:none" class="fr"></span>
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index ddbd220..696e305 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -596,7 +596,7 @@
handle->decryptInfo->decryptBufferLength = reply.readInt32();
}
} else {
- LOGE("no decryptHandle is generated in service side");
+ LOGV("no decryptHandle is generated in service side");
}
return handle;
}
@@ -1308,7 +1308,7 @@
delete handle->decryptInfo; handle->decryptInfo = NULL;
}
} else {
- LOGE("NULL decryptHandle is returned");
+ LOGV("NULL decryptHandle is returned");
}
delete handle; handle = NULL;
return DRM_NO_ERROR;
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index ec400b7..1eee5f2 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -51,6 +51,7 @@
}
int DrmManager::addUniqueId(int uniqueId) {
+ Mutex::Autolock _l(mLock);
if (0 == uniqueId) {
int temp = 0;
bool foundUniqueId = false;
@@ -78,6 +79,7 @@
}
void DrmManager::removeUniqueId(int uniqueId) {
+ Mutex::Autolock _l(mLock);
for (unsigned int i = 0; i < mUniqueIdVector.size(); i++) {
if (uniqueId == mUniqueIdVector.itemAt(i)) {
mUniqueIdVector.removeAt(i);
@@ -107,6 +109,7 @@
}
status_t DrmManager::unloadPlugIns() {
+ Mutex::Autolock _l(mLock);
mConvertSessionMap.clear();
mDecryptSessionMap.clear();
mPlugInManager.unloadPlugIns();
@@ -116,7 +119,7 @@
status_t DrmManager::setDrmServiceListener(
int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mListenerLock);
if (NULL != drmServiceListener.get()) {
mServiceListeners.add(uniqueId, drmServiceListener);
} else {
@@ -126,6 +129,7 @@
}
void DrmManager::addClient(int uniqueId) {
+ Mutex::Autolock _l(mLock);
if (!mSupportInfoToPlugInIdMap.isEmpty()) {
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
for (unsigned int index = 0; index < plugInIdList.size(); index++) {
@@ -137,6 +141,7 @@
}
void DrmManager::removeClient(int uniqueId) {
+ Mutex::Autolock _l(mLock);
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
for (unsigned int index = 0; index < plugInIdList.size(); index++) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
@@ -145,6 +150,7 @@
}
DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -154,6 +160,7 @@
}
DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -163,6 +170,7 @@
}
status_t DrmManager::installDrmEngine(int uniqueId, const String8& absolutePath) {
+ Mutex::Autolock _l(mLock);
mPlugInManager.loadPlugIn(absolutePath);
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(absolutePath);
@@ -176,6 +184,7 @@
}
bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInId(mimeType);
bool result = (EMPTY_STRING != plugInId) ? true : false;
@@ -194,6 +203,7 @@
}
DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -218,6 +228,7 @@
}
DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -228,6 +239,7 @@
status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
const String8& rightsPath, const String8& contentPath) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
status_t result = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != plugInId) {
@@ -238,6 +250,7 @@
}
String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -247,6 +260,7 @@
}
int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -256,6 +270,7 @@
}
int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -267,6 +282,7 @@
status_t DrmManager::consumeRights(
int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
status_t result = DRM_ERROR_UNKNOWN;
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->consumeRights(uniqueId, decryptHandle, action, reserve);
@@ -277,6 +293,7 @@
status_t DrmManager::setPlaybackStatus(
int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
status_t result = DRM_ERROR_UNKNOWN;
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->setPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
@@ -286,6 +303,7 @@
bool DrmManager::validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
if (EMPTY_STRING != plugInId) {
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -295,6 +313,7 @@
}
status_t DrmManager::removeRights(int uniqueId, const String8& path) {
+ Mutex::Autolock _l(mLock);
const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
status_t result = DRM_ERROR_UNKNOWN;
if (EMPTY_STRING != plugInId) {
@@ -318,6 +337,7 @@
}
int DrmManager::openConvertSession(int uniqueId, const String8& mimeType) {
+ Mutex::Autolock _l(mConvertLock);
int convertId = -1;
const String8 plugInId = getSupportedPlugInId(mimeType);
@@ -325,7 +345,6 @@
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
if (DRM_NO_ERROR == rDrmEngine.openConvertSession(uniqueId, mConvertId + 1)) {
- Mutex::Autolock _l(mConvertLock);
++mConvertId;
convertId = mConvertId;
mConvertSessionMap.add(convertId, &rDrmEngine);
@@ -338,6 +357,7 @@
int uniqueId, int convertId, const DrmBuffer* inputData) {
DrmConvertedStatus *drmConvertedStatus = NULL;
+ Mutex::Autolock _l(mConvertLock);
if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mConvertSessionMap.valueFor(convertId);
drmConvertedStatus = drmEngine->convertData(uniqueId, convertId, inputData);
@@ -346,6 +366,7 @@
}
DrmConvertedStatus* DrmManager::closeConvertSession(int uniqueId, int convertId) {
+ Mutex::Autolock _l(mConvertLock);
DrmConvertedStatus *drmConvertedStatus = NULL;
if (mConvertSessionMap.indexOfKey(convertId) != NAME_NOT_FOUND) {
@@ -358,6 +379,7 @@
status_t DrmManager::getAllSupportInfo(
int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+ Mutex::Autolock _l(mLock);
Vector<String8> plugInPathList = mPlugInManager.getPlugInIdList();
int size = plugInPathList.size();
int validPlugins = 0;
@@ -437,7 +459,7 @@
}
if (DRM_NO_ERROR != result) {
delete handle; handle = NULL;
- LOGE("DrmManager::openDecryptSession: no capable plug-in found");
+ LOGV("DrmManager::openDecryptSession: no capable plug-in found");
}
return handle;
}
@@ -458,6 +480,7 @@
status_t DrmManager::initializeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
status_t result = DRM_ERROR_UNKNOWN;
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->initializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
@@ -468,6 +491,8 @@
status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
status_t result = DRM_ERROR_UNKNOWN;
+
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->decrypt(
@@ -479,6 +504,7 @@
status_t DrmManager::finalizeDecryptUnit(
int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
status_t result = DRM_ERROR_UNKNOWN;
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
@@ -490,6 +516,7 @@
void* buffer, ssize_t numBytes, off64_t offset) {
ssize_t result = DECRYPT_FILE_ERROR;
+ Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->pread(uniqueId, decryptHandle, buffer, numBytes, offset);
@@ -546,7 +573,7 @@
}
void DrmManager::onInfo(const DrmInfoEvent& event) {
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mListenerLock);
for (unsigned int index = 0; index < mServiceListeners.size(); index++) {
int uniqueId = mServiceListeners.keyAt(index);
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
index 20fd8aa..90adb47f 100644
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -53,6 +53,10 @@
* associated with all DRM schemes.
*/
public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
+ /**
+ * TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+ */
+ public static final int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
/**
* constructor to create DrmErrorEvent object with given parameters
diff --git a/drm/java/android/drm/DrmInfoEvent.java b/drm/java/android/drm/DrmInfoEvent.java
index a778e06..72f37ea 100644
--- a/drm/java/android/drm/DrmInfoEvent.java
+++ b/drm/java/android/drm/DrmInfoEvent.java
@@ -45,6 +45,10 @@
* already done for the given account.
*/
public static final int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+ /**
+ * TYPE_RIGHTS_REMOVED, when the rights has been removed.
+ */
+ public static final int TYPE_RIGHTS_REMOVED = 6;
/**
* constructor to create DrmInfoEvent object with given parameters
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 782ffdb..aa56159 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -181,7 +181,7 @@
}
public void handleMessage(Message msg) {
- DrmInfoEvent event = null;
+ DrmInfoEvent info = null;
DrmErrorEvent error = null;
switch (msg.what) {
@@ -197,11 +197,15 @@
} catch (IOException e) {
e.printStackTrace();
}
- event = new DrmInfoEvent(uniqueId, infoType, message);
+ info = new DrmInfoEvent(uniqueId, infoType, message);
break;
}
- case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT: {
- event = new DrmInfoEvent(uniqueId, infoType, message);
+ case DrmInfoEvent.TYPE_ALREADY_REGISTERED_BY_ANOTHER_ACCOUNT:
+ case DrmInfoEvent.TYPE_RIGHTS_INSTALLED:
+ case DrmInfoEvent.TYPE_WAIT_FOR_RIGHTS:
+ case DrmInfoEvent.TYPE_ACCOUNT_ALREADY_REGISTERED:
+ case DrmInfoEvent.TYPE_RIGHTS_REMOVED: {
+ info = new DrmInfoEvent(uniqueId, infoType, message);
break;
}
default:
@@ -209,8 +213,8 @@
break;
}
- if (null != mOnInfoListener && null != event) {
- mOnInfoListener.onInfo(DrmManagerClient.this, event);
+ if (null != mOnInfoListener && null != info) {
+ mOnInfoListener.onInfo(DrmManagerClient.this, info);
}
if (null != mOnErrorListener && null != error) {
mOnErrorListener.onError(DrmManagerClient.this, error);
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index 7b51822..1d1e258 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -78,7 +78,6 @@
}
status_t DrmManagerClient::consumeRights(DecryptHandle* decryptHandle, int action, bool reserve) {
- Mutex::Autolock _l(mDecryptLock);
return mDrmManagerClientImpl->consumeRights(mUniqueId, decryptHandle, action, reserve);
}
@@ -131,7 +130,6 @@
status_t DrmManagerClient::initializeDecryptUnit(
DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
- Mutex::Autolock _l(mDecryptLock);
return mDrmManagerClientImpl->initializeDecryptUnit(
mUniqueId, decryptHandle, decryptUnitId, headerInfo);
}
@@ -139,19 +137,16 @@
status_t DrmManagerClient::decrypt(
DecryptHandle* decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
- Mutex::Autolock _l(mDecryptLock);
return mDrmManagerClientImpl->decrypt(
mUniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
status_t DrmManagerClient::finalizeDecryptUnit(DecryptHandle* decryptHandle, int decryptUnitId) {
- Mutex::Autolock _l(mDecryptLock);
return mDrmManagerClientImpl->finalizeDecryptUnit(mUniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmManagerClient::pread(
DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
- Mutex::Autolock _l(mDecryptLock);
return mDrmManagerClientImpl->pread(mUniqueId, decryptHandle, buffer, numBytes, offset);
}
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h
index e05366d..c7276f9 100644
--- a/drm/libdrmframework/include/DrmManager.h
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -147,6 +147,7 @@
int mDecryptSessionId;
int mConvertId;
Mutex mLock;
+ Mutex mListenerLock;
Mutex mDecryptLock;
Mutex mConvertLock;
TPlugInManager<IDrmEngine> mPlugInManager;
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h
new file mode 100644
index 0000000..8e6fc6e
--- /dev/null
+++ b/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef _ANDROID_GRAPHICS_SURFACETEXTURE_H
+#define _ANDROID_GRAPHICS_SURFACETEXTURE_H
+
+#include <android/native_window.h>
+
+#include "jni.h"
+
+namespace android {
+
+extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
+ JNIEnv* env, jobject thiz);
+
+} // namespace android
+
+#endif // _ANDROID_GRAPHICS_SURFACETEXTURE_H
diff --git a/include/drm/DrmInfoEvent.h b/include/drm/DrmInfoEvent.h
index 7b409ff..add33d3 100644
--- a/include/drm/DrmInfoEvent.h
+++ b/include/drm/DrmInfoEvent.h
@@ -43,6 +43,8 @@
//! TYPE_ACCOUNT_ALREADY_REGISTERED, when registration has been
//! already done for the given account.
static const int TYPE_ACCOUNT_ALREADY_REGISTERED = 5;
+ //! TYPE_RIGHTS_REMOVED, when the rights has been removed.
+ static const int TYPE_RIGHTS_REMOVED = 6;
/**
* The following constant values should be in sync with DrmErrorEvent.java
@@ -61,6 +63,11 @@
static const int TYPE_NO_INTERNET_CONNECTION = 2005;
//! TYPE_PROCESS_DRM_INFO_FAILED, when failed to process DrmInfo.
static const int TYPE_PROCESS_DRM_INFO_FAILED = 2006;
+ //! TYPE_REMOVE_ALL_RIGHTS_FAILED, when failed to remove all the rights objects
+ //! associated with all DRM schemes.
+ static const int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
+ //! TYPE_ACQUIRE_DRM_INFO_FAILED, when failed to acquire DrmInfo.
+ static const int TYPE_ACQUIRE_DRM_INFO_FAILED = 2008;
public:
/**
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index 085ebf1..12142bc 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -365,7 +365,6 @@
private:
int mUniqueId;
- Mutex mDecryptLock;
DrmManagerClientImpl* mDrmManagerClientImpl;
};
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 5f7cd90..293764d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -346,12 +346,14 @@
};
bool processAudioBuffer(const sp<ClientRecordThread>& thread);
- status_t openRecord(uint32_t sampleRate,
+ status_t openRecord_l(uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags,
audio_io_handle_t input);
+ audio_io_handle_t getInput_l();
+ status_t restoreRecord_l(audio_track_cblk_t*& cblk);
sp<IAudioRecord> mAudioRecord;
sp<IMemory> mCblkMemory;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 813a905..3e346db 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -437,7 +437,7 @@
};
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
- status_t createTrack(int streamType,
+ status_t createTrack_l(int streamType,
uint32_t sampleRate,
int format,
int channelCount,
@@ -446,6 +446,10 @@
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
bool enforceFrameCount);
+ void flush_l();
+ status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+ audio_io_handle_t getOutput_l();
+ status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart);
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index f7d837a..93b5d24 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -50,6 +50,9 @@
// Only submit one input buffer at one time.
kOnlySubmitOneInputBufferAtOneTime = 64,
+
+ // Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
+ kEnableGrallocUsageProtected = 128,
};
static sp<MediaSource> Create(
const sp<IOMX> &omx,
@@ -197,6 +200,7 @@
bool mIsMetaDataStoredInVideoBuffers;
bool mOnlySubmitOneBufferAtOneTime;
+ bool mEnableGrallocUsageProtected;
OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
bool isEncoder, const char *mime, const char *componentName,
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index c6990bf..4610135 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -31,6 +31,7 @@
#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
#define MAX_RUN_TIMEOUT_MS 1000
#define WAIT_PERIOD_MS 10
+#define RESTORE_TIMEOUT_MS 5000 // Maximum waiting time for a track to be restored
#define CBLK_UNDERRUN_MSK 0x0001
#define CBLK_UNDERRUN_ON 0x0001 // underrun (out) or overrrun (in) indication
@@ -47,6 +48,12 @@
#define CBLK_DISABLED_MSK 0x0010
#define CBLK_DISABLED_ON 0x0010 // track disabled by AudioFlinger due to underrun:
#define CBLK_DISABLED_OFF 0x0000 // must be re-started
+#define CBLK_RESTORING_MSK 0x0020
+#define CBLK_RESTORING_ON 0x0020 // track is being restored after invalidation
+#define CBLK_RESTORING_OFF 0x0000 // by AudioFlinger
+#define CBLK_RESTORED_MSK 0x0040
+#define CBLK_RESTORED_ON 0x0040 // track has been restored after invalidation
+#define CBLK_RESTORED_OFF 0x0040 // by AudioFlinger
struct audio_track_cblk_t
{
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 361e7dc..dea1b10 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -138,6 +138,10 @@
* This is an ASYNCHRONOUS call.
*/
virtual void signal() const = 0;
+
+ /* verify that an ISurface was created by SurfaceFlinger.
+ */
+ virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
};
// ----------------------------------------------------------------------------
@@ -161,7 +165,8 @@
SIGNAL,
CAPTURE_SCREEN,
TURN_ELECTRON_BEAM_OFF,
- TURN_ELECTRON_BEAM_ON
+ TURN_ELECTRON_BEAM_ON,
+ AUTHENTICATE_SURFACE,
};
virtual status_t onTransact( uint32_t code,
diff --git a/include/ui/Input.h b/include/ui/Input.h
index e92d7f5..d9d77c4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -144,6 +144,14 @@
};
/*
+ * Button state.
+ */
+enum {
+ // Primary button pressed (left mouse button).
+ BUTTON_STATE_PRIMARY = 1 << 0,
+};
+
+/*
* Describes the basic configuration of input devices that are present.
*/
struct InputConfiguration {
@@ -544,6 +552,8 @@
~InputDeviceInfo();
struct MotionRange {
+ int32_t axis;
+ uint32_t source;
float min;
float max;
float flat;
@@ -556,16 +566,17 @@
inline const String8 getName() const { return mName; }
inline uint32_t getSources() const { return mSources; }
- const MotionRange* getMotionRange(int32_t axis) const;
+ const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
void addSource(uint32_t source);
- void addMotionRange(int32_t axis, float min, float max, float flat, float fuzz);
- void addMotionRange(int32_t axis, const MotionRange& range);
+ void addMotionRange(int32_t axis, uint32_t source,
+ float min, float max, float flat, float fuzz);
+ void addMotionRange(const MotionRange& range);
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
inline int32_t getKeyboardType() const { return mKeyboardType; }
- inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const {
+ inline const Vector<MotionRange>& getMotionRanges() const {
return mMotionRanges;
}
@@ -575,7 +586,7 @@
uint32_t mSources;
int32_t mKeyboardType;
- KeyedVector<int32_t, MotionRange> mMotionRanges;
+ Vector<MotionRange> mMotionRanges;
};
/*
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index fd83f46..0ac34d0 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -95,6 +95,21 @@
* 5. Queue, dequeue, queue, dequeue, ad infinitum
*/
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+
+ /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+ * to the window compositor. The query sets the returned 'value' argument
+ * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+ * compositor and 0 if the buffers do not go directly to the window
+ * compositor.
+ *
+ * This can be used to determine whether protected buffer content should be
+ * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
+ * indicate that queued buffers will be protected from applications or users
+ * capturing their contents. If that behavior is desired then some other
+ * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+ * conjunction with this query.
+ */
+ NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
};
/* valid operations for the (*perform)() hook */
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 43b330c..a40fac9 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -156,6 +156,10 @@
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
*value = MIN_UNDEQUEUED_BUFFERS;
return NO_ERROR;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ // SurfaceTextureClient currently never queues frames to SurfaceFlinger.
+ *value = 0;
+ return NO_ERROR;
}
return BAD_VALUE;
}
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
new file mode 100644
index 0000000..1dd8885
--- /dev/null
+++ b/libs/gui/tests/Android.mk
@@ -0,0 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+ SurfaceTextureClient_test.cpp \
+
+shared_libraries := \
+ libcutils \
+ libutils \
+ libbinder \
+ libgui \
+ libstlport \
+
+static_libraries := \
+ libgtest \
+ libgtest_main \
+
+c_includes := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
new file mode 100644
index 0000000..0f140ff
--- /dev/null
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include <gui/SurfaceTextureClient.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class SurfaceTextureClientTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mST = new SurfaceTexture(123);
+ mSTC = new SurfaceTextureClient(mST);
+ }
+
+ virtual void TearDown() {
+ mST.clear();
+ mSTC.clear();
+ }
+
+ sp<SurfaceTexture> mST;
+ sp<SurfaceTextureClient> mSTC;
+};
+
+TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
+ sp<ANativeWindow> anw(mSTC);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(0, result);
+}
+
+}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 4a5620d..f9e29f1 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -592,11 +592,11 @@
void Context::launchThreads(WorkerCallback_t cbk, void *data) {
mWorkers.mLaunchData = data;
mWorkers.mLaunchCallback = cbk;
- mWorkers.mRunningCount = (int)mWorkers.mCount;
+ android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount);
for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
mWorkers.mLaunchSignals[ct].set();
}
- while (mWorkers.mRunningCount) {
+ while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) {
mWorkers.mCompleteSignal.wait();
}
}
@@ -707,8 +707,8 @@
}
mWorkers.mCompleteSignal.init();
- mWorkers.mRunningCount = 0;
- mWorkers.mLaunchCount = 0;
+ android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount);
+ android_atomic_release_store(0, &mWorkers.mLaunchCount);
for (uint32_t ct=0; ct < mWorkers.mCount; ct++) {
status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this);
if (status) {
@@ -717,6 +717,9 @@
break;
}
}
+ while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) {
+ usleep(100);
+ }
pthread_attr_destroy(&threadAttr);
return true;
}
@@ -736,14 +739,14 @@
// Cleanup compute threads.
mWorkers.mLaunchData = NULL;
mWorkers.mLaunchCallback = NULL;
- mWorkers.mRunningCount = (int)mWorkers.mCount;
+ android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount);
for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
mWorkers.mLaunchSignals[ct].set();
}
for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) {
status = pthread_join(mWorkers.mThreadId[ct], &res);
}
- rsAssert(!mWorkers.mRunningCount);
+ rsAssert(android_atomic_acquire_load(&mWorkers.mRunningCount) == 0);
// Global structure cleanup.
pthread_mutex_lock(&gInitMutex);
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 01ae23f..8951c3f 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -25,9 +25,11 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
#include <ui/DisplayInfo.h>
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <utils/Log.h>
// ---------------------------------------------------------------------------
@@ -178,6 +180,40 @@
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual bool authenticateSurface(const sp<ISurface>& surface) const
+ {
+ Parcel data, reply;
+ int err = NO_ERROR;
+ err = data.writeInterfaceToken(
+ ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error writing "
+ "interface descriptor: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ err = data.writeStrongBinder(surface->asBinder());
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error writing strong "
+ "binder to parcel: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
+ &reply);
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error performing "
+ "transaction: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ int32_t result = 0;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error retrieving "
+ "result: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ return result != 0;
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -273,6 +309,12 @@
status_t res = turnElectronBeamOn(mode);
reply->writeInt32(res);
} break;
+ case AUTHENTICATE_SURFACE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ int32_t result = authenticateSurface(surface) ? 1 : 0;
+ reply->writeInt32(result);
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 818114a..afabbf4 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -712,6 +712,10 @@
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
*value = MIN_UNDEQUEUED_BUFFERS;
return NO_ERROR;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ *value = sf->authenticateSurface(mSurface) ? 1 : 0;
+ return NO_ERROR;
}
return BAD_VALUE;
}
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
index 5053e7d..212b8e7 100644
--- a/libs/surfaceflinger_client/tests/Android.mk
+++ b/libs/surfaceflinger_client/tests/Android.mk
@@ -1 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+ Surface_test.cpp \
+
+shared_libraries := \
+ libcutils \
+ libutils \
+ libbinder \
+ libsurfaceflinger_client \
+ libstlport \
+
+static_libraries := \
+ libgtest \
+ libgtest_main \
+
+c_includes := \
+ bionic \
+ bionic/libstdc++/include \
+ external/gtest/include \
+ external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+ $(eval include $(CLEAR_VARS)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+ $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+ $(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+ $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/surfaceflinger_client/tests/Surface_test.cpp
new file mode 100644
index 0000000..74ebf4e
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/Surface_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class SurfaceTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mSurfaceControl = mComposerClient->createSurface(getpid(),
+ String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);
+
+ ASSERT_TRUE(mSurfaceControl != NULL);
+ ASSERT_TRUE(mSurfaceControl->isValid());
+
+ ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+ ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+ mSurface = mSurfaceControl->getSurface();
+ ASSERT_TRUE(mSurface != NULL);
+ }
+
+ virtual void TearDown() {
+ mComposerClient->dispose();
+ }
+
+ sp<Surface> mSurface;
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+};
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(1, result);
+}
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
+ mSurfaceControl.clear();
+
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(1, result);
+}
+
+// This test probably doesn't belong here.
+TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
+ sp<ANativeWindow> anw(mSurface);
+
+ // Verify the screenshot works with no protected buffers.
+ sp<IMemoryHeap> heap;
+ uint32_t w=0, h=0;
+ PixelFormat fmt=0;
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+ 40000));
+ ASSERT_TRUE(heap != NULL);
+
+ // Set the PROTECTED usage bit and verify that the screenshot fails. Note
+ // that we need to dequeue a buffer in order for it to actually get
+ // allocated in SurfaceFlinger.
+ ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
+ GRALLOC_USAGE_PROTECTED));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+ android_native_buffer_t* buf = 0;
+ for (int i = 0; i < 4; i++) {
+ // Loop to make sure SurfaceFlinger has retired a protected buffer.
+ ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ }
+ heap = 0;
+ w = h = fmt = 0;
+ ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt,
+ 64, 64, 0, 40000));
+ ASSERT_TRUE(heap == NULL);
+
+ // XXX: This should not be needed, but it seems that the new buffers don't
+ // correctly show up after the upcoming dequeue/lock/queue loop without it.
+ // We should look into this at some point.
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+
+ // Un-set the PROTECTED usage bit and verify that the screenshot works
+ // again. Note that we have to change the buffers geometry to ensure that
+ // the buffers get reallocated, as the new usage bits are a subset of the
+ // old.
+ ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0));
+ for (int i = 0; i < 4; i++) {
+ // Loop to make sure SurfaceFlinger has retired a protected buffer.
+ ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ }
+ heap = 0;
+ w = h = fmt = 0;
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+ 40000));
+ ASSERT_TRUE(heap != NULL);
+}
+
+}
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0ed0866..e2e698e 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -657,23 +657,30 @@
mMotionRanges.clear();
}
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const {
- ssize_t index = mMotionRanges.indexOfKey(axis);
- return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
+ int32_t axis, uint32_t source) const {
+ size_t numRanges = mMotionRanges.size();
+ for (size_t i = 0; i < numRanges; i++) {
+ const MotionRange& range = mMotionRanges.itemAt(i);
+ if (range.axis == axis && range.source == source) {
+ return ⦥
+ }
+ }
+ return NULL;
}
void InputDeviceInfo::addSource(uint32_t source) {
mSources |= source;
}
-void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
float flat, float fuzz) {
- MotionRange range = { min, max, flat, fuzz };
- addMotionRange(axis, range);
+ MotionRange range = { axis, source, min, max, flat, fuzz };
+ mMotionRanges.add(range);
}
-void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) {
- mMotionRanges.add(axis, range);
+void InputDeviceInfo::addMotionRange(const MotionRange& range) {
+ mMotionRanges.add(range);
}
} // namespace android
diff --git a/libs/usb/Android.mk b/libs/usb/Android.mk
index b4e1fbf..129828f 100644
--- a/libs/usb/Android.mk
+++ b/libs/usb/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2008 The Android Open Source Project
+# Copyright (C) 2011 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.
diff --git a/libs/usb/src/com/android/future/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java
index cdd2b73..3d0707f 100644
--- a/libs/usb/src/com/android/future/usb/UsbAccessory.java
+++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java
@@ -23,14 +23,16 @@
private final String mManufacturer;
private final String mModel;
- private final String mType;
+ private final String mDescription;
private final String mVersion;
+ private final String mUri;
/* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer();
mModel = accessory.getModel();
- mType = accessory.getType();
+ mDescription = accessory.getDescription();
mVersion = accessory.getVersion();
+ mUri = accessory.getUri();
}
/**
@@ -52,12 +54,12 @@
}
/**
- * Returns the type of the accessory.
+ * Returns a user visible description of the accessory.
*
- * @return the accessory type
+ * @return the accessory description
*/
- public String getType() {
- return mType;
+ public String getDescription() {
+ return mDescription;
}
/**
@@ -69,6 +71,17 @@
return mVersion;
}
+ /**
+ * Returns the URI for the accessory.
+ * This is an optional URI that might show information about the accessory
+ * or provide the option to download an application for the accessory
+ *
+ * @return the accessory URI
+ */
+ public String getUri() {
+ return mUri;
+ }
+
private static boolean compare(String s1, String s2) {
if (s1 == null) return (s2 == null);
return s1.equals(s2);
@@ -80,17 +93,28 @@
UsbAccessory accessory = (UsbAccessory)obj;
return (compare(mManufacturer, accessory.getManufacturer()) &&
compare(mModel, accessory.getModel()) &&
- compare(mType, accessory.getType()) &&
- compare(mVersion, accessory.getVersion()));
+ compare(mDescription, accessory.getDescription()) &&
+ compare(mVersion, accessory.getVersion()) &&
+ compare(mUri, accessory.getUri()));
}
return false;
}
@Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mDescription == null ? 0 : mDescription.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()) ^
+ (mUri == null ? 0 : mUri.hashCode()));
+ }
+
+ @Override
public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel +
- ", mType=" + mType +
- ", mVersion=" + mVersion + "]";
+ ", mDescription=" + mDescription +
+ ", mVersion=" + mVersion +
+ ", mUri=" + mUri + "]";
}
}
diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
index f74b291..840e1e3 100644
--- a/libs/usb/src/com/android/future/usb/UsbManager.java
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -17,6 +17,7 @@
package com.android.future.usb;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.IUsbManager;
@@ -55,28 +56,39 @@
public static final String ACTION_USB_ACCESSORY_DETACHED =
"android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+ /**
+ * Name of extra added to the {@link android.app.PendingIntent}
+ * passed into {#requestPermission} or {#requestPermission}
+ * containing a boolean value indicating whether the user granted permission or not.
+ */
+ public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+ private final Context mContext;
private final IUsbManager mService;
- private UsbManager(IUsbManager service) {
+ private UsbManager(Context context, IUsbManager service) {
+ mContext = context;
mService = service;
}
/**
* Returns a new instance of this class.
*
+ * @param context the caller's {@link android.content.Context}
* @return UsbManager instance.
*/
- public static UsbManager getInstance() {
+ public static UsbManager getInstance(Context context) {
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
- return new UsbManager(IUsbManager.Stub.asInterface(b));
+ return new UsbManager(context, IUsbManager.Stub.asInterface(b));
}
/**
* Returns the {@link com.google.android.usb.UsbAccessory} for
* a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED}
- * broadcast Intent
+ * broadcast Intent. This can also be used to retrieve the accessory from the result
+ * of a call to {#requestPermission}.
*
- * @return UsbAccessory for the broadcast.
+ * @return UsbAccessory for the intent.
*/
public static UsbAccessory getAccessory(Intent intent) {
android.hardware.usb.UsbAccessory accessory =
@@ -118,10 +130,54 @@
try {
return mService.openAccessory(new android.hardware.usb.UsbAccessory(
accessory.getManufacturer(),accessory.getModel(),
- accessory.getType(), accessory.getVersion()));
+ accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in openAccessory" , e);
return null;
}
}
+
+ /**
+ * Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(android.hardware.usb.UsbAccessory} or
+ * by the user choosing the caller as the default application for the accessory.
+ *
+ * @param accessory to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbAccessory accessory) {
+ try {
+ return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
+ accessory.getManufacturer(),accessory.getModel(),
+ accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in hasPermission", e);
+ return false;
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the accessory.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the
+ * PendingIntent to indicate success or failure.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
+ * @param accessory to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+ try {
+ mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
+ accessory.getManufacturer(),accessory.getModel(),
+ accessory.getDescription(), accessory.getVersion(), accessory.getUri()),
+ mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in requestPermission", e);
+ }
+ }
}
diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk
index 98b6090..d555961 100644
--- a/libs/usb/tests/AccessoryChat/Android.mk
+++ b/libs/usb/tests/AccessoryChat/Android.mk
@@ -1,3 +1,19 @@
+#
+# Copyright (C) 2011 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.
+#
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
index 97e2ade..d6093ae 100644
--- a/libs/usb/tests/AccessoryChat/AndroidManifest.xml
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.accessorychat">
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
index 94cc0ce..3c0de69 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -133,10 +133,19 @@
} else {
printf("Found possible android device - attempting to switch to accessory mode\n");
+ uint16_t protocol;
+ ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
+ ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
+ if (ret == 2)
+ printf("device supports protocol version %d\n", protocol);
+ else
+ fprintf(stderr, "failed to read protocol version\n");
+
send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
- send_string(device, ACCESSORY_STRING_TYPE, "Sample Program");
+ send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program");
send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+ send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
ACCESSORY_START, 0, 0, 0, 0, 0);
diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
index 5cf02c7..f9a5bf4 100644
--- a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
+++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
@@ -17,9 +17,11 @@
package com.android.accessorychat;
import android.app.Activity;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -42,18 +44,47 @@
public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener {
private static final String TAG = "AccessoryChat";
- TextView mLog;
- EditText mEditText;
- ParcelFileDescriptor mFileDescriptor;
- FileInputStream mInputStream;
- FileOutputStream mOutputStream;
+
+ private static final String ACTION_USB_PERMISSION =
+ "com.android.accessorychat.action.USB_PERMISSION";
+
+ private TextView mLog;
+ private EditText mEditText;
+ private ParcelFileDescriptor mFileDescriptor;
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+ private UsbManager mUsbManager;
+ private PendingIntent mPermissionIntent;
+ private boolean mPermissionRequestPending;
private static final int MESSAGE_LOG = 1;
+ private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
+ synchronized (this) {
+ UsbAccessory accessory = UsbManager.getAccessory(intent);
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ openAccessory(accessory);
+ } else {
+ Log.d(TAG, "permission denied for accessory " + accessory);
+ }
+ mPermissionRequestPending = false;
+ }
+ }
+ }
+ };
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mUsbManager = UsbManager.getInstance(this);
+ mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+ IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+ registerReceiver(mUsbReceiver, filter);
+
setContentView(R.layout.accessory_chat);
mLog = (TextView)findViewById(R.id.log);
mEditText = (EditText)findViewById(R.id.message);
@@ -66,21 +97,20 @@
Intent intent = getIntent();
Log.d(TAG, "intent: " + intent);
- UsbManager manager = UsbManager.getInstance();
- UsbAccessory[] accessories = manager.getAccessoryList();
+ UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) {
- mFileDescriptor = manager.openAccessory(accessory);
- if (mFileDescriptor != null) {
- FileDescriptor fd = mFileDescriptor.getFileDescriptor();
- mInputStream = new FileInputStream(fd);
- mOutputStream = new FileOutputStream(fd);
- Thread thread = new Thread(null, this, "AccessoryChat");
- thread.start();
+ if (mUsbManager.hasPermission(accessory)) {
+ openAccessory(accessory);
} else {
- Log.d(TAG, "openAccessory fail");
+ synchronized (mUsbReceiver) {
+ if (!mPermissionRequestPending) {
+ mUsbManager.requestPermission(accessory, mPermissionIntent);
+ mPermissionRequestPending = true;
+ }
+ }
}
- } else {
+ } else {
Log.d(TAG, "mAccessory is null");
}
}
@@ -100,9 +130,24 @@
@Override
public void onDestroy() {
+ unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
+ private void openAccessory(UsbAccessory accessory) {
+ mFileDescriptor = mUsbManager.openAccessory(accessory);
+ if (mFileDescriptor != null) {
+ FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+ mInputStream = new FileInputStream(fd);
+ mOutputStream = new FileOutputStream(fd);
+ Thread thread = new Thread(null, this, "AccessoryChat");
+ thread.start();
+ Log.d(TAG, "openAccessory succeeded");
+ } else {
+ Log.d(TAG, "openAccessory fail");
+ }
+ }
+
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) {
try {
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5a73d2d..9d0cba3 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -110,6 +110,8 @@
private static final int MSG_PLAY_SOUND_EFFECT = 7;
private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
private static final int MSG_LOAD_SOUND_EFFECTS = 9;
+ private static final int MSG_SET_FORCE_USE = 10;
+
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -805,7 +807,7 @@
if (mode != mMode) {
// automatically handle audio focus for mode changes
- handleFocusForCalls(mMode, mode);
+ handleFocusForCalls(mMode, mode, cb);
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
mMode = mode;
@@ -864,7 +866,7 @@
}
/** pre-condition: oldMode != newMode */
- private void handleFocusForCalls(int oldMode, int newMode) {
+ private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) {
// if ringing
if (newMode == AudioSystem.MODE_RINGTONE) {
// if not ringing silently
@@ -872,8 +874,8 @@
if (ringVolume > 0) {
// request audio focus for the communication focus entry
requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
- null, null /* both allowed to be null only for this clientId */,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+ null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
}
@@ -884,8 +886,8 @@
// request audio focus for the communication focus entry
// (it's ok if focus was already requested during ringing)
requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
- null, null /* both allowed to be null only for this clientId */,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+ null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
}
// if exiting call
@@ -1170,22 +1172,15 @@
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return;
}
- if (on) {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
- mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
- } else {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
- mForcedUseForComm = AudioSystem.FORCE_NONE;
- }
+ mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
+
+ sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+ AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
}
/** @see AudioManager#isSpeakerphoneOn() */
public boolean isSpeakerphoneOn() {
- if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
- return true;
- } else {
- return false;
- }
+ return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
}
/** @see AudioManager#setBluetoothScoOn() */
@@ -1193,24 +1188,17 @@
if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
return;
}
- if (on) {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
- AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
- mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
- } else {
- AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
- AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE);
- mForcedUseForComm = AudioSystem.FORCE_NONE;
- }
+ mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
+
+ sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+ AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
+ sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE,
+ AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
}
/** @see AudioManager#isBluetoothScoOn() */
public boolean isBluetoothScoOn() {
- if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
- return true;
- } else {
- return false;
- }
+ return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
}
/** @see AudioManager#startBluetoothSco() */
@@ -1935,6 +1923,10 @@
}
}
+ private void setForceUse(int usage, int config) {
+ AudioSystem.setForceUse(usage, config);
+ }
+
@Override
public void handleMessage(Message msg) {
int baseMsgWhat = getMsgBase(msg.what);
@@ -2026,6 +2018,10 @@
// msg.obj == address of BTA2DP device
makeA2dpDeviceUnavailableNow( (String) msg.obj );
break;
+
+ case MSG_SET_FORCE_USE:
+ setForceUse(msg.arg1, msg.arg2);
+ break;
}
}
}
@@ -2547,10 +2543,9 @@
// the main stream type for the audio focus request is currently not used. It may
// potentially be used to handle multiple stream type-dependent audio focuses.
- // we need a valid binder callback for clients other than the AudioService's phone
- // state listener
- if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId) && ((cb == null) || !cb.pingBinder())) {
- Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting");
+ // we need a valid binder callback for clients
+ if (!cb.pingBinder()) {
+ Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
@@ -2591,17 +2586,14 @@
}//synchronized(mAudioFocusLock)
// handle the potential premature death of the new holder of the focus
- // (premature death == death before abandoning focus) for a client which is not the
- // AudioService's phone state listener
- if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
- // Register for client death notification
- AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
- try {
- cb.linkToDeath(afdh, 0);
- } catch (RemoteException e) {
- // client has already died!
- Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
- }
+ // (premature death == death before abandoning focus)
+ // Register for client death notification
+ AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+ try {
+ cb.linkToDeath(afdh, 0);
+ } catch (RemoteException e) {
+ // client has already died!
+ Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
}
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index 3e8fe94..fa9d26d 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -131,6 +131,11 @@
if (durationMs > getMaximumDuration()) {
throw new IllegalArgumentException("The duration is too large");
}
+ if (afterMediaItem != null) {
+ mNativeHelper = afterMediaItem.getNativeContext();
+ }else {
+ mNativeHelper = beforeMediaItem.getNativeContext();
+ }
}
/**
diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java
index f7d17cb..22788d4 100755
--- a/media/java/android/media/videoeditor/TransitionAlpha.java
+++ b/media/java/android/media/videoeditor/TransitionAlpha.java
@@ -104,13 +104,6 @@
mWidth = dbo.outWidth;
mHeight = dbo.outHeight;
- if (afterMediaItem != null) {
- mNativeHelper = afterMediaItem.getNativeContext();
- }else {
- mNativeHelper = beforeMediaItem.getNativeContext();
- }
-
-
mRGBMaskFile = String.format(mNativeHelper.getProjectPath() +
"/" + "mask" + transitionId+ ".rgb");
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index ad67bb9..d245f588 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -271,7 +271,7 @@
/**
* Returns true if the object is abstract (that is, it has no representation
- * in the underlying file system.
+ * in the underlying file system).
*
* @param format the format of the object
* @return true if the object is abstract
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 22961d7f..af37c9e 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -17,7 +17,7 @@
package android.mtp;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbDeviceConnection;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -44,17 +44,20 @@
}
/**
- * Opens the MTP or PTP device and return an {@link android.mtp.MtpDevice} for it.
+ * Opens the MTP device. Once the device is open it takes ownership of the
+ * {@link android.hardware.usb.UsbDeviceConnection}.
+ * The connection will be closed when you call {@link #close()}
+ * The connection will also be closed if this method fails.
*
- * @param manager reference to {@link android.hardware.usb.UsbManager}
+ * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device
* @return true if the device was successfully opened.
*/
- public boolean open(UsbManager manager) {
- if (manager.openDevice(mDevice)) {
- return native_open(mDevice.getDeviceName(), mDevice.getFileDescriptor());
- } else {
- return false;
+ public boolean open(UsbDeviceConnection connection) {
+ boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
+ if (!result) {
+ connection.close();
}
+ return result;
}
/**
@@ -195,7 +198,7 @@
* @param objectHandle handle of the object to query
* @return the object's storage unit ID
*/
- public long getStorageID(int objectHandle) {
+ public long getStorageId(int objectHandle) {
return native_get_storage_id(objectHandle);
}
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index fd32665..f5fcb4e 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -311,9 +311,9 @@
if (objectInfo->mName)
env->SetObjectField(info, field_objectInfo_name, env->NewStringUTF(objectInfo->mName));
if (objectInfo->mDateCreated)
- env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated);
+ env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL);
if (objectInfo->mDateModified)
- env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified);
+ env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified * 1000LL);
if (objectInfo->mKeywords)
env->SetObjectField(info, field_objectInfo_keywords,
env->NewStringUTF(objectInfo->mKeywords));
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1d6ffa0..a18bedb 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,6 +128,9 @@
{
LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
+
+ AutoMutex lock(mLock);
+
if (mAudioRecord != 0) {
return INVALID_OPERATION;
}
@@ -183,7 +186,7 @@
mSessionId = sessionId;
// create the IAudioRecord
- status = openRecord(sampleRate, format, channelCount,
+ status = openRecord_l(sampleRate, format, channelCount,
frameCount, flags, input);
if (status != NO_ERROR) {
return status;
@@ -282,21 +285,31 @@
}
AutoMutex lock(mLock);
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
if (mActive == 0) {
mActive = 1;
- ret = mAudioRecord->start();
- if (ret == DEAD_OBJECT) {
- LOGV("start() dead IAudioRecord: creating a new one");
- ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, getInput());
- if (ret == NO_ERROR) {
- ret = mAudioRecord->start();
+
+ cblk->lock.lock();
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ cblk->lock.unlock();
+ ret = mAudioRecord->start();
+ cblk->lock.lock();
+ if (ret == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
}
}
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ ret = restoreRecord_l(cblk);
+ }
+ cblk->lock.unlock();
if (ret == NO_ERROR) {
- mNewPosition = mCblk->user + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
+ mNewPosition = cblk->user + mUpdatePeriod;
+ cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ cblk->waitTimeMs = 0;
if (t != 0) {
t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -353,6 +366,7 @@
uint32_t AudioRecord::getSampleRate()
{
+ AutoMutex lock(mLock);
return mCblk->sampleRate;
}
@@ -400,6 +414,7 @@
{
if (position == 0) return BAD_VALUE;
+ AutoMutex lock(mLock);
*position = mCblk->user;
return NO_ERROR;
@@ -415,7 +430,8 @@
// -------------------------------------------------------------------------
-status_t AudioRecord::openRecord(
+// must be called with mLock held
+status_t AudioRecord::openRecord_l(
uint32_t sampleRate,
int format,
int channelCount,
@@ -459,6 +475,7 @@
status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
+ AutoMutex lock(mLock);
int active;
status_t result;
audio_track_cblk_t* cblk = mCblk;
@@ -483,7 +500,19 @@
cblk->lock.unlock();
return WOULD_BLOCK;
}
- result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ cblk->lock.unlock();
+ mLock.lock();
+ if (mActive == 0) {
+ return status_t(STOPPED);
+ }
+ cblk->lock.lock();
+ }
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ goto create_new_record;
+ }
if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += waitTimeMs;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
@@ -491,16 +520,17 @@
"user=%08x, server=%08x", cblk->user, cblk->server);
cblk->lock.unlock();
result = mAudioRecord->start();
- if (result == DEAD_OBJECT) {
- LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
- result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, getInput());
- if (result == NO_ERROR) {
- cblk = mCblk;
- mAudioRecord->start();
- }
- }
cblk->lock.lock();
+ if (result == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
+create_new_record:
+ result = AudioRecord::restoreRecord_l(cblk);
+ }
+ if (result != NO_ERROR) {
+ LOGW("obtainBuffer create Track error %d", result);
+ cblk->lock.unlock();
+ return result;
+ }
cblk->waitTimeMs = 0;
}
if (--waitCount == 0) {
@@ -540,12 +570,19 @@
void AudioRecord::releaseBuffer(Buffer* audioBuffer)
{
- audio_track_cblk_t* cblk = mCblk;
- cblk->stepUser(audioBuffer->frameCount);
+ AutoMutex lock(mLock);
+ mCblk->stepUser(audioBuffer->frameCount);
}
audio_io_handle_t AudioRecord::getInput()
{
+ AutoMutex lock(mLock);
+ return getInput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioRecord::getInput_l()
+{
mInput = AudioSystem::getInput(mInputSource,
mCblk->sampleRate,
mFormat, mChannels,
@@ -573,6 +610,12 @@
return BAD_VALUE;
}
+ mLock.lock();
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ mLock.unlock();
do {
@@ -613,9 +656,17 @@
uint32_t frames = mRemainingFrames;
size_t readSize;
+ mLock.lock();
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+ mLock.unlock();
+
// Manage marker callback
if (!mMarkerReached && (mMarkerPosition > 0)) {
- if (mCblk->user >= mMarkerPosition) {
+ if (cblk->user >= mMarkerPosition) {
mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
mMarkerReached = true;
}
@@ -623,7 +674,7 @@
// Manage new position callback
if (mUpdatePeriod > 0) {
- while (mCblk->user >= mNewPosition) {
+ while (cblk->user >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
}
@@ -669,11 +720,11 @@
// Manage overrun callback
- if (mActive && (mCblk->framesAvailable_l() == 0)) {
- LOGV("Overrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
- if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+ if (mActive && (cblk->framesAvailable() == 0)) {
+ LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+ if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
mCbf(EVENT_OVERRUN, mUserData, 0);
- mCblk->flags |= CBLK_UNDERRUN_ON;
+ cblk->flags |= CBLK_UNDERRUN_ON;
}
}
@@ -685,6 +736,69 @@
return true;
}
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioRecord and IMemory in case they are recreated here.
+// If the IAudioRecord is successfully restored, the cblk pointer is updated
+status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
+{
+ status_t result;
+
+ if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+ LOGW("dead IAudioRecord, creating a new one");
+
+ cblk->flags |= CBLK_RESTORING_ON;
+ // signal old cblk condition so that other threads waiting for available buffers stop
+ // waiting now
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+
+ // if the new IAudioRecord is created, openRecord_l() will modify the
+ // following member variables: mAudioRecord, mCblkMemory and mCblk.
+ // It will also delete the strong references on previous IAudioRecord and IMemory
+ result = openRecord_l(cblk->sampleRate, mFormat, mChannelCount,
+ mFrameCount, mFlags, getInput_l());
+ if (result == NO_ERROR) {
+ result = mAudioRecord->start();
+ }
+ if (result != NO_ERROR) {
+ mActive = false;
+ }
+
+ // signal old cblk condition for other threads waiting for restore completion
+ cblk->lock.lock();
+ cblk->flags |= CBLK_RESTORED_MSK;
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+ } else {
+ if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+ LOGW("dead IAudioRecord, waiting for a new one to be created");
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+ cblk->lock.unlock();
+ mLock.lock();
+ } else {
+ LOGW("dead IAudioRecord, already restored");
+ result = NO_ERROR;
+ cblk->lock.unlock();
+ }
+ if (result != NO_ERROR || mActive == 0) {
+ result = status_t(STOPPED);
+ }
+ }
+ LOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+ result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+ if (result == NO_ERROR) {
+ // from now on we switch to the newly created cblk
+ cblk = mCblk;
+ }
+ cblk->lock.lock();
+
+ LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
+
+ return result;
+}
+
// =========================================================================
AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c1bed59..8d8f67b 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -148,6 +148,7 @@
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+ AutoMutex lock(mLock);
if (mAudioTrack != 0) {
LOGE("Track already in use");
return INVALID_OPERATION;
@@ -211,8 +212,15 @@
mAuxEffectId = 0;
// create the IAudioTrack
- status_t status = createTrack(streamType, sampleRate, format, channelCount,
- frameCount, flags, sharedBuffer, output, true);
+ status_t status = createTrack_l(streamType,
+ sampleRate,
+ format,
+ channelCount,
+ frameCount,
+ flags,
+ sharedBuffer,
+ output,
+ true);
if (status != NO_ERROR) {
return status;
@@ -312,37 +320,38 @@
}
AutoMutex lock(mLock);
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+
if (mActive == 0) {
mActive = 1;
- mNewPosition = mCblk->server + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
- mCblk->flags &= ~CBLK_DISABLED_ON;
+ mNewPosition = cblk->server + mUpdatePeriod;
+ cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+ cblk->waitTimeMs = 0;
+ cblk->flags &= ~CBLK_DISABLED_ON;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
}
- if (mCblk->flags & CBLK_INVALID_MSK) {
- LOGW("start() track %p invalidated, creating a new one", this);
- // no need to clear the invalid flag as this cblk will not be used anymore
- // force new track creation
- status = DEAD_OBJECT;
- } else {
+ LOGV("start %p before lock cblk %p", this, mCblk);
+ cblk->lock.lock();
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ cblk->lock.unlock();
status = mAudioTrack->start();
- }
- if (status == DEAD_OBJECT) {
- LOGV("start() dead IAudioTrack: creating a new one");
- status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
- if (status == NO_ERROR) {
- status = mAudioTrack->start();
- if (status == NO_ERROR) {
- mNewPosition = mCblk->server + mUpdatePeriod;
- }
+ cblk->lock.lock();
+ if (status == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
}
}
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ status = restoreTrack_l(cblk, true);
+ }
+ cblk->lock.unlock();
if (status != NO_ERROR) {
LOGV("start() failed");
mActive = 0;
@@ -375,14 +384,14 @@
mAudioTrack->stop();
// Cancel loops (If we are in the middle of a loop, playback
// would not stop until loopCount reaches 0).
- setLoop(0, 0, 0);
+ setLoop_l(0, 0, 0);
// the playback head position will reset to 0, so if a marker is set, we need
// to activate it again
mMarkerReached = false;
// Force flush if a shared buffer is used otherwise audioflinger
// will not stop before end of buffer is reached.
if (mSharedBuffer != 0) {
- flush();
+ flush_l();
}
if (t != 0) {
t->requestExit();
@@ -403,6 +412,13 @@
void AudioTrack::flush()
{
+ AutoMutex lock(mLock);
+ flush_l();
+}
+
+// must be called with mLock held
+void AudioTrack::flush_l()
+{
LOGV("flush");
// clear playback marker and periodic update counter
@@ -445,6 +461,7 @@
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
mVolume[LEFT] = left;
mVolume[RIGHT] = right;
@@ -470,6 +487,7 @@
if (level > 1.0f) {
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
mSendLevel = level;
@@ -495,17 +513,26 @@
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
+ AutoMutex lock(mLock);
mCblk->sampleRate = rate;
return NO_ERROR;
}
uint32_t AudioTrack::getSampleRate()
{
+ AutoMutex lock(mLock);
return mCblk->sampleRate;
}
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
+ AutoMutex lock(mLock);
+ return setLoop_l(loopStart, loopEnd, loopCount);
+}
+
+// must be called with mLock held
+status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
audio_track_cblk_t* cblk = mCblk;
Mutex::Autolock _l(cblk->lock);
@@ -540,6 +567,7 @@
status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
{
+ AutoMutex lock(mLock);
if (loopStart != 0) {
*loopStart = mCblk->loopStart;
}
@@ -599,6 +627,7 @@
status_t AudioTrack::setPosition(uint32_t position)
{
+ AutoMutex lock(mLock);
Mutex::Autolock _l(mCblk->lock);
if (!stopped()) return INVALID_OPERATION;
@@ -614,7 +643,7 @@
status_t AudioTrack::getPosition(uint32_t *position)
{
if (position == 0) return BAD_VALUE;
-
+ AutoMutex lock(mLock);
*position = mCblk->server;
return NO_ERROR;
@@ -622,9 +651,11 @@
status_t AudioTrack::reload()
{
+ AutoMutex lock(mLock);
+
if (!stopped()) return INVALID_OPERATION;
- flush();
+ flush_l();
mCblk->stepUser(mCblk->frameCount);
@@ -633,6 +664,13 @@
audio_io_handle_t AudioTrack::getOutput()
{
+ AutoMutex lock(mLock);
+ return getOutput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioTrack::getOutput_l()
+{
return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
}
@@ -654,7 +692,8 @@
// -------------------------------------------------------------------------
-status_t AudioTrack::createTrack(
+// must be called with mLock held
+status_t AudioTrack::createTrack_l(
int streamType,
uint32_t sampleRate,
int format,
@@ -774,6 +813,7 @@
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
+ AutoMutex lock(mLock);
int active;
status_t result;
audio_track_cblk_t* cblk = mCblk;
@@ -800,12 +840,17 @@
return WOULD_BLOCK;
}
if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ mLock.unlock();
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
- }
- if (cblk->flags & CBLK_INVALID_MSK) {
- LOGW("obtainBuffer() track %p invalidated, creating a new one", this);
- // no need to clear the invalid flag as this cblk will not be used anymore
cblk->lock.unlock();
+ mLock.lock();
+ if (mActive == 0) {
+ return status_t(STOPPED);
+ }
+ cblk->lock.lock();
+ }
+
+ if (cblk->flags & CBLK_INVALID_MSK) {
goto create_new_track;
}
if (__builtin_expect(result!=NO_ERROR, false)) {
@@ -819,18 +864,17 @@
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
result = mAudioTrack->start();
- if (result == DEAD_OBJECT) {
- LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
-create_new_track:
- result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
- if (result == NO_ERROR) {
- cblk = mCblk;
- cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mAudioTrack->start();
- }
- }
cblk->lock.lock();
+ if (result == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
+create_new_track:
+ result = restoreTrack_l(cblk, false);
+ }
+ if (result != NO_ERROR) {
+ LOGW("obtainBuffer create Track error %d", result);
+ cblk->lock.unlock();
+ return result;
+ }
}
cblk->waitTimeMs = 0;
}
@@ -848,7 +892,7 @@
}
// restart track if it was disabled by audioflinger due to previous underrun
- if (cblk->flags & CBLK_DISABLED_MSK) {
+ if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
cblk->flags &= ~CBLK_DISABLED_ON;
LOGW("obtainBuffer() track %p disabled, restarting", this);
mAudioTrack->start();
@@ -883,8 +927,8 @@
void AudioTrack::releaseBuffer(Buffer* audioBuffer)
{
- audio_track_cblk_t* cblk = mCblk;
- cblk->stepUser(audioBuffer->frameCount);
+ AutoMutex lock(mLock);
+ mCblk->stepUser(audioBuffer->frameCount);
}
// -------------------------------------------------------------------------
@@ -903,6 +947,13 @@
LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ mLock.lock();
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ mLock.unlock();
+
ssize_t written = 0;
const int8_t *src = (const int8_t *)buffer;
Buffer audioBuffer;
@@ -953,21 +1004,29 @@
uint32_t frames;
size_t writtenSize;
+ mLock.lock();
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+ mLock.unlock();
+
// Manage underrun callback
- if (mActive && (mCblk->framesReady() == 0)) {
- LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
- if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+ if (mActive && (cblk->framesReady() == 0)) {
+ LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+ if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
- if (mCblk->server == mCblk->frameCount) {
+ if (cblk->server == cblk->frameCount) {
mCbf(EVENT_BUFFER_END, mUserData, 0);
}
- mCblk->flags |= CBLK_UNDERRUN_ON;
+ cblk->flags |= CBLK_UNDERRUN_ON;
if (mSharedBuffer != 0) return false;
}
}
// Manage loop end callback
- while (mLoopCount > mCblk->loopCount) {
+ while (mLoopCount > cblk->loopCount) {
int loopCount = -1;
mLoopCount--;
if (mLoopCount >= 0) loopCount = mLoopCount;
@@ -977,7 +1036,7 @@
// Manage marker callback
if (!mMarkerReached && (mMarkerPosition > 0)) {
- if (mCblk->server >= mMarkerPosition) {
+ if (cblk->server >= mMarkerPosition) {
mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
mMarkerReached = true;
}
@@ -985,7 +1044,7 @@
// Manage new position callback
if (mUpdatePeriod > 0) {
- while (mCblk->server >= mNewPosition) {
+ while (cblk->server >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
}
@@ -1068,6 +1127,84 @@
return true;
}
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioTrack and IMemory in case they are recreated here.
+// If the IAudioTrack is successfully restored, the cblk pointer is updated
+status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
+{
+ status_t result;
+
+ if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+ LOGW("dead IAudioTrack, creating a new one from %s",
+ fromStart ? "start()" : "obtainBuffer()");
+
+ cblk->flags |= CBLK_RESTORING_ON;
+ // signal old cblk condition so that other threads waiting for available buffers stop
+ // waiting now
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+
+ // if the new IAudioTrack is created, createTrack_l() will modify the
+ // following member variables: mAudioTrack, mCblkMemory and mCblk.
+ // It will also delete the strong references on previous IAudioTrack and IMemory
+ result = createTrack_l(mStreamType,
+ cblk->sampleRate,
+ mFormat,
+ mChannelCount,
+ mFrameCount,
+ mFlags,
+ mSharedBuffer,
+ getOutput_l(),
+ false);
+
+ if (result == NO_ERROR) {
+ if (!fromStart) {
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ }
+ result = mAudioTrack->start();
+ if (fromStart && result == NO_ERROR) {
+ mNewPosition = mCblk->server + mUpdatePeriod;
+ }
+ }
+ if (result != NO_ERROR) {
+ mActive = false;
+ }
+
+ // signal old cblk condition for other threads waiting for restore completion
+ cblk->lock.lock();
+ cblk->flags |= CBLK_RESTORED_MSK;
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+ } else {
+ if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+ LOGW("dead IAudioTrack, waiting for a new one");
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+ cblk->lock.unlock();
+ mLock.lock();
+ } else {
+ LOGW("dead IAudioTrack, already restored");
+ result = NO_ERROR;
+ cblk->lock.unlock();
+ }
+ if (result != NO_ERROR || mActive == 0) {
+ result = status_t(STOPPED);
+ }
+ }
+ LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+ result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+ if (result == NO_ERROR) {
+ // from now on we switch to the newly created cblk
+ cblk = mCblk;
+ }
+ cblk->lock.lock();
+
+ LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result);
+
+ return result;
+}
+
status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
{
@@ -1197,7 +1334,9 @@
this->server = s;
- cv.signal();
+ if (!(flags & CBLK_INVALID_MSK)) {
+ cv.signal();
+ }
lock.unlock();
return true;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4c744bd..5734c7e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -45,6 +45,7 @@
#include <surfaceflinger/Surface.h>
#include <gui/ISurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
+#include <surfaceflinger/ISurfaceComposer.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -1189,6 +1190,19 @@
}
status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
+
+ // Either the application or the DRM system can independently say
+ // that there must be a hardware-protected path to an external video sink.
+ // For now we always require a hardware-protected path to external video sink
+ // if content is DRMed, but eventually this could be optional per DRM agent.
+ // When the application wants protection, then
+ // (USE_SURFACE_ALLOC && (mSurface != 0) &&
+ // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp))
+ // will be true, but that part is already handled by SurfaceFlinger.
+ if (mDecryptHandle != NULL) {
+ flags |= OMXCodec::kEnableGrallocUsageProtected;
+ }
+ LOGV("initVideoDecoder flags=0x%x", flags);
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4a94e0d..3e26a95 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -528,6 +528,12 @@
mOnlySubmitOneBufferAtOneTime = true;
}
+ mEnableGrallocUsageProtected = false;
+ if (flags & kEnableGrallocUsageProtected) {
+ mEnableGrallocUsageProtected = true;
+ }
+ LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
+
if (!(flags & kIgnoreCodecSpecificData)) {
uint32_t type;
const void *data;
@@ -1751,7 +1757,11 @@
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
+ if (mEnableGrallocUsageProtected) {
+ usage |= GRALLOC_USAGE_PROTECTED;
+ }
+ LOGV("native_window_set_usage usage=0x%x", usage);
err = native_window_set_usage(
mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 801edb0..0b0c80d 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -28,7 +28,7 @@
namespace android {
MtpDataPacket::MtpDataPacket()
- : MtpPacket(512),
+ : MtpPacket(16384), // MAX_USBFS_BUFFER_SIZE
mOffset(MTP_CONTAINER_HEADER_SIZE)
{
}
@@ -399,10 +399,10 @@
if (length >= MTP_CONTAINER_HEADER_SIZE) {
// look at the length field to see if the data spans multiple packets
uint32_t totalLength = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
+ allocate(totalLength);
while (totalLength > length) {
- allocate(length + mAllocationIncrement);
request->buffer = mBuffer + length;
- request->buffer_length = mAllocationIncrement;
+ request->buffer_length = totalLength - length;
int ret = transfer(request);
if (ret >= 0)
length += ret;
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 4ea8849..2e86159 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -819,6 +819,10 @@
return mResponse.getResponseCode();
}
int ret = mResponse.read(mRequestIn1);
+ // handle zero length packets, which might occur if the data transfer
+ // ends on a packet boundary
+ if (ret == 0)
+ ret = mResponse.read(mRequestIn1);
if (ret >= MTP_CONTAINER_HEADER_SIZE) {
mResponse.dump();
return mResponse.getResponseCode();
diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk
index 1d81129..46596a7 100644
--- a/media/tests/CameraBrowser/Android.mk
+++ b/media/tests/CameraBrowser/Android.mk
@@ -7,4 +7,6 @@
LOCAL_PACKAGE_NAME := CameraBrowser
+LOCAL_SDK_VERSION := current
+
include $(BUILD_PACKAGE)
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
index f642d93..af17ded 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java
@@ -20,7 +20,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.mtp.MtpClient;
import android.mtp.MtpDevice;
import android.mtp.MtpDeviceInfo;
import android.os.Bundle;
@@ -79,8 +78,8 @@
view = (TwoLineListItem)convertView;
}
- TextView textView1 = (TextView)view.findViewById(com.android.internal.R.id.text1);
- TextView textView2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
+ TextView textView1 = (TextView)view.findViewById(android.R.id.text1);
+ TextView textView2 = (TextView)view.findViewById(android.R.id.text2);
MtpDevice device = mDeviceList.get(position);
MtpDeviceInfo info = device.getDeviceInfo();
if (info != null) {
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
index 6f1edfea..8075862 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java
@@ -17,8 +17,6 @@
package com.android.camerabrowser;
import android.app.Application;
-import android.mtp.MtpClient;
-
public class CameraBrowserApplication extends Application {
diff --git a/media/java/android/mtp/MtpClient.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
similarity index 84%
rename from media/java/android/mtp/MtpClient.java
rename to media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
index 40e2f9b..edb5e37 100644
--- a/media/java/android/mtp/MtpClient.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-package android.mtp;
+package com.android.camerabrowser;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
+import android.mtp.MtpDevice;
+import android.mtp.MtpDeviceInfo;
+import android.mtp.MtpObjectInfo;
+import android.mtp.MtpStorageInfo;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -41,6 +47,9 @@
private static final String TAG = "MtpClient";
+ private static final String ACTION_USB_PERMISSION =
+ "android.mtp.MtpClient.action.USB_PERMISSION";
+
private final Context mContext;
private final UsbManager mUsbManager;
private final ArrayList<Listener> mListeners = new ArrayList<Listener>();
@@ -49,29 +58,47 @@
// mDevices is also used for synchronization in this class.
private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>();
+ private final PendingIntent mPermissionIntent;
+
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
String deviceName = usbDevice.getDeviceName();
synchronized (mDevices) {
MtpDevice mtpDevice = mDevices.get(deviceName);
- if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
+ if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
if (mtpDevice == null) {
mtpDevice = openDeviceLocked(usbDevice);
}
if (mtpDevice != null) {
- mDevices.put(deviceName, mtpDevice);
for (Listener listener : mListeners) {
listener.deviceAdded(mtpDevice);
}
}
- } else if (mtpDevice != null) {
- mDevices.remove(deviceName);
- for (Listener listener : mListeners) {
- listener.deviceRemoved(mtpDevice);
+ } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+ if (mtpDevice != null) {
+ mDevices.remove(deviceName);
+ for (Listener listener : mListeners) {
+ listener.deviceRemoved(mtpDevice);
+ }
+ }
+ } else if (ACTION_USB_PERMISSION.equals(action)) {
+ boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
+ false);
+ Log.d(TAG, "ACTION_USB_PERMISSION: " + permission);
+ if (permission) {
+ if (mtpDevice == null) {
+ mtpDevice = openDeviceLocked(usbDevice);
+ }
+ if (mtpDevice != null) {
+ for (Listener listener : mListeners) {
+ listener.deviceAdded(mtpDevice);
+ }
+ }
}
}
}
@@ -126,10 +153,11 @@
public MtpClient(Context context) {
mContext = context;
mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
-
+ mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
+ filter.addAction(ACTION_USB_PERMISSION);
context.registerReceiver(mUsbReceiver, filter);
}
@@ -142,9 +170,17 @@
*/
private MtpDevice openDeviceLocked(UsbDevice usbDevice) {
if (isCamera(usbDevice)) {
- MtpDevice mtpDevice = new MtpDevice(usbDevice);
- if (mtpDevice.open(mUsbManager)) {
- return mtpDevice;
+ if (!mUsbManager.hasPermission(usbDevice)) {
+ mUsbManager.requestPermission(usbDevice, mPermissionIntent);
+ } else {
+ UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice);
+ if (connection != null) {
+ MtpDevice mtpDevice = new MtpDevice(usbDevice);
+ if (mtpDevice.open(connection)) {
+ mDevices.put(usbDevice.getDeviceName(), mtpDevice);
+ return mtpDevice;
+ }
+ }
}
}
return null;
@@ -218,13 +254,8 @@
// Query the USB manager since devices might have attached
// before we added our listener.
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
- String deviceName = usbDevice.getDeviceName();
- MtpDevice mtpDevice = mDevices.get(deviceName);
- if (mtpDevice == null) {
- mtpDevice = openDeviceLocked(usbDevice);
- }
- if (mtpDevice != null) {
- mDevices.put(deviceName, mtpDevice);
+ if (mDevices.get(usbDevice.getDeviceName()) == null) {
+ openDeviceLocked(usbDevice);
}
}
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
index 82251d9..68fed7b 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java
@@ -22,7 +22,6 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.mtp.MtpClient;
import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
index e9ea9f3..ef69c44 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java
@@ -23,7 +23,6 @@
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.mtp.MtpClient;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
import android.net.Uri;
diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
index 7d5a5da..64320fe 100644
--- a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
+++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java
@@ -19,7 +19,6 @@
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
-import android.mtp.MtpClient;
import android.mtp.MtpDevice;
import android.mtp.MtpStorageInfo;
import android.os.Bundle;
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 7f92eec..219cd19 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -20,6 +20,7 @@
#include <android/native_window_jni.h>
#include <surfaceflinger/Surface.h>
#include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
using namespace android;
@@ -31,6 +32,14 @@
return win.get();
}
+ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture) {
+ sp<ANativeWindow> win = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
+ if (win != NULL) {
+ win->incStrong((void*)ANativeWindow_acquire);
+ }
+ return win.get();
+}
+
void ANativeWindow_acquire(ANativeWindow* window) {
window->incStrong((void*)ANativeWindow_acquire);
}
diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h
index b9e72ef..408c263 100644
--- a/native/include/android/native_window_jni.h
+++ b/native/include/android/native_window_jni.h
@@ -33,6 +33,14 @@
*/
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
+/**
+ * Return the ANativeWindow associated with a Java SurfaceTexture object,
+ * for interacting with it through native code. This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture);
+
#ifdef __cplusplus
};
#endif
diff --git a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
index 602ea1a..f0b8d12 100644
--- a/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
+++ b/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp
@@ -186,11 +186,6 @@
GraphicBuffer::USAGE_SW_WRITE_RARELY;
const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12;
const int yuvTexOffsetY = 0;
-const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf;
-const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
-const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
-const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
-const int yuvTexStrideU = yuvTexStrideV;
const bool yuvTexSameUV = false;
static sp<GraphicBuffer> yuvTexBuffer;
static GLuint yuvTex;
@@ -200,6 +195,11 @@
int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1;
yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat,
yuvTexUsage);
+ int yuvTexStrideY = yuvTexBuffer->getStride();
+ int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
+ int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+ int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
+ int yuvTexStrideU = yuvTexStrideV;
char* buf = NULL;
status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
if (err != 0) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index fa63edb..744798e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -27,6 +27,7 @@
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
+import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
@@ -58,15 +59,20 @@
private static final String KEY_SECURE = "secure";
private static final String KEY_LOCALE = "locale";
+ //Version 2 adds STATE_WIFI_CONFIG
+ private static final int STATE_VERSION_1 = 1;
+ private static final int STATE_VERSION_1_SIZE = 4;
+
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
- private static final int STATE_VERSION = 1;
+ private static final int STATE_VERSION = 2;
- private static final int STATE_SYSTEM = 0;
- private static final int STATE_SECURE = 1;
- private static final int STATE_LOCALE = 2;
- private static final int STATE_WIFI = 3;
- private static final int STATE_SIZE = 4; // The number of state items
+ private static final int STATE_SYSTEM = 0;
+ private static final int STATE_SECURE = 1;
+ private static final int STATE_LOCALE = 2;
+ private static final int STATE_WIFI_SUPPLICANT = 3;
+ private static final int STATE_WIFI_CONFIG = 4;
+ private static final int STATE_SIZE = 5; // The number of state items
private static String[] sortedSystemKeys = null;
private static String[] sortedSecureKeys = null;
@@ -91,12 +97,18 @@
// the key to store the WIFI data under, should be sorted as last, so restore happens last.
// use very late unicode character to quasi-guarantee last sort position.
private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
+ private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
private SettingsHelper mSettingsHelper;
+ private WifiManager mWfm;
+ private static String mWifiConfigFile;
public void onCreate() {
mSettingsHelper = new SettingsHelper(this);
super.onCreate();
+
+ WifiManager mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ if (mWfm != null) mWifiConfigFile = mWfm.getConfigFile();
}
@Override
@@ -106,7 +118,8 @@
byte[] systemSettingsData = getSystemSettings();
byte[] secureSettingsData = getSecureSettings();
byte[] locale = mSettingsHelper.getLocaleData();
- byte[] wifiData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
+ byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
+ byte[] wifiConfigData = getFileData(mWifiConfigFile);
long[] stateChecksums = readOldChecksums(oldState);
@@ -116,8 +129,12 @@
writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
stateChecksums[STATE_LOCALE] =
writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
- stateChecksums[STATE_WIFI] =
- writeIfChanged(stateChecksums[STATE_WIFI], KEY_WIFI_SUPPLICANT, wifiData, data);
+ stateChecksums[STATE_WIFI_SUPPLICANT] =
+ writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+ wifiSupplicantData, data);
+ stateChecksums[STATE_WIFI_CONFIG] =
+ writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+ data);
writeNewChecksums(stateChecksums, newState);
}
@@ -148,7 +165,9 @@
byte[] localeData = new byte[size];
data.readEntityData(localeData, 0, size);
mSettingsHelper.setLocaleData(localeData);
- } else {
+ } else if (KEY_WIFI_CONFIG.equals(key)) {
+ restoreFileData(mWifiConfigFile, data);
+ } else {
data.skipEntityData();
}
}
@@ -162,7 +181,11 @@
try {
int stateVersion = dataInput.readInt();
- if (stateVersion == STATE_VERSION) {
+ if (stateVersion == STATE_VERSION_1) {
+ for (int i = 0; i < STATE_VERSION_1_SIZE; i++) {
+ stateChecksums[i] = dataInput.readLong();
+ }
+ } else if (stateVersion == STATE_VERSION) {
for (int i = 0; i < STATE_SIZE; i++) {
stateChecksums[i] = dataInput.readLong();
}
@@ -353,6 +376,60 @@
return result;
}
+ private byte[] getFileData(String filename) {
+ InputStream is = null;
+ try {
+ File file = new File(filename);
+ is = new FileInputStream(file);
+
+ //Will truncate read on a very long file,
+ //should not happen for a config file
+ byte[] bytes = new byte[(int)file.length()];
+
+ int offset = 0;
+ int numRead = 0;
+ while (offset < bytes.length
+ && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+ offset += numRead;
+ }
+
+ //read failure
+ if (offset < bytes.length) {
+ Log.w(TAG, "Couldn't backup " + filename);
+ return EMPTY_DATA;
+ }
+ return bytes;
+ } catch (IOException ioe) {
+ Log.w(TAG, "Couldn't backup " + filename);
+ return EMPTY_DATA;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ }
+
+ private void restoreFileData(String filename, BackupDataInput data) {
+ byte[] bytes = new byte[data.getDataSize()];
+ if (bytes.length <= 0) return;
+ try {
+ data.readEntityData(bytes, 0, bytes.length);
+ File file = new File(filename);
+ if (file.exists()) file.delete();
+
+ OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
+ os.write(bytes);
+ os.close();
+ } catch (IOException ioe) {
+ Log.w(TAG, "Couldn't restore " + filename);
+ }
+ }
+
+
private byte[] getWifiSupplicant(String filename) {
BufferedReader br = null;
try {
@@ -455,10 +532,9 @@
}
private int enableWifi(boolean enable) {
- WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- if (wfm != null) {
- int state = wfm.getWifiState();
- wfm.setWifiEnabled(enable);
+ if (mWfm != null) {
+ int state = mWfm.getWifiState();
+ mWfm.setWifiEnabled(enable);
return state;
}
return WifiManager.WIFI_STATE_UNKNOWN;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d3d1750..bbe146d6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.GET_TASKS" />
+ <uses-permission android:name="android.permission.MANAGE_USB" />
<application
android:persistent="true"
@@ -39,5 +40,40 @@
android:exported="true">
</activity>
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbConfirmActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbPermissionActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbResolverActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbAccessoryUriActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
</application>
</manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
index ff74c35..6ff0899 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
index 6375b1b..6dcdefb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
index ef886b8..5ee9e0a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
index 92882bd..a74e731 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
index cf5c4c3..441739a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
index 24b6d25..a666c75 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
index b147583..2045c0c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
index 594ad6a..063a86c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
index 2879550..1e4aebb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
index c763976..52e8a8e 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
index 883808a..c69c44f 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
new file mode 100644
index 0000000..0413ae3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
index 8ea42c7..61e7772a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
index 71429ae..74b018a 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
index 5c34554..d3364bc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
index 44e7072..e65d6ed 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
index 7cd2893..f5b07e6 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
index 23eb1d6..fbb31b8 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
index ad28667..c1f2f97 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
index 048dfd1..8721d5c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
index 224ae1f..b8feac6 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
index b85859b..6854a2b 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
index d7f3960..efff76c 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
index 54915b9..3a5c7e2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
index bd44b52..dc1ce8e 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
index 8654aa0..35056d3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
index c10629f..dcfcc00 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
index 753c9f9..e61b6ba 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
index 65a886a..f0f86e5 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
index 6e90ce4..1025e81 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
index cce7d9b..c4cc59f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
index c4e33bd..4976752 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
index 433a2c5..380a5f4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
index 81401b2..d97b1de 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
index a1a9794..174d65c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
index e429ea1..abbdbc0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
index e3bcaf9..f1f4c1c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
index 26db91e..f767994 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
index 957c5ba..7c97a01 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_in.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
index aec6050..c0665c4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_inout.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
index bb8eea0..8746388 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_out.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
index 75906a2..150a6c7 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
index 528e4ce..76f86dc 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
index 1eb5aad..1f0dd89 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
index 5f2c230..5e7ae35 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
index 2c27620..b861bc9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
index 4cb06be..8f16376 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
index fd9c350..67f46d3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
index e8aed95..165348c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
index c629387..d53d3bc 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
index 8e039ce..1629575 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
index 0cb0a08..e87bcec 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
index c3cd10b..fd44002 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
index 650f67b..e455ad6 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
index f5b1618..6613585 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
index eddc487..7502a54 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
index 1eb0142..1309176 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
index 4c8e7c3..810714e 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
index 657dc04..72176ba 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
index 359e8f8..82a2bf0 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
index e5b0841..1e6c604 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
index 4fe8df3..13aee06 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
index a7a7bea..76c48a8 100644
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-hdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
index 2cbec7b..73cdabe 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
index 0efb9c9..b5a39cc 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
index 2eae1e1..6de880c 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
index 7e82c4c..2dbbfc0 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
index d37f1e5..a45f011 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
index 5f7349e..517a6bb 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
index 31358ec..5226c1c 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_connected_roam.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
index e5a3484..a845648 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
index 2a3a5dc..1d15587 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
index 5dbd1ab..52d5736 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
index 51d1f76..79a2a05 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
index 10d81ca..b032594 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
index 1d9bda0..c4abcc9 100644
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-xlarge-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
index bfa6c36..3f172e6 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_item.xml
@@ -38,8 +38,8 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:layout_marginLeft="123dip"
- android:layout_marginTop="16dip"
+ android:layout_marginLeft="131dip"
+ android:layout_marginTop="13dip"
android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
android:adjustViewBounds="true"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
index eda19b7..42940be 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_recent_panel.xml
@@ -51,7 +51,7 @@
android:stackFromBottom="true"
android:fadingEdge="vertical"
android:scrollbars="none"
- android:fadingEdgeLength="30dip"
+ android:fadingEdgeLength="20dip"
android:listSelector="@drawable/recents_thumbnail_bg_selector"
/>
diff --git a/packages/SystemUI/res/values-ar-xlarge/strings.xml b/packages/SystemUI/res/values-ar-xlarge/strings.xml
index af0eed0..d4fb873 100644
--- a/packages/SystemUI/res/values-ar-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ar-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi متصل"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"جارٍ البحث عن GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"تم تعيين الموقع بواسطة GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"إيقاف التنبيهات"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"انقر هنا لإعادة تشغيل التنبيهات."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2b22302..5f29418c 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"تم إنشاء الاتصال بالإنترنت عن طريق البلوتوث."</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"تهيئة طرق الإدخال"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"استخدام لوحة المفاتيح الفعلية"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg-xlarge/strings.xml b/packages/SystemUI/res/values-bg-xlarge/strings.xml
index d44366d..4e730ae 100644
--- a/packages/SystemUI/res/values-bg-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-bg-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: има връзка"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Търси се GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Местоположението е зададено от GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Известията са изключени"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Докоснете тук, за да включите отново известията."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index faf802b..174d024 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth има връзка с тетъринг"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Конфигуриране на въвеждането"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Използване на физ. клав."</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca-xlarge/strings.xml b/packages/SystemUI/res/values-ca-xlarge/strings.xml
index a0ace2c..9fc74d0 100644
--- a/packages/SystemUI/res/values-ca-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ca-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: connectat"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"S\'està cercant un GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"S\'ha establert la ubicació per GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificacions desactivades"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Pica aquí per tornar a activar les notificacions."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 73ef49e..80979c0 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth sense fil"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configura mètodes d\'entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilitza un teclat físic"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs-xlarge/strings.xml b/packages/SystemUI/res/values-cs-xlarge/strings.xml
index 5fe365c..05b1248 100644
--- a/packages/SystemUI/res/values-cs-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-cs-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: připojeno"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Vyhledávání satelitů GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Poloha nastavena pomocí GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Oznámení jsou vypnuta"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Chcete-li oznámení znovu zapnout, klepněte sem."</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 66eecd6..31bf102 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Nakonfigurovat metody vstupu"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Použít fyz. klávesnici"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da-xlarge/strings.xml b/packages/SystemUI/res/values-da-xlarge/strings.xml
index ae430b3..dd20e64 100644
--- a/packages/SystemUI/res/values-da-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-da-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi er forbundet"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Søger efter GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Placeringen er angivet ved hjælp af GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Meddelelser: Fra"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tryk her for at slå meddelelser til igen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 15f370b..3a08cc1 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-tethering anvendt"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurer inputmetoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Brug fysisk tastatur"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de-xlarge/strings.xml b/packages/SystemUI/res/values-de-xlarge/strings.xml
index 825cd0d..cc782da 100644
--- a/packages/SystemUI/res/values-de-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-de-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Mit WLAN verbunden"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Suche nach GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Standort durch GPS festgelegt"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Benachrichtigungen aus"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tippen Sie hier, um Benachrichtigungen wieder einzuschalten."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e13f723..91e56d4 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Eingabemethoden konfigurieren"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Physische Tastatur"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el-xlarge/strings.xml b/packages/SystemUI/res/values-el-xlarge/strings.xml
index 4902bb5..4f7814a 100644
--- a/packages/SystemUI/res/values-el-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-el-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: συνδέθηκε"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Αναζήτηση για GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Ρύθμιση τοποθεσίας με GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Ειδοποιήσεις ανενεργές"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Πατήστε εδώ για να ενεργοποιήσετε τις ειδοποιήσεις"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 069277d..3bc5636 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Έγινε σύνδεση μέσω Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Διαμόρφωση μεθόδων εισαγωγής"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Χρήση κανονικού πληκτρολ."</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml b/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
index de1eb52..68986f0 100644
--- a/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi connected"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Searching for GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Location set by GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notifications off"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tap here to turn notifications back on."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9efd6b2..2e5a722 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tethered"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configure input methods"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Use physical keyboard"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
index 2ace144..fa9b762 100644
--- a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"WiFi conectado"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"La ubicación se estableció por GPS."</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificaciones desactivadas"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Presiona aquí para volver a activar las notificaciones."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 8f477c8..19d72c7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Usar teclado físico"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-xlarge/strings.xml b/packages/SystemUI/res/values-es-xlarge/strings.xml
index dd490fb..a7588da 100644
--- a/packages/SystemUI/res/values-es-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Con conexión WiFi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Ubicación definida por GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificaciones desactivadas"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Toca aquí para volver a activar las notificaciones."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 25465d9..e410f6e 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de introducción"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizar teclado físico"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa-xlarge/strings.xml b/packages/SystemUI/res/values-fa-xlarge/strings.xml
index 6e0654d..a8e2543 100644
--- a/packages/SystemUI/res/values-fa-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fa-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi متصل شد"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"جستجوی GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"مکان تنظیم شده توسط GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"اعلان ها خاموش"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"برای روشن کردن مجدد اعلان ها، اینجا را ضربه بزنید."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4e15435..c9a1a7f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"پیکربندی روش های ورودی"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"از صفحه کلید فیزیکی استفاده کنید"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi-xlarge/strings.xml b/packages/SystemUI/res/values-fi-xlarge/strings.xml
index 7d49e9b..754c577 100644
--- a/packages/SystemUI/res/values-fi-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fi-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wifi yhdistetty"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Haetaan GPS-yhteyttä"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Sijainti määritetty GPS:n avulla"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Ilmoitukset pois käytöstä"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Ota ilmoitukset uudelleen käyttöön napauttamalla tätä."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 252b97f..882261d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth yhdistetty"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Määritä syöttötavat"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Käytä fyysistä näppäimistöä"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-xlarge/strings.xml b/packages/SystemUI/res/values-fr-xlarge/strings.xml
index 98dc6c0..08f673d 100644
--- a/packages/SystemUI/res/values-fr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-fr-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Connecté au Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Recherche de GPS en cours"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Position définie par GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notifications désactivées"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Appuyez ici pour réactiver les notifications."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b903452..2b23276 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Connexion Bluetooth partagée"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurer les modes de saisie"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utiliser clavier physique"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr-xlarge/strings.xml b/packages/SystemUI/res/values-hr-xlarge/strings.xml
index 08adaf0..b6e15dc 100644
--- a/packages/SystemUI/res/values-hr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-hr-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: povezano"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Pretraživanje GPS-a"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Lokaciju utvrdio GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Obavijesti isključene"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Dotaknite ovdje da biste ponovo uključili obavijesti."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 916f2c3..dad674b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth posredno povezan"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfiguriraj načine ulaza"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Rabi fizičku tipkovnicu"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu-xlarge/strings.xml b/packages/SystemUI/res/values-hu-xlarge/strings.xml
index 41d60fc..fe2e5ee 100644
--- a/packages/SystemUI/res/values-hu-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-hu-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi csatlakozva"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"GPS keresése"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"A GPS beállította a helyet"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Értesítések kikapcsolva"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Itt érintse meg az értesítések bekapcsolásához."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f41c89c..9da81ab 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth megosztva"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Beviteli módok konfigurálása"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Valódi bill. használata"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in-xlarge/strings.xml b/packages/SystemUI/res/values-in-xlarge/strings.xml
index 8d95060..a4ca341 100644
--- a/packages/SystemUI/res/values-in-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-in-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi tersambung"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Menelusuri GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Lokasi yang disetel oleh GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Pemberitahuan mati"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Ketuk di sini untuk menghidupkan lagi pemberitahuan."</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 0d5b411..0ade50c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tertambat"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurasikan metode masukan"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Gunakan keyboard fisik"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it-xlarge/strings.xml b/packages/SystemUI/res/values-it-xlarge/strings.xml
index 68393fb..24d88744 100644
--- a/packages/SystemUI/res/values-it-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-it-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: connesso"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Ricerca del GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Posizione stabilita dal GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notifiche disattivate"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tocca qui per riattivare le notifiche."</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index c94dbb5..71e86da 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth con tethering"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configura metodi di input"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizza tastiera fisica"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw-xlarge/strings.xml b/packages/SystemUI/res/values-iw-xlarge/strings.xml
index fd3ce0e..97172b8 100644
--- a/packages/SystemUI/res/values-iw-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-iw-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi מחובר"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"מחפש GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"מיקום מוגדר על ידי GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"מצב התראות כבוי"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"הקש כאן כדי להפעיל מחדש את ההתראות."</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 85beeb3..4e78670 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth קשור"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"הגדר שיטות קלט"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"השתמש במקלדת הפיזית"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja-xlarge/strings.xml b/packages/SystemUI/res/values-ja-xlarge/strings.xml
index c7c0824..e67e0e1 100644
--- a/packages/SystemUI/res/values-ja-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ja-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi接続済み"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"GPSで検索中"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPSにより現在地が設定されました"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"通知OFF"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"通知を有効にするにはここをタップします。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9cb8189..86a5da5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetoothテザリング接続"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"入力方法の設定"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"物理キーボードを使用"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko-xlarge/strings.xml b/packages/SystemUI/res/values-ko-xlarge/strings.xml
index 3777154..e28ac63 100644
--- a/packages/SystemUI/res/values-ko-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ko-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 연결됨"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"GPS 검색"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPS에서 설정한 위치"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"알림 사용 안함"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"알림을 다시 사용하려면 여기를 누르세요."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4504f61..440ebb6 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"블루투스 테더링됨"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"입력 방법 구성"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"물리적 키보드 사용"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt-xlarge/strings.xml b/packages/SystemUI/res/values-lt-xlarge/strings.xml
index 90dd501..12e8bb3 100644
--- a/packages/SystemUI/res/values-lt-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-lt-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Prisijungta prie „Wi-Fi“"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Ieškoma GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPS nustatyta vieta"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Pranešimai išjungti"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Palieskite čia, kad vėl įjungtumėte pranešimus."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5985ee6..9bf5f74 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"„Bluetooth“ susieta"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigūruoti įvesties metodus"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Naudoti fizinę klaviatūrą"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv-xlarge/strings.xml b/packages/SystemUI/res/values-lv-xlarge/strings.xml
index c533ecb..aecb471 100644
--- a/packages/SystemUI/res/values-lv-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-lv-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Izv. sav. ar Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Notiek GPS meklēšana..."</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPS iestatītā atrašanās vieta"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Paziņojumi ir izslēgti."</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Pieskarieties šeit, lai vēlreiz ieslēgtu paziņojumus."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 808d374..5c14342 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth piesaiste"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurēt ievades metodes"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Izmantot fizisku tastatūru"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb-xlarge/strings.xml b/packages/SystemUI/res/values-nb-xlarge/strings.xml
index 2bf63e8..717ee79 100644
--- a/packages/SystemUI/res/values-nb-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-nb-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: tilkoblet"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Søker etter GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Posisjon angitt av GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Varslinger er slått av"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Trykk her for å slå på varslinger igjen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e23a17f..1671dcf 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurer inndatametoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Bruk fysisk tastatur"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl-xlarge/strings.xml b/packages/SystemUI/res/values-nl-xlarge/strings.xml
index 7a63401..7c84a7a 100644
--- a/packages/SystemUI/res/values-nl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-nl-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Verbonden via Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Zoeken naar GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Locatie bepaald met GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Meldingen uit"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tik hier om meldingen weer in te schakelen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 56136fa..ac3255f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth getetherd"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Invoermethoden configureren"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Fysiek toetsenbord gebruiken"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl-xlarge/strings.xml b/packages/SystemUI/res/values-pl-xlarge/strings.xml
index 1334b70..9db1cab 100644
--- a/packages/SystemUI/res/values-pl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pl-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: połączono"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Wyszukiwanie sygnału GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Lokalizacja ustawiona wg GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Powiadomienia wyłączone"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Dotknij tutaj, aby z powrotem włączyć powiadomienia."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7ccb037..1af9d68 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth – podłączono"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfiguruj metody wprowadzania"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Używaj klawiatury fizycznej"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml b/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
index a5d6bac..7860208 100644
--- a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi ligado"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"A procurar GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Localização definida por GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificações desativadas"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Toque aqui para voltar a ativar as notificações."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 088240c..2f0e269 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ligado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizar teclado físico"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-xlarge/strings.xml b/packages/SystemUI/res/values-pt-xlarge/strings.xml
index 5209ab9..2a1786d 100644
--- a/packages/SystemUI/res/values-pt-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-pt-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Procurando GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Localização definida por GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificações desativadas"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Toque aqui para ativar novamente as notificações."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 7636aed..d9e68e8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configurar métodos de entrada"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Usar o teclado físico"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index debba7a..aa35dd4 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -61,4 +61,20 @@
<skip />
<!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
<skip />
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro-xlarge/strings.xml b/packages/SystemUI/res/values-ro-xlarge/strings.xml
index 2dedd3b..21fd0ad 100644
--- a/packages/SystemUI/res/values-ro-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ro-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi conectat"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Se caută dispozitivul GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Locaţie setată prin GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Notificările sunt dezactivate"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Apăsaţi aici pentru a reactiva notificările."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e62eb6e..4c14b7d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Configuraţi metode de intrare"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Utilizaţi tastat. fizică"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru-xlarge/strings.xml b/packages/SystemUI/res/values-ru-xlarge/strings.xml
index 212fa83..bc31fb1 100644
--- a/packages/SystemUI/res/values-ru-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-ru-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi подкл."</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Выполняется поиск при помощи GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Местоположение установлено при помощи GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Показ уведомлений отключен"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Нажмите здесь, чтобы снова включить показ уведомлений."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d57289e..2e2de6e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Общий модем доступен через Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Настроить способ ввода"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Использовать физическую клавиатуру"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk-xlarge/strings.xml b/packages/SystemUI/res/values-sk-xlarge/strings.xml
index 0fcdd4a..ee9e613 100644
--- a/packages/SystemUI/res/values-sk-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sk-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi: pripojené"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Hľadanie signálu GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Poloha určená pomocou GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Upozornenia sú vypnuté"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Klepnutím tu upozornenia znova povolíte."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 78a7149..12d40ae 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Zdieľané dátové pripojenie cez Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurovať metódy vstupu"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Použiť fyzickú klávesnicu"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl-xlarge/strings.xml b/packages/SystemUI/res/values-sl-xlarge/strings.xml
index 615c565..57ed9a7 100644
--- a/packages/SystemUI/res/values-sl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sl-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi – povezano"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Iskanje GPS-a"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Lokacija nastavljena z GPS-om"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Obvestila izklopljena"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Tapnite tukaj, da spet vklopite obvestila."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index be77583..62d946a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetna povezava prek Bluetootha"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Nastavitev načinov vnosa"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Uporabi fizično tipkovn."</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr-xlarge/strings.xml b/packages/SystemUI/res/values-sr-xlarge/strings.xml
index d66765b..95fbc2f 100644
--- a/packages/SystemUI/res/values-sr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sr-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi је повезан"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Тражи се GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Локацију је подесио GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Обавештења су искључена"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Додирните овде да бисте поново укључили обавештења."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 2e9a18b..e319132 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Веза преко Bluetooth-а"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Конфигуриши методе уноса"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Користи физичку тастатуру"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv-xlarge/strings.xml b/packages/SystemUI/res/values-sv-xlarge/strings.xml
index b53269e..ce608c2 100644
--- a/packages/SystemUI/res/values-sv-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-sv-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi-ansluten"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Sökning efter GPS pågår"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Platsen har identifierats av GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Aviseringar inaktiverade"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Knacka lätt här om du vill aktivera aviseringar igen."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 041d309..ba9f55e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetdelning via Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurera inmatningsmetoder"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Använd fysiska tangenter"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th-xlarge/strings.xml b/packages/SystemUI/res/values-th-xlarge/strings.xml
index 8222140..824de38 100644
--- a/packages/SystemUI/res/values-th-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-th-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"เชื่อมต่อ Wi-Fi แล้ว"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"การค้นหาสำหรับ GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"ตำแหน่งที่กำหนดโดย GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"การแจ้งเตือนปิดอยู่"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"แตะที่นี่เพื่อเปิดการแจ้งเตือนอีกครั้ง"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 4cac345..192fe2c 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"บลูทูธที่ปล่อยสัญญาณ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"กำหนดค่าวิธีการป้อนข้อมูล"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"ใช้แป้นพิมพ์จริง"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl-xlarge/strings.xml b/packages/SystemUI/res/values-tl-xlarge/strings.xml
index 0eef090..582adbc 100644
--- a/packages/SystemUI/res/values-tl-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-tl-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Konektado ang WiFi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Naghahanap ng GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Lokasyon na itinatakda ng GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Naka-off ang mga notification"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Mag-tap dito upang i-on muli ang mga notification."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 8d10afd..a99014d 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Na-tether ang bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"I-configure paraan ng input"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Gamitin ang pisikal na keyboard"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr-xlarge/strings.xml b/packages/SystemUI/res/values-tr-xlarge/strings.xml
index 8c382fb..6db515f 100644
--- a/packages/SystemUI/res/values-tr-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-tr-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Kablosuz bağlandı"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"GPS aranıyor"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Konum GPS ile belirlendi"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Bildirimler kapalı"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Bildirimleri tekrar açmak için buraya hafifçe vurun."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d6f1482..2019a38 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth paylaşımı tamam"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Giriş yöntemlerini yapılandır"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Fiziksel klavyeyi kullan"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk-xlarge/strings.xml b/packages/SystemUI/res/values-uk-xlarge/strings.xml
index 6b1b193..81e50c0 100644
--- a/packages/SystemUI/res/values-uk-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-uk-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi під\'єднано"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Виконується пошук за допомогою GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Місцезнаходження встановлено за допомогою GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Сповіщення вимкнено"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Торкніться тут, щоб знову ввімкнути сповіщення."</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 1d4694b..999ea9a 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Створено прив\'язку Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Налаштувати методи введення"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Викор. реальну клавіатуру"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi-xlarge/strings.xml b/packages/SystemUI/res/values-vi-xlarge/strings.xml
index b44e1c3..6382fae 100644
--- a/packages/SystemUI/res/values-vi-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-vi-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Đã kết nối Wi-Fi"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"Tìm kiếm GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"Vị trí đặt bởi GPS"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"Tắt thông báo"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"Chạm vào đây để bật lại thông báo."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b1eaa8b..dd286800 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth được dùng làm điểm truy cập Internet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Định cấu hình phương pháp nhập liệu"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Sử dụng bàn phím vật lý"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
index f599dca..207ebe4 100644
--- a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 已连接"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"正在搜索 GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPS 设置的位置"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"通知已关闭"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"点按此处可以重新打开通知。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3a5f88b..d2a5578 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"蓝牙已绑定"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"配置输入法"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"使用物理键盘"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
index 2191db7..14a10f2 100644
--- a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
@@ -24,8 +24,6 @@
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"Wi-Fi 已連線"</string>
<string name="gps_notification_searching_text" msgid="894185519046488403">"正在搜尋 GPS"</string>
<string name="gps_notification_found_text" msgid="5306445324124275852">"GPS 已定位"</string>
- <!-- no translation found for notifications_off_title (2297252328026582111) -->
- <skip />
- <!-- no translation found for notifications_off_text (3754847213329718358) -->
- <skip />
+ <string name="notifications_off_title" msgid="2297252328026582111">"關閉通知"</string>
+ <string name="notifications_off_text" msgid="3754847213329718358">"輕觸這裡即可重新開啟通知。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 203cd08..f165bee 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -45,4 +45,20 @@
<string name="bluetooth_tethered" msgid="7094101612161133267">"已透過藍牙進行網際網路共用"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"設定輸入方式"</string>
<string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"使用實體鍵盤"</string>
+ <!-- no translation found for usb_device_permission_prompt (5340926456453429244) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (1896291816269399727) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for label_ignore (5473234388203739668) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ebd48e7..8998674 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -115,4 +115,29 @@
<!-- Label of a toggle switch to disable use of the physical keyboard in favor of the IME. [CHAR LIMIT=25] -->
<string name="status_bar_use_physical_keyboard">Use physical keyboard</string>
+
+ <!-- Prompt for the USB device permission dialog [CHAR LIMIT=80] -->
+ <string name="usb_device_permission_prompt">Allow the application %1$s to access the USB device?</string>
+
+ <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_permission_prompt">Allow the application %1$s to access the USB accessory?</string>
+
+ <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
+ <string name="usb_device_confirm_prompt">Open %1$s when this USB device is connected?</string>
+
+ <!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_confirm_prompt">Open %1$s when this USB accessory is connected?</string>
+
+ <!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_uri_prompt">Additional information for this device may be found at: %1$s</string>
+
+ <!-- Title for USB accessory dialog. Used when the name of the accessory cannot be determined. [CHAR LIMIT=50] -->
+ <string name="title_usb_accessory">USB accessory</string>
+
+ <!-- View button label for USB dialogs. [CHAR LIMIT=15] -->
+ <string name="label_view">View</string>
+
+ <!-- Ignore button label for USB dialogs. [CHAR LIMIT=15] -->
+ <string name="label_ignore">Ignore</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index b17e41b..69585ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -94,6 +94,7 @@
int mWifiLevel;
String mWifiSsid;
int mWifiIconId = 0;
+ int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
// bluetooth
private boolean mBluetoothTethered = false;
@@ -153,9 +154,7 @@
// wifi
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- HandlerThread handlerThread = new HandlerThread("WifiServiceThread");
- handlerThread.start();
- Handler handler = new WifiHandler(handlerThread.getLooper());
+ Handler handler = new WifiHandler();
mWifiChannel = new AsyncChannel();
Messenger wifiMessenger = mWifiManager.getMessenger();
if (wifiMessenger != null) {
@@ -549,11 +548,6 @@
// ===== Wifi ===================================================================
class WifiHandler extends Handler {
-
- WifiHandler(Looper looper) {
- super(looper);
- }
-
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -566,17 +560,9 @@
}
break;
case WifiManager.DATA_ACTIVITY_NOTIFICATION:
- int dataActivity = msg.arg1;
- /* TODO: update icons based on data activity */
- switch (dataActivity) {
- case WifiManager.DATA_ACTIVITY_IN:
- break;
- case WifiManager.DATA_ACTIVITY_OUT:
- break;
- case WifiManager.DATA_ACTIVITY_INOUT:
- break;
- case WifiManager.DATA_ACTIVITY_NONE:
- break;
+ if (msg.arg1 != mWifiActivity) {
+ mWifiActivity = msg.arg1;
+ refreshViews();
}
break;
default:
@@ -697,6 +683,19 @@
label = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
} else {
label = mWifiSsid;
+ switch (mWifiActivity) {
+ case WifiManager.DATA_ACTIVITY_IN:
+ dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_in;
+ break;
+ case WifiManager.DATA_ACTIVITY_OUT:
+ dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_out;
+ break;
+ case WifiManager.DATA_ACTIVITY_INOUT:
+ dataDirectionOverlayIconId = R.drawable.stat_sys_wifi_inout;
+ break;
+ case WifiManager.DATA_ACTIVITY_NONE:
+ break;
+ }
}
combinedSignalIconId = mWifiIconId;
dataTypeIconId = 0;
@@ -884,6 +883,9 @@
pw.println(mWifiSsid);
pw.print(" mWifiIconId=");
pw.println(mWifiIconId);
+ pw.print(" mWifiActivity=");
+ pw.println(mWifiActivity);
+
pw.println(" - Bluetooth ----");
pw.print(" mBtReverseTethered=");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index 737a52b..c5a7df2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -513,9 +513,7 @@
paint.setFilterBitmap(true);
paint.setAlpha(255);
final int srcWidth = thumbnail.getWidth();
- final int height = thumbnail.getHeight();
- final int srcHeight = srcWidth > height ? height
- : (height - height * srcWidth / height);
+ final int srcHeight = thumbnail.getHeight();
canvas.drawBitmap(thumbnail,
new Rect(0, 0, srcWidth-1, srcHeight-1),
new RectF(GLOW_PADDING,
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
new file mode 100644
index 0000000..eefb1c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+/**
+ * If the attached USB accessory has a URL associated with it, and that URL is valid,
+ * show this dialog to the user to allow them to optionally visit that URL for more
+ * information or software downloads.
+ * Otherwise (no valid URL) this activity does nothing at all, finishing immediately.
+ */
+public class UsbAccessoryUriActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+
+ private static final String TAG = "UsbAccessoryUriActivity";
+
+ private UsbAccessory mAccessory;
+ private Uri mUri;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ String uriString = intent.getStringExtra("uri");
+ mUri = (uriString == null ? null : Uri.parse(uriString));
+
+ // sanity check before displaying dialog
+ if (mUri == null) {
+ Log.e(TAG, "could not parse Uri " + uriString);
+ finish();
+ return;
+ }
+ String scheme = mUri.getScheme();
+ if (!"http".equals(scheme) && !"https".equals(scheme)) {
+ Log.e(TAG, "Uri not http or https: " + mUri);
+ finish();
+ return;
+ }
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mTitle = mAccessory.getDescription();
+ if (ap.mTitle == null || ap.mTitle.length() == 0) {
+ ap.mTitle = getString(R.string.title_usb_accessory);
+ }
+ ap.mMessage = getString(R.string.usb_accessory_uri_prompt, mUri);
+ ap.mPositiveButtonText = getString(R.string.label_view);
+ ap.mNegativeButtonText = getString(R.string.label_ignore);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ setupAlert();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ // launch the browser
+ Intent intent = new Intent(Intent.ACTION_VIEW, mUri);
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed for " + mUri);
+ }
+ }
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
new file mode 100644
index 0000000..4e6f81f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbConfirmActivity extends AlertActivity
+ implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+ private static final String TAG = "UsbConfirmActivity";
+
+ private CheckBox mAlwaysUse;
+ private TextView mClearDefaultHint;
+ private UsbDevice mDevice;
+ private UsbAccessory mAccessory;
+ private ResolveInfo mResolveInfo;
+ private boolean mPermissionGranted;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo");
+
+ PackageManager packageManager = getPackageManager();
+ String appName = mResolveInfo.loadLabel(packageManager).toString();
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mIcon = mResolveInfo.loadIcon(packageManager);
+ ap.mTitle = appName;
+ if (mDevice == null) {
+ ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ } else {
+ ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+ }
+ ap.mPositiveButtonText = getString(com.android.internal.R.string.ok);
+ ap.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ // add "always use" checkbox
+ LayoutInflater inflater = (LayoutInflater)getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ mAlwaysUse.setText(com.android.internal.R.string.alwaysUse);
+ mAlwaysUse.setOnCheckedChangeListener(this);
+ mClearDefaultHint = (TextView)ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
+
+ setupAlert();
+
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ try {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+ int uid = mResolveInfo.activityInfo.applicationInfo.uid;
+ boolean alwaysUse = mAlwaysUse.isChecked();
+ Intent intent = null;
+
+ if (mDevice != null) {
+ intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+
+ // grant permission for the device
+ service.grantDevicePermission(mDevice, uid);
+ // set or clear default setting
+ if (alwaysUse) {
+ service.setDevicePackage(mDevice, mResolveInfo.activityInfo.packageName);
+ } else {
+ service.setDevicePackage(mDevice, null);
+ }
+ } else if (mAccessory != null) {
+ intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+
+ // grant permission for the accessory
+ service.grantAccessoryPermission(mAccessory, uid);
+ // set or clear default setting
+ if (alwaysUse) {
+ service.setAccessoryPackage(mAccessory,
+ mResolveInfo.activityInfo.packageName);
+ } else {
+ service.setAccessoryPackage(mAccessory, null);
+ }
+ }
+
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(
+ new ComponentName(mResolveInfo.activityInfo.packageName,
+ mResolveInfo.activityInfo.name));
+ startActivity(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start activity", e);
+ }
+ }
+ finish();
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mClearDefaultHint == null) return;
+
+ if(isChecked) {
+ mClearDefaultHint.setVisibility(View.VISIBLE);
+ } else {
+ mClearDefaultHint.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
new file mode 100644
index 0000000..1edebbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+
+// This class is used to close UsbPermissionsActivity and UsbResolverActivity
+// if their device/accessory is disconnected while the dialog is still open
+class UsbDisconnectedReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ private UsbDevice mDevice;
+ private UsbAccessory mAccessory;
+
+ public UsbDisconnectedReceiver(Activity activity, UsbDevice device) {
+ mActivity = activity;
+ mDevice = device;
+
+ IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
+ activity.registerReceiver(this, filter);
+ }
+
+ public UsbDisconnectedReceiver(Activity activity, UsbAccessory accessory) {
+ mActivity = activity;
+ mAccessory = accessory;
+
+ IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ activity.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ if (device != null && device.equals(mDevice)) {
+ mActivity.finish();
+ }
+ } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+ UsbAccessory accessory =
+ (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory != null && accessory.equals(mAccessory)) {
+ mActivity.finish();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
new file mode 100644
index 0000000..27cce6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbPermissionActivity extends AlertActivity
+ implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+ private static final String TAG = "UsbPermissionActivity";
+
+ private CheckBox mAlwaysUse;
+ private TextView mClearDefaultHint;
+ private UsbDevice mDevice;
+ private UsbAccessory mAccessory;
+ private PendingIntent mPendingIntent;
+ private String mPackageName;
+ private int mUid;
+ private boolean mPermissionGranted;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ mUid = intent.getIntExtra("uid", 0);
+ mPackageName = intent.getStringExtra("package");
+
+ PackageManager packageManager = getPackageManager();
+ ApplicationInfo aInfo;
+ try {
+ aInfo = packageManager.getApplicationInfo(mPackageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "unable to look up package name", e);
+ finish();
+ return;
+ }
+ String appName = aInfo.loadLabel(packageManager).toString();
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mIcon = aInfo.loadIcon(packageManager);
+ ap.mTitle = appName;
+ if (mDevice == null) {
+ ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ } else {
+ ap.mMessage = getString(R.string.usb_device_permission_prompt, appName);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+ }
+ ap.mPositiveButtonText = getString(com.android.internal.R.string.ok);
+ ap.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ // add "always use" checkbox
+ LayoutInflater inflater = (LayoutInflater)getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ mAlwaysUse.setText(com.android.internal.R.string.alwaysUse);
+ mAlwaysUse.setOnCheckedChangeListener(this);
+ mClearDefaultHint = (TextView)ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
+
+ setupAlert();
+
+ }
+
+ @Override
+ public void onDestroy() {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+
+ // send response via pending intent
+ Intent intent = new Intent();
+ try {
+ if (mDevice != null) {
+ intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
+ if (mPermissionGranted) {
+ service.grantDevicePermission(mDevice, mUid);
+ if (mAlwaysUse.isChecked()) {
+ service.setDevicePackage(mDevice, mPackageName);
+ }
+ }
+ }
+ if (mAccessory != null) {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+ if (mPermissionGranted) {
+ service.grantAccessoryPermission(mAccessory, mUid);
+ if (mAlwaysUse.isChecked()) {
+ service.setAccessoryPackage(mAccessory, mPackageName);
+ }
+ }
+ }
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
+ mPendingIntent.send(this, 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "PendingIntent was cancelled");
+ } catch (RemoteException e) {
+ Log.e(TAG, "IUsbService connection failed", e);
+ }
+
+ if (mDisconnectedReceiver != null) {
+ unregisterReceiver(mDisconnectedReceiver);
+ }
+ super.onDestroy();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ mPermissionGranted = true;
+ }
+ finish();
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mClearDefaultHint == null) return;
+
+ if(isChecked) {
+ mClearDefaultHint.setVisibility(View.VISIBLE);
+ } else {
+ mClearDefaultHint.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/services/java/com/android/server/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
similarity index 66%
rename from services/java/com/android/server/usb/UsbResolverActivity.java
rename to packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index e8a09a5..7c63820 100644
--- a/services/java/com/android/server/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.usb;
+package com.android.systemui.usb;
import com.android.internal.app.ResolverActivity;
@@ -39,6 +39,10 @@
public static final String TAG = "UsbResolverActivity";
public static final String EXTRA_RESOLVE_INFOS = "rlist";
+ private UsbDevice mDevice;
+ private UsbAccessory mAccessory;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
@@ -50,14 +54,30 @@
}
Intent target = (Intent)targetParcelable;
ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
- Log.d(TAG, "rList.size() " + rList.size());
CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
super.onCreate(savedInstanceState, target, title, null, rList,
- true, /* Set alwaysUseOption to true to enable "always use this app" checkbox. */
- true /* Set alwaysChoose to display activity when only one choice is available.
- This is necessary because this activity is needed for the user to allow
- the application permission to access the device */
- );
+ true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
+
+ mDevice = (UsbDevice)target.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ if (mDevice != null) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+ } else {
+ mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (mAccessory == null) {
+ Log.e(TAG, "no device or accessory");
+ finish();
+ return;
+ }
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mDisconnectedReceiver != null) {
+ unregisterReceiver(mDisconnectedReceiver);
+ }
+ super.onDestroy();
}
protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
@@ -65,28 +85,24 @@
IBinder b = ServiceManager.getService(USB_SERVICE);
IUsbManager service = IUsbManager.Stub.asInterface(b);
int uid = ri.activityInfo.applicationInfo.uid;
- String action = intent.getAction();
- if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
- UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ if (mDevice != null) {
// grant permission for the device
- service.grantDevicePermission(device, uid);
+ service.grantDevicePermission(mDevice, uid);
// set or clear default setting
if (alwaysCheck) {
- service.setDevicePackage(device, ri.activityInfo.packageName);
+ service.setDevicePackage(mDevice, ri.activityInfo.packageName);
} else {
- service.setDevicePackage(device, null);
+ service.setDevicePackage(mDevice, null);
}
- } else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
- UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(
- UsbManager.EXTRA_ACCESSORY);
+ } else if (mAccessory != null) {
// grant permission for the accessory
- service.grantAccessoryPermission(accessory, uid);
+ service.grantAccessoryPermission(mAccessory, uid);
// set or clear default setting
if (alwaysCheck) {
- service.setAccessoryPackage(accessory, ri.activityInfo.packageName);
+ service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
} else {
- service.setAccessoryPackage(accessory, null);
+ service.setAccessoryPackage(mAccessory, null);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index 8d70a7b..ae23df6 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -103,6 +103,8 @@
int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
| WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
| WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
/*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
if (!mNeedsInput) {
@@ -142,7 +144,7 @@
mKeyguardView.onScreenTurnedOn();
}
}
-
+ mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
mKeyguardHost.setVisibility(View.VISIBLE);
mKeyguardView.requestFocus();
}
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 2bc57b5..a9d5ce4 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -232,6 +232,8 @@
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
+ if (DBG) Log.v(TAG, "*** LockScreen accel is "
+ + (mEnergyWave.isHardwareAccelerated() ? "on":"off"));
// Don't poke the wake lock when returning to a state where the handle is
// not grabbed since that can happen when the system (instead of the user)
// cancels the grab.
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index e37a6b1..e2da740 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -820,8 +820,10 @@
bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
|| containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
sizeof_bit_array(KEY_MAX + 1));
- bool haveGamepadButtons =containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
- sizeof_bit_array(BTN_DIGI));
+ bool haveGamepadButtons = containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_MISC),
+ sizeof_bit_array(BTN_MOUSE))
+ || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
+ sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
@@ -850,6 +852,16 @@
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
}
+ // See if this device is a joystick.
+ // Ignore touchscreens because they use the same absolute axes for other purposes.
+ // Assumes that joysticks always have gamepad buttons in order to distinguish them
+ // from other devices such as accelerometers that also have absolute axes.
+ if (haveGamepadButtons
+ && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
+ && containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
+ device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
+ }
+
// figure out the switches this device reports
bool haveSwitches = false;
for (int i=0; i<EV_SW; i++) {
@@ -874,15 +886,21 @@
}
}
- if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
+ // Load the key map.
+ // We need to do this for joysticks too because the key layout may specify axes.
+ status_t keyMapStatus = NAME_NOT_FOUND;
+ if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
// Load the keymap for the device.
- status_t status = loadKeyMap(device);
+ keyMapStatus = loadKeyMap(device);
+ }
+ // Configure the keyboard, gamepad or virtual keyboard.
+ if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Set system properties for the keyboard.
setKeyboardProperties(device, false);
// Register the keyboard as a built-in keyboard if it is eligible.
- if (!status
+ if (!keyMapStatus
&& mBuiltInKeyboardId == -1
&& isEligibleBuiltInKeyboard(device->identifier,
device->configuration, &device->keyMap)) {
@@ -913,16 +931,6 @@
}
}
- // See if this device is a joystick.
- // Ignore touchscreens because they use the same absolute axes for other purposes.
- // Assumes that joysticks always have buttons and the keymap has been loaded.
- if (device->classes & INPUT_DEVICE_CLASS_GAMEPAD
- && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
- if (containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
- device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
- }
- }
-
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
LOGV("Dropping device: id=%d, path='%s', name='%s'",
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index ab42a1f..7053a94 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -85,8 +85,6 @@
int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
- inline int32_t getRange() const { return maxValue - minValue; }
-
inline void clear() {
valid = false;
minValue = 0;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index e614e81..19295e6d 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -2245,6 +2245,21 @@
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
+ if (policyFlags & POLICY_FLAG_ALT) {
+ metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
+ }
+ if (policyFlags & POLICY_FLAG_ALT_GR) {
+ metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
+ }
+ if (policyFlags & POLICY_FLAG_SHIFT) {
+ metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
+ }
+ if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
+ metaState |= AMETA_CAPS_LOCK_ON;
+ }
+ if (policyFlags & POLICY_FLAG_FUNCTION) {
+ metaState |= AMETA_FUNCTION_ON;
+ }
policyFlags |= POLICY_FLAG_TRUSTED;
@@ -2328,17 +2343,17 @@
}
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- if (motionEntry->deviceId != deviceId) {
- // Keep looking for this device.
+ if (motionEntry->deviceId != deviceId
+ || motionEntry->source != source) {
+ // Keep looking for this device and source.
continue;
}
if (motionEntry->action != action
- || motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
- // Last motion event in the queue for this device is not compatible for
- // appending new samples. Stop here.
+ // Last motion event in the queue for this device and source is
+ // not compatible for appending new samples. Stop here.
goto NoBatchingOrStreaming;
}
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 00c3eb7..3029028 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -33,6 +33,7 @@
// Log debug messages about pointer assignment calculations.
#define DEBUG_POINTER_ASSIGNMENT 0
+
#include "InputReader.h"
#include <cutils/log.h>
@@ -88,6 +89,18 @@
return value ? "true" : "false";
}
+static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
+ const int32_t map[][4], size_t mapSize) {
+ if (orientation != DISPLAY_ORIENTATION_0) {
+ for (size_t i = 0; i < mapSize; i++) {
+ if (value == map[i][0]) {
+ return map[i][orientation];
+ }
+ }
+ }
+ return value;
+}
+
static const int32_t keyCodeRotationMap[][4] = {
// key codes enumerated counter-clockwise with the original (unrotated) key first
// no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
@@ -96,24 +109,80 @@
{ AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT },
{ AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP },
};
-static const int keyCodeRotationMapSize =
+static const size_t keyCodeRotationMapSize =
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
- if (orientation != DISPLAY_ORIENTATION_0) {
- for (int i = 0; i < keyCodeRotationMapSize; i++) {
- if (keyCode == keyCodeRotationMap[i][0]) {
- return keyCodeRotationMap[i][orientation];
- }
- }
- }
- return keyCode;
+ return rotateValueUsingRotationMap(keyCode, orientation,
+ keyCodeRotationMap, keyCodeRotationMapSize);
+}
+
+static const int32_t edgeFlagRotationMap[][4] = {
+ // edge flags enumerated counter-clockwise with the original (unrotated) edge flag first
+ // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
+ { AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT,
+ AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT },
+ { AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP,
+ AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM },
+ { AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT,
+ AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT },
+ { AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+ AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP },
+};
+static const size_t edgeFlagRotationMapSize =
+ sizeof(edgeFlagRotationMap) / sizeof(edgeFlagRotationMap[0]);
+
+static int32_t rotateEdgeFlag(int32_t edgeFlag, int32_t orientation) {
+ return rotateValueUsingRotationMap(edgeFlag, orientation,
+ edgeFlagRotationMap, edgeFlagRotationMapSize);
}
static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
}
+static uint32_t getButtonStateForScanCode(int32_t scanCode) {
+ // Currently all buttons are mapped to the primary button.
+ switch (scanCode) {
+ case BTN_LEFT:
+ case BTN_RIGHT:
+ case BTN_MIDDLE:
+ case BTN_SIDE:
+ case BTN_EXTRA:
+ case BTN_FORWARD:
+ case BTN_BACK:
+ case BTN_TASK:
+ return BUTTON_STATE_PRIMARY;
+ default:
+ return 0;
+ }
+}
+
+// Returns true if the pointer should be reported as being down given the specified
+// button states.
+static bool isPointerDown(uint32_t buttonState) {
+ return buttonState & BUTTON_STATE_PRIMARY;
+}
+
+static int32_t calculateEdgeFlagsUsingPointerBounds(
+ const sp<PointerControllerInterface>& pointerController, float x, float y) {
+ int32_t edgeFlags = 0;
+ float minX, minY, maxX, maxY;
+ if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
+ if (x <= minX) {
+ edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
+ } else if (x >= maxX) {
+ edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+ }
+ if (y <= minY) {
+ edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
+ } else if (y >= maxY) {
+ edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+ }
+ }
+ return edgeFlags;
+}
+
// --- InputReader ---
@@ -244,23 +313,23 @@
}
// Keyboard-like devices.
- uint32_t keyboardSources = 0;
+ uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
- keyboardSources |= AINPUT_SOURCE_KEYBOARD;
+ keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
- keyboardSources |= AINPUT_SOURCE_DPAD;
+ keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
- keyboardSources |= AINPUT_SOURCE_GAMEPAD;
+ keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
- if (keyboardSources != 0) {
- device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType));
+ if (keyboardSource != 0) {
+ device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
}
// Cursor-like devices.
@@ -591,22 +660,22 @@
dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
- const KeyedVector<int32_t, InputDeviceInfo::MotionRange> ranges = deviceInfo.getMotionRanges();
+ const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
if (!ranges.isEmpty()) {
dump.append(INDENT2 "Motion Ranges:\n");
for (size_t i = 0; i < ranges.size(); i++) {
- int32_t axis = ranges.keyAt(i);
- const char* label = getAxisLabel(axis);
+ const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+ const char* label = getAxisLabel(range.axis);
char name[32];
if (label) {
strncpy(name, label, sizeof(name));
name[sizeof(name) - 1] = '\0';
} else {
- snprintf(name, sizeof(name), "%d", axis);
+ snprintf(name, sizeof(name), "%d", range.axis);
}
- const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
- dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
- name, range.min, range.max, range.flat, range.fuzz);
+ dump.appendFormat(INDENT3 "%s: source=0x%08x, "
+ "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+ name, range.source, range.min, range.max, range.flat, range.fuzz);
}
}
@@ -811,8 +880,8 @@
// --- KeyboardInputMapper ---
KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
- uint32_t sources, int32_t keyboardType) :
- InputMapper(device), mSources(sources),
+ uint32_t source, int32_t keyboardType) :
+ InputMapper(device), mSource(source),
mKeyboardType(keyboardType) {
initializeLocked();
}
@@ -826,7 +895,7 @@
}
uint32_t KeyboardInputMapper::getSources() {
- return mSources;
+ return mSource;
}
void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -919,6 +988,7 @@
bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
return scanCode < BTN_MOUSE
|| scanCode >= KEY_OK
+ || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE)
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
@@ -1009,10 +1079,7 @@
getContext()->fadePointer();
}
- if (policyFlags & POLICY_FLAG_FUNCTION) {
- newMetaState |= AMETA_FUNCTION_ON;
- }
- getDispatcher()->notifyKey(when, getDeviceId(), mSources, policyFlags,
+ getDispatcher()->notifyKey(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
}
@@ -1092,7 +1159,7 @@
}
uint32_t CursorInputMapper::getSources() {
- return mSources;
+ return mSource;
}
void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1101,20 +1168,20 @@
if (mParameters.mode == Parameters::MODE_POINTER) {
float minX, minY, maxX, maxY;
if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
- info->addMotionRange(AMOTION_EVENT_AXIS_X, minX, maxX, 0.0f, 0.0f);
- info->addMotionRange(AMOTION_EVENT_AXIS_Y, minY, maxY, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f);
}
} else {
- info->addMotionRange(AMOTION_EVENT_AXIS_X, -1.0f, 1.0f, 0.0f, mXScale);
- info->addMotionRange(AMOTION_EVENT_AXIS_Y, -1.0f, 1.0f, 0.0f, mYScale);
+ info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale);
+ info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale);
}
- info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f);
if (mHaveVWheel) {
- info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
}
if (mHaveHWheel) {
- info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
}
}
@@ -1131,7 +1198,8 @@
dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel));
dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
- dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
+ dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mLocked.buttonState);
+ dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mLocked.buttonState)));
dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
} // release lock
}
@@ -1145,7 +1213,7 @@
// Configure device mode.
switch (mParameters.mode) {
case Parameters::MODE_POINTER:
- mSources = AINPUT_SOURCE_MOUSE;
+ mSource = AINPUT_SOURCE_MOUSE;
mXPrecision = 1.0f;
mYPrecision = 1.0f;
mXScale = 1.0f;
@@ -1153,7 +1221,7 @@
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
break;
case Parameters::MODE_NAVIGATION:
- mSources = AINPUT_SOURCE_TRACKBALL;
+ mSource = AINPUT_SOURCE_TRACKBALL;
mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
@@ -1210,16 +1278,18 @@
void CursorInputMapper::initializeLocked() {
mAccumulator.clear();
- mLocked.down = false;
+ mLocked.buttonState = 0;
mLocked.downTime = 0;
}
void CursorInputMapper::reset() {
for (;;) {
+ uint32_t buttonState;
{ // acquire lock
AutoMutex _l(mLock);
- if (! mLocked.down) {
+ buttonState = mLocked.buttonState;
+ if (!buttonState) {
initializeLocked();
break; // done
}
@@ -1227,8 +1297,10 @@
// Synthesize button up event on reset.
nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
- mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
- mAccumulator.btnMouse = false;
+ mAccumulator.clear();
+ mAccumulator.buttonDown = 0;
+ mAccumulator.buttonUp = buttonState;
+ mAccumulator.fields = Accumulator::FIELD_BUTTONS;
sync(when);
}
@@ -1237,24 +1309,25 @@
void CursorInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
- case EV_KEY:
- switch (rawEvent->scanCode) {
- case BTN_LEFT:
- case BTN_RIGHT:
- case BTN_MIDDLE:
- case BTN_SIDE:
- case BTN_EXTRA:
- case BTN_FORWARD:
- case BTN_BACK:
- case BTN_TASK:
- mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
- mAccumulator.btnMouse = rawEvent->value != 0;
+ case EV_KEY: {
+ uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+ if (buttonState) {
+ if (rawEvent->value) {
+ mAccumulator.buttonDown = buttonState;
+ mAccumulator.buttonUp = 0;
+ } else {
+ mAccumulator.buttonDown = 0;
+ mAccumulator.buttonUp = buttonState;
+ }
+ mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+
// Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
// we need to ensure that we report the up/down promptly.
sync(rawEvent->when);
break;
}
break;
+ }
case EV_REL:
switch (rawEvent->scanCode) {
@@ -1293,30 +1366,34 @@
return; // no new state changes, so nothing to do
}
- int motionEventAction;
+ int32_t motionEventAction;
+ int32_t motionEventEdgeFlags;
PointerCoords pointerCoords;
nsecs_t downTime;
float vscroll, hscroll;
{ // acquire lock
AutoMutex _l(mLock);
- bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
+ bool down, downChanged;
+ bool wasDown = isPointerDown(mLocked.buttonState);
+ bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS;
+ if (buttonsChanged) {
+ mLocked.buttonState = (mLocked.buttonState | mAccumulator.buttonDown)
+ & ~mAccumulator.buttonUp;
- if (downChanged) {
- if (mAccumulator.btnMouse) {
- if (!mLocked.down) {
- mLocked.down = true;
- mLocked.downTime = when;
- } else {
- downChanged = false;
- }
+ down = isPointerDown(mLocked.buttonState);
+
+ if (!wasDown && down) {
+ mLocked.downTime = when;
+ downChanged = true;
+ } else if (wasDown && !down) {
+ downChanged = true;
} else {
- if (mLocked.down) {
- mLocked.down = false;
- } else {
- downChanged = false;
- }
+ downChanged = false;
}
+ } else {
+ down = wasDown;
+ downChanged = false;
}
downTime = mLocked.downTime;
@@ -1324,8 +1401,8 @@
float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
if (downChanged) {
- motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
- } else if (mLocked.down || mPointerController == NULL) {
+ motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+ } else if (down || mPointerController == NULL) {
motionEventAction = AMOTION_EVENT_ACTION_MOVE;
} else {
motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
@@ -1364,21 +1441,29 @@
pointerCoords.clear();
+ motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+
if (mPointerController != NULL) {
mPointerController->move(deltaX, deltaY);
- if (downChanged) {
- mPointerController->setButtonState(mLocked.down ? POINTER_BUTTON_1 : 0);
+ if (buttonsChanged) {
+ mPointerController->setButtonState(mLocked.buttonState);
}
+
float x, y;
mPointerController->getPosition(&x, &y);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+
+ if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
+ motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds(
+ mPointerController, x, y);
+ }
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
}
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mLocked.down ? 1.0f : 0.0f);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) {
vscroll = mAccumulator.relWheel;
@@ -1406,8 +1491,8 @@
int32_t metaState = mContext->getGlobalMetaState();
int32_t pointerId = 0;
- getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
- motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
+ motionEventAction, 0, metaState, motionEventEdgeFlags,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
mAccumulator.clear();
@@ -1416,7 +1501,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
}
@@ -1433,7 +1518,9 @@
void CursorInputMapper::fadePointer() {
{ // acquire lock
AutoMutex _l(mLock);
- mPointerController->fade();
+ if (mPointerController != NULL) {
+ mPointerController->fade();
+ }
} // release lock
}
@@ -1453,7 +1540,7 @@
}
uint32_t TouchInputMapper::getSources() {
- return mSources;
+ return mTouchSource;
}
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1464,38 +1551,33 @@
// Ensure surface information is up to date so that orientation changes are
// noticed immediately.
- configureSurfaceLocked();
+ if (!configureSurfaceLocked()) {
+ return;
+ }
- info->addMotionRange(AMOTION_EVENT_AXIS_X, mLocked.orientedRanges.x);
- info->addMotionRange(AMOTION_EVENT_AXIS_Y, mLocked.orientedRanges.y);
+ info->addMotionRange(mLocked.orientedRanges.x);
+ info->addMotionRange(mLocked.orientedRanges.y);
if (mLocked.orientedRanges.havePressure) {
- info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE,
- mLocked.orientedRanges.pressure);
+ info->addMotionRange(mLocked.orientedRanges.pressure);
}
if (mLocked.orientedRanges.haveSize) {
- info->addMotionRange(AMOTION_EVENT_AXIS_SIZE,
- mLocked.orientedRanges.size);
+ info->addMotionRange(mLocked.orientedRanges.size);
}
if (mLocked.orientedRanges.haveTouchSize) {
- info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
- mLocked.orientedRanges.touchMajor);
- info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR,
- mLocked.orientedRanges.touchMinor);
+ info->addMotionRange(mLocked.orientedRanges.touchMajor);
+ info->addMotionRange(mLocked.orientedRanges.touchMinor);
}
if (mLocked.orientedRanges.haveToolSize) {
- info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR,
- mLocked.orientedRanges.toolMajor);
- info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR,
- mLocked.orientedRanges.toolMinor);
+ info->addMotionRange(mLocked.orientedRanges.toolMajor);
+ info->addMotionRange(mLocked.orientedRanges.toolMinor);
}
if (mLocked.orientedRanges.haveOrientation) {
- info->addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION,
- mLocked.orientedRanges.orientation);
+ info->addMotionRange(mLocked.orientedRanges.orientation);
}
} // release lock
}
@@ -1509,9 +1591,8 @@
dumpRawAxes(dump);
dumpCalibration(dump);
dumpSurfaceLocked(dump);
+
dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
- dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin);
- dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin);
dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale);
dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale);
dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mLocked.xPrecision);
@@ -1523,7 +1604,10 @@
dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias);
dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale);
dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale);
- dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale);
+ dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mLocked.orientationScale);
+
+ dump.appendFormat(INDENT3 "Last Touch:\n");
+ dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
} // release lock
}
@@ -1557,10 +1641,10 @@
// Configure sources.
switch (mParameters.deviceType) {
case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
- mSources = AINPUT_SOURCE_TOUCHSCREEN;
+ mTouchSource = AINPUT_SOURCE_TOUCHSCREEN;
break;
case Parameters::DEVICE_TYPE_TOUCH_PAD:
- mSources = AINPUT_SOURCE_TOUCHPAD;
+ mTouchSource = AINPUT_SOURCE_TOUCHPAD;
break;
default:
assert(false);
@@ -1593,17 +1677,20 @@
deviceTypeString)) {
if (deviceTypeString == "touchScreen") {
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
- } else if (deviceTypeString != "touchPad") {
+ } else if (deviceTypeString == "touchPad") {
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else {
LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
}
}
- bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
- mParameters.orientationAware = isTouchScreen;
+ mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
- mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1;
+ mParameters.associatedDisplayId = mParameters.orientationAware
+ || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+ ? 0 : -1;
}
void TouchInputMapper::dumpParameters(String8& dump) {
@@ -1657,21 +1744,36 @@
}
bool TouchInputMapper::configureSurfaceLocked() {
+ // Ensure we have valid X and Y axes.
+ if (!mRawAxes.x.valid || !mRawAxes.y.valid) {
+ LOGW(INDENT "Touch device '%s' did not report support for X or Y axis! "
+ "The device will be inoperable.", getDeviceName().string());
+ return false;
+ }
+
// Update orientation and dimensions if needed.
int32_t orientation = DISPLAY_ORIENTATION_0;
- int32_t width = mRawAxes.x.getRange();
- int32_t height = mRawAxes.y.getRange();
+ int32_t width = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+ int32_t height = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
if (mParameters.associatedDisplayId >= 0) {
- bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
- bool wantOrientation = mParameters.orientationAware;
-
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
- wantSize ? &width : NULL, wantSize ? &height : NULL,
- wantOrientation ? &orientation : NULL)) {
+ &mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight,
+ &mLocked.associatedDisplayOrientation)) {
return false;
}
+
+ // A touch screen inherits the dimensions of the display.
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+ width = mLocked.associatedDisplayWidth;
+ height = mLocked.associatedDisplayHeight;
+ }
+
+ // The device inherits the orientation of the display if it is orientation aware.
+ if (mParameters.orientationAware) {
+ orientation = mLocked.associatedDisplayOrientation;
+ }
}
bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1681,39 +1783,24 @@
bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
if (sizeChanged) {
- LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d",
+ LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d",
getDeviceId(), getDeviceName().string(), width, height);
mLocked.surfaceWidth = width;
mLocked.surfaceHeight = height;
// Configure X and Y factors.
- if (mRawAxes.x.valid && mRawAxes.y.valid) {
- mLocked.xOrigin = mCalibration.haveXOrigin
- ? mCalibration.xOrigin
- : mRawAxes.x.minValue;
- mLocked.yOrigin = mCalibration.haveYOrigin
- ? mCalibration.yOrigin
- : mRawAxes.y.minValue;
- mLocked.xScale = mCalibration.haveXScale
- ? mCalibration.xScale
- : float(width) / mRawAxes.x.getRange();
- mLocked.yScale = mCalibration.haveYScale
- ? mCalibration.yScale
- : float(height) / mRawAxes.y.getRange();
- mLocked.xPrecision = 1.0f / mLocked.xScale;
- mLocked.yPrecision = 1.0f / mLocked.yScale;
+ mLocked.xScale = float(width) / (mRawAxes.x.maxValue - mRawAxes.x.minValue + 1);
+ mLocked.yScale = float(height) / (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1);
+ mLocked.xPrecision = 1.0f / mLocked.xScale;
+ mLocked.yPrecision = 1.0f / mLocked.yScale;
- configureVirtualKeysLocked();
- } else {
- LOGW(INDENT "Touch device did not report support for X or Y axis!");
- mLocked.xOrigin = 0;
- mLocked.yOrigin = 0;
- mLocked.xScale = 1.0f;
- mLocked.yScale = 1.0f;
- mLocked.xPrecision = 1.0f;
- mLocked.yPrecision = 1.0f;
- }
+ mLocked.orientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
+ mLocked.orientedRanges.x.source = mTouchSource;
+ mLocked.orientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
+ mLocked.orientedRanges.y.source = mTouchSource;
+
+ configureVirtualKeysLocked();
// Scale factor for terms that are not oriented in a particular axis.
// If the pixels are square then xScale == yScale otherwise we fake it
@@ -1726,11 +1813,16 @@
// TouchMajor and TouchMinor factors.
if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) {
mLocked.orientedRanges.haveTouchSize = true;
+
+ mLocked.orientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
+ mLocked.orientedRanges.touchMajor.source = mTouchSource;
mLocked.orientedRanges.touchMajor.min = 0;
mLocked.orientedRanges.touchMajor.max = diagonalSize;
mLocked.orientedRanges.touchMajor.flat = 0;
mLocked.orientedRanges.touchMajor.fuzz = 0;
+
mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor;
+ mLocked.orientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
}
// ToolMajor and ToolMinor factors.
@@ -1774,11 +1866,16 @@
}
mLocked.orientedRanges.haveToolSize = true;
+
+ mLocked.orientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
+ mLocked.orientedRanges.toolMajor.source = mTouchSource;
mLocked.orientedRanges.toolMajor.min = 0;
mLocked.orientedRanges.toolMajor.max = diagonalSize;
mLocked.orientedRanges.toolMajor.flat = 0;
mLocked.orientedRanges.toolMajor.fuzz = 0;
+
mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor;
+ mLocked.orientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
}
// Pressure factors.
@@ -1807,6 +1904,9 @@
}
mLocked.orientedRanges.havePressure = true;
+
+ mLocked.orientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
+ mLocked.orientedRanges.pressure.source = mTouchSource;
mLocked.orientedRanges.pressure.min = 0;
mLocked.orientedRanges.pressure.max = 1.0;
mLocked.orientedRanges.pressure.flat = 0;
@@ -1823,6 +1923,9 @@
}
mLocked.orientedRanges.haveSize = true;
+
+ mLocked.orientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
+ mLocked.orientedRanges.size.source = mTouchSource;
mLocked.orientedRanges.size.min = 0;
mLocked.orientedRanges.size.max = 1.0;
mLocked.orientedRanges.size.flat = 0;
@@ -1839,6 +1942,8 @@
}
}
+ mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
+ mLocked.orientedRanges.orientation.source = mTouchSource;
mLocked.orientedRanges.orientation.min = - M_PI_2;
mLocked.orientedRanges.orientation.max = M_PI_2;
mLocked.orientedRanges.orientation.flat = 0;
@@ -1847,38 +1952,51 @@
}
if (orientationChanged || sizeChanged) {
- // Compute oriented surface dimensions, precision, and scales.
- float orientedXScale, orientedYScale;
+ // Compute oriented surface dimensions, precision, scales and ranges.
+ // Note that the maximum value reported is an inclusive maximum value so it is one
+ // unit less than the total width or height of surface.
switch (mLocked.surfaceOrientation) {
case DISPLAY_ORIENTATION_90:
case DISPLAY_ORIENTATION_270:
mLocked.orientedSurfaceWidth = mLocked.surfaceHeight;
mLocked.orientedSurfaceHeight = mLocked.surfaceWidth;
+
mLocked.orientedXPrecision = mLocked.yPrecision;
mLocked.orientedYPrecision = mLocked.xPrecision;
- orientedXScale = mLocked.yScale;
- orientedYScale = mLocked.xScale;
+
+ mLocked.orientedRanges.x.min = 0;
+ mLocked.orientedRanges.x.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue)
+ * mLocked.yScale;
+ mLocked.orientedRanges.x.flat = 0;
+ mLocked.orientedRanges.x.fuzz = mLocked.yScale;
+
+ mLocked.orientedRanges.y.min = 0;
+ mLocked.orientedRanges.y.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue)
+ * mLocked.xScale;
+ mLocked.orientedRanges.y.flat = 0;
+ mLocked.orientedRanges.y.fuzz = mLocked.xScale;
break;
+
default:
mLocked.orientedSurfaceWidth = mLocked.surfaceWidth;
mLocked.orientedSurfaceHeight = mLocked.surfaceHeight;
+
mLocked.orientedXPrecision = mLocked.xPrecision;
mLocked.orientedYPrecision = mLocked.yPrecision;
- orientedXScale = mLocked.xScale;
- orientedYScale = mLocked.yScale;
+
+ mLocked.orientedRanges.x.min = 0;
+ mLocked.orientedRanges.x.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue)
+ * mLocked.xScale;
+ mLocked.orientedRanges.x.flat = 0;
+ mLocked.orientedRanges.x.fuzz = mLocked.xScale;
+
+ mLocked.orientedRanges.y.min = 0;
+ mLocked.orientedRanges.y.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue)
+ * mLocked.yScale;
+ mLocked.orientedRanges.y.flat = 0;
+ mLocked.orientedRanges.y.fuzz = mLocked.yScale;
break;
}
-
- // Configure position ranges.
- mLocked.orientedRanges.x.min = 0;
- mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth;
- mLocked.orientedRanges.x.flat = 0;
- mLocked.orientedRanges.x.fuzz = orientedXScale;
-
- mLocked.orientedRanges.y.min = 0;
- mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight;
- mLocked.orientedRanges.y.flat = 0;
- mLocked.orientedRanges.y.fuzz = orientedYScale;
}
return true;
@@ -1891,8 +2009,6 @@
}
void TouchInputMapper::configureVirtualKeysLocked() {
- assert(mRawAxes.x.valid && mRawAxes.y.valid);
-
Vector<VirtualKeyDefinition> virtualKeyDefinitions;
getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
@@ -1906,8 +2022,8 @@
int32_t touchScreenLeft = mRawAxes.x.minValue;
int32_t touchScreenTop = mRawAxes.y.minValue;
- int32_t touchScreenWidth = mRawAxes.x.getRange();
- int32_t touchScreenHeight = mRawAxes.y.getRange();
+ int32_t touchScreenWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+ int32_t touchScreenHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
const VirtualKeyDefinition& virtualKeyDefinition =
@@ -1942,7 +2058,6 @@
* touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
-
}
}
@@ -1965,12 +2080,6 @@
const PropertyMap& in = getDevice()->getConfiguration();
Calibration& out = mCalibration;
- // Position
- out.haveXOrigin = in.tryGetProperty(String8("touch.position.xOrigin"), out.xOrigin);
- out.haveYOrigin = in.tryGetProperty(String8("touch.position.yOrigin"), out.yOrigin);
- out.haveXScale = in.tryGetProperty(String8("touch.position.xScale"), out.xScale);
- out.haveYScale = in.tryGetProperty(String8("touch.position.yScale"), out.yScale);
-
// Touch Size
out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT;
String8 touchSizeCalibrationString;
@@ -2182,20 +2291,6 @@
void TouchInputMapper::dumpCalibration(String8& dump) {
dump.append(INDENT3 "Calibration:\n");
- // Position
- if (mCalibration.haveXOrigin) {
- dump.appendFormat(INDENT4 "touch.position.xOrigin: %d\n", mCalibration.xOrigin);
- }
- if (mCalibration.haveYOrigin) {
- dump.appendFormat(INDENT4 "touch.position.yOrigin: %d\n", mCalibration.yOrigin);
- }
- if (mCalibration.haveXScale) {
- dump.appendFormat(INDENT4 "touch.position.xScale: %0.3f\n", mCalibration.xScale);
- }
- if (mCalibration.haveYScale) {
- dump.appendFormat(INDENT4 "touch.position.yScale: %0.3f\n", mCalibration.yScale);
- }
-
// Touch Size
switch (mCalibration.touchSizeCalibration) {
case Calibration::TOUCH_SIZE_CALIBRATION_NONE:
@@ -2363,8 +2458,10 @@
uint32_t policyFlags = 0;
if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
- // Hide the pointer on an initial down.
- getContext()->fadePointer();
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+ // If this is a touch screen, hide the pointer on an initial down.
+ getContext()->fadePointer();
+ }
// Initial downs on external touch devices should wake the device.
// We don't do this for internal touch screens to prevent them from waking
@@ -2378,7 +2475,7 @@
// Process touches and virtual keys.
TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
if (touchResult == DISPATCH_TOUCH) {
- detectGestures(when);
+ suppressSwipeOntoVirtualKeys(when);
dispatchTouches(when, policyFlags);
}
@@ -2505,7 +2602,7 @@
return touchResult;
}
-void TouchInputMapper::detectGestures(nsecs_t when) {
+void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) {
// Disable all virtual key touches that happen within a short time interval of the
// most recent touch. The idea is to filter out stray virtual key presses when
// interacting with the touch screen.
@@ -2623,14 +2720,14 @@
int32_t motionEventAction) {
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
- int32_t motionEventEdgeFlags = 0;
+ int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
float xPrecision, yPrecision;
{ // acquire lock
AutoMutex _l(mLock);
// Walk through the the active pointers and map touch screen coordinates (TouchData) into
- // display coordinates (PointerCoords) and adjust for display orientation.
+ // display or surface coordinates (PointerCoords) and adjust for display orientation.
for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
@@ -2638,10 +2735,6 @@
const PointerData& in = touch->pointers[inIndex];
- // X and Y
- float x = float(in.x - mLocked.xOrigin) * mLocked.xScale;
- float y = float(in.y - mLocked.yOrigin) * mLocked.yScale;
-
// ToolMajor and ToolMinor
float toolMajor, toolMinor;
switch (mCalibration.toolSizeCalibration) {
@@ -2779,33 +2872,34 @@
orientation = 0;
}
- // Adjust coords for orientation.
+ // X and Y
+ // Adjust coords for surface orientation.
+ float x, y;
switch (mLocked.surfaceOrientation) {
- case DISPLAY_ORIENTATION_90: {
- float xTemp = x;
- x = y;
- y = mLocked.surfaceWidth - xTemp;
+ case DISPLAY_ORIENTATION_90:
+ x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+ y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
orientation -= M_PI_2;
if (orientation < - M_PI_2) {
orientation += M_PI;
}
break;
- }
- case DISPLAY_ORIENTATION_180: {
- x = mLocked.surfaceWidth - x;
- y = mLocked.surfaceHeight - y;
+ case DISPLAY_ORIENTATION_180:
+ x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+ y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
break;
- }
- case DISPLAY_ORIENTATION_270: {
- float xTemp = x;
- x = mLocked.surfaceHeight - y;
- y = xTemp;
+ case DISPLAY_ORIENTATION_270:
+ x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+ y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
orientation += M_PI_2;
if (orientation > M_PI_2) {
orientation -= M_PI;
}
break;
- }
+ default:
+ x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+ y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+ break;
}
// Write output coords.
@@ -2831,18 +2925,22 @@
// Check edge flags by looking only at the first pointer since the flags are
// global to the event.
if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
- float x = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
- float y = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
+ uint32_t inIndex = touch->idToIndex[pointerIds[0]];
+ const PointerData& in = touch->pointers[inIndex];
- if (x <= 0) {
- motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
- } else if (x >= mLocked.orientedSurfaceWidth) {
- motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+ if (in.x <= mRawAxes.x.minValue) {
+ motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
+ mLocked.surfaceOrientation);
+ } else if (in.x >= mRawAxes.x.maxValue) {
+ motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
+ mLocked.surfaceOrientation);
}
- if (y <= 0) {
- motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
- } else if (y >= mLocked.orientedSurfaceHeight) {
- motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+ if (in.y <= mRawAxes.y.minValue) {
+ motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
+ mLocked.surfaceOrientation);
+ } else if (in.y >= mRawAxes.y.maxValue) {
+ motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+ mLocked.surfaceOrientation);
}
}
@@ -2850,18 +2948,15 @@
yPrecision = mLocked.orientedYPrecision;
} // release lock
- getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), mTouchSource, policyFlags,
motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
xPrecision, yPrecision, mDownTime);
}
bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
- if (mRawAxes.x.valid && mRawAxes.y.valid) {
- return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
- && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
- }
- return true;
+ return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
+ && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
}
const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked(
@@ -3069,11 +3164,6 @@
* points has moved more than a screen height from the last position,
* then drop it. */
bool TouchInputMapper::applyBadTouchFilter() {
- // This hack requires valid axis parameters.
- if (! mRawAxes.y.valid) {
- return false;
- }
-
uint32_t pointerCount = mCurrentTouch.pointerCount;
// Nothing to do if there are no points.
@@ -3092,7 +3182,7 @@
// the long size of the screen to be bad. This was a magic value
// determined by looking at the maximum distance it is feasible
// to actually move in one sample.
- int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16;
+ int32_t maxDeltaY = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) * 7 / 16;
// XXX The original code in InputDevice.java included commented out
// code for testing the X axis. Note that when we drop a point
@@ -3153,11 +3243,6 @@
* the coordinate value for one axis has jumped to the other pointer's location.
*/
bool TouchInputMapper::applyJumpyTouchFilter() {
- // This hack requires valid axis parameters.
- if (! mRawAxes.y.valid) {
- return false;
- }
-
uint32_t pointerCount = mCurrentTouch.pointerCount;
if (mLastTouch.pointerCount != pointerCount) {
#if DEBUG_HACKS
@@ -3214,7 +3299,7 @@
}
if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
- int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
+ int jumpyEpsilon = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) / JUMPY_EPSILON_DIVISOR;
// We only replace the single worst jumpy point as characterized by pointer distance
// in a single axis.
@@ -3854,9 +3939,11 @@
for (size_t i = 0; i < mAxes.size(); i++) {
const Axis& axis = mAxes.valueAt(i);
- info->addMotionRange(axis.axisInfo.axis, axis.min, axis.max, axis.flat, axis.fuzz);
+ info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK,
+ axis.min, axis.max, axis.flat, axis.fuzz);
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
- info->addMotionRange(axis.axisInfo.highAxis, axis.min, axis.max, axis.flat, axis.fuzz);
+ info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK,
+ axis.min, axis.max, axis.flat, axis.fuzz);
}
}
}
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index e2cf08e7..68002ca 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -389,7 +389,7 @@
class KeyboardInputMapper : public InputMapper {
public:
- KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType);
+ KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
virtual ~KeyboardInputMapper();
virtual uint32_t getSources();
@@ -414,7 +414,7 @@
int32_t scanCode;
};
- uint32_t mSources;
+ uint32_t mSource;
int32_t mKeyboardType;
// Immutable configuration parameters.
@@ -493,7 +493,7 @@
struct Accumulator {
enum {
- FIELD_BTN_MOUSE = 1,
+ FIELD_BUTTONS = 1,
FIELD_REL_X = 2,
FIELD_REL_Y = 4,
FIELD_REL_WHEEL = 8,
@@ -502,7 +502,9 @@
uint32_t fields;
- bool btnMouse;
+ uint32_t buttonDown;
+ uint32_t buttonUp;
+
int32_t relX;
int32_t relY;
int32_t relWheel;
@@ -513,7 +515,7 @@
}
} mAccumulator;
- int32_t mSources;
+ int32_t mSource;
float mXScale;
float mYScale;
float mXPrecision;
@@ -527,7 +529,7 @@
sp<PointerControllerInterface> mPointerController;
struct LockedState {
- bool down;
+ uint32_t buttonState;
nsecs_t downTime;
} mLocked;
@@ -629,7 +631,7 @@
};
// Input sources supported by the device.
- int32_t mSources;
+ uint32_t mTouchSource; // sources when reporting touch data
// Immutable configuration parameters.
struct Parameters {
@@ -650,16 +652,6 @@
// Immutable calibration parameters in parsed form.
struct Calibration {
- // Position
- bool haveXOrigin;
- int32_t xOrigin;
- bool haveYOrigin;
- int32_t yOrigin;
- bool haveXScale;
- float xScale;
- bool haveYScale;
- float yScale;
-
// Touch Size
enum TouchSizeCalibration {
TOUCH_SIZE_CALIBRATION_DEFAULT,
@@ -755,12 +747,14 @@
int32_t surfaceOrientation;
int32_t surfaceWidth, surfaceHeight;
+ // The associated display orientation and width and height set by configureSurfaceLocked().
+ int32_t associatedDisplayOrientation;
+ int32_t associatedDisplayWidth, associatedDisplayHeight;
+
// Translation and scaling factors, orientation-independent.
- int32_t xOrigin;
float xScale;
float xPrecision;
- int32_t yOrigin;
float yScale;
float yPrecision;
@@ -882,7 +876,7 @@
void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
int32_t motionEventAction);
- void detectGestures(nsecs_t when);
+ void suppressSwipeOntoVirtualKeys(nsecs_t when);
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
@@ -912,7 +906,7 @@
FIELD_ABS_X = 2,
FIELD_ABS_Y = 4,
FIELD_ABS_PRESSURE = 8,
- FIELD_ABS_TOOL_WIDTH = 16
+ FIELD_ABS_TOOL_WIDTH = 16,
};
uint32_t fields;
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index 954872b..a4ee295 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -109,12 +109,12 @@
switch (mLocked.displayOrientation) {
case DISPLAY_ORIENTATION_90:
case DISPLAY_ORIENTATION_270:
- *outMaxX = mLocked.displayHeight;
- *outMaxY = mLocked.displayWidth;
+ *outMaxX = mLocked.displayHeight - 1;
+ *outMaxY = mLocked.displayWidth - 1;
break;
default:
- *outMaxX = mLocked.displayWidth;
- *outMaxY = mLocked.displayHeight;
+ *outMaxX = mLocked.displayWidth - 1;
+ *outMaxY = mLocked.displayHeight - 1;
break;
}
return true;
@@ -309,48 +309,53 @@
AutoMutex _l(mLock);
if (mLocked.displayOrientation != orientation) {
- float absoluteX, absoluteY;
+ // Apply offsets to convert from the pixel top-left corner position to the pixel center.
+ // This creates an invariant frame of reference that we can easily rotate when
+ // taking into account that the pointer may be located at fractional pixel offsets.
+ float x = mLocked.pointerX + 0.5f;
+ float y = mLocked.pointerY + 0.5f;
+ float temp;
- // Map from oriented display coordinates to absolute display coordinates.
+ // Undo the previous rotation.
switch (mLocked.displayOrientation) {
case DISPLAY_ORIENTATION_90:
- absoluteX = mLocked.displayWidth - mLocked.pointerY;
- absoluteY = mLocked.pointerX;
+ temp = x;
+ x = mLocked.displayWidth - y;
+ y = temp;
break;
case DISPLAY_ORIENTATION_180:
- absoluteX = mLocked.displayWidth - mLocked.pointerX;
- absoluteY = mLocked.displayHeight - mLocked.pointerY;
+ x = mLocked.displayWidth - x;
+ y = mLocked.displayHeight - y;
break;
case DISPLAY_ORIENTATION_270:
- absoluteX = mLocked.pointerY;
- absoluteY = mLocked.displayHeight - mLocked.pointerX;
- break;
- default:
- absoluteX = mLocked.pointerX;
- absoluteY = mLocked.pointerY;
+ temp = x;
+ x = y;
+ y = mLocked.displayHeight - temp;
break;
}
- // Map from absolute display coordinates to oriented display coordinates.
+ // Perform the new rotation.
switch (orientation) {
case DISPLAY_ORIENTATION_90:
- mLocked.pointerX = absoluteY;
- mLocked.pointerY = mLocked.displayWidth - absoluteX;
+ temp = x;
+ x = y;
+ y = mLocked.displayWidth - x;
break;
case DISPLAY_ORIENTATION_180:
- mLocked.pointerX = mLocked.displayWidth - absoluteX;
- mLocked.pointerY = mLocked.displayHeight - absoluteY;
+ x = mLocked.displayWidth - x;
+ y = mLocked.displayHeight - y;
break;
case DISPLAY_ORIENTATION_270:
- mLocked.pointerX = mLocked.displayHeight - absoluteY;
- mLocked.pointerY = absoluteX;
- break;
- default:
- mLocked.pointerX = absoluteX;
- mLocked.pointerY = absoluteY;
+ temp = x;
+ x = mLocked.displayHeight - y;
+ y = temp;
break;
}
+ // Apply offsets to convert from the pixel center to the pixel top-left corner position
+ // and save the results.
+ mLocked.pointerX = x - 0.5f;
+ mLocked.pointerY = y - 0.5f;
mLocked.displayOrientation = orientation;
updateLocked();
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index e28dd7d..e1dab5c 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -31,10 +31,6 @@
namespace android {
-enum {
- POINTER_BUTTON_1 = 1 << 0,
-};
-
/**
* Interface for tracking a single (mouse) pointer.
*
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index d77cb2f..67a2e21 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -405,7 +405,8 @@
String8 name;
uint32_t classes;
PropertyMap configuration;
- KeyedVector<int, RawAbsoluteAxisInfo> axes;
+ KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
+ KeyedVector<int, bool> relativeAxes;
KeyedVector<int32_t, int32_t> keyCodeStates;
KeyedVector<int32_t, int32_t> scanCodeStates;
KeyedVector<int32_t, int32_t> switchStates;
@@ -460,7 +461,7 @@
device->configuration.addAll(configuration);
}
- void addAxis(int32_t deviceId, int axis,
+ void addAbsoluteAxis(int32_t deviceId, int axis,
int32_t minValue, int32_t maxValue, int flat, int fuzz) {
Device* device = getDevice(deviceId);
@@ -470,7 +471,12 @@
info.maxValue = maxValue;
info.flat = flat;
info.fuzz = fuzz;
- device->axes.add(axis, info);
+ device->absoluteAxes.add(axis, info);
+ }
+
+ void addRelativeAxis(int32_t deviceId, int32_t axis) {
+ Device* device = getDevice(deviceId);
+ device->relativeAxes.add(axis, true);
}
void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
@@ -560,9 +566,9 @@
RawAbsoluteAxisInfo* outAxisInfo) const {
Device* device = getDevice(deviceId);
if (device) {
- ssize_t index = device->axes.indexOfKey(axis);
+ ssize_t index = device->absoluteAxes.indexOfKey(axis);
if (index >= 0) {
- *outAxisInfo = device->axes.valueAt(index);
+ *outAxisInfo = device->absoluteAxes.valueAt(index);
return OK;
}
}
@@ -570,6 +576,10 @@
}
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ return device->relativeAxes.indexOfKey(axis) >= 0;
+ }
return false;
}
@@ -1487,13 +1497,15 @@
}
static void assertMotionRange(const InputDeviceInfo& info,
- int32_t rangeType, float min, float max, float flat, float fuzz) {
- const InputDeviceInfo::MotionRange* range = info.getMotionRange(rangeType);
- ASSERT_TRUE(range != NULL) << "Range: " << rangeType;
- ASSERT_NEAR(min, range->min, EPSILON) << "Range: " << rangeType;
- ASSERT_NEAR(max, range->max, EPSILON) << "Range: " << rangeType;
- ASSERT_NEAR(flat, range->flat, EPSILON) << "Range: " << rangeType;
- ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Range: " << rangeType;
+ int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
+ const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
+ ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
+ ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
+ ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
+ ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
+ ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
+ ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
+ ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
}
static void assertPointerCoords(const PointerCoords& coords,
@@ -2001,22 +2013,25 @@
mapper->populateDeviceInfo(&info);
// Initially there may not be a valid motion range.
- ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X));
- ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
- 0.0f, 1.0f, 0.0f, 0.0f));
+ ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
+ ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+ AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
// When the bounds are set, then there should be a valid motion range.
- mFakePointerController->setBounds(1, 2, 800, 480);
+ mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
InputDeviceInfo info2;
mapper->populateDeviceInfo(&info2);
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X,
- 1, 800, 0.0f, 0.0f));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y,
- 2, 480, 0.0f, 0.0f));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+ AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
+ 1, 800 - 1, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+ AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE,
+ 2, 480 - 1, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+ AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE,
0.0f, 1.0f, 0.0f, 0.0f));
}
@@ -2028,11 +2043,14 @@
InputDeviceInfo info;
mapper->populateDeviceInfo(&info);
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X,
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+ AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
-1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y,
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+ AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL,
-1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+ AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL,
0.0f, 1.0f, 0.0f, 0.0f));
}
@@ -2320,9 +2338,9 @@
};
const int32_t TouchInputMapperTest::RAW_X_MIN = 25;
-const int32_t TouchInputMapperTest::RAW_X_MAX = 1020;
+const int32_t TouchInputMapperTest::RAW_X_MAX = 1019;
const int32_t TouchInputMapperTest::RAW_Y_MIN = 30;
-const int32_t TouchInputMapperTest::RAW_Y_MAX = 1010;
+const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009;
const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0;
const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
@@ -2333,8 +2351,8 @@
const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
const int32_t TouchInputMapperTest::RAW_ID_MIN = 0;
const int32_t TouchInputMapperTest::RAW_ID_MAX = 9;
-const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH;
-const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT;
+const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
+const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = {
{ KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 },
@@ -2353,19 +2371,19 @@
}
int32_t TouchInputMapperTest::toRawX(float displayX) {
- return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH + RAW_X_MIN);
+ return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN);
}
int32_t TouchInputMapperTest::toRawY(float displayY) {
- return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT + RAW_Y_MIN);
+ return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
}
float TouchInputMapperTest::toDisplayX(int32_t rawX) {
- return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN);
+ return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
}
float TouchInputMapperTest::toDisplayY(int32_t rawY) {
- return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN);
+ return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1);
}
@@ -2385,14 +2403,18 @@
void SingleTouchInputMapperTest::prepareAxes(int axes) {
if (axes & POSITION) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
- mFakeEventHub->addAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
+ RAW_X_MIN, RAW_X_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y,
+ RAW_Y_MIN, RAW_Y_MAX, 0, 0);
}
if (axes & PRESSURE) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE,
+ RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
}
if (axes & TOOL) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH,
+ RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
}
}
@@ -2950,12 +2972,12 @@
// Rotation 90.
prepareDisplay(DISPLAY_ORIENTATION_90);
- processDown(mapper, toRawX(50), toRawY(75));
+ processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
- ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
- ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+ ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
processUp(mapper);
processSync(mapper);
@@ -2963,12 +2985,12 @@
// Rotation 180.
prepareDisplay(DISPLAY_ORIENTATION_180);
- processDown(mapper, toRawX(50), toRawY(75));
+ processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
- ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
- ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+ ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
processUp(mapper);
processSync(mapper);
@@ -2976,12 +2998,12 @@
// Rotation 270.
prepareDisplay(DISPLAY_ORIENTATION_270);
- processDown(mapper, toRawX(50), toRawY(75));
+ processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
- ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
- ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+ ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
processUp(mapper);
processSync(mapper);
@@ -3040,33 +3062,37 @@
void MultiTouchInputMapperTest::prepareAxes(int axes) {
if (axes & POSITION) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X,
+ RAW_X_MIN, RAW_X_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y,
+ RAW_Y_MIN, RAW_Y_MAX, 0, 0);
}
if (axes & TOUCH) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR,
+ RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
if (axes & MINOR) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
}
}
if (axes & TOOL) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR,
+ RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
if (axes & MINOR) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0);
}
}
if (axes & ORIENTATION) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_ORIENTATION,
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION,
RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0);
}
if (axes & PRESSURE) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_PRESSURE,
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE,
RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
}
if (axes & ID) {
- mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
+ mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
RAW_ID_MIN, RAW_ID_MAX, 0, 0);
}
}
@@ -3601,8 +3627,8 @@
float y = toDisplayY(rawY);
float pressure = float(rawTouchMajor) / RAW_TOUCH_MAX;
float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX;
- float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN),
- float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN));
+ float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1),
+ float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1));
float toolMajor = float(rawToolMajor) * scale;
float toolMinor = float(rawToolMinor) * scale;
float touchMajor = min(float(rawTouchMajor) * scale, toolMajor);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index adc49ae..0000237 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -29,12 +29,12 @@
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.wifi.IWifiManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.SupplicantState;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiStateMachine;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WpsConfiguration;
import android.net.wifi.WpsResult;
@@ -62,6 +62,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -99,9 +100,6 @@
/* Chipset supports background scan */
private final boolean mBackgroundScanSupported;
- // true if the user enabled Wifi while in airplane mode
- private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
-
private final LockList mLocks = new LockList();
// some wifi lock statistics
private int mFullHighPerfLocksAcquired;
@@ -144,6 +142,14 @@
private static final String ACTION_DEVICE_IDLE =
"com.android.server.WifiManager.action.DEVICE_IDLE";
+ private static final int WIFI_DISABLED = 0;
+ private static final int WIFI_ENABLED = 1;
+ /* Wifi enabled while in airplane mode */
+ private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
+
+ private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+ private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+
private boolean mIsReceiverRegistered = false;
@@ -338,11 +344,11 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // clear our flag indicating the user has overwridden airplane mode
- mAirplaneModeOverwridden.set(false);
- // on airplane disable, restore Wifi if the saved state indicates so
- if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
- persistWifiEnabled(true);
+ mAirplaneModeOn.set(isAirplaneModeOn());
+ /* On airplane mode disable, restore wifi state if necessary */
+ if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
+ mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+ persistWifiEnabled(true);
}
updateWifiState();
}
@@ -402,9 +408,10 @@
* This function is used only at boot time
*/
public void checkAndStartWifi() {
- /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
- boolean wifiEnabled = !isAirplaneModeOn()
- && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
+ mAirplaneModeOn.set(isAirplaneModeOn());
+ mWifiState.set(getPersistedWifiState());
+ /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
+ boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled);
@@ -423,21 +430,39 @@
return (wifiSavedState == 1);
}
- private boolean getPersistedWifiEnabled() {
+ private int getPersistedWifiState() {
final ContentResolver cr = mContext.getContentResolver();
try {
- return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
+ return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
} catch (Settings.SettingNotFoundException e) {
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
- return false;
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
+ return WIFI_DISABLED;
+ }
+ }
+
+ private boolean shouldWifiBeEnabled() {
+ if (mAirplaneModeOn.get()) {
+ return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+ } else {
+ return mWifiState.get() != WIFI_DISABLED;
}
}
private void persistWifiEnabled(boolean enabled) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
+ if (enabled) {
+ if (isAirplaneModeOn() && isAirplaneToggleable()) {
+ mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+ } else {
+ mWifiState.set(WIFI_ENABLED);
+ }
+ } else {
+ mWifiState.set(WIFI_DISABLED);
+ }
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
}
+
/**
* see {@link android.net.wifi.WifiManager#pingSupplicant()}
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -490,11 +515,6 @@
Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
- // set a flag if the user is enabling Wifi while in airplane mode
- if (enable && isAirplaneModeOn() && isAirplaneToggleable()) {
- mAirplaneModeOverwridden.set(true);
- }
-
if (enable) {
reportStartWorkSource();
}
@@ -862,8 +882,6 @@
mWifiStateMachine.clearBlacklist();
}
-
-
/**
* Get a reference to handler. This is used by a client to establish
* an AsyncChannel communication with WifiService
@@ -878,6 +896,14 @@
return new Messenger(mAsyncServiceHandler);
}
+ /**
+ * Get the IP and proxy configuration file
+ */
+ public String getConfigFile() {
+ enforceAccessPermission();
+ return mWifiStateMachine.getConfigFile();
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1037,11 +1063,8 @@
}
private void updateWifiState() {
- boolean wifiEnabled = getPersistedWifiEnabled();
- boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
boolean lockHeld = mLocks.hasLocks();
int strongestLockMode = WifiManager.WIFI_MODE_FULL;
- boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
if (lockHeld) {
@@ -1053,11 +1076,11 @@
}
/* Disable tethering when airplane mode is enabled */
- if (airplaneMode) {
+ if (mAirplaneModeOn.get()) {
mWifiStateMachine.setWifiApEnabled(null, false);
}
- if (wifiShouldBeEnabled) {
+ if (shouldWifiBeEnabled()) {
if (wifiShouldBeStarted) {
reportStartWorkSource();
mWifiStateMachine.setWifiEnabled(true);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0fab964..267c76a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3151,6 +3151,9 @@
try {
pm.setPackageStoppedState(packageName, true);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + packageName + ": " + e);
}
}
} finally {
@@ -5559,6 +5562,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + cpr.appInfo.packageName + ": " + e);
}
ProcessRecord proc = startProcessLocked(cpi.processName,
@@ -5840,6 +5846,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
info.packageName, false);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + info.packageName + ": " + e);
}
if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
@@ -6673,8 +6682,10 @@
mProcessCrashTimes.remove(app.info.processName, app.info.uid);
app.removed = true;
removeProcessLocked(app, false);
+ mMainStack.resumeTopActivityLocked(null);
return false;
}
+ mMainStack.resumeTopActivityLocked(null);
} else {
ActivityRecord r = mMainStack.topRunningActivityLocked(null);
if (r.app == app) {
@@ -6780,7 +6791,7 @@
* @param crashInfo describing the exception
*/
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
- ProcessRecord r = findAppProcess(app);
+ ProcessRecord r = findAppProcess(app, "Crash");
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
app == null ? "system" : (r == null ? "unknown" : r.processName),
@@ -6799,7 +6810,10 @@
IBinder app,
int violationMask,
StrictMode.ViolationInfo info) {
- ProcessRecord r = findAppProcess(app);
+ ProcessRecord r = findAppProcess(app, "StrictMode");
+ if (r == null) {
+ return;
+ }
if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
@@ -6973,7 +6987,7 @@
*/
public boolean handleApplicationWtf(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) {
- ProcessRecord r = findAppProcess(app);
+ ProcessRecord r = findAppProcess(app, "WTF");
EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
app == null ? "system" : (r == null ? "unknown" : r.processName),
@@ -6995,7 +7009,7 @@
* @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
* @return the corresponding {@link ProcessRecord} object, or null if none could be found
*/
- private ProcessRecord findAppProcess(IBinder app) {
+ private ProcessRecord findAppProcess(IBinder app, String reason) {
if (app == null) {
return null;
}
@@ -7011,7 +7025,9 @@
}
}
- Slog.w(TAG, "Can't find mystery application: " + app);
+ Slog.w(TAG, "Can't find mystery application for " + reason
+ + " from pid=" + Binder.getCallingPid()
+ + " uid=" + Binder.getCallingUid() + ": " + app);
return null;
}
}
@@ -9396,6 +9412,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + r.packageName + ": " + e);
}
final String appName = r.processName;
@@ -10297,6 +10316,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
app.packageName, false);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + app.packageName + ": " + e);
}
BackupRecord r = new BackupRecord(ss, app, backupMode);
@@ -11625,6 +11647,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false);
} catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + r.curComponent.getPackageName() + ": " + e);
}
// Is this receiver's application already running?
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 3a613bb..c087aecf 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1299,6 +1299,9 @@
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false);
} catch (RemoteException e1) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + next.packageName + ": " + e);
}
// We are starting up the next activity, so tell the window manager
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 2f22fe1..de0b114 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -16,11 +16,14 @@
package com.android.server.usb;
+import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -33,7 +36,7 @@
import android.os.FileUtils;
import android.os.Process;
import android.util.Log;
-import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.Xml;
import com.android.internal.content.PackageMonitor;
@@ -62,17 +65,18 @@
private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
private final Context mContext;
+ private final PackageManager mPackageManager;
- // maps UID to user approved USB devices
- private final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
- new SparseArray<ArrayList<DeviceFilter>>();
- // maps UID to user approved USB accessories
- private final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
- new SparseArray<ArrayList<AccessoryFilter>>();
+ // Temporary mapping USB device name to list of UIDs with permissions for the device
+ private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
+ new HashMap<String, SparseBooleanArray>();
+ // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
+ private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
+ new HashMap<UsbAccessory, SparseBooleanArray>();
// Maps DeviceFilter to user preferred application package
private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
new HashMap<DeviceFilter, String>();
- // Maps DeviceFilter to user preferred application package
+ // Maps AccessoryFilter to user preferred application package
private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
new HashMap<AccessoryFilter, String>();
@@ -185,6 +189,14 @@
return false;
}
+ public boolean matches(DeviceFilter f) {
+ if (mVendorId != -1 && f.mVendorId != mVendorId) return false;
+ if (mProductId != -1 && f.mProductId != mProductId) return false;
+
+ // check device class/subclass/protocol
+ return matches(f.mClass, f.mSubclass, f.mProtocol);
+ }
+
@Override
public boolean equals(Object obj) {
// can't compare if we have wildcard strings
@@ -234,22 +246,18 @@
public final String mManufacturer;
// USB accessory model (or null for unspecified)
public final String mModel;
- // USB accessory type (or null for unspecified)
- public final String mType;
// USB accessory version (or null for unspecified)
public final String mVersion;
- public AccessoryFilter(String manufacturer, String model, String type, String version) {
+ public AccessoryFilter(String manufacturer, String model, String version) {
mManufacturer = manufacturer;
mModel = model;
- mType = type;
mVersion = version;
}
public AccessoryFilter(UsbAccessory accessory) {
mManufacturer = accessory.getManufacturer();
mModel = accessory.getModel();
- mType = accessory.getType();
mVersion = accessory.getVersion();
}
@@ -257,7 +265,6 @@
throws XmlPullParserException, IOException {
String manufacturer = null;
String model = null;
- String type = null;
String version = null;
int count = parser.getAttributeCount();
@@ -269,13 +276,11 @@
manufacturer = value;
} else if ("model".equals(name)) {
model = value;
- } else if ("type".equals(name)) {
- type = value;
} else if ("version".equals(name)) {
version = value;
}
}
- return new AccessoryFilter(manufacturer, model, type, version);
+ return new AccessoryFilter(manufacturer, model, version);
}
public void write(XmlSerializer serializer)throws IOException {
@@ -286,9 +291,6 @@
if (mModel != null) {
serializer.attribute(null, "model", mModel);
}
- if (mType != null) {
- serializer.attribute(null, "type", mType);
- }
if (mVersion != null) {
serializer.attribute(null, "version", mVersion);
}
@@ -298,29 +300,33 @@
public boolean matches(UsbAccessory acc) {
if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
if (mModel != null && !acc.getModel().equals(mModel)) return false;
- if (mType != null && !acc.getType().equals(mType)) return false;
if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
return true;
}
+ public boolean matches(AccessoryFilter f) {
+ if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
+ if (mModel != null && !f.mModel.equals(mModel)) return false;
+ if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
+ return true;
+ }
+
@Override
public boolean equals(Object obj) {
// can't compare if we have wildcard strings
- if (mManufacturer == null || mModel == null || mType == null || mVersion == null) {
+ if (mManufacturer == null || mModel == null || mVersion == null) {
return false;
}
if (obj instanceof AccessoryFilter) {
AccessoryFilter filter = (AccessoryFilter)obj;
return (mManufacturer.equals(filter.mManufacturer) &&
mModel.equals(filter.mModel) &&
- mType.equals(filter.mType) &&
mVersion.equals(filter.mVersion));
}
if (obj instanceof UsbAccessory) {
UsbAccessory accessory = (UsbAccessory)obj;
return (mManufacturer.equals(accessory.getManufacturer()) &&
mModel.equals(accessory.getModel()) &&
- mType.equals(accessory.getType()) &&
mVersion.equals(accessory.getVersion()));
}
return false;
@@ -330,7 +336,6 @@
public int hashCode() {
return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
(mModel == null ? 0 : mModel.hashCode()) ^
- (mType == null ? 0 : mType.hashCode()) ^
(mVersion == null ? 0 : mVersion.hashCode()));
}
@@ -338,78 +343,35 @@
public String toString() {
return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
"\", mModel=\"" + mModel +
- "\", mType=\"" + mType +
"\", mVersion=\"" + mVersion + "\"]";
}
}
private class MyPackageMonitor extends PackageMonitor {
- public void onPackageRemoved(String packageName, int uid) {
- synchronized (mLock) {
- // clear all activity preferences for the package
- if (clearPackageDefaultsLocked(packageName)) {
- writeSettingsLocked();
- }
- }
+
+ public void onPackageAdded(String packageName, int uid) {
+ handlePackageUpdate(packageName);
}
- public void onUidRemoved(int uid) {
- synchronized (mLock) {
- // clear all permissions for the UID
- if (clearUidDefaultsLocked(uid)) {
- writeSettingsLocked();
- }
- }
+ public void onPackageChanged(String packageName, int uid, String[] components) {
+ handlePackageUpdate(packageName);
+ }
+
+ public void onPackageRemoved(String packageName, int uid) {
+ clearDefaults(packageName);
}
}
MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
public UsbDeviceSettingsManager(Context context) {
mContext = context;
+ mPackageManager = context.getPackageManager();
synchronized (mLock) {
readSettingsLocked();
}
mPackageMonitor.register(context, true);
}
- private void readDevicePermission(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int uid = -1;
- ArrayList<DeviceFilter> filters = new ArrayList<DeviceFilter>();
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- if ("uid".equals(parser.getAttributeName(i))) {
- uid = Integer.parseInt(parser.getAttributeValue(i));
- break;
- }
- }
- XmlUtils.nextElement(parser);
- while ("usb-device".equals(parser.getName())) {
- filters.add(DeviceFilter.read(parser));
- XmlUtils.nextElement(parser);
- }
- mDevicePermissionMap.put(uid, filters);
- }
-
- private void readAccessoryPermission(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int uid = -1;
- ArrayList<AccessoryFilter> filters = new ArrayList<AccessoryFilter>();
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- if ("uid".equals(parser.getAttributeName(i))) {
- uid = Integer.parseInt(parser.getAttributeValue(i));
- break;
- }
- }
- XmlUtils.nextElement(parser);
- while ("usb-accessory".equals(parser.getName())) {
- filters.add(AccessoryFilter.read(parser));
- XmlUtils.nextElement(parser);
- }
- mAccessoryPermissionMap.put(uid, filters);
- }
-
private void readPreference(XmlPullParser parser)
throws XmlPullParserException, IOException {
String packageName = null;
@@ -441,11 +403,7 @@
XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName();
- if ("device-permission".equals(tagName)) {
- readDevicePermission(parser);
- } else if ("accessory-permission".equals(tagName)) {
- readAccessoryPermission(parser);
- } else if ("preference".equals(tagName)) {
+ if ("preference".equals(tagName)) {
readPreference(parser);
} else {
XmlUtils.nextElement(parser);
@@ -478,32 +436,6 @@
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "settings");
- int count = mDevicePermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mDevicePermissionMap.keyAt(i);
- ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
- serializer.startTag(null, "device-permission");
- serializer.attribute(null, "uid", Integer.toString(uid));
- int filterCount = filters.size();
- for (int j = 0; j < filterCount; j++) {
- filters.get(j).write(serializer);
- }
- serializer.endTag(null, "device-permission");
- }
-
- count = mAccessoryPermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mAccessoryPermissionMap.keyAt(i);
- ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
- serializer.startTag(null, "accessory-permission");
- serializer.attribute(null, "uid", Integer.toString(uid));
- int filterCount = filters.size();
- for (int j = 0; j < filterCount; j++) {
- filters.get(j).write(serializer);
- }
- serializer.endTag(null, "accessory-permission");
- }
-
for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
serializer.startTag(null, "preference");
serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
@@ -535,11 +467,10 @@
private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
UsbDevice device, UsbAccessory accessory) {
ActivityInfo ai = info.activityInfo;
- PackageManager pm = mContext.getPackageManager();
XmlResourceParser parser = null;
try {
- parser = ai.loadXmlMetaData(pm, metaDataName);
+ parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
if (parser == null) {
Log.w(TAG, "no meta-data for " + info);
return false;
@@ -572,8 +503,7 @@
private final ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) {
ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
- PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+ List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
PackageManager.GET_META_DATA);
int count = resolveInfos.size();
for (int i = 0; i < count; i++) {
@@ -588,8 +518,7 @@
private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
UsbAccessory accessory, Intent intent) {
ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
- PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent,
+ List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
PackageManager.GET_META_DATA);
int count = resolveInfos.size();
for (int i = 0; i < count; i++) {
@@ -602,53 +531,26 @@
}
public void deviceAttached(UsbDevice device) {
- Intent deviceIntent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
- deviceIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
- deviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ArrayList<ResolveInfo> matches;
String defaultPackage;
synchronized (mLock) {
- matches = getDeviceMatchesLocked(device, deviceIntent);
+ matches = getDeviceMatchesLocked(device, intent);
// Launch our default activity directly, if we have one.
// Otherwise we will start the UsbResolverActivity to allow the user to choose.
defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
}
- int count = matches.size();
- // don't show the resolver activity if there are no choices available
- if (count == 0) return;
-
- if (defaultPackage != null) {
- for (int i = 0; i < count; i++) {
- ResolveInfo rInfo = matches.get(i);
- if (rInfo.activityInfo != null &&
- defaultPackage.equals(rInfo.activityInfo.packageName)) {
- try {
- deviceIntent.setComponent(new ComponentName(
- defaultPackage, rInfo.activityInfo.name));
- mContext.startActivity(deviceIntent);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "startActivity failed", e);
- }
- return;
- }
- }
- }
-
- Intent intent = new Intent(mContext, UsbResolverActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- intent.putExtra(Intent.EXTRA_INTENT, deviceIntent);
- intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "unable to start UsbResolverActivity");
- }
+ resolveActivity(intent, matches, defaultPackage, device, null);
}
public void deviceDetached(UsbDevice device) {
+ // clear temporary permissions for the device
+ mDevicePermissionMap.remove(device.getDeviceName());
+
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
Log.d(TAG, "usbDeviceRemoved, sending " + intent);
@@ -656,93 +558,322 @@
}
public void accessoryAttached(UsbAccessory accessory) {
- Intent accessoryIntent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
- accessoryIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
- accessoryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ArrayList<ResolveInfo> matches;
String defaultPackage;
synchronized (mLock) {
- matches = getAccessoryMatchesLocked(accessory, accessoryIntent);
+ matches = getAccessoryMatchesLocked(accessory, intent);
// Launch our default activity directly, if we have one.
// Otherwise we will start the UsbResolverActivity to allow the user to choose.
defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
}
- int count = matches.size();
- // don't show the resolver activity if there are no choices available
- if (count == 0) return;
-
- if (defaultPackage != null) {
- for (int i = 0; i < count; i++) {
- ResolveInfo rInfo = matches.get(i);
- if (rInfo.activityInfo != null &&
- defaultPackage.equals(rInfo.activityInfo.packageName)) {
- try {
- accessoryIntent.setComponent(new ComponentName(
- defaultPackage, rInfo.activityInfo.name));
- mContext.startActivity(accessoryIntent);
- } catch (ActivityNotFoundException e) {
- Log.e(TAG, "startActivity failed", e);
- }
- return;
- }
- }
- }
-
- Intent intent = new Intent(mContext, UsbResolverActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- intent.putExtra(Intent.EXTRA_INTENT, accessoryIntent);
- intent.putParcelableArrayListExtra(UsbResolverActivity.EXTRA_RESOLVE_INFOS, matches);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "unable to start UsbResolverActivity");
- }
+ resolveActivity(intent, matches, defaultPackage, null, accessory);
}
public void accessoryDetached(UsbAccessory accessory) {
+ // clear temporary permissions for the accessory
+ mAccessoryPermissionMap.remove(accessory);
+
Intent intent = new Intent(
UsbManager.ACTION_USB_ACCESSORY_DETACHED);
intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
mContext.sendBroadcast(intent);
}
- public void checkPermission(UsbDevice device) {
- if (device == null) return;
- synchronized (mLock) {
- ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(Binder.getCallingUid());
- if (filterList != null) {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- DeviceFilter filter = filterList.get(i);
- if (filter.equals(device)) {
- // permission allowed
- return;
+ private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
+ String defaultPackage, UsbDevice device, UsbAccessory accessory) {
+ int count = matches.size();
+
+ // don't show the resolver activity if there are no choices available
+ if (count == 0) {
+ if (accessory != null) {
+ String uri = accessory.getUri();
+ if (uri != null && uri.length() > 0) {
+ // display URI to user
+ // start UsbResolverActivity so user can choose an activity
+ Intent dialogIntent = new Intent();
+ dialogIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbAccessoryUriActivity");
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ dialogIntent.putExtra("uri", uri);
+ try {
+ mContext.startActivity(dialogIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start UsbAccessoryUriActivity");
}
}
}
+
+ // do nothing
+ return;
}
- throw new SecurityException("User has not given permission to device " + device);
+
+ ResolveInfo defaultRI = null;
+ if (count == 1 && defaultPackage == null) {
+ // Check to see if our single choice is on the system partition.
+ // If so, treat it as our default without calling UsbResolverActivity
+ ResolveInfo rInfo = matches.get(0);
+ if (rInfo.activityInfo != null &&
+ rInfo.activityInfo.applicationInfo != null &&
+ (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ defaultRI = rInfo;
+ }
+ }
+
+ if (defaultRI == null && defaultPackage != null) {
+ // look for default activity
+ for (int i = 0; i < count; i++) {
+ ResolveInfo rInfo = matches.get(i);
+ if (rInfo.activityInfo != null &&
+ defaultPackage.equals(rInfo.activityInfo.packageName)) {
+ defaultRI = rInfo;
+ break;
+ }
+ }
+ }
+
+ if (defaultRI != null) {
+ // grant permission for default activity
+ if (device != null) {
+ grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
+ } else if (accessory != null) {
+ grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
+ }
+
+ // start default activity directly
+ try {
+ intent.setComponent(
+ new ComponentName(defaultRI.activityInfo.packageName,
+ defaultRI.activityInfo.name));
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ } else {
+ Intent resolverIntent = new Intent();
+ resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ if (count == 1) {
+ // start UsbConfirmActivity if there is only one choice
+ resolverIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbConfirmActivity");
+ resolverIntent.putExtra("rinfo", matches.get(0));
+
+ if (device != null) {
+ resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ } else {
+ resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ }
+ } else {
+ // start UsbResolverActivity so user can choose an activity
+ resolverIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbResolverActivity");
+ resolverIntent.putParcelableArrayListExtra("rlist", matches);
+ resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
+ }
+ try {
+ mContext.startActivity(resolverIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start activity " + resolverIntent);
+ }
+ }
+ }
+
+ private boolean clearCompatibleMatchesLocked(String packageName, DeviceFilter filter) {
+ boolean changed = false;
+ for (DeviceFilter test : mDevicePreferenceMap.keySet()) {
+ if (filter.matches(test)) {
+ mDevicePreferenceMap.remove(test);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
+ boolean changed = false;
+ for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
+ if (filter.matches(test)) {
+ mAccessoryPreferenceMap.remove(test);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
+ String metaDataName) {
+ XmlResourceParser parser = null;
+ boolean changed = false;
+
+ try {
+ parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
+ if (parser == null) return false;
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if ("usb-device".equals(tagName)) {
+ DeviceFilter filter = DeviceFilter.read(parser);
+ if (clearCompatibleMatchesLocked(packageName, filter)) {
+ changed = true;
+ }
+ }
+ else if ("usb-accessory".equals(tagName)) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ if (clearCompatibleMatchesLocked(packageName, filter)) {
+ changed = true;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return changed;
+ }
+
+ // Check to see if the package supports any USB devices or accessories.
+ // If so, clear any non-matching preferences for matching devices/accessories.
+ private void handlePackageUpdate(String packageName) {
+ synchronized (mLock) {
+ PackageInfo info;
+ boolean changed = false;
+
+ try {
+ info = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+ return;
+ }
+
+ ActivityInfo[] activities = info.activities;
+ if (activities == null) return;
+ for (int i = 0; i < activities.length; i++) {
+ // check for meta-data, both for devices and accessories
+ if (handlePackageUpdateLocked(packageName, activities[i],
+ UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
+ changed = true;
+ }
+ if (handlePackageUpdateLocked(packageName, activities[i],
+ UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ writeSettingsLocked();
+ }
+ }
+ }
+
+ public boolean hasPermission(UsbDevice device) {
+ synchronized (mLock) {
+ SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
+ if (uidList == null) {
+ return false;
+ }
+ return uidList.get(Binder.getCallingUid());
+ }
+ }
+
+ public boolean hasPermission(UsbAccessory accessory) {
+ synchronized (mLock) {
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ return false;
+ }
+ return uidList.get(Binder.getCallingUid());
+ }
+ }
+
+ public void checkPermission(UsbDevice device) {
+ if (!hasPermission(device)) {
+ throw new SecurityException("User has not given permission to device " + device);
+ }
}
public void checkPermission(UsbAccessory accessory) {
- if (accessory == null) return;
- synchronized (mLock) {
- ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(Binder.getCallingUid());
- if (filterList != null) {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- AccessoryFilter filter = filterList.get(i);
- if (filter.equals(accessory)) {
- // permission allowed
- return;
- }
- }
- }
+ if (!hasPermission(accessory)) {
+ throw new SecurityException("User has not given permission to accessory " + accessory);
}
- throw new SecurityException("User has not given permission to accessory " + accessory);
+ }
+
+ private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
+ int uid = Binder.getCallingUid();
+
+ // compare uid with packageName to foil apps pretending to be someone else
+ try {
+ ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
+ if (aInfo.uid != uid) {
+ throw new IllegalArgumentException("package " + packageName +
+ " does not match caller's uid " + uid);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("package " + packageName + " not found");
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbPermissionActivity");
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Intent.EXTRA_INTENT, pi);
+ intent.putExtra("package", packageName);
+ intent.putExtra("uid", uid);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start UsbPermissionActivity");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
+ Intent intent = new Intent();
+
+ // respond immediately if permission has already been granted
+ if (hasPermission(device)) {
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ }
+ return;
+ }
+
+ // start UsbPermissionActivity so user can choose an activity
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ requestPermissionDialog(intent, packageName, pi);
+ }
+
+ public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+ Intent intent = new Intent();
+
+ // respond immediately if permission has already been granted
+ if (hasPermission(accessory)) {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ }
+ return;
+ }
+
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ requestPermissionDialog(intent, packageName, pi);
}
public void setDevicePackage(UsbDevice device, String packageName) {
@@ -783,73 +914,43 @@
public void grantDevicePermission(UsbDevice device, int uid) {
synchronized (mLock) {
- ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(uid);
- if (filterList == null) {
- filterList = new ArrayList<DeviceFilter>();
- mDevicePermissionMap.put(uid, filterList);
- } else {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- if (filterList.get(i).equals(device)) return;
- }
+ String deviceName = device.getDeviceName();
+ SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+ if (uidList == null) {
+ uidList = new SparseBooleanArray(1);
+ mDevicePermissionMap.put(deviceName, uidList);
}
- filterList.add(new DeviceFilter(device));
- writeSettingsLocked();
+ uidList.put(uid, true);
}
}
public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
synchronized (mLock) {
- ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid);
- if (filterList == null) {
- filterList = new ArrayList<AccessoryFilter>();
- mAccessoryPermissionMap.put(uid, filterList);
- } else {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- if (filterList.get(i).equals(accessory)) return;
- }
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ uidList = new SparseBooleanArray(1);
+ mAccessoryPermissionMap.put(accessory, uidList);
}
- filterList.add(new AccessoryFilter(accessory));
- writeSettingsLocked();
+ uidList.put(uid, true);
}
}
- public boolean hasDefaults(String packageName, int uid) {
+ public boolean hasDefaults(String packageName) {
synchronized (mLock) {
- if (mDevicePermissionMap.get(uid) != null) return true;
- if (mAccessoryPermissionMap.get(uid) != null) return true;
if (mDevicePreferenceMap.values().contains(packageName)) return true;
if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
return false;
}
}
- public void clearDefaults(String packageName, int uid) {
+ public void clearDefaults(String packageName) {
synchronized (mLock) {
- boolean packageCleared = clearPackageDefaultsLocked(packageName);
- boolean uidCleared = clearUidDefaultsLocked(uid);
- if (packageCleared || uidCleared) {
+ if (clearPackageDefaultsLocked(packageName)) {
writeSettingsLocked();
}
}
}
- private boolean clearUidDefaultsLocked(int uid) {
- boolean cleared = false;
- int index = mDevicePermissionMap.indexOfKey(uid);
- if (index >= 0) {
- mDevicePermissionMap.removeAt(index);
- cleared = true;
- }
- index = mAccessoryPermissionMap.indexOfKey(uid);
- if (index >= 0) {
- mAccessoryPermissionMap.removeAt(index);
- cleared = true;
- }
- return cleared;
- }
-
private boolean clearPackageDefaultsLocked(String packageName) {
boolean cleared = false;
synchronized (mLock) {
@@ -882,24 +983,24 @@
public void dump(FileDescriptor fd, PrintWriter pw) {
synchronized (mLock) {
pw.println(" Device permissions:");
- int count = mDevicePermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mDevicePermissionMap.keyAt(i);
- pw.println(" " + "uid " + uid + ":");
- ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
- for (DeviceFilter filter : filters) {
- pw.println(" " + filter);
+ for (String deviceName : mDevicePermissionMap.keySet()) {
+ pw.print(" " + deviceName + ": ");
+ SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+ int count = uidList.size();
+ for (int i = 0; i < count; i++) {
+ pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
+ pw.println("");
}
pw.println(" Accessory permissions:");
- count = mAccessoryPermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mAccessoryPermissionMap.keyAt(i);
- pw.println(" " + "uid " + uid + ":");
- ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
- for (AccessoryFilter filter : filters) {
- pw.println(" " + filter);
+ for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+ pw.print(" " + accessory + ": ");
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ int count = uidList.size();
+ for (int i = 0; i < count; i++) {
+ pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
+ pw.println("");
}
pw.println(" Device preferences:");
for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 8170c61..8b419f3 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,7 @@
package com.android.server.usb;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -422,10 +423,7 @@
/* returns the currently attached USB accessory (device mode) */
public UsbAccessory getCurrentAccessory() {
- synchronized (mLock) {
- mDeviceManager.checkPermission(mCurrentAccessory);
- return mCurrentAccessory;
- }
+ return mCurrentAccessory;
}
/* opens the currently attached USB accessory (device mode) */
@@ -454,6 +452,24 @@
mDeviceManager.setAccessoryPackage(accessory, packageName);
}
+ public boolean hasDevicePermission(UsbDevice device) {
+ return mDeviceManager.hasPermission(device);
+ }
+
+ public boolean hasAccessoryPermission(UsbAccessory accessory) {
+ return mDeviceManager.hasPermission(accessory);
+ }
+
+ public void requestDevicePermission(UsbDevice device, String packageName,
+ PendingIntent pi) {
+ mDeviceManager.requestPermission(device, packageName, pi);
+ }
+
+ public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
+ PendingIntent pi) {
+ mDeviceManager.requestPermission(accessory, packageName, pi);
+ }
+
public void grantDevicePermission(UsbDevice device, int uid) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.grantDevicePermission(device, uid);
@@ -464,14 +480,14 @@
mDeviceManager.grantAccessoryPermission(accessory, uid);
}
- public boolean hasDefaults(String packageName, int uid) {
+ public boolean hasDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- return mDeviceManager.hasDefaults(packageName, uid);
+ return mDeviceManager.hasDefaults(packageName);
}
- public void clearDefaults(String packageName, int uid) {
+ public void clearDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- mDeviceManager.clearDefaults(packageName, uid);
+ mDeviceManager.clearDefaults(packageName);
}
/*
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index eed41a0..33e6a36 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4727,7 +4727,15 @@
SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
}
- public Bitmap screenshotApplications(IBinder appToken, int maxWidth, int maxHeight) {
+ /**
+ * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
+ * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
+ * of the target image.
+ *
+ * @param width the width of the target bitmap
+ * @param height the height of the target bitmap
+ */
+ public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
@@ -4739,7 +4747,7 @@
final Rect frame = new Rect();
float scale;
- int sw, sh, dw, dh;
+ int dw, dh;
int rot;
synchronized(mWindowMap) {
@@ -4791,19 +4799,23 @@
if (maxLayer < ws.mAnimLayer) {
maxLayer = ws.mAnimLayer;
}
- final Rect wf = ws.mFrame;
- final Rect cr = ws.mContentInsets;
- int left = wf.left + cr.left;
- int top = wf.top + cr.top;
- int right = wf.right - cr.right;
- int bottom = wf.bottom - cr.bottom;
- frame.union(left, top, right, bottom);
+
+ // Don't include wallpaper in bounds calculation
+ if (!ws.mIsWallpaper) {
+ final Rect wf = ws.mFrame;
+ final Rect cr = ws.mContentInsets;
+ int left = wf.left + cr.left;
+ int top = wf.top + cr.top;
+ int right = wf.right - cr.right;
+ int bottom = wf.bottom - cr.bottom;
+ frame.union(left, top, right, bottom);
+ }
}
Binder.restoreCallingIdentity(ident);
// Constrain frame to the screen size.
frame.intersect(0, 0, dw, dh);
-
+
if (frame.isEmpty() || maxLayer == 0) {
return null;
}
@@ -4814,15 +4826,7 @@
int fh = frame.height();
// First try reducing to fit in x dimension.
- scale = maxWidth/(float)fw;
- sw = maxWidth;
- sh = (int)(fh*scale);
- if (sh > maxHeight) {
- // y dimension became too long; constrain by that.
- scale = maxHeight/(float)fh;
- sw = (int)(fw*scale);
- sh = maxHeight;
- }
+ scale = width/(float)fw;
// The screen shot will contain the entire screen.
dw = (int)(dw*scale);
@@ -4841,8 +4845,8 @@
+ ") to layer " + maxLayer);
return null;
}
-
- Bitmap bm = Bitmap.createBitmap(sw, sh, rawss.getConfig());
+
+ Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
Matrix matrix = new Matrix();
ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
@@ -5460,8 +5464,9 @@
shortSize = (int)(shortSize/dm.density);
// These semi-magic numbers define our compatibility modes for
- // applications with different screens. Don't change unless you
- // make sure to test lots and lots of apps!
+ // applications with different screens. These are guarantees to
+ // app developers about the space they can expect for a particular
+ // configuration. DO NOT CHANGE!
if (longSize < 470) {
// This is shorter than an HVGA normal density screen (which
// is 480 pixels on its long side).
@@ -5469,12 +5474,12 @@
| Configuration.SCREENLAYOUT_LONG_NO;
} else {
// What size is this screen screen?
- if (longSize >= 800 && shortSize >= 600) {
- // SVGA or larger screens at medium density are the point
+ if (longSize >= 960 && shortSize >= 720) {
+ // 1.5xVGA or larger screens at medium density are the point
// at which we consider it to be an extra large screen.
mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
- } else if (longSize >= 530 && shortSize >= 400) {
- // SVGA or larger screens at high density are the point
+ } else if (longSize >= 640 && shortSize >= 480) {
+ // VGA or larger screens at medium density are the point
// at which we consider it to be a large screen.
mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
} else {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 3be3b1b..80dddc2 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -727,14 +727,14 @@
};
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Going to sleep.");
#endif
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Poking user activity.");
#endif
android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
@@ -743,7 +743,7 @@
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
-#ifdef DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("handleInterceptActions: Not passing key to user.");
#endif
}
@@ -1103,12 +1103,11 @@
env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
- const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+ const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
for (size_t i = 0; i < ranges.size(); i++) {
- int rangeType = ranges.keyAt(i);
- const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
+ const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
- rangeType, range.min, range.max, range.flat, range.fuzz);
+ range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1321,7 +1320,7 @@
"<init>", "()V");
GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
- "addMotionRange", "(IFFFF)V");
+ "addMotionRange", "(IIFFFF)V");
GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
"mId", "I");
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 3c49e54..c66f181 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -193,12 +193,13 @@
return NULL;
}
jclass stringClass = env->FindClass("java/lang/String");
- jobjectArray strArray = env->NewObjectArray(4, stringClass, NULL);
+ jobjectArray strArray = env->NewObjectArray(5, stringClass, NULL);
if (!strArray) goto out;
set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
- set_accessory_string(env, fd, ACCESSORY_GET_STRING_TYPE, strArray, 2);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
out:
close(fd);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 697e879..ce1ab3d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -340,11 +340,14 @@
if (rec->addConnection(connection)) {
// this sensor is already activated, but we are adding a
// connection that uses it. Immediately send down the last
- // known value of the requested sensor.
- sensors_event_t scratch;
- sensors_event_t& event(mLastEventSeen.editValueFor(handle));
- if (event.version == sizeof(sensors_event_t)) {
- connection->sendEvents(&event, 1);
+ // known value of the requested sensor if it's not a
+ // "continuous" sensor.
+ if (sensor->getSensor().getMinDelay() == 0) {
+ sensors_event_t scratch;
+ sensors_event_t& event(mLastEventSeen.editValueFor(handle));
+ if (event.version == sizeof(sensors_event_t)) {
+ connection->sendEvents(&event, 1);
+ }
}
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 57af001..1297363 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -57,7 +57,6 @@
mNeedsDithering(false),
mSecure(false),
mProtectedByApp(false),
- mProtectedByDRM(false),
mTextureManager(),
mBufferManager(mTextureManager),
mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
@@ -191,7 +190,6 @@
mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
- mProtectedByDRM = (flags & ISurfaceComposer::eProtectedByDRM) ? true : false;
mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
(flags & ISurfaceComposer::eOpaque) == 0;
@@ -392,6 +390,12 @@
return LayerBase::needsFiltering();
}
+bool Layer::isProtected() const
+{
+ sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+ return (activeBuffer != 0) &&
+ (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
status_t Layer::setBufferCount(int bufferCount)
{
@@ -515,7 +519,7 @@
// request EGLImage for all buffers
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
}
- if (mProtectedByApp || mProtectedByDRM) {
+ if (mProtectedByApp) {
// need a hardware-protected path to external video sink
usage |= GraphicBuffer::USAGE_PROTECTED;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index bccc900..128f93d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,8 +80,7 @@
virtual bool needsDithering() const { return mNeedsDithering; }
virtual bool needsFiltering() const;
virtual bool isSecure() const { return mSecure; }
- virtual bool isProtectedByApp() const { return mProtectedByApp; }
- virtual bool isProtectedByDRM() const { return mProtectedByDRM; }
+ virtual bool isProtected() const;
virtual sp<Surface> createSurface() const;
virtual status_t ditch();
virtual void onRemoved();
@@ -222,7 +221,6 @@
// page-flip thread (currently main thread)
bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
- bool mProtectedByDRM; // DRM agent requires protected path to external sink
Region mPostedDirtyRegion;
// page-flip thread and transaction thread (currently main thread)
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index bfe92e6..7162e47 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -197,16 +197,10 @@
virtual bool isSecure() const { return false; }
/**
- * isProtectedByApp - true if application says this surface is protected, that
- * is if it requires a hardware-protected data path to an external sink.
+ * isProtected - true if the layer may contain protected content in the
+ * GRALLOC_USAGE_PROTECTED sense.
*/
- virtual bool isProtectedByApp() const { return false; }
-
- /**
- * isProtectedByDRM - true if DRM agent says this surface is protected, that
- * is if it requires a hardware-protected data path to an external sink.
- */
- virtual bool isProtectedByDRM() const { return false; }
+ virtual bool isProtected() const { return false; }
/** Called from the main thread, when the surface is removed from the
* draw list */
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 554fa43..a9fa1ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -327,6 +327,40 @@
const_cast<SurfaceFlinger*>(this)->signalEvent();
}
+bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
+ Mutex::Autolock _l(mStateLock);
+ sp<IBinder> surfBinder(surface->asBinder());
+
+ // Check the visible layer list for the ISurface
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+ if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+ return true;
+ }
+ }
+
+ // Check the layers in the purgatory. This check is here so that if a
+ // Surface gets destroyed before all the clients are done using it, the
+ // error will not be reported as "surface XYZ is not authenticated", but
+ // will instead fail later on when the client tries to use the surface,
+ // which should be reported as "surface XYZ returned an -ENODEV". The
+ // purgatorized layers are no less authentic than the visible ones, so this
+ // should not cause any harm.
+ size_t purgatorySize = mLayerPurgatory.size();
+ for (size_t i=0 ; i<purgatorySize ; i++) {
+ const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+ sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+ if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime, uint32_t flags)
{
@@ -2135,6 +2169,19 @@
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
return BAD_VALUE;
+ // make sure none of the layers are protected
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ const uint32_t z = layer->drawingState().z;
+ if (z >= minLayerZ && z <= maxLayerZ) {
+ if (layer->isProtected()) {
+ return INVALID_OPERATION;
+ }
+ }
+ }
+
if (!GLExtensions::getInstance().haveFramebufferObject())
return INVALID_OPERATION;
@@ -2183,8 +2230,6 @@
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
- const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
- const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
const uint32_t z = layer->drawingState().z;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6dd91ac..9566819 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -209,6 +209,7 @@
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual void signal() const;
+ virtual bool authenticateSurface(const sp<ISurface>& surface) const;
virtual status_t captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
diff --git a/tests/HugeBackup/Android.mk b/tests/HugeBackup/Android.mk
new file mode 100644
index 0000000..4789bc8
--- /dev/null
+++ b/tests/HugeBackup/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := HugeBackup
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+include $(BUILD_PACKAGE)
diff --git a/tests/HugeBackup/AndroidManifest.xml b/tests/HugeBackup/AndroidManifest.xml
new file mode 100644
index 0000000..923881b
--- /dev/null
+++ b/tests/HugeBackup/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Declare the contents of this Android application. The namespace
+ attribute brings in the Android platform namespace, and the package
+ supplies a unique name for the application. When writing your
+ own application, the package name must be changed from "com.example.*"
+ to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.hugebackup"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- The backup/restore mechanism was introduced in API version 8 -->
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8" />
+
+ <application android:label="Huge Backup"
+ android:backupAgent="HugeAgent">
+
+ <meta-data android:name="com.google.android.backup.api_key"
+ android:value="AEdPqrEAAAAINyoagzQOEEpIH3yw7LYCFN7CRX4FMd6TGIGVaA" />
+
+ <activity android:name="HugeBackupActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+</manifest>
diff --git a/tests/HugeBackup/proguard.flags b/tests/HugeBackup/proguard.flags
new file mode 100644
index 0000000..b4d01bf
--- /dev/null
+++ b/tests/HugeBackup/proguard.flags
@@ -0,0 +1,3 @@
+-keepclassmembers class com.android.hugebackup.HugeBackupActivity {
+ public void onRestoreButtonClick(android.view.View);
+}
diff --git a/tests/HugeBackup/res/layout/backup_restore.xml b/tests/HugeBackup/res/layout/backup_restore.xml
new file mode 100644
index 0000000..7f11984
--- /dev/null
+++ b/tests/HugeBackup/res/layout/backup_restore.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<!-- Layout description of the BackupRestore sample's main activity -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ScrollView
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView android:text="@string/filling_text"
+ android:textSize="20dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="10dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <RadioGroup android:id="@+id/filling_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="20dp"
+ android:orientation="vertical">
+
+ <RadioButton android:id="@+id/bacon"
+ android:text="@string/bacon_label"/>
+ <RadioButton android:id="@+id/pastrami"
+ android:text="@string/pastrami_label"/>
+ <RadioButton android:id="@+id/hummus"
+ android:text="@string/hummus_label"/>
+
+ </RadioGroup>
+
+ <TextView android:text="@string/extras_text"
+ android:textSize="20dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="10dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <CheckBox android:id="@+id/mayo"
+ android:text="@string/mayo_text"
+ android:layout_marginLeft="20dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <CheckBox android:id="@+id/tomato"
+ android:text="@string/tomato_text"
+ android:layout_marginLeft="20dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ </ScrollView>
+
+ <Button android:id="@+id/restore_button"
+ android:text="@string/restore_text"
+ android:onClick="onRestoreButtonClick"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_weight="0" />
+
+</LinearLayout>
diff --git a/tests/HugeBackup/res/values/strings.xml b/tests/HugeBackup/res/values/strings.xml
new file mode 100644
index 0000000..c0b9226
--- /dev/null
+++ b/tests/HugeBackup/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<resources>
+ <string name="filling_text">Choose a sandwich filling:</string>
+ <string name="bacon_label">Bacon</string>
+ <string name="pastrami_label">Pastrami</string>
+ <string name="hummus_label">Hummus</string>
+
+ <string name="extras_text">Extras:</string>
+ <string name="mayo_text">Mayonnaise\?</string>
+ <string name="tomato_text">Tomato\?</string>
+
+ <string name="restore_text">Restore last data</string>
+</resources>
diff --git a/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java b/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java
new file mode 100644
index 0000000..f90bd9f
--- /dev/null
+++ b/tests/HugeBackup/src/com/android/hugebackup/HugeAgent.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.hugebackup;
+
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.os.ParcelFileDescriptor;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * This is the backup/restore agent class for the BackupRestore sample
+ * application. This particular agent illustrates using the backup and
+ * restore APIs directly, without taking advantage of any helper classes.
+ */
+public class HugeAgent extends BackupAgent {
+ /**
+ * We put a simple version number into the state files so that we can
+ * tell properly how to read "old" versions if at some point we want
+ * to change what data we back up and how we store the state blob.
+ */
+ static final int AGENT_VERSION = 1;
+
+ /**
+ * Pick an arbitrary string to use as the "key" under which the
+ * data is backed up. This key identifies different data records
+ * within this one application's data set. Since we only maintain
+ * one piece of data we don't need to distinguish, so we just pick
+ * some arbitrary tag to use.
+ */
+ static final String APP_DATA_KEY = "alldata";
+ static final String HUGE_DATA_KEY = "colossus";
+
+ /** The app's current data, read from the live disk file */
+ boolean mAddMayo;
+ boolean mAddTomato;
+ int mFilling;
+
+ /** The location of the application's persistent data file */
+ File mDataFile;
+
+ /** For convenience, we set up the File object for the app's data on creation */
+ @Override
+ public void onCreate() {
+ mDataFile = new File(getFilesDir(), HugeBackupActivity.DATA_FILE_NAME);
+ }
+
+ /**
+ * The set of data backed up by this application is very small: just
+ * two booleans and an integer. With such a simple dataset, it's
+ * easiest to simply store a copy of the backed-up data as the state
+ * blob describing the last dataset backed up. The state file
+ * contents can be anything; it is private to the agent class, and
+ * is never stored off-device.
+ *
+ * <p>One thing that an application may wish to do is tag the state
+ * blob contents with a version number. This is so that if the
+ * application is upgraded, the next time it attempts to do a backup,
+ * it can detect that the last backup operation was performed by an
+ * older version of the agent, and might therefore require different
+ * handling.
+ */
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // First, get the current data from the application's file. This
+ // may throw an IOException, but in that case something has gone
+ // badly wrong with the app's data on disk, and we do not want
+ // to back up garbage data. If we just let the exception go, the
+ // Backup Manager will handle it and simply skip the current
+ // backup operation.
+ synchronized (HugeBackupActivity.sDataLock) {
+ RandomAccessFile file = new RandomAccessFile(mDataFile, "r");
+ mFilling = file.readInt();
+ mAddMayo = file.readBoolean();
+ mAddTomato = file.readBoolean();
+ }
+
+ // If the new state file descriptor is null, this is the first time
+ // a backup is being performed, so we know we have to write the
+ // data. If there <em>is</em> a previous state blob, we want to
+ // double check whether the current data is actually different from
+ // our last backup, so that we can avoid transmitting redundant
+ // data to the storage backend.
+ boolean doBackup = (oldState == null);
+ if (!doBackup) {
+ doBackup = compareStateFile(oldState);
+ }
+
+ // If we decided that we do in fact need to write our dataset, go
+ // ahead and do that. The way this agent backs up the data is to
+ // flatten it into a single buffer, then write that to the backup
+ // transport under the single key string.
+ if (doBackup) {
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+
+ // We use a DataOutputStream to write structured data into
+ // the buffering stream
+ DataOutputStream outWriter = new DataOutputStream(bufStream);
+ outWriter.writeInt(mFilling);
+ outWriter.writeBoolean(mAddMayo);
+ outWriter.writeBoolean(mAddTomato);
+
+ // Okay, we've flattened the data for transmission. Pull it
+ // out of the buffering stream object and send it off.
+ byte[] buffer = bufStream.toByteArray();
+ int len = buffer.length;
+ data.writeEntityHeader(APP_DATA_KEY, len);
+ data.writeEntityData(buffer, len);
+
+ // ***** pathological behavior *****
+ // Now, in order to incur deliberate too-much-data failures,
+ // try to back up 20 MB of data besides what we already pushed.
+ final int MEGABYTE = 1024*1024;
+ final int NUM_MEGS = 20;
+ buffer = new byte[MEGABYTE];
+ data.writeEntityHeader(HUGE_DATA_KEY, NUM_MEGS * MEGABYTE);
+ for (int i = 0; i < NUM_MEGS; i++) {
+ data.writeEntityData(buffer, MEGABYTE);
+ }
+ }
+
+ // Finally, in all cases, we need to write the new state blob
+ writeStateFile(newState);
+ }
+
+ /**
+ * Helper routine - read a previous state file and decide whether to
+ * perform a backup based on its contents.
+ *
+ * @return <code>true</code> if the application's data has changed since
+ * the last backup operation; <code>false</code> otherwise.
+ */
+ boolean compareStateFile(ParcelFileDescriptor oldState) {
+ FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
+ DataInputStream in = new DataInputStream(instream);
+
+ try {
+ int stateVersion = in.readInt();
+ if (stateVersion > AGENT_VERSION) {
+ // Whoops; the last version of the app that backed up
+ // data on this device was <em>newer</em> than the current
+ // version -- the user has downgraded. That's problematic.
+ // In this implementation, we recover by simply rewriting
+ // the backup.
+ return true;
+ }
+
+ // The state data we store is just a mirror of the app's data;
+ // read it from the state file then return 'true' if any of
+ // it differs from the current data.
+ int lastFilling = in.readInt();
+ boolean lastMayo = in.readBoolean();
+ boolean lastTomato = in.readBoolean();
+
+ return (lastFilling != mFilling)
+ || (lastTomato != mAddTomato)
+ || (lastMayo != mAddMayo);
+ } catch (IOException e) {
+ // If something went wrong reading the state file, be safe
+ // and back up the data again.
+ return true;
+ }
+ }
+
+ /**
+ * Write out the new state file: the version number, followed by the
+ * three bits of data as we sent them off to the backup transport.
+ */
+ void writeStateFile(ParcelFileDescriptor stateFile) throws IOException {
+ FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+
+ out.writeInt(AGENT_VERSION);
+ out.writeInt(mFilling);
+ out.writeBoolean(mAddMayo);
+ out.writeBoolean(mAddTomato);
+ }
+
+ /**
+ * This application does not do any "live" restores of its own data,
+ * so the only time a restore will happen is when the application is
+ * installed. This means that the activity itself is not going to
+ * be running while we change its data out from under it. That, in
+ * turn, means that there is no need to send out any sort of notification
+ * of the new data: we only need to read the data from the stream
+ * provided here, build the application's new data file, and then
+ * write our new backup state blob that will be consulted at the next
+ * backup operation.
+ *
+ * <p>We don't bother checking the versionCode of the app who originated
+ * the data because we have never revised the backup data format. If
+ * we had, the 'appVersionCode' parameter would tell us how we should
+ * interpret the data we're about to read.
+ */
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // We should only see one entity in the data stream, but the safest
+ // way to consume it is using a while() loop
+ while (data.readNextHeader()) {
+ String key = data.getKey();
+ int dataSize = data.getDataSize();
+
+ if (APP_DATA_KEY.equals(key)) {
+ // It's our saved data, a flattened chunk of data all in
+ // one buffer. Use some handy structured I/O classes to
+ // extract it.
+ byte[] dataBuf = new byte[dataSize];
+ data.readEntityData(dataBuf, 0, dataSize);
+ ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+ DataInputStream in = new DataInputStream(baStream);
+
+ mFilling = in.readInt();
+ mAddMayo = in.readBoolean();
+ mAddTomato = in.readBoolean();
+
+ // Now we are ready to construct the app's data file based
+ // on the data we are restoring from.
+ synchronized (HugeBackupActivity.sDataLock) {
+ RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
+ file.setLength(0L);
+ file.writeInt(mFilling);
+ file.writeBoolean(mAddMayo);
+ file.writeBoolean(mAddTomato);
+ }
+ } else {
+ // Curious! This entity is data under a key we do not
+ // understand how to process. Just skip it.
+ data.skipEntityData();
+ }
+ }
+
+ // The last thing to do is write the state blob that describes the
+ // app's data as restored from backup.
+ writeStateFile(newState);
+ }
+}
diff --git a/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java b/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java
new file mode 100644
index 0000000..84e31aa
--- /dev/null
+++ b/tests/HugeBackup/src/com/android/hugebackup/HugeBackupActivity.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.hugebackup;
+
+import android.app.Activity;
+import android.app.backup.BackupManager;
+import android.app.backup.RestoreObserver;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.RadioGroup;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Deliberately back up waaaaaaay too much data. Cloned with some alterations
+ * from the Backup/Restore sample application.
+ */
+public class HugeBackupActivity extends Activity {
+ static final String TAG = "HugeBackupActivity";
+
+ /**
+ * We serialize access to our persistent data through a global static
+ * object. This ensures that in the unlikely event of the our backup/restore
+ * agent running to perform a backup while our UI is updating the file, the
+ * agent will not accidentally read partially-written data.
+ *
+ * <p>Curious but true: a zero-length array is slightly lighter-weight than
+ * merely allocating an Object, and can still be synchronized on.
+ */
+ static final Object[] sDataLock = new Object[0];
+
+ /** Also supply a global standard file name for everyone to use */
+ static final String DATA_FILE_NAME = "saved_data";
+
+ /** The various bits of UI that the user can manipulate */
+ RadioGroup mFillingGroup;
+ CheckBox mAddMayoCheckbox;
+ CheckBox mAddTomatoCheckbox;
+
+ /** Cache a reference to our persistent data file */
+ File mDataFile;
+
+ /** Also cache a reference to the Backup Manager */
+ BackupManager mBackupManager;
+
+ /** Set up the activity and populate its UI from the persistent data. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ /** Establish the activity's UI */
+ setContentView(R.layout.backup_restore);
+
+ /** Once the UI has been inflated, cache the controls for later */
+ mFillingGroup = (RadioGroup) findViewById(R.id.filling_group);
+ mAddMayoCheckbox = (CheckBox) findViewById(R.id.mayo);
+ mAddTomatoCheckbox = (CheckBox) findViewById(R.id.tomato);
+
+ /** Set up our file bookkeeping */
+ mDataFile = new File(getFilesDir(), HugeBackupActivity.DATA_FILE_NAME);
+
+ /** It is handy to keep a BackupManager cached */
+ mBackupManager = new BackupManager(this);
+
+ /**
+ * Finally, build the UI from the persistent store
+ */
+ populateUI();
+ }
+
+ /**
+ * Configure the UI based on our persistent data, creating the
+ * data file and establishing defaults if necessary.
+ */
+ void populateUI() {
+ RandomAccessFile file;
+
+ // Default values in case there's no data file yet
+ int whichFilling = R.id.pastrami;
+ boolean addMayo = false;
+ boolean addTomato = false;
+
+ /** Hold the data-access lock around access to the file */
+ synchronized (HugeBackupActivity.sDataLock) {
+ boolean exists = mDataFile.exists();
+ try {
+ file = new RandomAccessFile(mDataFile, "rw");
+ if (exists) {
+ Log.v(TAG, "datafile exists");
+ whichFilling = file.readInt();
+ addMayo = file.readBoolean();
+ addTomato = file.readBoolean();
+ Log.v(TAG, " mayo=" + addMayo
+ + " tomato=" + addTomato
+ + " filling=" + whichFilling);
+ } else {
+ // The default values were configured above: write them
+ // to the newly-created file.
+ Log.v(TAG, "creating default datafile");
+ writeDataToFileLocked(file,
+ addMayo, addTomato, whichFilling);
+
+ // We also need to perform an initial backup; ask for one
+ mBackupManager.dataChanged();
+ }
+ } catch (IOException ioe) {
+ }
+ }
+
+ /** Now that we've processed the file, build the UI outside the lock */
+ mFillingGroup.check(whichFilling);
+ mAddMayoCheckbox.setChecked(addMayo);
+ mAddTomatoCheckbox.setChecked(addTomato);
+
+ /**
+ * We also want to record the new state when the user makes changes,
+ * so install simple observers that do this
+ */
+ mFillingGroup.setOnCheckedChangeListener(
+ new RadioGroup.OnCheckedChangeListener() {
+ public void onCheckedChanged(RadioGroup group,
+ int checkedId) {
+ // As with the checkbox listeners, rewrite the
+ // entire state file
+ Log.v(TAG, "New radio item selected: " + checkedId);
+ recordNewUIState();
+ }
+ });
+
+ CompoundButton.OnCheckedChangeListener checkListener
+ = new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView,
+ boolean isChecked) {
+ // Whichever one is altered, we rewrite the entire UI state
+ Log.v(TAG, "Checkbox toggled: " + buttonView);
+ recordNewUIState();
+ }
+ };
+ mAddMayoCheckbox.setOnCheckedChangeListener(checkListener);
+ mAddTomatoCheckbox.setOnCheckedChangeListener(checkListener);
+ }
+
+ /**
+ * Handy helper routine to write the UI data to a file.
+ */
+ void writeDataToFileLocked(RandomAccessFile file,
+ boolean addMayo, boolean addTomato, int whichFilling)
+ throws IOException {
+ file.setLength(0L);
+ file.writeInt(whichFilling);
+ file.writeBoolean(addMayo);
+ file.writeBoolean(addTomato);
+ Log.v(TAG, "NEW STATE: mayo=" + addMayo
+ + " tomato=" + addTomato
+ + " filling=" + whichFilling);
+ }
+
+ /**
+ * Another helper; this one reads the current UI state and writes that
+ * to the persistent store, then tells the backup manager that we need
+ * a backup.
+ */
+ void recordNewUIState() {
+ boolean addMayo = mAddMayoCheckbox.isChecked();
+ boolean addTomato = mAddTomatoCheckbox.isChecked();
+ int whichFilling = mFillingGroup.getCheckedRadioButtonId();
+ try {
+ synchronized (HugeBackupActivity.sDataLock) {
+ RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");
+ writeDataToFileLocked(file, addMayo, addTomato, whichFilling);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to record new UI state");
+ }
+
+ mBackupManager.dataChanged();
+ }
+
+ /**
+ * Click handler, designated in the layout, that runs a restore of the app's
+ * most recent data when the button is pressed.
+ */
+ public void onRestoreButtonClick(View v) {
+ Log.v(TAG, "Requesting restore of our most recent data");
+ mBackupManager.requestRestore(
+ new RestoreObserver() {
+ public void restoreFinished(int error) {
+ /** Done with the restore! Now draw the new state of our data */
+ Log.v(TAG, "Restore finished, error = " + error);
+ populateUI();
+ }
+ }
+ );
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 88fd678..922cd4c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -33,6 +33,7 @@
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
import java.awt.image.BufferedImage;
import java.util.List;
@@ -290,7 +291,7 @@
Paint paint) {
draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
false /*forceSrcMode*/, new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
for (int i = 0 ; i < count ; i += 4) {
graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
(int)pts[i + offset + 2], (int)pts[i + offset + 3]);
@@ -314,12 +315,12 @@
Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
return sManager.addNewDelegate(newDelegate);
- } else {
- // create a new Canvas_Delegate and return its new native int.
- Canvas_Delegate newDelegate = new Canvas_Delegate();
-
- return sManager.addNewDelegate(newDelegate);
}
+
+ // create a new Canvas_Delegate and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+ return sManager.addNewDelegate(newDelegate);
}
@LayoutlibDelegate
@@ -650,7 +651,7 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
}
});
@@ -668,8 +669,8 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
// draw
if (style == Paint.Style.FILL.nativeInt ||
@@ -692,8 +693,8 @@
if (oval.right > oval.left && oval.bottom > oval.top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
// draw
if (style == Paint.Style.FILL.nativeInt ||
@@ -722,10 +723,32 @@
@LayoutlibDelegate
/*package*/ static void native_drawArc(int nativeCanvas,
- RectF oval, float startAngle, float sweep, boolean useCenter, int paint) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Canvas.drawArc is not supported.", null, null /*data*/);
+ final RectF oval, final float startAngle, final float sweep,
+ final boolean useCenter, int paint) {
+ if (oval.right > oval.left && oval.bottom > oval.top) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
+
+ Arc2D.Float arc = new Arc2D.Float(
+ oval.left, oval.top, oval.width(), oval.height(),
+ -startAngle, -sweep,
+ useCenter ? Arc2D.PIE : Arc2D.OPEN);
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fill(arc);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.draw(arc);
+ }
+ }
+ });
+ }
}
@LayoutlibDelegate
@@ -734,8 +757,8 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
// draw
if (style == Paint.Style.FILL.nativeInt ||
@@ -766,9 +789,9 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
Shape shape = pathDelegate.getJavaShape();
- int style = paint.getStyle();
+ int style = paintDelegate.getStyle();
if (style == Paint.Style.FILL.nativeInt ||
style == Paint.Style.FILL_AND_STROKE.nativeInt) {
@@ -947,23 +970,23 @@
final float startX, final float startY, int flags, int paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
// WARNING: the logic in this method is similar to Paint_Delegate.measureText.
// Any change to this method should be reflected in Paint.measureText
// Paint.TextAlign indicates how the text is positioned relative to X.
// LEFT is the default and there's nothing to do.
float x = startX;
float y = startY;
- if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) {
- float m = paint.measureText(text, index, count);
- if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+ if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+ float m = paintDelegate.measureText(text, index, count);
+ if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
x -= m / 2;
- } else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+ } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
x -= m;
}
}
- List<FontInfo> fonts = paint.getFonts();
+ List<FontInfo> fonts = paintDelegate.getFonts();
if (fonts.size() > 0) {
FontInfo mainFont = fonts.get(0);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 6c9f48f..64f19d3 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -28,10 +28,12 @@
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
/**
* Delegate implementing the native methods of android.graphics.Path
@@ -331,58 +333,91 @@
@LayoutlibDelegate
/*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addOval is not supported.", null, null /*data*/);
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.append(new Ellipse2D.Float(
+ oval.left, oval.top, oval.width(), oval.height()), false);
}
@LayoutlibDelegate
/*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addCircle is not supported.", null, null /*data*/);
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // because x/y is the center of the circle, need to offset this by the radius
+ pathDelegate.mPath.append(new Ellipse2D.Float(
+ x - radius, y - radius, radius * 2, radius * 2), false);
}
@LayoutlibDelegate
/*package*/ static void native_addArc(int nPath, RectF oval,
float startAngle, float sweepAngle) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addArc is not supported.", null, null /*data*/);
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // because x/y is the center of the circle, need to offset this by the radius
+ pathDelegate.mPath.append(new Arc2D.Float(
+ oval.left, oval.top, oval.width(), oval.height(),
+ -startAngle, -sweepAngle, Arc2D.OPEN), false);
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(int nPath, RectF rect,
- float rx, float ry, int dir) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addRoundRect is not supported.", null, null /*data*/);
+ /*package*/ static void native_addRoundRect(
+ int nPath, RectF rect, float rx, float ry, int dir) {
+
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.append(new RoundRectangle2D.Float(
+ rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addRoundRect is not supported.", null, null /*data*/);
+ /*package*/ static void native_addRoundRect(int nPath, RectF rect, float[] radii, int dir) {
+ // Java2D doesn't support different rounded corners in each corner, so just use the
+ // first value.
+ native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+
+ // there can be a case where this API is used but with similar values for all corners, so
+ // in that case we don't warn.
+ // we only care if 2 corners are different so just compare to the next one.
+ for (int i = 0 ; i < 3 ; i++) {
+ if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Different corner sizes are not supported in Path.addRoundRect.",
+ null, null /*data*/);
+ break;
+ }
+ }
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addPath is not supported.", null, null /*data*/);
+ addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src) {
- native_addPath(nPath, src, 0, 0);
+ addPath(nPath, src, null /*transform*/);
}
@LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, int matrix) {
- // FIXME
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
- "Path.addPath is not supported.", null, null /*data*/);
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ addPath(nPath, src, matrixDelegate.getAffineTransform());
}
@LayoutlibDelegate
@@ -487,6 +522,26 @@
return null;
}
+ private static void addPath(int destPath, int srcPath, AffineTransform transform) {
+ Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
+ if (destPathDelegate == null) {
+ return;
+ }
+
+ Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
+ if (srcPathDelegate == null) {
+ return;
+ }
+
+ if (transform != null) {
+ destPathDelegate.mPath.append(
+ srcPathDelegate.mPath.getPathIterator(transform), false);
+ } else {
+ destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
+ }
+ }
+
+
/**
* Returns whether the path is empty.
* @return true if the path is empty.
@@ -652,10 +707,9 @@
* mod 360.
* @param forceMoveTo If true, always begin a new contour with the arc
*/
- private void arcTo(RectF oval, float startAngle, float sweepAngle,
- boolean forceMoveTo) {
- Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), startAngle,
- sweepAngle, Arc2D.OPEN);
+ private void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {
+ Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), -startAngle,
+ -sweepAngle, Arc2D.OPEN);
mPath.append(arc, true /*connect*/);
resetLastPointFromPath();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index acc7379..e6e9647 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -192,7 +192,7 @@
Capability.UNBOUND_RENDERING,
Capability.CUSTOM_BACKGROUND_COLOR,
Capability.RENDER,
- Capability.LAYOUT_ONLY,
+ //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
Capability.EMBEDDED_LAYOUT,
Capability.VIEW_MANIPULATION,
Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index c1d7600..138a455 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -412,9 +412,7 @@
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
- }
-
- if (RenderResources.REFERENCE_NULL.equals(s)) {
+ } else if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
@@ -486,23 +484,32 @@
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
- }
-
- if (RenderResources.REFERENCE_NULL.equals(s)) {
+ } else if (RenderResources.REFERENCE_NULL.equals(s)) {
return defValue;
}
- // FIXME huh?
+ if (ResourceHelper.stringToFloat(s, mValue)) {
+ float f = mValue.getDimension(mBridgeResources.mMetrics);
- float f = getDimension(index, defValue);
- final int res = (int)(f+0.5f);
- if (res != 0) return res;
- if (f == 0) return 0;
- if (f > 0) return 1;
+ if (f < 0) {
+ // negative values are not allowed in pixel dimensions
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Negative pixel dimension: " + s,
+ null, null /*data*/);
+ return defValue;
+ }
- Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
- "Can't convert to dimension: " + Integer.toString(index),
- null, null /*data*/);
+ if (f == 0) return 0;
+ if (f < 1) return 1;
+
+ return (int)(f+0.5f);
+ }
+
+ // looks like we were unable to resolve the dimension value
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+ s, mNames[index]), null /*data*/);
return defValue;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 69f46e6..649160e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -377,7 +377,7 @@
}
// check the first character
- if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+ if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
return false;
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1d115b1..16a61db 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -104,5 +104,7 @@
void clearBlacklist();
Messenger getMessenger();
+
+ String getConfigFile();
}
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index e6decc88..6455d84 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -1347,4 +1347,8 @@
}
return sb.toString();
}
+
+ public static String getConfigFile() {
+ return ipConfigFile;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5238899..2e49a77 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1176,6 +1176,18 @@
}
/**
+ * Returns the file in which IP and proxy configuration data is stored
+ * @hide
+ */
+ public String getConfigFile() {
+ try {
+ return mService.getConfigFile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Allows an application to keep the Wi-Fi radio awake.
* Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
* Acquiring a WifiLock will keep the radio on until the lock is released. Multiple
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 717dcf0..4346b327 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -887,6 +887,13 @@
}
/**
+ * Returns the wifi configuration file
+ */
+ public String getConfigFile() {
+ return WifiConfigStore.getConfigFile();
+ }
+
+ /**
* Send a message indicating bluetooth adapter connection state changed
*/
public void sendBluetoothAdapterStateChange(int state) {