Merge "AudioService: SCO audio backward compatibility" into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index 8115472..bd88877 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,7 @@
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
+ core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index 0bc9bd2..2ec1533 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37,8 +37,6 @@
field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
field public static final java.lang.String CAMERA = "android.permission.CAMERA";
- field public static final java.lang.String CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = "android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
- field public static final java.lang.String CAN_REQUEST_TOUCH_EXPLORATION_MODE = "android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE";
field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -322,6 +320,9 @@
field public static final int cacheColorHint = 16843009; // 0x1010101
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
+ field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+ field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
+ field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
field public static final deprecated int capitalize = 16843113; // 0x1010169
@@ -1703,7 +1704,6 @@
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
- field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1722,11 +1722,11 @@
field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
- field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
+ field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974304; // 0x10301e0
field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
- field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
+ field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1749,11 +1749,11 @@
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
- field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
+ field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
- field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
+ field public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1761,14 +1761,12 @@
field public static final int Theme_Light = 16973836; // 0x103000c
field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
- field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_NoDisplay = 16973909; // 0x1030055
field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
- field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
field public static final int Theme_Panel = 16973913; // 0x1030059
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -2107,16 +2105,22 @@
public class AccessibilityServiceInfo implements android.os.Parcelable {
ctor public AccessibilityServiceInfo();
+ method public static java.lang.String capabilityToString(int);
method public int describeContents();
method public static java.lang.String feedbackTypeToString(int);
method public static java.lang.String flagToString(int);
- method public boolean getCanRetrieveWindowContent();
+ method public deprecated boolean getCanRetrieveWindowContent();
+ method public int getCapabilities();
method public deprecated java.lang.String getDescription();
method public java.lang.String getId();
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
method public java.lang.String loadDescription(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
+ field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+ field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int DEFAULT = 1; // 0x1
field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
@@ -2129,6 +2133,7 @@
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public int eventTypes;
field public int feedbackType;
@@ -3117,9 +3122,9 @@
method public void onTerminate();
method public void onTrimMemory(int);
method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
- method public void registerOnProvideAssistData(android.app.Application.OnProvideAssistData);
+ method public void registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
- method public void unregisterOnProvideAssistData(android.app.Application.OnProvideAssistData);
+ method public void unregisterOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
}
public static abstract interface Application.ActivityLifecycleCallbacks {
@@ -3132,7 +3137,7 @@
method public abstract void onActivityStopped(android.app.Activity);
}
- public static abstract interface Application.OnProvideAssistData {
+ public static abstract interface Application.OnProvideAssistDataListener {
method public abstract void onProvideAssistData(android.app.Activity, android.os.Bundle);
}
@@ -4628,13 +4633,11 @@
method public boolean isEnabled();
method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
- method public boolean registerCallback(android.bluetooth.BluetoothAdapterCallback);
method public boolean setName(java.lang.String);
method public boolean startDiscovery();
- method public boolean startLeScan();
- method public boolean startLeScan(java.util.UUID[]);
- method public void stopLeScan();
- method public boolean unRegisterCallback(android.bluetooth.BluetoothAdapterCallback);
+ method public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@@ -4665,12 +4668,8 @@
field public static final int STATE_TURNING_ON = 11; // 0xb
}
- public abstract class BluetoothAdapterCallback {
- ctor public BluetoothAdapterCallback();
- method public void onCallbackRegistration(int);
- method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
- field public static final int CALLBACK_REGISTERED = 0; // 0x0
- field public static final int CALLBACK_REGISTRATION_FAILURE = 1; // 0x1
+ public static abstract interface BluetoothAdapter.LeScanCallback {
+ method public abstract void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
}
public class BluetoothAssignedNumbers {
@@ -10471,13 +10470,14 @@
package android.hardware.location {
public final class GeofenceHardware {
- method public boolean addCircularFence(int, double, double, double, int, int, int, int, int, android.hardware.location.GeofenceHardwareCallback);
- method public int[] getMonitoringTypesAndStatus();
+ method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
+ method public int[] getMonitoringTypes();
+ method public int getStatusOfMonitoringType(int);
method public boolean pauseGeofence(int, int);
- method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+ method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
method public boolean removeGeofence(int, int);
method public boolean resumeGeofence(int, int, int);
- method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+ method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
field public static final int GEOFENCE_ENTERED = 1; // 0x1
field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
@@ -10496,13 +10496,33 @@
public abstract class GeofenceHardwareCallback {
ctor public GeofenceHardwareCallback();
method public void onGeofenceAdd(int, int);
- method public void onGeofenceChange(int, int, android.location.Location, long, int);
method public void onGeofencePause(int, int);
method public void onGeofenceRemove(int, int);
method public void onGeofenceResume(int, int);
+ method public void onGeofenceTransition(int, int, android.location.Location, long, int);
+ }
+
+ public abstract class GeofenceHardwareMonitorCallback {
+ ctor public GeofenceHardwareMonitorCallback();
method public void onMonitoringSystemChange(int, boolean, android.location.Location);
}
+ public final class GeofenceHardwareRequest {
+ ctor public GeofenceHardwareRequest();
+ method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
+ method public int getLastTransition();
+ method public double getLatitude();
+ method public double getLongitude();
+ method public int getMonitorTransitions();
+ method public int getNotificationResponsiveness();
+ method public double getRadius();
+ method public int getUnknownTimer();
+ method public void setLastTransition(int);
+ method public void setMonitorTransitions(int);
+ method public void setNotificationResponsiveness(int);
+ method public void setUnknownTimer(int);
+ }
+
}
package android.hardware.usb {
@@ -10574,11 +10594,11 @@
}
public class UsbDeviceConnection {
- method public deprecated int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
+ method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int, int);
method public boolean claimInterface(android.hardware.usb.UsbInterface, boolean);
method public void close();
- method public deprecated int controlTransfer(int, int, int, int, byte[], int, int);
+ method public int controlTransfer(int, int, int, int, byte[], int, int);
method public int controlTransfer(int, int, int, int, byte[], int, int, int);
method public int getFileDescriptor();
method public byte[] getRawDescriptors();
@@ -11796,6 +11816,66 @@
ctor public MediaCryptoException(java.lang.String);
}
+ public final class MediaDrm {
+ ctor public MediaDrm(java.util.UUID) throws android.media.MediaDrmException;
+ method public void closeSession(byte[]);
+ method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
+ method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+ method public byte[] getPropertyByteArray(java.lang.String);
+ method public java.lang.String getPropertyString(java.lang.String);
+ method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
+ method public java.util.List<byte[]> getSecureStops();
+ method public static final boolean isCryptoSchemeSupported(java.util.UUID);
+ method public byte[] openSession();
+ method public byte[] provideKeyResponse(byte[], byte[]);
+ method public void provideProvisionResponse(byte[]);
+ method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
+ method public final void release();
+ method public void releaseSecureStops(byte[]);
+ method public void removeKeys(byte[]);
+ method public void restoreKeys(byte[], byte[]);
+ method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+ method public void setPropertyByteArray(java.lang.String, byte[]);
+ method public void setPropertyString(java.lang.String, java.lang.String);
+ field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
+ field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
+ field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+ field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+ field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
+ field public static final int KEY_TYPE_RELEASE = 3; // 0x3
+ field public static final int KEY_TYPE_STREAMING = 1; // 0x1
+ field public static final java.lang.String PROPERTY_ALGORITHM = "algorithm";
+ field public static final java.lang.String PROPERTY_DESCRIPTION = "description";
+ field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+ field public static final java.lang.String PROPERTY_VENDOR = "vendor";
+ field public static final java.lang.String PROPERTY_VERSION = "version";
+ }
+
+ public final class MediaDrm.CryptoSession {
+ method public byte[] decrypt(byte[], byte[], byte[]);
+ method public byte[] encrypt(byte[], byte[], byte[]);
+ method public byte[] sign(byte[], byte[]);
+ method public boolean verify(byte[], byte[], byte[]);
+ }
+
+ public static final class MediaDrm.KeyRequest {
+ method public byte[] getData();
+ method public java.lang.String getDefaultUrl();
+ }
+
+ public static abstract interface MediaDrm.OnEventListener {
+ method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
+ }
+
+ public static final class MediaDrm.ProvisionRequest {
+ method public byte[] getData();
+ method public java.lang.String getDefaultUrl();
+ }
+
+ public final class MediaDrmException extends java.lang.Exception {
+ ctor public MediaDrmException(java.lang.String);
+ }
+
public final class MediaExtractor {
ctor public MediaExtractor();
method public boolean advance();
@@ -17041,6 +17121,7 @@
method public int getThreadId();
method protected void onLooperPrepared();
method public boolean quit();
+ method public boolean quitSafely();
}
public abstract interface IBinder {
@@ -17081,6 +17162,7 @@
method public static void prepare();
method public static void prepareMainLooper();
method public void quit();
+ method public void quitSafely();
method public void setMessageLogging(android.util.Printer);
}
@@ -21490,7 +21572,7 @@
method public int getLac();
method public int getMcc();
method public int getMnc();
- method public int getPsc();
+ method public deprecated int getPsc();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -21506,6 +21588,17 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
+ public final class CellIdentityWcdma implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCid();
+ method public int getLac();
+ method public int getMcc();
+ method public int getMnc();
+ method public int getPsc();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public abstract class CellInfo implements android.os.Parcelable {
method public int describeContents();
method public long getTimeStamp();
@@ -21535,6 +21628,13 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
+ public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
+ method public android.telephony.CellIdentityWcdma getCellIdentity();
+ method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public abstract class CellLocation {
ctor public CellLocation();
method public static android.telephony.CellLocation getEmpty();
@@ -21590,6 +21690,17 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
+ public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean equals(java.lang.Object);
+ method public int getAsuLevel();
+ method public int getDbm();
+ method public int getLevel();
+ method public int hashCode();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
@@ -30044,7 +30155,6 @@
method public void setRelativeScrollPosition(int, int);
method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
method public void setRemoteAdapter(int, android.content.Intent);
- method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>, int);
method public void setScrollPosition(int, int);
method public void setShort(int, java.lang.String, short);
method public void setString(int, java.lang.String, java.lang.String);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 31de98d..1e3d5be 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -308,6 +308,8 @@
* android:accessibilityFlags="flagDefault"
* android:settingsActivity="foo.bar.TestBackActivity"
* android:canRetrieveWindowContent="true"
+ * android:canRequestTouchExplorationMode="true"
+ * android:canRequestEnhancedWebAccessibility="true"
* . . .
* /></pre>
*/
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d82b9a3..40f45b7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
@@ -38,7 +39,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import com.android.internal.R;
+
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* This class describes an {@link AccessibilityService}. The system notifies an
@@ -61,6 +67,49 @@
private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
/**
+ * Capability: This accessibility service can retrieve the active window content.
+ */
+ public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
+
+ /**
+ * Capability: This accessibility service can request touch exploration mode in which
+ * touched items are spoken aloud and the UI can be explored via gestures.
+ */
+ public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
+
+ /**
+ * Capability: This accessibility service can request enhanced web accessibility
+ * enhancements. For example, installing scripts to make app content more accessible.
+ */
+ public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
+
+ /**
+ * Capability: This accessibility service can request to filter the key event stream.
+ */
+ public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
+
+ private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
+ new SparseArray<CapabilityInfo>();
+ static {
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+ new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+ R.string.capability_title_canRetrieveWindowContent,
+ R.string.capability_desc_canRetrieveWindowContent));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+ R.string.capability_title_canRequestTouchExploration,
+ R.string.capability_desc_canRequestTouchExploration));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+ R.string.capability_title_canRequestEnhancedWebAccessibility,
+ R.string.capability_desc_canRequestEnhancedWebAccessibility));
+ sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+ new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+ R.string.capability_title_canRequestFilterKeyEvents,
+ R.string.capability_desc_canRequestFilterKeyEvents));
+ }
+
+ /**
* Denotes spoken feedback.
*/
public static final int FEEDBACK_SPOKEN = 0x0000001;
@@ -152,9 +201,11 @@
* <p>
* For accessibility services targeting API version higher than
* {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
- * this flag have to request the
- * {@link android.Manifest.permission#CAN_REQUEST_TOUCH_EXPLORATION_MODE}
- * permission or the flag will be ignored.
+ * this flag have to declare this capability in their meta-data by setting
+ * the attribute {@link android.R.attr#canRequestTouchExplorationMode
+ * canRequestTouchExplorationMode} to true, otherwise this flag will
+ * be ignored. For how to declare the meta-data of a service refer to
+ * {@value AccessibilityService#SERVICE_META_DATA}.
* </p>
* <p>
* Services targeting API version equal to or lower than
@@ -175,9 +226,11 @@
* device will not have enhanced web accessibility enabled since there may be
* another enabled service that requested it.
* <p>
- * Clients that want to set this flag have to request the
- * {@link android.Manifest.permission#CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY}
- * permission or the flag will be ignored.
+ * Services that want to set this flag have to declare this capability
+ * in their meta-data by setting the attribute {@link android.R.attr
+ * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
+ * true, otherwise this flag will be ignored. For how to declare the meta-data
+ * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
* </p>
*/
public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
@@ -192,6 +245,25 @@
public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
/**
+ * This flag requests from the system to filter key events. If this flag
+ * is set the accessibility service will receive the key events before
+ * applications allowing it implement global shortcuts. Setting this flag
+ * does not guarantee that this service will filter key events since only
+ * one service can do so at any given time. This avoids user confusion due
+ * to behavior change in case different key filtering services are enabled.
+ * If there is already another key filtering service enabled, this one will
+ * not receive key events.
+ * <p>
+ * Services that want to set this flag have to declare this capability
+ * in their meta-data by setting the attribute {@link android.R.attr
+ * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
+ * otherwise this flag will be ignored. For how to declare the meta-data
+ * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
+ * </p>
+ */
+ public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
+
+ /**
* The event types an {@link AccessibilityService} is interested in.
* <p>
* <strong>Can be dynamically set at runtime.</strong>
@@ -259,6 +331,9 @@
* @see #DEFAULT
* @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
* @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+ * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+ * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
+ * @see #FLAG_REPORT_VIEW_IDS
*/
public int flags;
@@ -279,9 +354,9 @@
private String mSettingsActivityName;
/**
- * Flag whether this accessibility service can retrieve window content.
+ * Bit mask with capabilities of this service.
*/
- private boolean mCanRetrieveWindowContent;
+ private int mCapabilities;
/**
* Resource id of the description of the accessibility service.
@@ -360,9 +435,22 @@
com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
mSettingsActivityName = asAttributes.getString(
com.android.internal.R.styleable.AccessibilityService_settingsActivity);
- mCanRetrieveWindowContent = asAttributes.getBoolean(
- com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
- false);
+ if (asAttributes.getBoolean(com.android.internal.R.styleable
+ .AccessibilityService_canRetrieveWindowContent, false)) {
+ mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
+ }
+ if (asAttributes.getBoolean(com.android.internal.R.styleable
+ .AccessibilityService_canRequestTouchExplorationMode, false)) {
+ mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
+ }
+ if (asAttributes.getBoolean(com.android.internal.R.styleable
+ .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
+ mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
+ }
+ if (asAttributes.getBoolean(com.android.internal.R.styleable
+ .AccessibilityService_canRequestFilterKeyEvents, false)) {
+ mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
+ }
TypedValue peekedValue = asAttributes.peekValue(
com.android.internal.R.styleable.AccessibilityService_description);
if (peekedValue != null) {
@@ -446,9 +534,26 @@
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
* </p>
* @return True if window content can be retrieved.
+ *
+ * @deprecated Use {@link #getCapabilities()}.
*/
public boolean getCanRetrieveWindowContent() {
- return mCanRetrieveWindowContent;
+ return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
+ }
+
+ /**
+ * Returns the bit mask of capabilities this accessibility service has such as
+ * being able to retrieve the active window content, etc.
+ *
+ * @return The capability bit mask.
+ *
+ * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
+ * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
+ * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+ * @see #CAPABILITY_FILTER_KEY_EVENTS
+ */
+ public int getCapabilities() {
+ return mCapabilities;
}
/**
@@ -502,7 +607,7 @@
parcel.writeString(mId);
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
- parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+ parcel.writeInt(mCapabilities);
parcel.writeInt(mDescriptionResId);
parcel.writeString(mNonLocalizedDescription);
}
@@ -516,7 +621,7 @@
mId = parcel.readString();
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
- mCanRetrieveWindowContent = (parcel.readInt() == 1);
+ mCapabilities = parcel.readInt();
mDescriptionResId = parcel.readInt();
mNonLocalizedDescription = parcel.readString();
}
@@ -567,7 +672,7 @@
stringBuilder.append(", ");
stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
stringBuilder.append(", ");
- stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent);
+ appendCapabilities(stringBuilder, mCapabilities);
return stringBuilder.toString();
}
@@ -628,6 +733,20 @@
stringBuilder.append("]");
}
+ private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
+ stringBuilder.append("capabilities:");
+ stringBuilder.append("[");
+ while (capabilities != 0) {
+ final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
+ stringBuilder.append(capabilityToString(capabilityBit));
+ capabilities &= ~capabilityBit;
+ if (capabilities != 0) {
+ stringBuilder.append(", ");
+ }
+ }
+ stringBuilder.append("]");
+ }
+
/**
* Returns the string representation of a feedback type. For example,
* {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
@@ -699,12 +818,77 @@
return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
+ case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+ return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+ case FLAG_REPORT_VIEW_IDS:
+ return "FLAG_REPORT_VIEW_IDS";
+ case FLAG_REQUEST_FILTER_KEY_EVENTS:
+ return "FLAG_REQUEST_FILTER_KEY_EVENTS";
default:
return null;
}
}
/**
+ * Returns the string representation of a capability. For example,
+ * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
+ * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
+ *
+ * @param capability The capability.
+ * @return The string representation.
+ */
+ public static String capabilityToString(int capability) {
+ switch (capability) {
+ case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
+ return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
+ case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
+ return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
+ case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+ return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+ case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
+ return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ /**
+ * @hide
+ * @return The list of {@link CapabilityInfo} objects.
+ */
+ public List<CapabilityInfo> getCapabilityInfos() {
+ if (mCapabilities == 0) {
+ return Collections.emptyList();
+ }
+ int capabilities = mCapabilities;
+ List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
+ while (capabilities != 0) {
+ final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
+ capabilities &= ~capabilityBit;
+ CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
+ if (capabilityInfo != null) {
+ capabilityInfos.add(capabilityInfo);
+ }
+ }
+ return capabilityInfos;
+ }
+
+ /**
+ * @hide
+ */
+ public static final class CapabilityInfo {
+ public final int capability;
+ public final int titleResId;
+ public final int descResId;
+
+ public CapabilityInfo(int capability, int titleResId, int descResId) {
+ this.capability = capability;
+ this.titleResId = titleResId;
+ this.descResId = descResId;
+ }
+ }
+
+ /**
* @see Parcelable.Creator
*/
public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a26bdbc..6b5df7f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1353,8 +1353,8 @@
* of the assist Intent. The default implementation does nothing.
*
* <p>This function will be called after any global assist callbacks that had
- * been registered with {@link Application#registerOnProvideAssistData
- * Application.registerOnProvideAssistData}.
+ * been registered with {@link Application#registerOnProvideAssistDataListener
+ * Application.registerOnProvideAssistDataListener}.
*/
public void onProvideAssistData(Bundle data) {
}
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 0d7f0a7..75e4bab 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -17,17 +17,14 @@
package android.app;
import java.util.ArrayList;
-import java.util.List;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
-import android.content.RestrictionEntry;
import android.content.res.Configuration;
import android.os.Bundle;
-import android.os.UserManager;
/**
* Base class for those who need to maintain global application state. You can
@@ -49,7 +46,7 @@
new ArrayList<ComponentCallbacks>();
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
- private ArrayList<OnProvideAssistData> mAssistCallbacks = null;
+ private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
/** @hide */
public LoadedApk mLoadedApk;
@@ -65,10 +62,10 @@
}
/**
- * Callback interface for use with {@link Application#registerOnProvideAssistData}
- * and {@link Application#unregisterOnProvideAssistData}.
+ * Callback interface for use with {@link Application#registerOnProvideAssistDataListener}
+ * and {@link Application#unregisterOnProvideAssistDataListener}.
*/
- public interface OnProvideAssistData {
+ public interface OnProvideAssistDataListener {
/**
* This is called when the user is requesting an assist, to build a full
* {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
@@ -158,16 +155,16 @@
}
}
- public void registerOnProvideAssistData(OnProvideAssistData callback) {
+ public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
synchronized (this) {
if (mAssistCallbacks == null) {
- mAssistCallbacks = new ArrayList<OnProvideAssistData>();
+ mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>();
}
mAssistCallbacks.add(callback);
}
}
- public void unregisterOnProvideAssistData(OnProvideAssistData callback) {
+ public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
synchronized (this) {
if (mAssistCallbacks != null) {
mAssistCallbacks.remove(callback);
@@ -280,7 +277,7 @@
}
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
- ((OnProvideAssistData)callbacks[i]).onProvideAssistData(activity, data);
+ ((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data);
}
}
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2e9c9e3..3498bb8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,7 +20,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.os.Binder;
-import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelUuid;
@@ -30,11 +29,14 @@
import android.util.Pair;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
@@ -357,9 +359,7 @@
private final IBluetoothManager mManagerService;
private IBluetooth mService;
- private Handler mServiceRecordHandler;
- private BluetoothAdapterCallback mCallback;
- private int mClientIf;
+ private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
/**
* Get a handle to the default local Bluetooth adapter.
@@ -394,7 +394,7 @@
mService = managerService.registerAdapter(mManagerCallback);
} catch (RemoteException e) {Log.e(TAG, "", e);}
mManagerService = managerService;
- mServiceRecordHandler = null;
+ mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
}
/**
@@ -1409,72 +1409,38 @@
}
/**
- * Register an callback to receive async results, such as LE scan result.
+ * Callback interface used to deliver LE scan results.
*
- * <p>This is an asynchronous call. The callback
- * {@link BluetoothAdapterCallback#onCallbackRegistration}
- * is used to notify success or failure if the function returns true.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks.
- * @return If true, the callback will be called to notify success or failure,
- * false on immediate error
+ * @see #startLeScan(LeScanCallback)
+ * @see #startLeScan(UUID[], LeScanCallback)
*/
- public boolean registerCallback(BluetoothAdapterCallback callback) {
- try {
- IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
- mCallback = callback;
- UUID uuid = UUID.randomUUID();
- if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
-
- iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- return false;
- }
- }
-
- /**
- * Unregister the registered callback.
- */
- public boolean unRegisterCallback(BluetoothAdapterCallback callback) {
- if (callback != mCallback) return false;
- try {
- IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-
- iGatt.unregisterClient(mClientIf);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- return false;
- }
+ public interface LeScanCallback {
+ /**
+ * Callback reporting an LE device found during a device scan initiated
+ * by the {@link BluetoothAdapter#startLeScan} function.
+ *
+ * @param device Identifies the remote device
+ * @param rssi The RSSI value for the remote device as reported by the
+ * Bluetooth hardware. 0 if no RSSI value is available.
+ * @param scanRecord The content of the advertisement record offered by
+ * the remote device.
+ */
+ public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
}
/**
* Starts a scan for Bluetooth LE devices.
*
* <p>Results of the scan are reported using the
- * {@link BluetoothAdapterCallback#onLeScan} callback.
+ * {@link LeScanCallback#onLeScan} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
+ * @param callback the callback LE scan results are delivered
* @return true, if the scan was started successfully
*/
- public boolean startLeScan() {
- if (DBG) Log.d(TAG, "startLeScan()");
- if (mClientIf == 0) return false;
-
- try {
- IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
- iGatt.startScan(mClientIf, false);
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
- return false;
- }
-
- return true;
+ public boolean startLeScan(LeScanCallback callback) {
+ return startLeScan(null, callback);
}
/**
@@ -1482,155 +1448,281 @@
* advertise given services.
*
* <p>Devices which advertise all specified services are reported using the
- * {@link BluetoothAdapterCallback#onLeScan} callback.
+ * {@link LeScanCallback#onLeScan} callback.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param serviceUuids Array of services to look for
+ * @param callback the callback LE scan results are delivered
* @return true, if the scan was started successfully
*/
- public boolean startLeScan(UUID[] serviceUuids) {
- if (DBG) Log.d(TAG, "startLeScan() - with UUIDs");
- if (mClientIf == 0) return false;
+ public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
+ if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
- try {
- IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
- ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
- for(int i = 0; i != uuids.length; ++i) {
- uuids[i] = new ParcelUuid(serviceUuids[i]);
- }
- iGatt.startScanWithUuids(mClientIf, false, uuids);
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
+ if (callback == null) {
+ if (DBG) Log.e(TAG, "startLeScan: null callback");
return false;
}
- return true;
+ synchronized(mLeScanClients) {
+ if (mLeScanClients.containsKey(callback)) {
+ if (DBG) Log.e(TAG, "LE Scan has already started");
+ return false;
+ }
+
+ try {
+ IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+ UUID uuid = UUID.randomUUID();
+ GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
+
+ iGatt.registerClient(new ParcelUuid(uuid), wrapper);
+ if (wrapper.scanStarted()) {
+ mLeScanClients.put(callback, wrapper);
+ return true;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+ return false;
}
/**
* Stops an ongoing Bluetooth LE device scan.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param callback used to identify which scan to stop
+ * must be the same handle used to start the scan
*/
- public void stopLeScan() {
- if (DBG) Log.d(TAG, "stopScan()");
- if (mClientIf == 0) return;
-
- try {
- IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
- iGatt.stopScan(mClientIf, false);
- } catch (RemoteException e) {
- Log.e(TAG,"",e);
+ public void stopLeScan(LeScanCallback callback) {
+ if (DBG) Log.d(TAG, "stopLeScan()");
+ GattCallbackWrapper wrapper;
+ synchronized(mLeScanClients) {
+ wrapper = mLeScanClients.remove(callback);
+ if (wrapper == null) return;
}
+ wrapper.stopLeScan();
}
/**
* Bluetooth GATT interface callbacks
*/
- private final IBluetoothGattCallback mBluetoothGattCallback =
- new IBluetoothGattCallback.Stub() {
- /**
- * Application interface registered - app is ready to go
- */
- public void onClientRegistered(int status, int clientIf) {
- if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
- + " clientIf=" + clientIf);
- mClientIf = clientIf;
- mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ?
- BluetoothAdapterCallback.CALLBACK_REGISTERED :
- BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE);
- }
+ private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
+ private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
+ private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
- public void onClientConnectionState(int status, int clientIf,
- boolean connected, String address) {
- // no op
- }
+ private final LeScanCallback mLeScanCb;
+ // mLeHandle 0: not registered
+ // -1: scan stopped
+ // >0: registered and scan started
+ private int mLeHandle;
+ private final UUID[] mScanFilter;
+ private WeakReference<BluetoothAdapter> mBluetoothAdapter;
- /**
- * Callback reporting an LE scan result.
- * @hide
- */
- public void onScanResult(String address, int rssi, byte[] advData) {
- if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+ public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter,
+ LeScanCallback leScanCb, UUID[] uuid) {
+ mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
+ mLeScanCb = leScanCb;
+ mScanFilter = uuid;
+ mLeHandle = 0;
+ }
- try {
- mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
+ public boolean scanStarted() {
+ boolean started = false;
+ synchronized(this) {
+ if (mLeHandle == -1) return false;
+
+ int count = 0;
+ // wait for callback registration and LE scan to start
+ while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) {
+ try {
+ wait(LE_CALLBACK_REG_TIMEOUT);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Callback reg wait interrupted: " + e);
+ }
+ count++;
}
+ started = (mLeHandle > 0);
}
+ return started;
+ }
- public void onGetService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid) {
- // no op
+ public void stopLeScan() {
+ synchronized(this) {
+ if (mLeHandle <= 0) {
+ Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+ return;
+ }
+ BluetoothAdapter adapter = mBluetoothAdapter.get();
+ if (adapter != null) {
+ try {
+ IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+ iGatt.stopScan(mLeHandle, false);
+ iGatt.unregisterClient(mLeHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to stop scan and unregister" + e);
+ }
+ } else {
+ Log.e(TAG, "stopLeScan, BluetoothAdapter is null");
+ }
+ mLeHandle = -1;
+ notifyAll();
}
+ }
- public void onGetIncludedService(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int inclSrvcType, int inclSrvcInstId,
- ParcelUuid inclSrvcUuid) {
- // no op
+ /**
+ * Application interface registered - app is ready to go
+ */
+ public void onClientRegistered(int status, int clientIf) {
+ if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status +
+ " clientIf=" + clientIf);
+ synchronized(this) {
+ if (mLeHandle == -1) {
+ if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled");
+ }
+
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ mLeHandle = clientIf;
+ IBluetoothGatt iGatt = null;
+ try {
+ BluetoothAdapter adapter = mBluetoothAdapter.get();
+ if (adapter != null) {
+ iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+ if (mScanFilter == null) {
+ iGatt.startScan(mLeHandle, false);
+ } else {
+ ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length];
+ for(int i = 0; i != uuids.length; ++i) {
+ uuids[i] = new ParcelUuid(mScanFilter[i]);
+ }
+ iGatt.startScanWithUuids(mLeHandle, false, uuids);
+ }
+ } else {
+ Log.e(TAG, "onClientRegistered, BluetoothAdapter null");
+ mLeHandle = -1;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "fail to start le scan: " + e);
+ mLeHandle = -1;
+ }
+ if (mLeHandle == -1) {
+ // registration succeeded but start scan failed
+ if (iGatt != null) {
+ try {
+ iGatt.unregisterClient(mLeHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "fail to unregister callback: " + mLeHandle +
+ " error: " + e);
+ }
+ }
+ }
+ } else {
+ // registration failed
+ mLeHandle = -1;
+ }
+ notifyAll();
}
+ }
- public void onGetCharacteristic(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- int charProps) {
- // no op
+ public void onClientConnectionState(int status, int clientIf,
+ boolean connected, String address) {
+ // no op
+ }
+
+ /**
+ * Callback reporting an LE scan result.
+ * @hide
+ */
+ public void onScanResult(String address, int rssi, byte[] advData) {
+ if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+
+ // Check null in case the scan has been stopped
+ synchronized(this) {
+ if (mLeHandle <= 0) return;
}
-
- public void onGetDescriptor(String address, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- ParcelUuid descUuid) {
- // no op
+ try {
+ BluetoothAdapter adapter = mBluetoothAdapter.get();
+ if (adapter == null) {
+ Log.d(TAG, "onScanResult, BluetoothAdapter null");
+ return;
+ }
+ mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData);
+ } catch (Exception ex) {
+ Log.w(TAG, "Unhandled exception: " + ex);
}
+ }
- public void onSearchComplete(String address, int status) {
- // no op
- }
+ public void onGetService(String address, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid) {
+ // no op
+ }
- public void onCharacteristicRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid, byte[] value) {
- // no op
- }
+ public void onGetIncludedService(String address, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int inclSrvcType, int inclSrvcInstId,
+ ParcelUuid inclSrvcUuid) {
+ // no op
+ }
- public void onCharacteristicWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid) {
- // no op
- }
+ public void onGetCharacteristic(String address, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid,
+ int charProps) {
+ // no op
+ }
- public void onNotify(String address, int srvcType,
+ public void onGetDescriptor(String address, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid,
+ ParcelUuid descUuid) {
+ // no op
+ }
+
+ public void onSearchComplete(String address, int status) {
+ // no op
+ }
+
+ public void onCharacteristicRead(String address, int status, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid, byte[] value) {
+ // no op
+ }
+
+ public void onCharacteristicWrite(String address, int status, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid) {
+ // no op
+ }
+
+ public void onNotify(String address, int srvcType,
int srvcInstId, ParcelUuid srvcUuid,
int charInstId, ParcelUuid charUuid,
byte[] value) {
- // no op
- }
+ // no op
+ }
- public void onDescriptorRead(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- ParcelUuid descrUuid, byte[] value) {
- // no op
- }
+ public void onDescriptorRead(String address, int status, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid,
+ ParcelUuid descrUuid, byte[] value) {
+ // no op
+ }
- public void onDescriptorWrite(String address, int status, int srvcType,
- int srvcInstId, ParcelUuid srvcUuid,
- int charInstId, ParcelUuid charUuid,
- ParcelUuid descrUuid) {
- // no op
- }
+ public void onDescriptorWrite(String address, int status, int srvcType,
+ int srvcInstId, ParcelUuid srvcUuid,
+ int charInstId, ParcelUuid charUuid,
+ ParcelUuid descrUuid) {
+ // no op
+ }
- public void onExecuteWrite(String address, int status) {
- // no op
- }
+ public void onExecuteWrite(String address, int status) {
+ // no op
+ }
- public void onReadRemoteRssi(String address, int rssi, int status) {
- // no op
- }
- };
+ public void onReadRemoteRssi(String address, int rssi, int status) {
+ // no op
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java
deleted file mode 100644
index a726bc9..0000000
--- a/core/java/android/bluetooth/BluetoothAdapterCallback.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 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.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-
-/**
- * This abstract class is used to implement {@link BluetoothAdapter} callbacks.
- */
-public abstract class BluetoothAdapterCallback {
-
- /**
- * Indicates the callback has been registered successfully
- */
- public static final int CALLBACK_REGISTERED = 0;
-
- /**
- * Indicates the callback registration has failed
- */
- public static final int CALLBACK_REGISTRATION_FAILURE = 1;
-
- /**
- * Callback to inform change in registration state of the application.
- *
- * @param status Returns {@link #CALLBACK_REGISTERED} if the application
- * was successfully registered.
- */
- public void onCallbackRegistration(int status) {
- }
-
- /**
- * Callback reporting an LE device found during a device scan initiated
- * by the {@link BluetoothAdapter#startLeScan} function.
- *
- * @param device Identifies the remote device
- * @param rssi The RSSI value for the remote device as reported by the
- * Bluetooth hardware. 0 if no RSSI value is available.
- * @param scanRecord The content of the advertisement record offered by
- * the remote device.
- */
- public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 19083b5..172f3bc 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -127,7 +127,7 @@
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+ IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) return connectedDevices;
connectedDevices = iGatt.getDevicesMatchingConnectionStates(
@@ -172,7 +172,7 @@
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+ IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) return devices;
devices = iGatt.getDevicesMatchingConnectionStates(states);
} catch (RemoteException e) {
@@ -203,7 +203,7 @@
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+ IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) {
Log.e(TAG, "Fail to get GATT Server connection");
return null;
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 35bbb9c..e67d0d7 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -129,6 +129,9 @@
private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+ private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
+ mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
+ GeofenceHardwareMonitorCallbackWrapper>();
/**
* @hide
*/
@@ -137,8 +140,29 @@
}
/**
- * Returns all the hardware geofence monitoring systems and their status.
- * Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
+ * Returns all the hardware geofence monitoring systems which are supported
+ *
+ * <p> Call {@link #getStatusOfMonitoringType(int)} to know the current state
+ * of a monitoring system.
+ *
+ * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+ * geofencing in hardware.
+ *
+ * @return An array of all the monitoring types.
+ * An array of length 0 is returned in case of errors.
+ */
+ public int[] getMonitoringTypes() {
+ try {
+ return mService.getMonitoringTypes();
+ } catch (RemoteException e) {
+ }
+ return new int[0];
+ }
+
+ /**
+ * Returns current status of a hardware geofence monitoring system.
+ *
+ * <p>Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
* {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED}
*
* <p> Some supported hardware monitoring systems might not be available
@@ -147,18 +171,15 @@
* geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to
* {@link #MONITOR_CURRENTLY_UNAVAILABLE}.
*
- * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
- * geofencing in hardware.
- *
- * @return An array indexed by the various monitoring types and their status.
- * An array of length 0 is returned in case of errors.
+ * @param monitoringType
+ * @return Current status of the monitoring type.
*/
- public int[] getMonitoringTypesAndStatus() {
+ public int getStatusOfMonitoringType(int monitoringType) {
try {
- return mService.getMonitoringTypesAndStatus();
+ return mService.getStatusOfMonitoringType(monitoringType);
} catch (RemoteException e) {
+ return MONITOR_UNSUPPORTED;
}
- return new int[0];
}
/**
@@ -167,8 +188,10 @@
* <p> When the device detects that is has entered, exited or is uncertain
* about the area specified by the geofence, the given callback will be called.
*
- * <p> The {@link GeofenceHardwareCallback#onGeofenceChange} callback will be called,
- * with the following parameters
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the
+ * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be
+ * called with the following parameters when a transition event occurs.
* <ul>
* <li> The geofence Id
* <li> The location object indicating the last known location.
@@ -195,43 +218,46 @@
* which abstracts the hardware should be used instead. All the checks are done by the higher
* level public API. Any needed locking should be handled by the higher level API.
*
- * @param latitude Latitude of the area to be monitored.
- * @param longitude Longitude of the area to be monitored.
- * @param radius Radius (in meters) of the area to be monitored.
- * @param lastTransition The current state of the geofence. Can be one of
- * {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
- * {@link #GEOFENCE_UNCERTAIN}.
- * @param monitorTransitions Bitwise OR of {@link #GEOFENCE_ENTERED},
- * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
- * @param notificationResponsivenes Defines the best-effort description
- * of how soon should the callback be called when the transition
- * associated with the Geofence is triggered. For instance, if
- * set to 1000 millseconds with {@link #GEOFENCE_ENTERED},
- * the callback will be called 1000 milliseconds within entering
- * the geofence. This parameter is defined in milliseconds.
- * @param unknownTimer The time limit after which the
- * {@link #GEOFENCE_UNCERTAIN} transition
- * should be triggered. This paramter is defined in milliseconds.
+ * <p> Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to
+ * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object
+ * in this call.
+ *
+ * @param geofenceId The id associated with the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
+ * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the
+ * geofence.
* @param callback {@link GeofenceHardwareCallback} that will be use to notify the
* transition.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for addition.
+ * @throws IllegalArgumentException when the geofence request type is not supported.
*/
- public boolean addCircularFence(int geofenceId, double latitude, double longitude,
- double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
- int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) {
+ public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest
+ geofenceRequest, GeofenceHardwareCallback callback) {
try {
- return mService.addCircularFence(geofenceId, latitude, longitude, radius,
- lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer,
- monitoringType, getCallbackWrapper(callback));
+ if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+ return mService.addCircularFence(geofenceId, monitoringType,
+ geofenceRequest.getLatitude(),
+ geofenceRequest.getLongitude(), geofenceRequest.getRadius(),
+ geofenceRequest.getLastTransition(),
+ geofenceRequest.getMonitorTransitions(),
+ geofenceRequest.getNotificationResponsiveness(),
+ geofenceRequest.getUnknownTimer(),
+ getCallbackWrapper(callback));
+ } else {
+ throw new IllegalArgumentException("Geofence Request type not supported");
+ }
} catch (RemoteException e) {
}
return false;
}
/**
- * Removes a geofence added by {@link #addCircularFence} call.
+ * Removes a geofence added by {@link #addGeofence} call.
+ *
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the
+ * remove call from the hardware.
*
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -246,7 +272,7 @@
* @param geofenceId The id of the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for removal. .
*/
public boolean removeGeofence(int geofenceId, int monitoringType) {
try {
@@ -257,7 +283,11 @@
}
/**
- * Pauses the monitoring of a geofence added by {@link #addCircularFence} call.
+ * Pauses the monitoring of a geofence added by {@link #addGeofence} call.
+ *
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the
+ * pause call from the hardware.
*
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -272,7 +302,7 @@
* @param geofenceId The id of the geofence.
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @return true when the geofence is successfully sent to the hardware for pausing.
*/
public boolean pauseGeofence(int geofenceId, int monitoringType) {
try {
@@ -285,6 +315,10 @@
/**
* Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
*
+ * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+ * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the
+ * resume call from the hardware.
+ *
* <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
* {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
*
@@ -296,15 +330,15 @@
* level public API. Any needed locking should be handled by the higher level API.
*
* @param geofenceId The id of the geofence.
- * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
- * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
* @param monitoringType The type of the hardware subsystem that should be used
* to monitor the geofence.
- * @return true on success.
+ * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
+ * {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
+ * @return true when the geofence is successfully sent to the hardware for resumption.
*/
- public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+ public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
try {
- return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType);
+ return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition);
} catch (RemoteException e) {
}
return false;
@@ -333,10 +367,10 @@
* @return true on success
*/
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- GeofenceHardwareCallback callback) {
+ GeofenceHardwareMonitorCallback callback) {
try {
return mService.registerForMonitorStateChangeCallback(monitoringType,
- getCallbackWrapper(callback));
+ getMonitorCallbackWrapper(callback));
} catch (RemoteException e) {
}
return false;
@@ -361,12 +395,12 @@
* @return true on success
*/
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- GeofenceHardwareCallback callback) {
+ GeofenceHardwareMonitorCallback callback) {
boolean result = false;
try {
result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
- getCallbackWrapper(callback));
- if (result) removeCallback(callback);
+ getMonitorCallbackWrapper(callback));
+ if (result) removeMonitorCallback(callback);
} catch (RemoteException e) {
}
@@ -391,6 +425,38 @@
}
}
+ private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) {
+ synchronized (mMonitorCallbacks) {
+ mMonitorCallbacks.remove(callback);
+ }
+ }
+
+ private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper(
+ GeofenceHardwareMonitorCallback callback) {
+ synchronized (mMonitorCallbacks) {
+ GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback);
+ if (wrapper == null) {
+ wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback);
+ mMonitorCallbacks.put(callback, wrapper);
+ }
+ return wrapper;
+ }
+ }
+
+ class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub {
+ private WeakReference<GeofenceHardwareMonitorCallback> mCallback;
+
+ GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) {
+ mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c);
+ }
+
+ public void onMonitoringSystemChange(int monitoringType, boolean available,
+ Location location) {
+ GeofenceHardwareMonitorCallback c = mCallback.get();
+ if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
+ }
+ }
+
class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
private WeakReference<GeofenceHardwareCallback> mCallback;
@@ -398,17 +464,11 @@
mCallback = new WeakReference<GeofenceHardwareCallback>(c);
}
- public void onMonitoringSystemChange(int monitoringType, boolean available,
- Location location) {
- GeofenceHardwareCallback c = mCallback.get();
- if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
- }
-
- public void onGeofenceChange(int geofenceId, int transition, Location location,
+ public void onGeofenceTransition(int geofenceId, int transition, Location location,
long timestamp, int monitoringType) {
GeofenceHardwareCallback c = mCallback.get();
if (c != null) {
- c.onGeofenceChange(geofenceId, transition, location, timestamp,
+ c.onGeofenceTransition(geofenceId, transition, location, timestamp,
monitoringType);
}
}
@@ -428,7 +488,9 @@
public void onGeofencePause(int geofenceId, int status) {
GeofenceHardwareCallback c = mCallback.get();
- if (c != null) c.onGeofencePause(geofenceId, status);
+ if (c != null) {
+ c.onGeofencePause(geofenceId, status);
+ }
}
public void onGeofenceResume(int geofenceId, int status) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
index 8ab582a..6cad3da 100644
--- a/core/java/android/hardware/location/GeofenceHardwareCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -22,19 +22,6 @@
* The callback class associated with the APIs in {@link GeofenceHardware}
*/
public abstract class GeofenceHardwareCallback {
-
- /**
- * The callback called when the state of a monitoring system changes.
- * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
- * monitoring system.
- *
- * @param monitoringType The type of the monitoring system.
- * @param available Indicates whether the system is currently available or not.
- * @param location The last known location according to the monitoring system.
- */
- public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
- }
-
/**
* The callback called when there is a transition to report for the specific
* geofence.
@@ -47,7 +34,7 @@
* detected
* @param monitoringType Type of the monitoring system.
*/
- public void onGeofenceChange(int geofenceId, int transition, Location location,
+ public void onGeofenceTransition(int geofenceId, int transition, Location location,
long timestamp, int monitoringType) {
}
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 21f1ea6..a62b660 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -21,8 +21,10 @@
import android.location.IGpsGeofenceHardware;
import android.location.Location;
import android.location.LocationManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -48,8 +50,9 @@
private PowerManager.WakeLock mWakeLock;
private SparseArray<IGeofenceHardwareCallback> mGeofences =
new SparseArray<IGeofenceHardwareCallback>();
- private ArrayList<IGeofenceHardwareCallback>[] mCallbacks =
+ private ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
new ArrayList[GeofenceHardware.NUM_MONITORS];
+ private ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
private IGpsGeofenceHardware mGpsService;
@@ -63,11 +66,18 @@
private static final int RESUME_GEOFENCE_CALLBACK = 5;
private static final int ADD_GEOFENCE = 6;
private static final int REMOVE_GEOFENCE = 7;
+ private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8;
// mCallbacksHandler message types
private static final int GPS_GEOFENCE_STATUS = 1;
private static final int CALLBACK_ADD = 2;
private static final int CALLBACK_REMOVE = 3;
+ private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
+
+ // mReaperHandler message types
+ private static final int REAPER_GEOFENCE_ADDED = 1;
+ private static final int REAPER_MONITOR_CALLBACK_ADDED = 2;
+ private static final int REAPER_REMOVED = 3;
// The following constants need to match GpsLocationFlags enum in gps.h
private static final int LOCATION_INVALID = 0;
@@ -151,15 +161,28 @@
}
}
- public int[] getMonitoringTypesAndStatus() {
+ public int[] getMonitoringTypes() {
synchronized (mSupportedMonitorTypes) {
- return mSupportedMonitorTypes;
+ if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
+ GeofenceHardware.MONITOR_UNSUPPORTED) {
+ return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
+ }
+ return new int[0];
}
}
- public boolean addCircularFence(int geofenceId, double latitude, double longitude,
- double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
- int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) {
+ public int getStatusOfMonitoringType(int monitoringType) {
+ synchronized (mSupportedMonitorTypes) {
+ if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
+ throw new IllegalArgumentException("Unknown monitoring type");
+ }
+ return mSupportedMonitorTypes[monitoringType];
+ }
+ }
+
+ public boolean addCircularFence(int geofenceId, int monitoringType, double latitude,
+ double longitude, double radius, int lastTransition,int monitorTransitions,
+ int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) {
// This API is not thread safe. Operations on the same geofence need to be serialized
// by upper layers
if (DEBUG) {
@@ -190,7 +213,11 @@
default:
result = false;
}
- if (!result) {
+ if (result) {
+ m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
+ m.arg1 = monitoringType;
+ mReaperHandler.sendMessage(m);
+ } else {
m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE);
m.arg1 = geofenceId;
mGeofenceHandler.sendMessage(m);
@@ -245,7 +272,7 @@
}
- public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+ public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
// This API is not thread safe. Operations on the same geofence need to be serialized
// by upper layers
if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
@@ -268,7 +295,12 @@
}
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
+ Message reaperMessage =
+ mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
+ reaperMessage.arg1 = monitoringType;
+ mReaperHandler.sendMessage(reaperMessage);
+
Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
m.arg1 = monitoringType;
mCallbacksHandler.sendMessage(m);
@@ -276,7 +308,7 @@
}
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
m.arg1 = monitoringType;
mCallbacksHandler.sendMessage(m);
@@ -477,13 +509,25 @@
"Location: " + geofenceTransition.mLocation + ":" + mGeofences);
try {
- callback.onGeofenceChange(
+ callback.onGeofenceTransition(
geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
geofenceTransition.mLocation, geofenceTransition.mTimestamp,
GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
} catch (RemoteException e) {}
releaseWakeLock();
break;
+ case GEOFENCE_CALLBACK_BINDER_DIED:
+ // Find all geofences associated with this callback and remove them.
+ callback = (IGeofenceHardwareCallback) (msg.obj);
+ if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
+ int monitoringType = msg.arg1;
+ for (int i = 0; i < mGeofences.size(); i++) {
+ if (mGeofences.valueAt(i).equals(callback)) {
+ geofenceId = mGeofences.keyAt(i);
+ removeGeofence(mGeofences.keyAt(i), monitoringType);
+ mGeofences.remove(geofenceId);
+ }
+ }
}
}
};
@@ -493,8 +537,8 @@
@Override
public void handleMessage(Message msg) {
int monitoringType;
- ArrayList<IGeofenceHardwareCallback> callbackList;
- IGeofenceHardwareCallback callback;
+ ArrayList<IGeofenceHardwareMonitorCallback> callbackList;
+ IGeofenceHardwareMonitorCallback callback;
switch (msg.what) {
case GPS_GEOFENCE_STATUS:
@@ -508,7 +552,7 @@
if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
- for (IGeofenceHardwareCallback c: callbackList) {
+ for (IGeofenceHardwareMonitorCallback c: callbackList) {
try {
c.onMonitoringSystemChange(
GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
@@ -519,22 +563,71 @@
break;
case CALLBACK_ADD:
monitoringType = msg.arg1;
- callback = (IGeofenceHardwareCallback) msg.obj;
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
callbackList = mCallbacks[monitoringType];
if (callbackList == null) {
- callbackList = new ArrayList<IGeofenceHardwareCallback>();
+ callbackList = new ArrayList<IGeofenceHardwareMonitorCallback>();
mCallbacks[monitoringType] = callbackList;
}
if (!callbackList.contains(callback)) callbackList.add(callback);
break;
case CALLBACK_REMOVE:
monitoringType = msg.arg1;
- callback = (IGeofenceHardwareCallback) msg.obj;
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
callbackList = mCallbacks[monitoringType];
if (callbackList != null) {
callbackList.remove(callback);
}
break;
+ case MONITOR_CALLBACK_BINDER_DIED:
+ callback = (IGeofenceHardwareMonitorCallback) msg.obj;
+ if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback);
+ callbackList = mCallbacks[msg.arg1];
+ if (callbackList != null && callbackList.contains(callback)) {
+ callbackList.remove(callback);
+ }
+ }
+ }
+ };
+
+ // All operations on mReaper
+ private Handler mReaperHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Reaper r;
+ IGeofenceHardwareCallback callback;
+ IGeofenceHardwareMonitorCallback monitorCallback;
+ int monitoringType;
+
+ switch (msg.what) {
+ case REAPER_GEOFENCE_ADDED:
+ callback = (IGeofenceHardwareCallback) msg.obj;
+ monitoringType = msg.arg1;
+ r = new Reaper(callback, monitoringType);
+ if (!mReapers.contains(r)) {
+ mReapers.add(r);
+ IBinder b = callback.asBinder();
+ try {
+ b.linkToDeath(r, 0);
+ } catch (RemoteException e) {}
+ }
+ break;
+ case REAPER_MONITOR_CALLBACK_ADDED:
+ monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj;
+ monitoringType = msg.arg1;
+
+ r = new Reaper(monitorCallback, monitoringType);
+ if (!mReapers.contains(r)) {
+ mReapers.add(r);
+ IBinder b = monitorCallback.asBinder();
+ try {
+ b.linkToDeath(r, 0);
+ } catch (RemoteException e) {}
+ }
+ break;
+ case REAPER_REMOVED:
+ r = (Reaper) msg.obj;
+ mReapers.remove(r);
}
}
};
@@ -567,6 +660,57 @@
return RESOLUTION_LEVEL_NONE;
}
+ class Reaper implements IBinder.DeathRecipient {
+ private IGeofenceHardwareMonitorCallback mMonitorCallback;
+ private IGeofenceHardwareCallback mCallback;
+ private int mMonitoringType;
+
+ Reaper(IGeofenceHardwareCallback c, int monitoringType) {
+ mCallback = c;
+ mMonitoringType = monitoringType;
+ }
+
+ Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) {
+ mMonitorCallback = c;
+ mMonitoringType = monitoringType;
+ }
+
+ @Override
+ public void binderDied() {
+ Message m;
+ if (mCallback != null) {
+ m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback);
+ m.arg1 = mMonitoringType;
+ mGeofenceHandler.sendMessage(m);
+ } else if (mMonitorCallback != null) {
+ m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback);
+ m.arg1 = mMonitoringType;
+ mCallbacksHandler.sendMessage(m);
+ }
+ Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this);
+ mReaperHandler.sendMessage(reaperMessage);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
+ result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0);
+ result = 31 * result + mMonitoringType;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ Reaper rhs = (Reaper) obj;
+ return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback &&
+ rhs.mMonitoringType == mMonitoringType;
+ }
+ }
+
int getAllowedResolutionLevel(int pid, int uid) {
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
pid, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
new file mode 100644
index 0000000..b8e927e
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.location;
+
+import android.location.Location;
+
+/**
+ * The callback class associated with the status change of hardware montiors
+ * in {@link GeofenceHardware}
+ */
+public abstract class GeofenceHardwareMonitorCallback {
+ /**
+ * The callback called when the state of a monitoring system changes.
+ * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
+ * monitoring system
+ *
+ * @param monitoringType The type of the monitoring system.
+ * @param available Indicates whether the system is currenty available or not.
+ * @param location The last known location according to the monitoring system.
+ */
+ public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
+ }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java
new file mode 100644
index 0000000..6e7b592
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 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.location;
+
+import android.location.Location;
+
+/**
+ * This class represents the characteristics of the geofence.
+ *
+ * <p> Use this in conjunction with {@link GeofenceHardware} APIs.
+ */
+
+public final class GeofenceHardwareRequest {
+ static final int GEOFENCE_TYPE_CIRCLE = 0;
+ private int mType;
+ private double mLatitude;
+ private double mLongitude;
+ private double mRadius;
+ private int mLastTransition = GeofenceHardware.GEOFENCE_UNCERTAIN;
+ private int mUnknownTimer = 30000; // 30 secs
+ private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN |
+ GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED;
+ private int mNotificationResponsiveness = 5000; // 5 secs
+
+ private void setCircularGeofence(double latitude, double longitude, double radius) {
+ mLatitude = latitude;
+ mLongitude = longitude;
+ mRadius = radius;
+ mType = GEOFENCE_TYPE_CIRCLE;
+ }
+
+ /**
+ * Create a circular geofence.
+ *
+ * @param latitude Latitude of the geofence
+ * @param longitude Longitude of the geofence
+ * @param radius Radius of the geofence (in meters)
+ */
+ public static GeofenceHardwareRequest createCircularGeofence(double latitude,
+ double longitude, double radius) {
+ GeofenceHardwareRequest geofenceRequest = new GeofenceHardwareRequest();
+ geofenceRequest.setCircularGeofence(latitude, longitude, radius);
+ return geofenceRequest;
+ }
+
+ /**
+ * Set the last known transition of the geofence.
+ *
+ * @param lastTransition The current state of the geofence. Can be one of
+ * {@link GeofenceHardware#GEOFENCE_ENTERED}, {@link GeofenceHardware#GEOFENCE_EXITED},
+ * {@link GeofenceHardware#GEOFENCE_UNCERTAIN}.
+ */
+ public void setLastTransition(int lastTransition) {
+ mLastTransition = lastTransition;
+ }
+
+ /**
+ * Set the unknown timer for this geofence.
+ *
+ * @param unknownTimer The time limit after which the
+ * {@link GeofenceHardware#GEOFENCE_UNCERTAIN} transition
+ * should be triggered. This paramter is defined in milliseconds.
+ */
+ public void setUnknownTimer(int unknownTimer) {
+ mUnknownTimer = unknownTimer;
+ }
+
+ /**
+ * Set the transitions to be monitored.
+ *
+ * @param monitorTransitions Bitwise OR of {@link GeofenceHardware#GEOFENCE_ENTERED},
+ * {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN}
+ */
+ public void setMonitorTransitions(int monitorTransitions) {
+ mMonitorTransitions = monitorTransitions;
+ }
+
+ /**
+ * Set the notification responsiveness of the geofence.
+ *
+ * @param notificationResponsiveness (milliseconds) Defines the best-effort description
+ * of how soon should the callback be called when the transition
+ * associated with the Geofence is triggered. For instance, if
+ * set to 1000 millseconds with {@link GeofenceHardware#GEOFENCE_ENTERED},
+ * the callback will be called 1000 milliseconds within entering
+ * the geofence.
+ */
+ public void setNotificationResponsiveness(int notificationResponsiveness) {
+ mNotificationResponsiveness = notificationResponsiveness;
+ }
+
+ /**
+ * Returns the latitude of this geofence.
+ */
+ public double getLatitude() {
+ return mLatitude;
+ }
+
+ /**
+ * Returns the longitude of this geofence.
+ */
+ public double getLongitude() {
+ return mLongitude;
+ }
+
+ /**
+ * Returns the radius of this geofence.
+ */
+ public double getRadius() {
+ return mRadius;
+ }
+
+ /**
+ * Returns transitions monitored for this geofence.
+ */
+ public int getMonitorTransitions() {
+ return mMonitorTransitions;
+ }
+
+ /**
+ * Returns the unknownTimer of this geofence.
+ */
+ public int getUnknownTimer() {
+ return mUnknownTimer;
+ }
+
+ /**
+ * Returns the notification responsiveness of this geofence.
+ */
+ public int getNotificationResponsiveness() {
+ return mNotificationResponsiveness;
+ }
+
+ /**
+ * Returns the last transition of this geofence.
+ */
+ public int getLastTransition() {
+ return mLastTransition;
+ }
+
+ int getType() {
+ return mType;
+ }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 0eccee6..3bc70ee 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -68,23 +68,28 @@
mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
}
- public int[] getMonitoringTypesAndStatus() {
+ public int[] getMonitoringTypes() {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
- return mGeofenceHardwareImpl.getMonitoringTypesAndStatus();
+ return mGeofenceHardwareImpl.getMonitoringTypes();
}
- public boolean addCircularFence(int id, double lat, double longitude, double radius,
- int lastTransition, int monitorTransitions, int
- notificationResponsiveness, int unknownTimer, int monitoringType,
- IGeofenceHardwareCallback callback) {
+ public int getStatusOfMonitoringType(int monitoringType) {
+ mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+ "Location Hardware permission not granted to access hardware geofence");
+
+ return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
+ }
+ public boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+ double radius, int lastTransition, int monitorTransitions, int
+ notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
- return mGeofenceHardwareImpl.addCircularFence(id, lat, longitude, radius,
- lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer,
- monitoringType, callback);
+ return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude,
+ radius, lastTransition, monitorTransitions, notificationResponsiveness,
+ unknownTimer, callback);
}
public boolean removeGeofence(int id, int monitoringType) {
@@ -103,16 +108,16 @@
return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
}
- public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) {
+ public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
- return mGeofenceHardwareImpl.resumeGeofence(id, monitorTransitions, monitoringType);
+ return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
}
public boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
@@ -122,7 +127,7 @@
}
public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback) {
+ IGeofenceHardwareMonitorCallback callback) {
mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to access hardware geofence");
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 4ba02b8..6900070 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -18,19 +18,21 @@
import android.location.IGpsGeofenceHardware;
import android.hardware.location.IGeofenceHardwareCallback;
+import android.hardware.location.IGeofenceHardwareMonitorCallback;
/** @hide */
interface IGeofenceHardware {
void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
- int[] getMonitoringTypesAndStatus();
- boolean addCircularFence(int id, double lat, double longitude, double radius,
- int lastTransition, int monitorTransitions, int notificationResponsiveness,
- int unknownTimer, int monitoringType, in IGeofenceHardwareCallback callback);
+ int[] getMonitoringTypes();
+ int getStatusOfMonitoringType(int monitoringType);
+ boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+ double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback);
boolean removeGeofence(int id, int monitoringType);
boolean pauseGeofence(int id, int monitoringType);
- boolean resumeGeofence(int id, int monitorTransitions, int monitoringType);
+ boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
boolean registerForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback);
+ IGeofenceHardwareMonitorCallback callback);
boolean unregisterForMonitorStateChangeCallback(int monitoringType,
- IGeofenceHardwareCallback callback);
+ IGeofenceHardwareMonitorCallback callback);
}
diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
index 678fc49..3a8f430 100644
--- a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
@@ -20,8 +20,7 @@
/** @hide */
oneway interface IGeofenceHardwareCallback {
- void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
- void onGeofenceChange(int geofenceId, int transition, in Location location,
+ void onGeofenceTransition(int geofenceId, int transition, in Location location,
long timestamp, int monitoringType);
void onGeofenceAdd(int geofenceId, int status);
void onGeofenceRemove(int geofenceId, int status);
diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
new file mode 100644
index 0000000..0b6e04b
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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.location;
+
+import android.location.Location;
+
+/** @hide */
+oneway interface IGeofenceHardwareMonitorCallback {
+ void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
+}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 0856e27..b2034b2 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -107,6 +107,11 @@
* {@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.
+ * <p>
+ * This method transfers data starting from index 0 in the buffer.
+ * To specify a different offset, use
+ * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
+ * </p>
*
* @param requestType request type for this transaction
* @param request request ID for this transaction
@@ -118,11 +123,7 @@
* @param timeout in milliseconds
* @return length of data transferred (or zero) for success,
* or negative value for failure
- *
- * @deprecated Use {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}
- * which accepts a buffer start index.
*/
- @Deprecated
public int controlTransfer(int requestType, int request, int value,
int index, byte[] buffer, int length, int timeout) {
return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
@@ -142,22 +143,27 @@
* @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 start the index of the first byte in the buffer to send or receive
+ * @param offset the index of the first byte in the buffer 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 controlTransfer(int requestType, int request, int value, int index,
- byte[] buffer, int start, int length, int timeout) {
- checkBounds(buffer, start, length);
+ byte[] buffer, int offset, int length, int timeout) {
+ checkBounds(buffer, offset, length);
return native_control_request(requestType, request, value, index,
- buffer, start, length, timeout);
+ buffer, offset, length, timeout);
}
/**
* Performs a bulk transaction on the given endpoint.
- * The direction of the transfer is determined by the direction of the endpoint
+ * The direction of the transfer is determined by the direction of the endpoint.
+ * <p>
+ * This method transfers data starting from index 0 in the buffer.
+ * To specify a different offset, use
+ * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}.
+ * </p>
*
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive
@@ -165,11 +171,7 @@
* @param timeout in milliseconds
* @return length of data transferred (or zero) for success,
* or negative value for failure
- *
- * @deprecated Use {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}
- * which accepts a buffer start index.
*/
- @Deprecated
public int bulkTransfer(UsbEndpoint endpoint,
byte[] buffer, int length, int timeout) {
return bulkTransfer(endpoint, buffer, 0, length, timeout);
@@ -177,20 +179,20 @@
/**
* Performs a bulk transaction on the given endpoint.
- * The direction of the transfer is determined by the direction of the 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 start the index of the first byte in the buffer to send or receive
+ * @param offset the index of the first byte in the buffer 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 start, int length, int timeout) {
- checkBounds(buffer, start, length);
- return native_bulk_request(endpoint.getAddress(), buffer, start, length, timeout);
+ byte[] buffer, int offset, int length, int timeout) {
+ checkBounds(buffer, offset, length);
+ return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
}
/**
@@ -235,9 +237,9 @@
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 start, int length, int timeout);
+ int index, byte[] buffer, int offset, int length, int timeout);
private native int native_bulk_request(int endpoint, byte[] buffer,
- int start, int length, int timeout);
+ int offset, int length, int timeout);
private native UsbRequest native_request_wait();
private native String native_get_serial();
}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 94de448..14d8f07 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -413,27 +413,32 @@
/**
* Runs the specified task synchronously.
- *
+ * <p>
* If the current thread is the same as the handler thread, then the runnable
* runs immediately without being enqueued. Otherwise, posts the runnable
* to the handler and waits for it to complete before returning.
- *
+ * </p><p>
* This method is dangerous! Improper use can result in deadlocks.
* Never call this method while any locks are held or use it in a
* possibly re-entrant manner.
- *
+ * </p><p>
* This method is occasionally useful in situations where a background thread
* must synchronously await completion of a task that must run on the
* handler's thread. However, this problem is often a symptom of bad design.
* Consider improving the design (if possible) before resorting to this method.
- *
+ * </p><p>
* One example of where you might want to use this method is when you just
* set up a Handler thread and need to perform some initialization steps on
* it before continuing execution.
- *
+ * </p><p>
* If timeout occurs then this method returns <code>false</code> but the runnable
* will remain posted on the handler and may already be in progress or
* complete at a later time.
+ * </p><p>
+ * When using this method, be sure to use {@link Looper#quitSafely} when
+ * quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely.
+ * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
+ * </p>
*
* @param r The Runnable that will be executed synchronously.
* @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index daf1f59..2904105 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -48,6 +48,7 @@
protected void onLooperPrepared() {
}
+ @Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
@@ -83,12 +84,25 @@
}
return mLooper;
}
-
+
/**
- * Ask the currently running looper to quit. If the thread has not
- * been started or has finished (that is if {@link #getLooper} returns
- * null), then false is returned. Otherwise the looper is asked to
- * quit and true is returned.
+ * Quits the handler thread's looper.
+ * <p>
+ * Causes the handler thread's looper to terminate without processing any
+ * more messages in the message queue.
+ * </p><p>
+ * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+ * For example, the {@link Handler#sendMessage(Message)} method will return false.
+ * </p><p class="note">
+ * Using this method may be unsafe because some messages may not be delivered
+ * before the looper terminates. Consider using {@link #quitSafely} instead to ensure
+ * that all pending work is completed in an orderly manner.
+ * </p>
+ *
+ * @return True if the looper looper has been asked to quit or false if the
+ * thread had not yet started running.
+ *
+ * @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
@@ -98,7 +112,34 @@
}
return false;
}
-
+
+ /**
+ * Quits the handler thread's looper safely.
+ * <p>
+ * Causes the handler thread's looper to terminate as soon as all remaining messages
+ * in the message queue that are already due to be delivered have been handled.
+ * Pending delayed messages with due times in the future will not be delivered.
+ * </p><p>
+ * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+ * For example, the {@link Handler#sendMessage(Message)} method will return false.
+ * </p><p>
+ * If the thread has not been started or has finished (that is if
+ * {@link #getLooper} returns null), then false is returned.
+ * Otherwise the looper is asked to quit and true is returned.
+ * </p>
+ *
+ * @return True if the looper looper has been asked to quit or false if the
+ * thread had not yet started running.
+ */
+ public boolean quitSafely() {
+ Looper looper = getLooper();
+ if (looper != null) {
+ looper.quitSafely();
+ return true;
+ }
+ return false;
+ }
+
/**
* Returns the identifier of this thread. See Process.myTid().
*/
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index fa28765..d5cf771 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -202,18 +202,37 @@
/**
* Quits the looper.
* <p>
- * Causes the {@link #loop} method to terminate as soon as all remaining messages
- * in the message queue that are already due to be delivered have been handled.
- * However delayed messages with due times in the future may not be handled before
- * the loop terminates.
+ * Causes the {@link #loop} method to terminate without processing any
+ * more messages in the message queue.
* </p><p>
- * Any attempt to post messages to the queue after {@link #quit} has been called
- * will fail. For example, the {@link Handler#sendMessage(Message)} method will
- * return false when the looper is being terminated.
+ * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+ * For example, the {@link Handler#sendMessage(Message)} method will return false.
+ * </p><p class="note">
+ * Using this method may be unsafe because some messages may not be delivered
+ * before the looper terminates. Consider using {@link #quitSafely} instead to ensure
+ * that all pending work is completed in an orderly manner.
* </p>
+ *
+ * @see #quitSafely
*/
public void quit() {
- mQueue.quit();
+ mQueue.quit(false);
+ }
+
+ /**
+ * Quits the looper safely.
+ * <p>
+ * Causes the {@link #loop} method to terminate as soon as all remaining messages
+ * in the message queue that are already due to be delivered have been handled.
+ * However pending delayed messages with due times in the future will not be
+ * delivered before the loop terminates.
+ * </p><p>
+ * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+ * For example, the {@link Handler#sendMessage(Message)} method will return false.
+ * </p>
+ */
+ public void quitSafely() {
+ mQueue.quit(true);
}
/**
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c058bfc..bf7e5ca 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -219,7 +219,7 @@
}
}
- void quit() {
+ void quit(boolean safe) {
if (!mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit.");
}
@@ -229,6 +229,12 @@
return;
}
mQuiting = true;
+
+ if (safe) {
+ removeAllFutureMessagesLocked();
+ } else {
+ removeAllMessagesLocked();
+ }
}
nativeWake(mPtr);
}
@@ -473,4 +479,42 @@
}
}
}
+
+ private void removeAllMessagesLocked() {
+ Message p = mMessages;
+ while (p != null) {
+ Message n = p.next;
+ p.recycle();
+ p = n;
+ }
+ mMessages = null;
+ }
+
+ private void removeAllFutureMessagesLocked() {
+ final long now = SystemClock.uptimeMillis();
+ Message p = mMessages;
+ if (p != null) {
+ if (p.when > now) {
+ removeAllMessagesLocked();
+ } else {
+ Message n;
+ for (;;) {
+ n = p.next;
+ if (n == null) {
+ return;
+ }
+ if (n.when > now) {
+ break;
+ }
+ p = n;
+ }
+ p.next = null;
+ do {
+ p = n;
+ n = p.next;
+ p.recycle();
+ } while (n != null);
+ }
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 88ee414..4de5933 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -714,6 +714,17 @@
*/
public static final String EXTRA_AUTHORITIES = "authorities";
+ /**
+ * Activity Extra: Limit available options in launched activity based on the given account
+ * types.
+ * <p>
+ * This can be passed as an extra field in an Activity Intent with one or more account types
+ * as a String[]. This field is used by some intents to alter the behavior of the called
+ * activity.
+ * <p>
+ * Example: The {@link #ACTION_ADD_ACCOUNT} intent restricts the account types to the specified
+ * list.
+ */
public static final String EXTRA_ACCOUNT_TYPES = "account_types";
public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -3260,6 +3271,7 @@
/**
* This preference contains the string that shows for owner info on LockScreen.
* @hide
+ * @deprecated
*/
public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info";
@@ -3287,6 +3299,7 @@
/**
* This preference enables showing the owner info on LockScreen.
* @hide
+ * @deprecated
*/
public static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
"lock_screen_owner_info_enabled";
@@ -4102,9 +4115,7 @@
MOUNT_UMS_AUTOSTART,
MOUNT_UMS_PROMPT,
MOUNT_UMS_NOTIFY_ENABLED,
- UI_NIGHT_MODE,
- LOCK_SCREEN_OWNER_INFO,
- LOCK_SCREEN_OWNER_INFO_ENABLED
+ UI_NIGHT_MODE
};
/**
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index edfef56..4989c3a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -220,14 +220,14 @@
/**
* Gets a {@link Canvas} for drawing into this surface.
*
- * After drawing into the provided {@link Canvas}, the caller should
+ * After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* @param inOutDirty A rectangle that represents the dirty region that the caller wants
* to redraw. This function may choose to expand the dirty rectangle if for example
* the surface has been resized or if the previous contents of the surface were
- * not available. The caller should redraw the entire dirty region as represented
- * by the contents of the dirty rect upon return from this function.
+ * not available. The caller must redraw the entire dirty region as represented
+ * by the contents of the inOutDirty rectangle upon return from this function.
* The caller may also pass <code>null</code> instead, in the case where the
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 14fa9cb..793fb5e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -755,12 +755,36 @@
mHandler.sendMessage(msg);
}
+ /**
+ * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * The caller must redraw the entire surface.
+ * @return A canvas for drawing into the surface.
+ */
public Canvas lockCanvas() {
return internalLockCanvas(null);
}
- public Canvas lockCanvas(Rect dirty) {
- return internalLockCanvas(dirty);
+ /**
+ * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * @param inOutDirty A rectangle that represents the dirty region that the caller wants
+ * to redraw. This function may choose to expand the dirty rectangle if for example
+ * the surface has been resized or if the previous contents of the surface were
+ * not available. The caller must redraw the entire dirty region as represented
+ * by the contents of the inOutDirty rectangle upon return from this function.
+ * The caller may also pass <code>null</code> instead, in the case where the
+ * entire surface should be redrawn.
+ * @return A canvas for drawing into the surface.
+ */
+ public Canvas lockCanvas(Rect inOutDirty) {
+ return internalLockCanvas(inOutDirty);
}
private final Canvas internalLockCanvas(Rect dirty) {
@@ -810,6 +834,12 @@
return null;
}
+ /**
+ * Posts the new contents of the {@link Canvas} to the surface and
+ * releases the {@link Canvas}.
+ *
+ * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+ */
public void unlockCanvasAndPost(Canvas canvas) {
mSurface.unlockCanvasAndPost(canvas);
mSurfaceLock.unlock();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4fb2431..be26d20 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13380,18 +13380,32 @@
/**
* Sets a rectangular area on this view to which the view will be clipped
- * it is drawn. Setting the value to null will remove the clip bounds
+ * when it is drawn. Setting the value to null will remove the clip bounds
* and the view will draw normally, using its full bounds.
*
* @param clipBounds The rectangular area, in the local coordinates of
* this view, to which future drawing operations will be clipped.
*/
public void setClipBounds(Rect clipBounds) {
- mClipBounds = clipBounds;
if (clipBounds != null) {
- invalidate(clipBounds);
+ if (clipBounds.equals(mClipBounds)) {
+ return;
+ }
+ if (mClipBounds == null) {
+ invalidate();
+ mClipBounds = new Rect(clipBounds);
+ } else {
+ invalidate(Math.min(mClipBounds.left, clipBounds.left),
+ Math.min(mClipBounds.top, clipBounds.top),
+ Math.max(mClipBounds.right, clipBounds.right),
+ Math.max(mClipBounds.bottom, clipBounds.bottom));
+ mClipBounds.set(clipBounds);
+ }
} else {
- invalidate();
+ if (mClipBounds != null) {
+ invalidate();
+ mClipBounds = null;
+ }
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 48630a4..0212482 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -795,9 +795,7 @@
* <p>This flag can be controlled in your theme through the
* {@link android.R.attr#windowOverscan} attribute; this attribute
* is automatically set for you in the standard overscan themes
- * such as {@link android.R.style#Theme_NoTitleBar_Overscan},
- * {@link android.R.style#Theme_Black_NoTitleBar_Overscan},
- * {@link android.R.style#Theme_Light_NoTitleBar_Overscan},
+ * such as
* {@link android.R.style#Theme_Holo_NoActionBar_Overscan},
* {@link android.R.style#Theme_Holo_Light_NoActionBar_Overscan},
* {@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan}, and
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c7914f3..f42999d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -41,6 +41,7 @@
import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
import android.widget.RemoteViews.RemoteView;
import java.util.ArrayList;
@@ -1715,11 +1716,17 @@
}
// Attempt to restore accessibility focus.
- if (accessibilityFocusLayoutRestoreNode != null) {
- accessibilityFocusLayoutRestoreNode.performAction(
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
- } else if (accessibilityFocusLayoutRestoreView != null) {
- accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+ if (accessibilityFocusLayoutRestoreView != null) {
+ final AccessibilityNodeProvider provider =
+ accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
+ if ((accessibilityFocusLayoutRestoreNode != null) && (provider != null)) {
+ final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
+ accessibilityFocusLayoutRestoreNode.getSourceNodeId());
+ provider.performAction(virtualViewId,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+ } else {
+ accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+ }
} else if (accessibilityFocusPosition != INVALID_POSITION) {
// Bound the position within the visible children.
final int position = MathUtils.constrain(
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 83e2e79..07e66b7 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2108,6 +2108,8 @@
* RemoteViews. This count cannot change during the life-cycle of a given widget, so this
* parameter should account for the maximum possible number of types that may appear in the
* See {@link Adapter#getViewTypeCount()}.
+ *
+ * @hide
*/
public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 59ff597..d69bc31 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1354,7 +1354,7 @@
public void setHomeActionContentDescription(int resId) {
mHomeDescriptionRes = resId;
- mHomeDescription = getResources().getText(resId);
+ mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
}
static class SavedState extends BaseSavedState {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 555c7c2..d3ead26 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -140,6 +140,10 @@
public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
+ private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
+ private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
+ Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
+
private final Context mContext;
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
@@ -526,6 +530,22 @@
}
}
+ public void setOwnerInfo(String info, int userId) {
+ setString(LOCK_SCREEN_OWNER_INFO, info, userId);
+ }
+
+ public void setOwnerInfoEnabled(boolean enabled) {
+ setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
+ }
+
+ public String getOwnerInfo(int userId) {
+ return getString(LOCK_SCREEN_OWNER_INFO);
+ }
+
+ public boolean isOwnerInfoEnabled() {
+ return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
+ }
+
/**
* Compute the password quality from the given password string.
*/
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 514178d..cb14374 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -134,6 +134,7 @@
<protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
<protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
+ <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
<protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
<protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
@@ -544,6 +545,7 @@
<!-- =============================================== -->
<!-- Permissions for enabling accessibility features -->
<!-- =============================================== -->
+ <eat-comment />
<!-- Used for permissions that allow requesting certain accessibility features. -->
<permission-group android:name="android.permission-group.ACCESSIBILITY_FEATURES"
@@ -552,20 +554,6 @@
android:description="@string/permgroupdesc_accessibilityFeatures"
android:priority="380" />
- <!-- Allows an accessibility service to request touch exploration mode. -->
- <permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"
- android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
- android:label="@string/permlab_canRequestTouchExplorationMode"
- android:description="@string/permdesc_canRequestTouchExplorationMode"
- android:protectionLevel="dangerous" />
-
- <!-- Allows an accessibility service to request enhanced web accessibility. -->
- <permission android:name="android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"
- android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
- android:label="@string/permlab_canRequestEnahncedWebAccessibility"
- android:description="@string/permdesc_canRequestEnahncedWebAccessibility"
- android:protectionLevel="dangerous" />
-
<!-- ======================================= -->
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
@@ -836,6 +824,7 @@
<!-- ==================================================== -->
<!-- Permissions related to changing audio settings -->
<!-- ==================================================== -->
+ <eat-comment />
<!-- Used for permissions that provide direct access to speaker settings
the device. -->
@@ -1275,6 +1264,7 @@
<!-- ==================================================== -->
<!-- Permissions related to changing status bar -->
<!-- ==================================================== -->
+ <eat-comment />
<!-- Used for permissions that change the status bar -->
<permission-group android:name="android.permission-group.STATUS_BAR"
@@ -1293,6 +1283,7 @@
<!-- ==================================================== -->
<!-- Permissions related to accessing sync settings -->
<!-- ==================================================== -->
+ <eat-comment />
<!-- Used for permissions that access the sync settings or sync
related information. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ea194fc..f1119e2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Herlaai"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Die bladsy by \"<xliff:g id="TITLE">%s</xliff:g>\" sê:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigeer weg van hierdie bladsy?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Raak OK om voort te gaan, of Kanselleer om op die huidige bladsy te bly."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bevestig"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Wenk: Dubbeltik om in en uit te zoem."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Outovul"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 84eba57..d689022 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -387,7 +387,7 @@
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የጡባዊ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የስልክ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
<string name="permlab_movePackage" msgid="3289890271645921411">"የመተግበሪያ ሃብቶችን አንቀሳቅስ"</string>
- <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ ውጫዊ ሚዲያ እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ ውጫዊ ማህደረ መረጃ እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"ወሳኝ የማስታወሻ ውሂብ አንብብ"</string>
<string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያ ይፈቅዳሉ። ይህ ስለ ጡባዊ ተኮህ ምን እያደረክበት እንደሆነ የግላዊ ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
<string name="permdesc_readLogs" product="default" msgid="2063438140241560443">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያይፈቅዳሉ። ይህ ስለ ስልክህ ምን እያደረክበት እንደሆነ የግላዊ ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
@@ -403,9 +403,9 @@
<string name="permlab_setPreferredApplications" msgid="8463181628695396391">"ተመራጭ መተግበሪያዎች አዘጋጅ"</string>
<string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"ተመራጭ መተግበሪያዎችህን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ከአንተ የግል ውሂብ ለመሰብሰብ ያሉትን መተግበሪያዎች በመላክ፤ በመሄድ ላይ ያሉ መተግበሪያዎችን ተንኮል አዘል መተግበሪያዎች በዝምታ ሊለውጡ ይችላሉ፡፡"</string>
<string name="permlab_writeSettings" msgid="2226195290955224730">"የስርዓት ቅንብሮችን አስተካክል"</string>
- <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓትህን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ፡፡"</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች የስርዓትዎን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ።"</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"የስርዓት ቅንብሮችንደህንነት ቀይር"</string>
- <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ለመደበኛ ትግበራዎች አያስፈልግም።"</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ለመደበኛ ትግበራዎች አያስፈልግም።"</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"የGoogle አገልግሎቶች ካርታን ቀይር"</string>
<string name="permdesc_writeGservices" msgid="1287309437638380229">"ትግበራ የGoogle ካርታ አገልግሎቶችን ለመቀየር ይፈቅዳል።ለመደበኛ ትግበራዎች ጥቅም አይደለም።"</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"መነሻ ላይ አሂድ"</string>
@@ -541,8 +541,8 @@
<string name="permlab_accountManagerService" msgid="4829262349691386986">"እንደ አውርድአዸራጅአገልግሎት"</string>
<string name="permdesc_accountManagerService" msgid="1948455552333615954">" ወደ መለያ አረጋጋጮች ጥሪ ለማድረግ ለመተግበሪያ ይፈቅዳሉ።"</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን አግኝ"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
- <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"መለያዎችን ፍጠርና የይለፍ ቃላትን አስቀምጥ"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"የመለያ አረጋጋጭ መለያ መናጅ ችሎታን ለመጠቀም፣ መለያ መፍጠር እና የይለፍ ቃሎችን ለማግኘት እና ለማቀናጀት አክሎ ለመተግበሪያው ይፈቅዳሉ ።"</string>
<string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን አክል ወይም አስወግድ"</string>
@@ -554,7 +554,7 @@
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ሙሉ የአውታረ መረብ መዳረሻ"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"መተግበሪያው የአውታረ መረብ መሰኪያዎችን እንዲፈጥር እና ብጁ የአውታረ መረብ ፕሮቶኮሎችን እንዲጠቀም ይፈቅድለታል። አሳሹ እና ሌሎች መተግበሪያዎች ውሂብ ወደ በይነመረብ የመላኪያ መንገዶችን ስለሚያቀርቡውሂብ ወደ በይነመረብ ለመላክ ይህ ፍቃድ አያስፈልግም።"</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"የአውታረ መረብ ቅንብሮች እና ትራፊክ ለውጥ/ አቋርጥ"</string>
- <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንጅቶችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለአንተ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ፡፡"</string>
+ <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንብሮችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለእርስዎ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ።"</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"የአውታረ መረብ ተያያዥነትን ለውጥ"</string>
<string name="permdesc_changeNetworkState" msgid="6789123912476416214">"የእውታረ መረቡን ግንኙነት ሁኔታ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"የተያያዘ ግንኙነት ለውጥ"</string>
@@ -601,7 +601,7 @@
<string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"ጥበቃ ወደሚደረግለት ማከማቻ ያለ መዳረሻን ፈትሽ"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖር የUSB ማህደረ ትውስታ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
<string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖረው SD ካርድ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻዎን ይዘቶች ይቀይሩ ወይም ይሰርዙ"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"የSD ካርድህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"ወደ USB ማህደረ ትውስታው ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"ድጋሚ አስነሳ"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"በ«<xliff:g id="TITLE">%s</xliff:g>» ያለው ገጽ ይህን ይላል፦"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"ጃቫስክሪፕት"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"ከዚህ ገፅ ወጣ ብሎ ይዳስ? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" ለመቀጠል እሺ ፣ወይም የአሁኑ ገፅ ላይ ለመቆየት ይቅር ምረጥ።"</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"አረጋግጥ"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"ጠቃሚ ምክር፦ ለማጉላት እና ለማሳነስ ሁለቴ-መታ አድርግ።"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ራስ ሙላ"</string>
@@ -1174,20 +1181,20 @@
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"አዲስ፦ "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የቀረበ።"</string>
<string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
- <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎብዎት ይችላል"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
<string name="usb_storage_activity_title" msgid="4465055157209648641">"USB ብዙ ማከማቻ"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB ተያይዟል"</string>
<string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
<string name="usb_storage_message" product="default" msgid="805351000446037811">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"የUSB ማከማቻ አብራ"</string>
- <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
+ <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻዎን ለUSB ብዙ ማከማቻ መጠቀም ችግር አለ።"</string>
<string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"የ SD ካርድህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ተያይዟል"</string>
<string name="usb_storage_notification_message" msgid="939822783828183763">"ፋይሎችን ከ/ወደ ኮምፒዩተርህ ለመቅዳት ንካ።"</string>
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"የUSB ማከማቻ አጥፋ"</string>
<string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"የUSB ማከማቻ ለማጥፋት ንካ።"</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"USB ማከማቻ በጥቅም ላይ"</string>
- <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትህ በፊት፤ የAndroid USB ማከማቻህን ከኮምውተርህ ንቀል (\"አውጣ\")።"</string>
+ <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትዎ በፊት፤ የAndroid USB ማከማቻዎን ከኮምውተርዎ ይንቀሉ (\"ያውጡ\")።"</string>
<string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"የUSB ማከማቻ ከማጥፋት በፊት የAndroid SD ካርድህን ከኮምፒዩተርህ ላይ ንቀል(“አውጣ”)።"</string>
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB ማከማቻ አጥፋ"</string>
<string name="usb_storage_stop_error_message" msgid="1970374898263063836">"የ USB ማከማቻ ለማጥፋት ችግር ነበር። USB አስተናጋጅ መንቀልህን አረጋግጥ፤ ከዛም እንደገና ሞክር።"</string>
@@ -1380,7 +1387,7 @@
<string name="storage_usb" msgid="3017954059538517278">"የUSB ማከማቻ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
- <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንጅቶችን እና አጠቃቀምን ለማየት ንካ።"</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንብሮችን እና አጠቃቀምን ለማየት ይንኩ።"</string>
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G ውሂብ ቦዝኗል"</string>
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G ውሂብ ቦዝኗል"</string>
<string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"የተንቀሳቃሽ ውሂብ ቦዝኗል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d134ca4..0c611cd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"إعادة تشغيل"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"جافا سكريبت"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"هل تريد الانتقال بعيدًا عن هذه الصفحة؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"المس \"موافق\" للمتابعة، أو \"إلغاء\" للبقاء في الصفحة الحالية."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"تأكيد"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"نصيحة: اضغط مرتين للتكبير والتصغير."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ملء تلقائي"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9f3d3e6..eb2033c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Пакiнуць гэту старонку?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Націсніце \"OK\", каб працягнуць, або \"Адмена\", каб застацца на бягучай старонцы."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0983b5e..27a0f59 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Рестартиране"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Страницата на адрес „<xliff:g id="TITLE">%s</xliff:g>“ съобщава:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Искате ли да напуснете тази страница?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Докоснете „OK“, за да продължите, или „Отказ“, за да останете на нея."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Потвърждение"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Съвет: Докоснете двукратно, за да увеличите или намалите мащаба."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Автопоп."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index ccea866..4e68a6b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reinicia"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La pàgina de \"<xliff:g id="TITLE">%s</xliff:g>\" diu:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Vols sortir d\'aquesta pàgina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona D\'acord per continuar o Cancel·la per seguir a la pàgina actual."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c9a84cb..c92d249 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -155,7 +155,7 @@
<string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"Zaznamenat zprávu o chybě"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
<string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Restartovat"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chcete-li pokračovat, dotkněte se možnosti OK. Chcete-li zůstat na aktuální stránce, dotkněte se možnosti Zrušit."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím můžete zobrazení přiblížit nebo oddálit."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Aut.vyp."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0c7cf72..29a5776 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -156,7 +156,7 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
- <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid fra, at fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er slået FRA"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Genstart"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"På siden på \"<xliff:g id="TITLE">%s</xliff:g>\" står der:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du gå væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryk på OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip! Dobbeltklik for at zoome ind eller ud."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyld"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c03aa70..dcf27e3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Neustart"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Auf der Seite \"<xliff:g id="TITLE">%s</xliff:g>\" steht:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Diese Seite verlassen?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tippen Sie zum Fortfahren auf \"OK\" oder tippen Sie auf \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tipp: Zum Vergrößern und Verkleinern zweimal tippen"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"AutoFill"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6dcdbf1..414111d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Επανεκκίνηση"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Η σελίδα στον τίτλο \"<xliff:g id="TITLE">%s</xliff:g>\" λέει:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Απομάκρυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Αγγίξτε το στοιχείο \"OK\" για συνέχεια ή \"Ακύρωση\" για παραμονή στην τρέχουσα σελίδα."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Συμβουλή: Πατήστε δύο φορές για μεγέθυνση και σμίκρυνση."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Αυτόματη συμπλήρωση"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 08283c4..d95c1d9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reboot"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"The page at \"<xliff:g id="TITLE">%s</xliff:g>\" says:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigate away from this page?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Touch OK to continue or Cancel to stay on the current page."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirm"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip: double-tap to zoom in and out."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Auto-fill"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 98528f7..5005d41 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -773,7 +773,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dibujar el patrón de desbloqueo"</string>
- <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
+ <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Realizar llamada de emergencia"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Regresar a llamada"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo."</string>
@@ -783,7 +783,7 @@
<string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
<string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
- <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No hay tarjeta SIM."</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
<string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
@@ -795,7 +795,7 @@
<string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botón Pausa"</string>
<string name="lockscreen_transport_play_description" msgid="5888422938351019426">"Botón Reproducir"</string>
<string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"Botón Detener"</string>
- <string name="emergency_calls_only" msgid="6733978304386365407">"Sólo llamadas de emergencia"</string>
+ <string name="emergency_calls_only" msgid="6733978304386365407">"Solo llamadas de emergencia"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Red bloqueada"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con PUK."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Consejo: Toca dos veces para acercar y alejar la imagen."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1437,7 +1444,7 @@
<string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
<string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
- <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+ <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 485e1bf..d20f7fa 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Sugerencia: toca dos veces para ampliar o reducir el contenido."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1195,7 +1202,7 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si activas el almacenamiento USB, se detendrán algunas aplicaciones que estás usando y es posible que no estén disponibles hasta que lo desactives."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Error de funcionamiento de USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como disp. multimedia"</string>
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como dispositivo multimedia"</string>
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d2d4d63..c30e2a9 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Taaskäivita"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Leht „<xliff:g id="TITLE">%s</xliff:g>” ütleb järgmist."</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage valikut OK, praegusele lehele jäämiseks valikut Tühista."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f723c37..f254b52 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -622,7 +622,7 @@
<string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلانهای دسترسی"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. این هرگز برای برنامههای عادی ضروری نیست."</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامههای عادی لازم شود."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"راهاندازی مجدد"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"صفحه در \"<xliff:g id="TITLE">%s</xliff:g>\" میگوید:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"جاوا اسکریپت"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"از این صفحه خارج میشوید؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"برای ادامه روی تأیید و برای ماندن در همین صفحه روی لغو کلیک کنید."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"تأیید"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگنمایی و کوچکنمایی، دو بار ضربه بزنید."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7f7f07a..f75d474 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Käynnistä uudelleen"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Sivu <xliff:g id="TITLE">%s</xliff:g> sanoo:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Siirrytäänkö pois tältä sivulta?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Valitse OK, jos haluat jatkaa, tai Peruuta, jos et halua siirtyä pois sivulta."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Vahvista"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Vinkki: lähennä ja loitonna kaksoisnapauttamalla."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Aut. täyttö"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 65c4ce5..4a87fd0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Redémarrer"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" indique :"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Voulez-vous quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Appuyez sur \"OK\" pour continuer ou \"Annuler\" pour rester sur la page actuelle."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Conseil : Appuyez deux fois pour faire un zoom avant ou arrière."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Saisie auto"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 79dbfff..b922e401 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"इस पृष्ठ से दूर नेविगेट करें?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"जारी रखने के लिए ठीक को चुनें, या वर्तमान पृष्ठ पर रहने के लिए रद्द करें को चुनें."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"पुष्टि करें"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"युक्ति: ज़ूम इन और आउट करने के लिए डबल-टैप करें."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"स्वत: भरण"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 90b44d2..128b48c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Ponovno pokreni"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Stranica na adresi \"<xliff:g id="TITLE">%s</xliff:g>\" sadrži sljedeće:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Želite otići s ove lokacije?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Za nastavak dodirnite U redu, a za ostanak na trenutačnoj stranici dodirnite Odustani."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Potvrdi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Savjet: Dvaput dotaknite za povećavanje i smanjivanje."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Aut.pop."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d71ac23..0e0f13a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Újraindítás"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"A \"<xliff:g id="TITLE">%s</xliff:g>\" címen található oldal szerint:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Elhagyja ezt az oldalt?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"A folytatáshoz érintse meg az OK, a jelenlegi oldalon maradáshoz a Mégse lehetőséget."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Megerősítés"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tipp: érintse meg kétszer a nagyításhoz és kicsinyítéshez."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Kitöltés"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a9b33de..fd04f2a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Beranjak dari laman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh Oke untuk melanjutkan atau Batal untuk tetap pada laman ini."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Isiotomatis"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 560b049..7cda28a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -440,16 +440,16 @@
<string name="permlab_writeCalendar" msgid="8438874755193825647">"aggiunta o modifica di eventi di calendario e invio di email agli ospiti a insaputa dei proprietari"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul tablet, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
<string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul telefono, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di localizzazione fittizie per test"</string>
- <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+ <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di geolocalizzazione fittizie per test"</string>
+ <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"autorizzazione a installare un provider di localizzazione"</string>
- <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+ <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"posizione precisa (GPS e basata sulla rete)"</string>
- <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"posizione approssimativa (basata sulla rete)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"accesso a SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Riavvia"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La pagina all\'indirizzo \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tocca OK per continuare o Annulla per rimanere nella pagina corrente."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Suggerimento. Tocca due volte per aumentare e diminuire lo zoom."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Compilazione autom."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 42f0e2d..59b4f65 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"אתחל מחדש"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"בדף שבכתובת \'<xliff:g id="TITLE">%s</xliff:g>\' כתוב כך:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"לנווט אל מחוץ לדף זה?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"גע באפשרות \'אישור\' כדי להמשיך, או \'ביטול\' כדי להישאר בדף הנוכחי."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"אשר"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"טיפ: הקש פעמיים כדי להגדיל ולהקטין."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"מילוי אוטומטי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f6b93f9..4fafb60 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"再起動"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"<xliff:g id="TITLE">%s</xliff:g> のページ:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動する場合は[OK]、現在のページに留まる場合は[キャンセル]をタップしてください。"</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"確認"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"ヒント: ダブルタップで拡大/縮小できます。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自動入力"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5f50ac4..df40880 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"다시 부팅"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"자바스크립트"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 터치하고 현재 페이지에 그대로 있으려면 \'취소\'를 터치하세요."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"확인"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"도움말: 확대/축소하려면 두 번 탭합니다."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"자동완성"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9237a2c..ed31762 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Pakartotinai įkelti"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Puslapyje šiuo adresu: <xliff:g id="TITLE">%s</xliff:g>, teigiama:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Išeiti iš šio puslapio?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Palieskite „Gerai“, jei norite tęsti, arba palieskite „Atšaukti“, jei norite likti dabartiniame puslapyje."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Patvirtinti"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Patarimas: palieskite dukart, kad padidintumėte ar sumažintumėte mastelį."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automatinis pildymas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1de841e..3f30242 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Atsāknēt"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Lapā <xliff:g id="TITLE">%s</xliff:g> ir teikts:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Vai doties prom no šīs lapas?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pieskarieties Labi, lai turpinātu, vai Atcelt, lai paliktu pašreizējā lapā."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Apstiprināt"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Padoms. Divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automātiskā aizpilde"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index af5b866..5f49ed3 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"But semula"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Halaman di \'<xliff:g id="TITLE">%s</xliff:g>\' berkata:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigasi keluar dari halaman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh OK untuk meneruskan, atau Batal untuk terus berada di halaman semasa."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Sahkan"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Petua: Ketik dua kali untuk mengezum masuk dan keluar."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Auto isi"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e0d9bf2..a81f017 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Omstart"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Siden på «<xliff:g id="TITLE">%s</xliff:g>» sier:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du navigere bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Trykk på OK for å fortsette eller på Avbryt for å bli værende på siden."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tips: Dobbelttrykk for å zoome inn og ut."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2e92761..0558096 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Opnieuw opstarten"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' meldt het volgende:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies \'OK\' om door te gaan of \'Annuleren\' om op de huidige pagina te blijven."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip: dubbeltik om in en uit te zoomen."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autom. aanvullen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d8a4bf9..2fa77a9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Uruchom ponownie"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Dotknij OK, aby kontynuować, lub Anuluj, aby pozostać na tej stronie."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autouzupełnianie"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 66d50e6..edb3414 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -144,7 +144,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
- <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone irá encerrar."</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
<string name="reboot_safemode_confirm" msgid="55293944502784668">"Pretende reiniciar no modo de segurança? Se sim, irá desativar todas as aplicações de terceiros instaladas. Estas serão restauradas quando reiniciar novamente."</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toque em OK para continuar ou Cancelar para permanecer na página atual."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Sugestão: toque duas vezes para aumentar ou diminuir o zoom."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Preenchimento Automático"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3877158..184f704 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -160,9 +160,9 @@
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo de avião ATIVADO"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo de avião DESATIVADO"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" diz:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Preench. aut."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index ba863cb..7d10377 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1398,7 +1398,13 @@
<!-- no translation found for js_dialog_title (1987483977834603872) -->
<skip />
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
<skip />
<string name="save_password_label" msgid="6860261758665825069">"Confermar"</string>
<!-- no translation found for double_tap_toast (4595046515400268881) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 21fcf04..bad14405 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -622,7 +622,7 @@
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reporniţi"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Doriţi să părăsiţi această pagină?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Apăsaţi pe OK pentru a continua sau pe Anulaţi pentru a rămâne pe pagina curentă."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi şi micşoraţi prin dublă atingere."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 592271b..d9bf3e2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Подтвердите действие на <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Покинуть эту страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Совет: нажмите дважды, чтобы увеличить и уменьшить масштаб."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Автозаполнение"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 228a9e7..caedb22 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Reštartovať"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Stránka „<xliff:g id="TITLE">%s</xliff:g>“ uvádza:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustiť túto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ak chcete pokračovať, dotknite sa tlačidla OK. Ak chcete zostať na stránke, dotknite sa tlačidla Zrušiť."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Potvrdiť"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím môžete zobrazenie priblížiť alebo oddialiť."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Aut.dop."</string>
@@ -1051,7 +1058,7 @@
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
- <string name="app_running_notification_text" msgid="4653586947747330058">"Dotknutím sa zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
+ <string name="app_running_notification_text" msgid="4653586947747330058">"Dotykom si zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
<string name="ok" msgid="5970060430562524910">"OK"</string>
<string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 906c197..64df433 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Znova zaženi"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Na strani na »<xliff:g id="TITLE">%s</xliff:g>« piše:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Ali se želite premakniti s te strani"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Če želite nadaljevati, se dotaknite »V redu«, če želite ostati na trenutni strani, izberite »Prekliči«."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Potrdi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Nasvet: Tapnite dvakrat, če želite povečati ali pomanjšati."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Samoizp."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 102ced6..ec0384c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Поново покрени"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"На страници на адреси „<xliff:g id="TITLE">%s</xliff:g>“ пише следеће:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Желите ли да напустите ову страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Додирните Потврди да бисте наставили или Откажи да бисте остали на тренутно отвореној страници."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Потврда"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Савет: Додирните двапут да бисте увећали и умањили приказ."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Аутом. поп."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adeffc3..7993bf8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Starta om"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tips! Dubbelknacka om du vill zooma in eller ut."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bdc0155..535b805 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -138,7 +138,7 @@
<string name="turn_on_radio" msgid="3912793092339962371">"Washa mtandao-hewa"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Zima pasiwaya"</string>
<string name="screen_lock" msgid="799094655496098153">"Funga skrini"</string>
- <string name="power_off" msgid="4266614107412865048">"Nishati imezimwa"</string>
+ <string name="power_off" msgid="4266614107412865048">"Zima simu"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Programu ya milio imezimwa"</string>
<string name="silent_mode_vibrate" msgid="7072043388581551395">"Mtetemo wa programu ya milio"</string>
<string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
@@ -153,7 +153,7 @@
<string name="global_actions" product="tablet" msgid="408477140088053665">"Chaguo za kompyuta ndogo"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
- <string name="global_action_power_off" msgid="4471879440839879722">"Nishati imezimwa"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"Zima simu"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
<string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali yako ya sasa ya kifaa, ili kutuma ujumbe wa barua pepe. Itachukua muda mfupi kuanza ripoti ya hitilafu mpaka itakapokuwa tayari kutumwa; tafadhali vumilia."</string>
@@ -519,7 +519,7 @@
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
- <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta ndogo"</string>
+ <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta kibao"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"washa au zima simu"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Inaruhusu programu kuwasha au kuzima kompyuta kibao."</string>
<string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Inaruhusu programu kuwasha au kuzima simu."</string>
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Washa tena"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Ukurasa ulio \"<xliff:g id="TITLE">%s</xliff:g>\" unasema:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"HatiJava"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Toka kwa ukurasa huu?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Gusa Sawa ili kuendelea, au Ghairi ili kubaki kwenye ukurasa wa sasa."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Thibitisha"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Kidokezo: Gonga mara mbili ili kukuza ndani na nje."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Kujaza kiotomatiki"</string>
@@ -1060,7 +1067,7 @@
<string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
<string name="capital_on" msgid="1544682755514494298">"Washa"</string>
<string name="capital_off" msgid="6815870386972805832">"ZIMA"</string>
- <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo kwa kutumia"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo ukitumia"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Futa chaguo-msingi katika mipangilio ya Mfumo > Apps > iliyopakuliwa."</string>
<string name="chooseActivity" msgid="7486876147751803333">"Chagua kitendo"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a92db72..1c97cb0d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"ไปจากหน้าเว็บนี้หรือไม่"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"แตะ \"ตกลง\" เพื่อทำต่อ หรือ \"ยกเลิก\" เพื่ออยู่ที่หน้าเว็บปัจจุบัน"</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"ยืนยัน"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"เคล็ดลับ: แตะสองครั้งเพื่อขยายและย่อ"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"ป้อนอัตโนมัติ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e726333..45a5410 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"I-reboot"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Isinasaad ng pahina sa \"<xliff:g id="TITLE">%s</xliff:g>\" na:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Mag-navigate palayo mula sa pahinang ito?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pindutin ang OK upang magpatuloy, o Kanselahin upang manatili sa kasalukuyang pahina."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Kumpirmahin"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Tip: Mag-double tap upang mag-zoom in at out."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Autofill"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9e5e43b..77b1cc6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Yeniden başlat"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada şunlar belirtiliyor:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, mevcut sayfada kalmak için İptal\'i tıklayın."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe vurun."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bb223ea..0cdedc1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Перезав."</string>
<string name="js_dialog_title" msgid="1987483977834603872">"На сторінці за адресою \"<xliff:g id="TITLE">%s</xliff:g>\" написано:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Перейти з цієї сторінки?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Торкніться \"OK\", щоб продовжити, або \"Скасувати\", щоб залишитися на поточній сторінці."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Підтверд."</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Порада: двічі торкніться для збільшення чи зменшення."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Автозап."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a592144..7732f4a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Khởi động lại"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Trang tại \"<xliff:g id="TITLE">%s</xliff:g>\" cho biết:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Điều hướng khỏi trang này?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chạm OK để tiếp tục hoặc Hủy để ở lại trang hiện tại."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Xác nhận"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Mẹo: Nhấn đúp để phóng to và thu nhỏ."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Tự động điền"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 79c79f3..9d1c48c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"重新启动"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"网址为“<xliff:g id="TITLE">%s</xliff:g>”的网页显示:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"要从此页面导航至其他页面吗?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"触摸“确定”继续,或触摸“取消”留在当前页面。"</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"确认"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"提示:点按两次可放大或缩小。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自动填充"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dfd91a4..b4c41b4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"重新開機"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"「<xliff:g id="TITLE">%s</xliff:g>」網頁指出:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"離開這個頁面?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"輕觸 [確定] 離開這個頁面,或輕觸 [取消] 停留在這個頁面。"</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"確認"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"提示:輕按兩下即可縮放。"</string>
<string name="autofill_this_form" msgid="4616758841157816676">"自動填入功能"</string>
@@ -1475,7 +1482,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
- <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽偏高音量可能會損害您的聽力。"</string>
+ <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽高音量可能會損害您的聽力。"</string>
<string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
<string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 41ac207..e2f1478 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -864,7 +864,14 @@
<string name="factorytest_reboot" msgid="6320168203050791643">"Qalisa kabusha"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"Ikhasi eliku <xliff:g id="TITLE">%s</xliff:g> lithi:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"i-JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Phuma kuleli khasi? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Thinta KULUNGILE ukuqhubeka, noma Khansela ukuhlala kuleli khasi."</string>
+ <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+ <skip />
+ <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+ <skip />
<string name="save_password_label" msgid="6860261758665825069">"Qinisekisa"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Ithiphu: thepha kabili ukusondeza ngaphandle nangaphakathi."</string>
<string name="autofill_this_form" msgid="4616758841157816676">"Ukugcwalisa Ngokuzenzakalelayo"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c7a374..60f3f32 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2521,13 +2521,43 @@
<flag name="flagRequestTouchExplorationMode" value="0x00000004" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
<flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} -->
+ <flag name="flagReportViewIds" value="0x00000010" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} -->
+ <flag name="flagRequestFilterKeyEvents" value="0x00000020" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->
<attr name="settingsActivity" />
- <!-- Flag whether the accessibility service wants to be able to retrieve the
+ <!-- Attribute whether the accessibility service wants to be able to retrieve the
active window content. This setting cannot be changed at runtime. -->
<attr name="canRetrieveWindowContent" format="boolean" />
+ <!-- Attribute whether the accessibility service wants to be able to request touch
+ exploration mode in which touched items are spoken aloud and the UI can be
+ explored via gestures.
+ <p>
+ Required to allow setting the {@link android.accessibilityservice
+ #AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} flag.
+ </p>
+ -->
+ <attr name="canRequestTouchExplorationMode" format="boolean" />
+ <!-- Attribute whether the accessibility service wants to be able to request enhanced
+ web accessibility enhancements. For example, installing scripts to make app
+ content more accessible.
+ <p>
+ Required to allow setting the {@link android.accessibilityservice
+ #AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} flag.
+ </p>
+ -->
+ <attr name="canRequestEnhancedWebAccessibility" format="boolean" />
+ <!-- Attribute whether the accessibility service wants to be able to request to
+ filter key events.
+ <p>
+ Required to allow setting the {@link android.accessibilityservice
+ #AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} flag.
+ </p>
+ -->
+ <attr name="canRequestFilterKeyEvents" format="boolean" />
<!-- Short description of the accessibility serivce purpose or behavior.-->
<attr name="description" />
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cc50d8a..84e300a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -345,6 +345,12 @@
A value of -1 means no change in orientation by default. -->
<integer name="config_carDockRotation">-1</integer>
+ <!-- The number of degrees to rotate the display when the device has HDMI connected
+ but is not in a dock. A value of -1 means no change in orientation by default.
+ Use -1 except on older devices whose Hardware Composer HAL does not
+ provide full support for multiple displays. -->
+ <integer name="config_undockedHdmiRotation">-1</integer>
+
<!-- Control the default UI mode type to use when there is no other type override
happening. One of the following values (See Configuration.java):
1 UI_MODE_TYPE_NORMAL
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 074d91f..c150fe0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2043,10 +2043,10 @@
<public type="attr" name="childIndicatorEnd" />
<public type="attr" name="restrictedAccountType" />
<public type="attr" name="requiredAccountType" />
+ <public type="attr" name="canRequestTouchExplorationMode" />
+ <public type="attr" name="canRequestEnhancedWebAccessibility" />
+ <public type="attr" name="canRequestFilterKeyEvents" />
- <public type="style" name="Theme.NoTitleBar.Overscan" />
- <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
- <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
<public type="style" name="Theme.Holo.NoActionBar.Overscan" />
<public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
<public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3361ab7..db9602a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -545,6 +545,31 @@
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgroupdesc_accessibilityFeatures">Features that assistive technology can request.</string>
+ <!-- Title for the capability of an accessibility service to retrieve window content. -->
+ <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
+ <!-- Description for the capability of an accessibility service to retrieve window content. -->
+ <string name="capability_desc_canRetrieveWindowContent">Inspect the content of a window you\'re
+ interacting with.</string>
+
+ <!-- Title for the capability of an accessibility service to request touch exploration. -->
+ <string name="capability_title_canRequestTouchExploration">Turn on Explore by Touch</string>
+ <!-- Description for the capability of an accessibility service to request touch exploration. -->
+ <string name="capability_desc_canRequestTouchExploration">Touched items will be spoken aloud
+ and the screen can be explored using gestures.</string>
+
+ <!-- Title for the capability of an accessibility service to request enhanced web accessibility. -->
+ <string name="capability_title_canRequestEnhancedWebAccessibility">Turn on enhanced web
+ accessibility</string>
+ <!-- Description for the capability of an accessibility service to request enhanced web accessibility. -->
+ <string name="capability_desc_canRequestEnhancedWebAccessibility">Scripts may be installed to
+ make app content more accessible.</string>
+
+ <!-- Title for the capability of an accessibility service to request to filter key events. -->
+ <string name="capability_title_canRequestFilterKeyEvents">Observe text you type</string>
+ <!-- Description for the capability of an accessibility service to request to filter key events. -->
+ <string name="capability_desc_canRequestFilterKeyEvents">Includes personal data such as credit
+ card numbers and passwords.</string>
+
<!-- Permissions -->
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -945,20 +970,6 @@
interface of an accessibility service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_canRequestTouchExplorationMode">request explore by touch</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_canRequestTouchExplorationMode">Allows the hoder to request an
- interaction mode in which touched items are spoken aloud and the UI can be explored
- via gestures.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_canRequestEnahncedWebAccessibility">request enhanced web accessibility</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_canRequestEnahncedWebAccessibility">Allows the hoder to request
- enabling of web accessibility enhancements. For example, installing scripts to make
- app content more accessible.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindTextService">bind to a text service</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindTextService">Allows the holder to bind to the top-level
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 45ea182..fdf7c8f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -438,6 +438,14 @@
<java-symbol type="string" name="badPin" />
<java-symbol type="string" name="badPuk" />
<java-symbol type="string" name="byteShort" />
+ <java-symbol type="string" name="capability_desc_canRequestEnhancedWebAccessibility" />
+ <java-symbol type="string" name="capability_title_canRequestFilterKeyEvents" />
+ <java-symbol type="string" name="capability_desc_canRequestTouchExploration" />
+ <java-symbol type="string" name="capability_desc_canRetrieveWindowContent" />
+ <java-symbol type="string" name="capability_title_canRequestEnhancedWebAccessibility" />
+ <java-symbol type="string" name="capability_desc_canRequestFilterKeyEvents" />
+ <java-symbol type="string" name="capability_title_canRequestTouchExploration" />
+ <java-symbol type="string" name="capability_title_canRetrieveWindowContent" />
<java-symbol type="string" name="cfTemplateForwarded" />
<java-symbol type="string" name="cfTemplateForwardedTime" />
<java-symbol type="string" name="cfTemplateNotForwarded" />
@@ -1584,6 +1592,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
+ <java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
<java-symbol type="layout" name="am_compat_mode_dialog" />
<java-symbol type="layout" name="launch_warning" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e1750af..80f7486 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -405,16 +405,6 @@
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
- into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.NoTitleBar.Overscan">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowOverscan">true</item>
- <item name="android:windowContentOverlay">@null</item>
- </style>
-
<!-- Theme for a light background with dark text on top. Set your activity
to this theme if you would like such an appearance. As with the
default theme, you should try to assume little more than that the
@@ -508,16 +498,6 @@
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Variant of {@link #Theme_Light} that has no title bar and
- no status bar and extending into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Light.NoTitleBar.Overscan">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowOverscan">true</item>
- <item name="android:windowContentOverlay">@null</item>
- </style>
-
<!-- Variant on {@link #Theme} that ensures the background is
completely black. This is useful for things like image viewers and
media players. If you want the normal (dark background) theme
@@ -539,16 +519,6 @@
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
-
- <!-- Variant of {@link #Theme_Black} that has no title bar and
- no status bar and extending into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Black.NoTitleBar.Overscan">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowOverscan">true</item>
- <item name="android:windowContentOverlay">@null</item>
- </style>
<!-- Theme for windows that want to have the user's selected
wallpaper appear behind them (for API level 10 and lower). -->
diff --git a/data/keyboards/Vendor_0079_Product_0011.kl b/data/keyboards/Vendor_0079_Product_0011.kl
new file mode 100644
index 0000000..2ae2a01
--- /dev/null
+++ b/data/keyboards/Vendor_0079_Product_0011.kl
@@ -0,0 +1,23 @@
+# Copyright (C) 2013 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.
+
+# Classic NES Controller
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
index 99f046a..ca6fa59 100644
--- a/data/keyboards/Vendor_045e_Product_028e.kl
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -22,9 +22,9 @@
key 308 BUTTON_Y
key 310 BUTTON_L1
key 311 BUTTON_R1
-key 314 BUTTON_SELECT
+key 314 BUTTON_BACK
key 315 BUTTON_START
-key 316 BUTTON_MODE
+key 316 BUTTON_HOME
key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
diff --git a/data/keyboards/Vendor_046d_Product_c219.kl b/data/keyboards/Vendor_046d_Product_c219.kl
new file mode 100644
index 0000000..431dd03
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c219.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# Logitech Logitech Cordless RumblePad 2
+
+key 305 BUTTON_A
+key 306 BUTTON_B
+key 304 BUTTON_X
+key 307 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+key 313 BUTTON_START
+key 312 BUTTON_BACK
+key 314 BUTTON_THUMBL
+key 315 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c21f.kl b/data/keyboards/Vendor_046d_Product_c21f.kl
new file mode 100644
index 0000000..981d864
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c21f.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Logitech Wireless Gamepad F710
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index f8ac6a3..62c5f4d5 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -23,10 +23,10 @@
key 0x120 BUTTON_SELECT
key 0x123 BUTTON_START
-key 0x12f BUTTON_A
-key 0x12c BUTTON_B
-key 0x12e BUTTON_X
-key 0x12d BUTTON_Y
+key 0x12e BUTTON_A
+key 0x12d BUTTON_B
+key 0x12f BUTTON_X
+key 0x12c BUTTON_Y
key 0x12a BUTTON_L1
key 0x12b BUTTON_R1
key 0x128 BUTTON_L2
@@ -35,7 +35,7 @@
key 0x122 BUTTON_THUMBR
# PS key
-key 0x2d0 BUTTON_1
+key 0x2d0 BUTTON_HOME
# Left Analog Stick
axis 0x00 X
diff --git a/data/keyboards/Vendor_0583_Product_2060.kl b/data/keyboards/Vendor_0583_Product_2060.kl
new file mode 100644
index 0000000..92c8a14
--- /dev/null
+++ b/data/keyboards/Vendor_0583_Product_2060.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 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.
+
+# ION GO PAD
+
+key 288 BUTTON_A
+key 289 BUTTON_B
+key 290 BUTTON_X
+key 291 BUTTON_Y
+key 294 BUTTON_L1
+key 295 BUTTON_R1
+key 292 BUTTON_L2
+key 293 BUTTON_R2
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
new file mode 100644
index 0000000..0084969
--- /dev/null
+++ b/data/keyboards/Vendor_0a5c_Product_8502.kl
@@ -0,0 +1,33 @@
+# Copyright (C) 2013 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.
+
+# Snakebyte
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 288 BUTTON_X
+key 291 BUTTON_Y
+key 292 BUTTON_L1
+key 293 BUTTON_R1
+key 294 BUTTON_L2
+key 295 BUTTON_R2
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1038_Product_1412.kl b/data/keyboards/Vendor_1038_Product_1412.kl
new file mode 100644
index 0000000..551b0bd
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1412.kl
@@ -0,0 +1,31 @@
+# Copyright (C) 2013 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.
+
+# Steelseries Free
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 316 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_12bd_Product_d015.kl b/data/keyboards/Vendor_12bd_Product_d015.kl
new file mode 100644
index 0000000..557d62f
--- /dev/null
+++ b/data/keyboards/Vendor_12bd_Product_d015.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 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.
+
+# Hitgaming SNES Retro
+
+key 306 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 304 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 313 BUTTON_START
+key 312 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fd00.kl b/data/keyboards/Vendor_1689_Product_fd00.kl
new file mode 100644
index 0000000..6ce14ed
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd00.kl
@@ -0,0 +1,38 @@
+# Copyright (C) 2013 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.
+
+# Razer Onza Tournament Edition
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 307 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+key 706 DPAD_UP
+key 705 DPAD_RIGHT
+key 707 DPAD_DOWN
+key 704 DPAD_LEFT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
diff --git a/data/keyboards/Vendor_1689_Product_fd01.kl b/data/keyboards/Vendor_1689_Product_fd01.kl
new file mode 100644
index 0000000..8144515
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd01.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Razer Xbox 360 Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fe00.kl b/data/keyboards/Vendor_1689_Product_fe00.kl
new file mode 100644
index 0000000..90fe4af
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fe00.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Razer Sabertooth Elite
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f016.kl b/data/keyboards/Vendor_1bad_Product_f016.kl
new file mode 100644
index 0000000..b72fd5ce
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f016.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Madcatz Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f023.kl b/data/keyboards/Vendor_1bad_Product_f023.kl
new file mode 100644
index 0000000..c1588b2
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f023.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# Mad Catz MLG GamePad for Xbox 360
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f027.kl b/data/keyboards/Vendor_1bad_Product_f027.kl
new file mode 100644
index 0000000..ea0aa7a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f027.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# MadCatz FPS Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f036.kl b/data/keyboards/Vendor_1bad_Product_f036.kl
new file mode 100644
index 0000000..8cd906a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f036.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# MadCatz Generic XBox Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1d79_Product_0009.kl b/data/keyboards/Vendor_1d79_Product_0009.kl
new file mode 100644
index 0000000..78fe2cd
--- /dev/null
+++ b/data/keyboards/Vendor_1d79_Product_0009.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 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.
+
+# Nyko Playpad / Playpad Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 158 BUTTON_BACK
+key 172 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl
new file mode 100644
index 0000000..d9cd171
--- /dev/null
+++ b/data/keyboards/Vendor_2378_Product_100a.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+# OnLive, Inc. OnLive Wireless Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_SELECT
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/docs/html/images/mediadrm_decryption_sequence.png b/docs/html/images/mediadrm_decryption_sequence.png
new file mode 100644
index 0000000..2bd95ea
--- /dev/null
+++ b/docs/html/images/mediadrm_decryption_sequence.png
Binary files differ
diff --git a/docs/html/images/mediadrm_overview.png b/docs/html/images/mediadrm_overview.png
new file mode 100644
index 0000000..dd66bce
--- /dev/null
+++ b/docs/html/images/mediadrm_overview.png
Binary files differ
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index ad7edb1..c277c24 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -237,6 +237,8 @@
}
bool mergeAllowed() {
+ if (!state.mMatrix.isPureTranslate()) return false;
+
// checks that we're unclipped, and srcover
const Rect& opBounds = state.mBounds;
return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 1501c79..df87db3 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -44,7 +44,16 @@
return MediaCodecList.getSupportedTypes(mIndex);
}
+ /**
+ * Encapsulates the capabilities of a given codec component,
+ * i.e. what profile/level combinations it supports and what colorspaces
+ * it is capable of providing the decoded data in.
+ */
public static final class CodecCapabilities {
+ // Enumerates supported profile/level combinations as defined
+ // by the type of encoded data. These combinations impose restrictions
+ // on video resolution, bitrate... and limit the available encoder tools
+ // such as B-frame support, arithmetic coding...
public CodecProfileLevel[] profileLevels;
// from OMX_COLOR_FORMATTYPE
@@ -219,6 +228,11 @@
public int level;
};
+ /**
+ * Enumerates the capabilities of the codec component. Since a single
+ * component can support data of a variety of types, the type has to be
+ * specified to yield a meaningful result.
+ */
public final CodecCapabilities getCapabilitiesForType(
String type) {
return MediaCodecList.getCodecCapabilities(mIndex, type);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6872278..31fbc4a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -29,25 +29,69 @@
import android.util.Log;
/**
- * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto}
- * to obtain keys for decrypting protected media data.
- *
- * Crypto schemes are assigned 16 byte UUIDs,
- * the method {@link #isCryptoSchemeSupported} can be used to query if a given
- * scheme is supported on the device.
- *
+ * MediaDrm can be used to obtain keys for decrypting protected media streams, in
+ * conjunction with {@link android.media.MediaCrypto}. The MediaDrm APIs
+ * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
+ * may also be used to implement other encryption schemes.
+ * <p>
+ * Encrypted content is prepared using an encryption server and stored in a content
+ * library. The encrypted content is streamed or downloaded from the content library to
+ * client devices via content servers. Licenses to view the content are obtained from
+ * a License Server.
+ * <p>
+ * <p><img src="../../../images/mediadrm_overview.png"
+ * alt="MediaDrm Overview diagram"
+ * border="0" /></p>
+ * <p>
+ * Keys are requested from the license server using a key request. The key
+ * response is delivered to the client app, which provides the response to the
+ * MediaDrm API.
+ * <p>
+ * A Provisioning server may be required to distribute device-unique credentials to
+ * the devices.
+ * <p>
+ * Enforcing requirements related to the number of devices that may play content
+ * simultaneously can be performed either through key renewal or using the secure
+ * stop methods.
+ * <p>
+ * The following sequence diagram shows the interactions between the objects
+ * involved while playing back encrypted content:
+ * <p>
+ * <p><img src="../../../images/mediadrm_decryption_sequence.png"
+ * alt="MediaDrm Overview diagram"
+ * border="0" /></p>
+ * <p>
+ * The app first constructs {@link android.media.MediaExtractor} and
+ * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
+ * typically from metadata in the content, and uses this UUID to construct an instance
+ * of a MediaDrm object that is able to support the DRM scheme required by the content.
+ * Crypto schemes are assigned 16 byte UUIDs. The method {@link #isCryptoSchemeSupported}
+ * can be used to query if a given scheme is supported on the device.
+ * <p>
+ * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
+ * the session in subsequent interactions. The app next uses the MediaDrm object to
+ * obtain a key request message and send it to the license server, then provide
+ * the server's response to the MediaDrm object.
+ * <p>
+ * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
+ * sessionId. The MediaCrypto object is registered with the MediaCodec in the
+ * {@link MediaCodec.#configure} method to enable the codec to decrypt content.
+ * <p>
+ * When the app has constructed {@link android.media.MediaExtractor},
+ * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
+ * it proceeds to pull samples from the extractor and queue them into the decoder. For
+ * encrypted content, the samples returned from the extractor remain encrypted, they
+ * are only decrypted when the samples are delivered to the decoder.
+ * <p>
* <a name="Callbacks"></a>
* <h3>Callbacks</h3>
- * <p>Applications may want to register for informational events in order
- * to be informed of some internal state update during playback or streaming.
+ * <p>Applications should register for informational events in order
+ * to be informed of key state updates during playback or streaming.
* Registration for these events is done via a call to
- * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener,
- * In order to receive the respective callback
- * associated with this listener, applications are required to create
+ * {@link #setOnEventListener}. In order to receive the respective
+ * callback associated with this listener, applications are required to create
* MediaDrm objects on a thread with its own Looper running (main UI
* thread by default has a Looper running).
- *
- * @hide -- don't expose yet
*/
public final class MediaDrm {
@@ -116,7 +160,7 @@
/**
* Interface definition for a callback to be invoked when a drm event
- * occurs.
+ * occurs
*/
public interface OnEventListener
{
@@ -132,10 +176,30 @@
void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
}
- public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1;
- public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2;
- public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
- public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
+ /**
+ * This event type indicates that the app needs to request a certificate from
+ * the provisioning server. The request message data is obtained using
+ * {@link #getProvisionRequest}
+ */
+ public static final int EVENT_PROVISION_REQUIRED = 1;
+
+ /**
+ * This event type indicates that the app needs to request keys from a license
+ * server. The request message data is obtained using {@link #getKeyRequest}.
+ */
+ public static final int EVENT_KEY_REQUIRED = 2;
+
+ /**
+ * This event type indicates that the licensed usage duration for keys in a session
+ * has expired. The keys are no longer valid.
+ */
+ public static final int EVENT_KEY_EXPIRED = 3;
+
+ /**
+ * This event may indicate some specific vendor-defined condition, see your
+ * DRM provider documentation for details
+ */
+ public static final int EVENT_VENDOR_DEFINED = 4;
private static final int DRM_EVENT = 200;
@@ -183,7 +247,7 @@
}
/*
- * Called from native code when an interesting event happens. This method
+ * This method is called from native code when an event occurs. This method
* just uses the EventHandler system to post the event back to the main app thread.
* We use a weak reference to the original MediaPlayer object so that the native
* code is safe from the object disappearing from underneath it. (This is
@@ -203,89 +267,117 @@
}
/**
- * Open a new session with the MediaDrm object. A session ID is returned.
+ * Open a new session with the MediaDrm object. A session ID is returned.
*/
- public native byte[] openSession() throws MediaDrmException;
+ public native byte[] openSession();
/**
- * Close a session on the MediaDrm object that was previously opened
- * with {@link #openSession}.
+ * Close a session on the MediaDrm object that was previously opened
+ * with {@link #openSession}.
*/
- public native void closeSession(byte[] sessionId) throws MediaDrmException;
+ public native void closeSession(byte[] sessionId);
- public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
- public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
- public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3;
+ /**
+ * This key request type species that the keys will be for online use, they will
+ * not be saved to the device for subsequent use when the device is not connected
+ * to a network.
+ */
+ public static final int KEY_TYPE_STREAMING = 1;
- public final class KeyRequest {
- public KeyRequest() {}
- public byte[] data;
- public String defaultUrl;
+ /**
+ * This key request type specifies that the keys will be for offline use, they
+ * will be saved to the device for use when the device is not connected to a network.
+ */
+ public static final int KEY_TYPE_OFFLINE = 2;
+
+ /**
+ * This key request type specifies that previously saved offline keys should be released.
+ */
+ public static final int KEY_TYPE_RELEASE = 3;
+
+ /**
+ * Contains the opaque data an app uses to request keys from a license server
+ */
+ public final static class KeyRequest {
+ KeyRequest() {}
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the key request message to a
+ * server, if known. The app may prefer to use a different license
+ * server URL from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
+
+ private byte[] mData;
+ private String mDefaultUrl;
};
/**
* A key request/response exchange occurs between the app and a license server
* to obtain or release keys used to decrypt encrypted content.
+ * <p>
* getKeyRequest() is used to obtain an opaque key request byte array that is
* delivered to the license server. The opaque key request byte array is returned
* in KeyRequest.data. The recommended URL to deliver the key request to is
* returned in KeyRequest.defaultUrl.
- *
+ * <p>
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
* {@link #provideKeyResponse}.
*
* @param scope may be a sessionId or a keySetId, depending on the specified keyType.
- * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE,
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
* scope should be set to the sessionId the keys will be provided to. When the keyType
- * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
+ * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
* being released. Releasing keys from a device invalidates them for all sessions.
* @param init container-specific data, its meaning is interpreted based on the
* mime type provided in the mimeType parameter. It could contain, for example,
* the content ID, key ID or other data obtained from the content metadata that is
* required in generating the key request. init may be null when keyType is
- * MEDIA_DRM_KEY_TYPE_RELEASE.
+ * KEY_TYPE_RELEASE.
* @param mimeType identifies the mime type of the content
* @param keyType specifes the type of the request. The request may be to acquire
* keys for streaming or offline content, or to release previously acquired
* keys, which are identified by a keySetId.
-
* @param optionalParameters are included in the key request message to
* allow a client application to provide additional message parameters to the server.
*/
public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
String mimeType, int keyType,
- HashMap<String, String> optionalParameters)
- throws MediaDrmException;
+ HashMap<String, String> optionalParameters);
+
/**
* A key response is received from the license server by the app, then it is
* provided to the DRM engine plugin using provideKeyResponse. The byte array
* returned is a keySetId that can be used to later restore the keys to a new
- * session with the method {@link restoreKeys}, enabling offline key use.
+ * session with the method {@link #restoreKeys}, enabling offline key use.
*
* @param sessionId the session ID for the DRM session
* @param response the byte array response from the server
*/
- public native byte[] provideKeyResponse(byte[] sessionId, byte[] response)
- throws MediaDrmException;
+ public native byte[] provideKeyResponse(byte[] sessionId, byte[] response);
/**
* Restore persisted offline keys into a new session. keySetId identifies the
- * keys to load, obtained from a prior call to {@link provideKeyResponse}.
+ * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
*
* @param sessionId the session ID for the DRM session
* @param keySetId identifies the saved key set to restore
*/
- public native void restoreKeys(byte[] sessionId, byte[] keySetId)
- throws MediaDrmException;
+ public native void restoreKeys(byte[] sessionId, byte[] keySetId);
/**
* Remove the current keys from a session.
*
* @param sessionId the session ID for the DRM session
*/
- public native void removeKeys(byte[] sessionId) throws MediaDrmException;
+ public native void removeKeys(byte[] sessionId);
/**
* Request an informative description of the key status for the session. The status is
@@ -296,25 +388,41 @@
*
* @param sessionId the session ID for the DRM session
*/
- public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
- throws MediaDrmException;
+ public native HashMap<String, String> queryKeyStatus(byte[] sessionId);
- public final class ProvisionRequest {
- public ProvisionRequest() {}
- public byte[] data;
- public String defaultUrl;
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ */
+ public final static class ProvisionRequest {
+ ProvisionRequest() {}
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the provision request
+ * message to a server, if known. The app may prefer to use a different
+ * provisioning server URL obtained from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
+
+ private byte[] mData;
+ private String mDefaultUrl;
}
/**
* A provision request/response exchange occurs between the app and a provisioning
* server to retrieve a device certificate. If provisionining is required, the
- * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+ * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
* getProvisionRequest is used to obtain the opaque provision request byte array that
* should be delivered to the provisioning server. The provision request byte array
* is returned in ProvisionRequest.data. The recommended URL to deliver the provision
* request to is returned in ProvisionRequest.defaultUrl.
*/
- public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
+ public native ProvisionRequest getProvisionRequest();
/**
* After a provision response is received by the app, it is provided to the DRM
@@ -323,92 +431,91 @@
* @param response the opaque provisioning response byte array to provide to the
* DRM engine plugin.
*/
- public native void provideProvisionResponse(byte[] response)
- throws MediaDrmException;
+ public native void provideProvisionResponse(byte[] response);
/**
- * A means of enforcing the contractual requirement for a concurrent stream limit
- * per subscriber across devices is provided via SecureStop. SecureStop is a means
- * of securely monitoring the lifetime of sessions. Since playback on a device can
- * be interrupted due to reboot, power failure, etc. a means of persisting the
- * lifetime information on the device is needed.
- *
- * A signed version of the sessionID is written to persistent storage on the device
- * when each MediaCrypto object is created. The sessionID is signed by the device
- * private key to prevent tampering.
- *
+ * A means of enforcing limits on the number of concurrent streams per subscriber
+ * across devices is provided via SecureStop. This is achieved by securely
+ * monitoring the lifetime of sessions.
+ * <p>
+ * Information from the server related to the current playback session is written
+ * to persistent storage on the device when each MediaCrypto object is created.
+ * <p>
* In the normal case, playback will be completed, the session destroyed and the
- * Secure Stops will be queried. The App queries secure stops and forwards the
+ * Secure Stops will be queried. The app queries secure stops and forwards the
* secure stop message to the server which verifies the signature and notifies the
* server side database that the session destruction has been confirmed. The persisted
* record on the client is only removed after positive confirmation that the server
* received the message using releaseSecureStops().
*/
- public native List<byte[]> getSecureStops() throws MediaDrmException;
+ public native List<byte[]> getSecureStops();
/**
* Process the SecureStop server response message ssRelease. After authenticating
- * the message, remove the SecureStops identiied in the response.
+ * the message, remove the SecureStops identified in the response.
*
* @param ssRelease the server response indicating which secure stops to release
*/
- public native void releaseSecureStops(byte[] ssRelease)
- throws MediaDrmException;
+ public native void releaseSecureStops(byte[] ssRelease);
/**
- * Read a DRM engine plugin property value, given the property name string. There are
- * several forms of property access functions, depending on the data type returned.
- *
+ * String property name: identifies the maker of the DRM engine plugin
+ */
+ public static final String PROPERTY_VENDOR = "vendor";
+
+ /**
+ * String property name: identifies the version of the DRM engine plugin
+ */
+ public static final String PROPERTY_VERSION = "version";
+
+ /**
+ * String property name: describes the DRM engine plugin
+ */
+ public static final String PROPERTY_DESCRIPTION = "description";
+
+ /**
+ * String property name: a comma-separated list of cipher and mac algorithms
+ * supported by CryptoSession. The list may be empty if the DRM engine
+ * plugin does not support CryptoSession operations.
+ */
+ public static final String PROPERTY_ALGORITHM = "algorithm";
+
+ /**
+ * Read a DRM engine plugin String property value, given the property name string.
+ * <p>
* Standard fields names are:
- * vendor String - identifies the maker of the DRM engine plugin
- * version String - identifies the version of the DRM engine plugin
- * description String - describes the DRM engine plugin
- * deviceUniqueId byte[] - The device unique identifier is established during device
- * provisioning and provides a means of uniquely identifying
- * each device
- * algorithms String - a comma-separate list of cipher and mac algorithms supported
- * by CryptoSession. The list may be empty if the DRM engine
- * plugin does not support CryptoSession operations.
+ * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
+ * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHM}
*/
- public native String getPropertyString(String propertyName)
- throws MediaDrmException;
+ public native String getPropertyString(String propertyName);
- public native byte[] getPropertyByteArray(String propertyName)
- throws MediaDrmException;
/**
- * Write a DRM engine plugin property value. There are several forms of
- * property setting functions, depending on the data type being set.
+ * The device unique identifier is established during device provisioning and
+ * provides a means of uniquely identifying each device
*/
- public native void setPropertyString(String propertyName, String value)
- throws MediaDrmException;
-
- public native void setPropertyByteArray(String propertyName, byte[] value)
- throws MediaDrmException;
+ public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
/**
- * In addition to supporting decryption of DASH Common Encrypted Media, the
- * MediaDrm APIs provide the ability to securely deliver session keys from
- * an operator's session key server to a client device, based on the factory-installed
- * root of trust, and provide the ability to do encrypt, decrypt, sign and verify
- * with the session key on arbitrary user data.
- *
- * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
- * based on the established session keys. These keys are exchanged using the
- * getKeyRequest/provideKeyResponse methods.
- *
- * Applications of this capability could include securing various types of
- * purchased or private content, such as applications, books and other media,
- * photos or media delivery protocols.
- *
- * Operators can create session key servers that are functionally similar to a
- * license key server, except that instead of receiving license key requests and
- * providing encrypted content keys which are used specifically to decrypt A/V media
- * content, the session key server receives session key requests and provides
- * encrypted session keys which can be used for general purpose crypto operations.
+ * Read a DRM engine plugin byte array property value, given the property name string.
+ * <p>
+ * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
*/
+ public native byte[] getPropertyByteArray(String propertyName);
+
+
+ /**
+ * Set a DRM engine plugin String property value.
+ */
+ public native void setPropertyString(String propertyName, String value);
+
+ /**
+ * Set a DRM engine plugin byte array property value.
+ */
+ public native void setPropertyByteArray(String propertyName, byte[] value);
+
private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
String algorithm);
@@ -429,61 +536,112 @@
byte[] keyId, byte[] message,
byte[] signature);
+ /**
+ * In addition to supporting decryption of DASH Common Encrypted Media, the
+ * MediaDrm APIs provide the ability to securely deliver session keys from
+ * an operator's session key server to a client device, based on the factory-installed
+ * root of trust, and then perform encrypt, decrypt, sign and verify operations
+ * with the session key on arbitrary user data.
+ * <p>
+ * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
+ * based on the established session keys. These keys are exchanged using the
+ * getKeyRequest/provideKeyResponse methods.
+ * <p>
+ * Applications of this capability could include securing various types of
+ * purchased or private content, such as applications, books and other media,
+ * photos or media delivery protocols.
+ * <p>
+ * Operators can create session key servers that are functionally similar to a
+ * license key server, except that instead of receiving license key requests and
+ * providing encrypted content keys which are used specifically to decrypt A/V media
+ * content, the session key server receives session key requests and provides
+ * encrypted session keys which can be used for general purpose crypto operations.
+ * <p>
+ * A CryptoSession is obtained using {@link #getCryptoSession}
+ */
public final class CryptoSession {
private MediaDrm mDrm;
private byte[] mSessionId;
- /**
- * Construct a CryptoSession which can be used to encrypt, decrypt,
- * sign and verify messages or data using the session keys established
- * for the session using methods {@link getKeyRequest} and
- * {@link provideKeyResponse} using a session key server.
- *
- * @param sessionId the session ID for the session containing keys
- * to be used for encrypt, decrypt, sign and/or verify
- *
- * @param cipherAlgorithm the algorithm to use for encryption and
- * decryption ciphers. The algorithm string conforms to JCA Standard
- * Names for Cipher Transforms and is case insensitive. For example
- * "AES/CBC/PKCS5Padding".
- *
- * @param macAlgorithm the algorithm to use for sign and verify
- * The algorithm string conforms to JCA Standard Names for Mac
- * Algorithms and is case insensitive. For example "HmacSHA256".
- *
- * The list of supported algorithms for a DRM engine plugin can be obtained
- * using the method {@link getPropertyString("algorithms")}
- */
-
- public CryptoSession(MediaDrm drm, byte[] sessionId,
- String cipherAlgorithm, String macAlgorithm)
- throws MediaDrmException {
+ CryptoSession(MediaDrm drm, byte[] sessionId,
+ String cipherAlgorithm, String macAlgorithm)
+ {
mSessionId = sessionId;
mDrm = drm;
setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
setMacAlgorithmNative(drm, sessionId, macAlgorithm);
}
+ /**
+ * Encrypt data using the CryptoSession's cipher algorithm
+ *
+ * @param keyid specifies which key to use
+ * @param input the data to encrypt
+ * @param iv the initialization vector to use for the cipher
+ */
public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
return encryptNative(mDrm, mSessionId, keyid, input, iv);
}
+ /**
+ * Decrypt data using the CryptoSessions's cipher algorithm
+ *
+ * @param keyid specifies which key to use
+ * @param input the data to encrypt
+ * @param iv the initialization vector to use for the cipher
+ */
public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
return decryptNative(mDrm, mSessionId, keyid, input, iv);
}
+ /**
+ * Sign data using the CryptoSessions's mac algorithm.
+ *
+ * @param keyid specifies which key to use
+ * @param message the data for which a signature is to be computed
+ */
public byte[] sign(byte[] keyid, byte[] message) {
return signNative(mDrm, mSessionId, keyid, message);
}
+
+ /**
+ * Verify a signature using the CryptoSessions's mac algorithm. Return true
+ * if the signatures match, false if they do no.
+ *
+ * @param keyid specifies which key to use
+ * @param message the data to verify
+ * @param signature the reference signature which will be compared with the
+ * computed signature
+ */
public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
return verifyNative(mDrm, mSessionId, keyid, message, signature);
}
};
+ /**
+ * Obtain a CryptoSession object which can be used to encrypt, decrypt,
+ * sign and verify messages or data using the session keys established
+ * for the session using methods {@link #getKeyRequest} and
+ * {@link #provideKeyResponse} using a session key server.
+ *
+ * @param sessionId the session ID for the session containing keys
+ * to be used for encrypt, decrypt, sign and/or verify
+ * @param cipherAlgorithm the algorithm to use for encryption and
+ * decryption ciphers. The algorithm string conforms to JCA Standard
+ * Names for Cipher Transforms and is case insensitive. For example
+ * "AES/CBC/NoPadding".
+ * @param macAlgorithm the algorithm to use for sign and verify
+ * The algorithm string conforms to JCA Standard Names for Mac
+ * Algorithms and is case insensitive. For example "HmacSHA256".
+ * <p>
+ * The list of supported algorithms for a DRM engine plugin can be obtained
+ * using the method {@link #getPropertyString} with the property name
+ * "algorithms".
+ */
public CryptoSession getCryptoSession(byte[] sessionId,
String cipherAlgorithm,
String macAlgorithm)
- throws MediaDrmException {
+ {
return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
}
@@ -495,8 +653,7 @@
public native final void release();
private static native final void native_init();
- private native final void native_setup(Object mediadrm_this, byte[] uuid)
- throws MediaDrmException;
+ private native final void native_setup(Object mediadrm_this, byte[] uuid);
private native final void native_finalize();
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
index 6f81f90..d6f5ff4 100644
--- a/media/java/android/media/MediaDrmException.java
+++ b/media/java/android/media/MediaDrmException.java
@@ -19,8 +19,6 @@
/**
* Exception thrown if MediaDrm object could not be instantiated for
* whatever reason.
- *
- * @hide -- don't expose yet
*/
public final class MediaDrmException extends Exception {
public MediaDrmException(String detailMessage) {
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 4a5e82e..61a0134 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -999,7 +999,7 @@
if (mEventHandler != null) {
// signal new client
mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
/*arg1*/ generationId, /*arg2, ignored*/ 0));
// send the information
@@ -1007,12 +1007,12 @@
mEventHandler.removeMessages(MSG_REQUEST_METADATA);
mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
- mEventHandler.dispatchMessage(
+ mEventHandler.sendMessage(
mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
}
}
@@ -1020,7 +1020,7 @@
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
}
}
@@ -1028,7 +1028,7 @@
public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_PLUG_DISPLAY, w, h, rcd));
}
}
@@ -1036,7 +1036,7 @@
public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_UNPLUG_DISPLAY, rcd));
}
}
@@ -1044,7 +1044,7 @@
public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
// only post messages, we can't block here
if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
}
}
@@ -1053,7 +1053,7 @@
// only post messages, we can't block here
if (mEventHandler != null) {
mEventHandler.removeMessages(MSG_SEEK_TO);
- mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
new Long(timeMs)));
}
@@ -1145,6 +1145,7 @@
break;
case MSG_SEEK_TO:
onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
+ break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c32ba9d..d1b499e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -30,6 +30,7 @@
#include <media/IDrm.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -191,10 +192,62 @@
static bool throwExceptionAsNecessary(
JNIEnv *env, status_t err, const char *msg = NULL) {
+ const char *drmMessage = NULL;
+
+ switch(err) {
+ case ERROR_DRM_UNKNOWN:
+ drmMessage = "General DRM error";
+ break;
+ case ERROR_DRM_NO_LICENSE:
+ drmMessage = "No license";
+ break;
+ case ERROR_DRM_LICENSE_EXPIRED:
+ drmMessage = "License expired";
+ break;
+ case ERROR_DRM_SESSION_NOT_OPENED:
+ drmMessage = "Session not opened";
+ break;
+ case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
+ drmMessage = "Not initialized";
+ break;
+ case ERROR_DRM_DECRYPT:
+ drmMessage = "Decrypt error";
+ break;
+ case ERROR_DRM_CANNOT_HANDLE:
+ drmMessage = "Unsupported scheme or data format";
+ break;
+ case ERROR_DRM_TAMPER_DETECTED:
+ drmMessage = "Invalid state";
+ break;
+ case ERROR_DRM_NOT_PROVISIONED:
+ drmMessage = "Not provisioned";
+ break;
+ case ERROR_DRM_DEVICE_REVOKED:
+ drmMessage = "Device revoked";
+ break;
+ default:
+ break;
+ }
+
+ String8 vendorMessage;
+ if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
+ vendorMessage.format("DRM vendor-defined error: %d", err);
+ drmMessage = vendorMessage.string();
+ }
+
if (err == BAD_VALUE) {
jniThrowException(env, "java/lang/IllegalArgumentException", msg);
return true;
} else if (err != OK) {
+ String8 errbuf;
+ if (drmMessage != NULL) {
+ if (msg == NULL) {
+ msg = drmMessage;
+ } else {
+ errbuf.format("%s: %s", msg, drmMessage);
+ msg = errbuf.string();
+ }
+ }
jniThrowException(env, "java/lang/IllegalStateException", msg);
return true;
}
@@ -458,22 +511,22 @@
"(Ljava/lang/Object;IILjava/lang/Object;)V");
jfieldID field;
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
- GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+ GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
- GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
- GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
+ GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
- GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
- GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+ GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
+ GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index ab7ceb6..dac3506e 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -184,7 +184,6 @@
private int mDebugFlags;
private int mEGLContextClientVersion;
private boolean mPreserveEGLContextOnPause;
- private int mUserRenderMode;
/**
* The renderer only renders
@@ -246,7 +245,7 @@
if (mGLThread != null) {
// GLThread may still be running if this view was never
// attached to a window.
- mGLThread.requestExitAndWait();
+ mGLThread.quitSafely();
}
} finally {
super.finalize();
@@ -258,7 +257,6 @@
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this);
- mUserRenderMode = RENDERMODE_CONTINUOUSLY;
}
/**
@@ -516,7 +514,6 @@
default:
throw new IllegalArgumentException("renderMode");
}
- mUserRenderMode = renderMode;
mGLThread.setRenderMode(renderMode);
}
@@ -528,7 +525,7 @@
* @see #RENDERMODE_WHEN_DIRTY
*/
public int getRenderMode() {
- return mUserRenderMode;
+ return mGLThread.getRenderMode();
}
/**
@@ -608,9 +605,13 @@
if (LOG_ATTACH_DETACH) {
Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
}
+
+ final int renderMode = mGLThread != null ?
+ mGLThread.mRenderMode : RENDERMODE_CONTINUOUSLY;
+
if (mDetached && (mRenderer != null)) {
mGLThread = new GLThread(mThisWeakRef);
- mGLThread.setRenderMode(mUserRenderMode);
+ mGLThread.setRenderMode(renderMode);
mGLThread.start();
}
mDetached = false;
@@ -627,7 +628,11 @@
Log.d(TAG, "onDetachedFromWindow");
}
if (mGLThread != null) {
- mGLThread.requestExitAndWait();
+ mGLThread.quitSafely();
+ try {
+ mGLThread.join();
+ } catch (InterruptedException ex) {
+ }
}
mDetached = true;
super.onDetachedFromWindow();
@@ -1261,6 +1266,17 @@
private Handler mGLHandler;
private Choreographer mChoreographer;
+ // this runnable could be called often, so we keep an instance around
+ class GetRenderModeRunnable implements Runnable {
+ volatile public int renderMode;
+ @Override
+ public void run() {
+ renderMode = doGetRenderMode();
+ }
+ };
+
+ private final GetRenderModeRunnable mGetRenderModeRunnable = new GetRenderModeRunnable();
+
/*
* Set once at thread construction time, nulled out when the parent view is garbage
* called. This weak reference allows the GLSurfaceView to be garbage collected while
@@ -1511,7 +1527,7 @@
}
}
- private void doWindowResize(final int width, final int height) {
+ private void doWindowResize(int width, int height) {
// we were not drawing yet. Update the window size and
// state and attempt to draw a frame.
mSizeChanged = (mWidth != width || mHeight != height);
@@ -1522,9 +1538,13 @@
executeDraw();
}
- private void doSetRenderMode(final int renderMode) {
+ private void doSetRenderMode(int renderMode) {
mRenderMode = renderMode;
- requestRender();
+ }
+
+
+ private int doGetRenderMode() {
+ return mRenderMode;
}
/*
@@ -1607,12 +1627,9 @@
}, 0);
}
- public void requestExitAndWait() {
- getLooper().quit();
- try {
- this.join();
- } catch (InterruptedException e) {
- }
+ public int getRenderMode() {
+ mGLHandler.runWithScissors(mGetRenderModeRunnable, 0);
+ return mGetRenderModeRunnable.renderMode;
}
} // class GLThread
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 9146ccd..2c25236 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -54,7 +55,10 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+ }
+
Intent intent = getIntent();
String fingerprints = intent.getStringExtra("fingerprints");
mKey = intent.getStringExtra("key");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7cb6b09..7f3fc43 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -251,8 +251,9 @@
int mLidOpenRotation;
int mCarDockRotation;
int mDeskDockRotation;
- int mHdmiRotation;
- boolean mHdmiRotationLock;
+ int mUndockedHdmiRotation;
+ int mDemoHdmiRotation;
+ boolean mDemoHdmiRotationLock;
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
@@ -854,6 +855,8 @@
com.android.internal.R.integer.config_carDockRotation);
mDeskDockRotation = readRotation(
com.android.internal.R.integer.config_deskDockRotation);
+ mUndockedHdmiRotation = readRotation(
+ com.android.internal.R.integer.config_undockedHdmiRotation);
mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_carDockEnablesAccelerometer);
mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
@@ -1024,11 +1027,11 @@
// For demo purposes, allow the rotation of the HDMI display to be controlled.
// By default, HDMI locks rotation to landscape.
if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
- mHdmiRotation = mPortraitRotation;
+ mDemoHdmiRotation = mPortraitRotation;
} else {
- mHdmiRotation = mLandscapeRotation;
+ mDemoHdmiRotation = mLandscapeRotation;
}
- mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+ mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
}
@Override
@@ -4200,10 +4203,17 @@
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
- } else if (mHdmiPlugged && mHdmiRotationLock) {
- // Ignore sensor when plugged into HDMI.
+ } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+ // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
- preferredRotation = mHdmiRotation;
+ preferredRotation = mDemoHdmiRotation;
+ } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+ && mUndockedHdmiRotation >= 0) {
+ // Ignore sensor when plugged into HDMI and an undocked orientation has
+ // been specified in the configuration (only for legacy devices without
+ // full multi-display support).
+ // Note that the dock orientation overrides the HDMI orientation.
+ preferredRotation = mUndockedHdmiRotation;
} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// Application just wants to remain locked in the last rotation.
preferredRotation = lastRotation;
@@ -4967,7 +4977,8 @@
pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
- pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation);
- pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock);
+ pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
+ pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
+ pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index 77359ff..9b588036 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -23,12 +23,16 @@
import android.content.Context;
import android.os.BatteryManager;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Slog;
import android.view.View;
import android.widget.TextView;
@@ -37,6 +41,8 @@
import java.lang.ref.WeakReference;
import com.android.internal.R;
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
/***
* Manages a number of views inside of the given layout. See below for a list of widgets.
@@ -57,6 +63,8 @@
static final int SECURITY_MESSAGE_DURATION = 5000;
protected static final int FADE_DURATION = 750;
+ private static final String TAG = "KeyguardMessageArea";
+
// are we showing battery information?
boolean mShowingBatteryInfo = false;
@@ -82,6 +90,9 @@
CharSequence mMessage;
boolean mShowingMessage;
+ private CharSequence mSeparator;
+ private LockPatternUtils mLockPatternUtils;
+
Runnable mClearMessageRunnable = new Runnable() {
@Override
public void run() {
@@ -156,8 +167,6 @@
}
};
- private CharSequence mSeparator;
-
public KeyguardMessageArea(Context context) {
this(context, null);
}
@@ -165,6 +174,8 @@
public KeyguardMessageArea(Context context, AttributeSet attrs) {
super(context, attrs);
+ mLockPatternUtils = new LockPatternUtils(context);
+
// This is required to ensure marquee works
setSelected(true);
@@ -228,11 +239,12 @@
String getOwnerInfo() {
ContentResolver res = getContext().getContentResolver();
- final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res,
- Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
- return ownerInfoEnabled && !mShowingMessage ?
- Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO,
- UserHandle.USER_CURRENT) : null;
+ String info = null;
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+ if (ownerInfoEnabled && !mShowingMessage) {
+ info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+ }
+ return info;
}
private CharSequence getChargeInfo(MutableInt icon) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a28c387..f872cc3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1595,7 +1595,7 @@
ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
mSettings.getCurrentUserId());
- if (ai.enabledSetting
+ if (ai != null && ai.enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index e20a21f..41cc4d7 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -19,6 +19,11 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+
+import static android.content.Context.USER_SERVICE;
+import static android.Manifest.permission.READ_PROFILE;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
@@ -27,8 +32,10 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Slog;
@@ -40,6 +47,7 @@
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
+import java.util.List;
/**
* Keeps the lock pattern/password data and related settings for each user.
@@ -79,23 +87,52 @@
private void migrateOldData() {
try {
- if (getString("migrated", null, 0) != null) {
- // Already migrated
- return;
+ // These Settings moved before multi-user was enabled, so we only have to do it for the
+ // root user.
+ if (getString("migrated", null, 0) == null) {
+ final ContentResolver cr = mContext.getContentResolver();
+ for (String validSetting : VALID_SETTINGS) {
+ String value = Settings.Secure.getString(cr, validSetting);
+ if (value != null) {
+ setString(validSetting, value, 0);
+ }
+ }
+ // No need to move the password / pattern files. They're already in the right place.
+ setString("migrated", "true", 0);
+ Slog.i(TAG, "Migrated lock settings to new location");
}
- final ContentResolver cr = mContext.getContentResolver();
- for (String validSetting : VALID_SETTINGS) {
- String value = Settings.Secure.getString(cr, validSetting);
- if (value != null) {
- setString(validSetting, value, 0);
+ // These Settings changed after multi-user was enabled, hence need to be moved per user.
+ if (getString("migrated_user_specific", null, 0) == null) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final ContentResolver cr = mContext.getContentResolver();
+ List<UserInfo> users = um.getUsers();
+ for (int user = 0; user < users.size(); user++) {
+ int userId = users.get(user).getUserHandle().getIdentifier();
+ for (String perUserSetting : MIGRATE_SETTINGS_PER_USER) {
+ // Handle Strings
+ String value = Settings.Secure.getStringForUser(cr, perUserSetting, userId);
+ if (value != null) {
+ setString(perUserSetting, value, userId);
+ Settings.Secure.putStringForUser(cr, perUserSetting, "", userId);
+ continue;
+ }
+
+ // Handle integers
+ try {
+ int ivalue = Settings.Secure.getIntForUser(cr, perUserSetting, userId);
+ setLong(perUserSetting, ivalue, userId);
+ Settings.Secure.putIntForUser(cr, perUserSetting, 0, userId);
+ } catch (SettingNotFoundException e) {
+ }
+ }
}
+ // No need to move the password / pattern files. They're already in the right place.
+ setString("migrated_user_specific", "true", 0);
+ Slog.i(TAG, "Migrated per-user lock settings to new location");
}
- // No need to move the password / pattern files. They're already in the right place.
- setString("migrated", "true", 0);
- Slog.i(TAG, "Migrated lock settings to new location");
} catch (RemoteException re) {
- Slog.e(TAG, "Unable to migrate old data");
+ Slog.e(TAG, "Unable to migrate old data", re);
}
}
@@ -115,12 +152,16 @@
}
}
- private static final void checkReadPermission(int userId) {
+ private final void checkReadPermission(String requestedKey, int userId) {
final int callingUid = Binder.getCallingUid();
- if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID
- && UserHandle.getUserId(callingUid) != userId) {
- throw new SecurityException("uid=" + callingUid
- + " not authorized to read settings of user " + userId);
+ for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
+ String key = READ_PROFILE_PROTECTED_SETTINGS[i];
+ if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("uid=" + callingUid
+ + " needs permission " + READ_PROFILE + " to read "
+ + requestedKey + " for user " + userId);
+ }
}
}
@@ -147,7 +188,7 @@
@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
String value = readFromDb(key, null, userId);
return TextUtils.isEmpty(value) ?
@@ -156,7 +197,7 @@
@Override
public long getLong(String key, long defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
String value = readFromDb(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
@@ -164,7 +205,7 @@
@Override
public String getString(String key, String defaultValue, int userId) throws RemoteException {
- //checkReadPermission(userId);
+ checkReadPermission(key, userId);
return readFromDb(key, defaultValue, userId);
}
@@ -404,5 +445,13 @@
Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
Secure.LOCK_PATTERN_VISIBLE,
Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
- };
+ };
+
+ private static final String[] MIGRATE_SETTINGS_PER_USER = new String[] {
+ Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+ Secure.LOCK_SCREEN_OWNER_INFO
+ };
+
+ // These are protected with a read permission
+ private static final String[] READ_PROFILE_PROTECTED_SETTINGS = MIGRATE_SETTINGS_PER_USER;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 3bebf91..9a93f63 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -450,11 +450,16 @@
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
checkCallerIsSystem();
- if (true||DBG) {
- Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
- }
+
+ Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
+
mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+
+ // Now, cancel any outstanding notifications that are part of a just-disabled app
+ if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+ cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
+ }
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1f3ac96..2f64908 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -237,6 +237,11 @@
}
// We will update when the automation service dies.
UserState userState = getCurrentUserStateLocked();
+ // We have to reload the installed services since some services may
+ // have different attributes, resolve info (does not support equals),
+ // etc. Remove them then to force reload. Do it even if automation is
+ // running since when it goes away, we will have to reload as well.
+ userState.mInstalledServices.clear();
if (userState.mUiAutomationService == null) {
if (readConfigurationForUserStateLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -820,17 +825,21 @@
private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
// TODO: Now we are giving the key events to the last enabled
- // service that can handle them which is the last one
- // in our list since we write the last enabled as the
- // last record in the enabled services setting. Ideally,
- // the user should make the call which service handles
- // key events. However, only one service should handle
- // key events to avoid user frustration when different
- // behavior is observed from different combinations of
- // enabled accessibility services.
+ // service that can handle them Ideally, the user should
+ // make the call which service handles key events. However,
+ // only one service should handle key events to avoid user
+ // frustration when different behavior is observed from
+ // different combinations of enabled accessibility services.
UserState state = getCurrentUserStateLocked();
for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
Service service = state.mBoundServices.get(i);
+ // Key events are handled only by services that declared
+ // this capability and requested to filter key events.
+ if (!service.mRequestFilterKeyEvents ||
+ (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo
+ .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
+ continue;
+ }
if (service.mIsDefault == isDefault) {
service.notifyKeyEvent(event, policyFlags);
return true;
@@ -1160,7 +1169,9 @@
boolean setInputFilter = false;
AccessibilityInputFilter inputFilter = null;
synchronized (mLock) {
- if (userState.mIsAccessibilityEnabled) {
+ // Accessibility enabled means at least one service is enabled.
+ if (userState.mIsAccessibilityEnabled
+ || userState.mIsDisplayMagnificationEnabled) {
if (!mHasInputFilter) {
mHasInputFilter = true;
if (mInputFilter == null) {
@@ -1174,7 +1185,8 @@
if (userState.mIsDisplayMagnificationEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
}
- if (userState.mIsTouchExplorationEnabled) {
+ // Touch exploration without accessibility makes no sense.
+ if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
}
mInputFilter.setEnabledFeatures(flags);
@@ -1366,11 +1378,11 @@
return true;
}
} else {
- // Starting in JB-MR2 we request a permission to allow a service to enable
- // touch exploration and do not care if the service is in the white list.
- if (mContext.getPackageManager().checkPermission(
- android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
- service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+ // Starting in JB-MR2 we request an accessibility service to declare
+ // certain capabilities in its meta-data to allow it to enable the
+ // corresponding features.
+ if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+ & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
userState.mIsTouchExplorationEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
@@ -1399,9 +1411,8 @@
if (userState.mIsEnhancedWebAccessibilityEnabled) {
return false;
}
- if (service.mIsAutomation || mContext.getPackageManager().checkPermission(
- android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+ if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+ & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
userState.mIsEnhancedWebAccessibilityEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
@@ -1636,6 +1647,8 @@
boolean mRequestEnhancedWebAccessibility;
+ boolean mRequestFilterKeyEvents;
+
int mFetchFlags;
long mNotificationTimeout;
@@ -1681,7 +1694,8 @@
mAccessibilityServiceInfo = accessibilityServiceInfo;
mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
if (!mIsAutomation) {
- mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
+ mCanRetrieveScreenContent = (accessibilityServiceInfo.getCapabilities()
+ & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0;
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.accessibility_binding_label);
@@ -1720,9 +1734,11 @@
if (mResolveInfo != null) {
mRequestTouchExplorationMode = (info.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+ & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
mRequestEnhancedWebAccessibility = (info.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+ & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+ mRequestFilterKeyEvents = (info.flags
+ & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
}
}
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index a83675e..8c8b360 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -481,6 +481,7 @@
mRemoteDisplayConnected = false;
mHandler.removeCallbacks(mRtspTimeout);
+ mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
setRemoteSubmixOn(false);
unadvertiseDisplay();
@@ -626,6 +627,7 @@
}
setRemoteSubmixOn(true);
+ mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
final WifiP2pDevice oldDevice = mConnectedDevice;
final int port = getPortNumber(mConnectedDevice);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1d1fda5..bc442ce 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5490,6 +5490,7 @@
ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
Canvas canvas = new Canvas(bm);
+ canvas.drawColor(0xFF000000);
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 31e01c0..dbd48d9 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -93,21 +93,21 @@
}
/**
- * @return Network Id 0..65535
+ * @return Network Id 0..65535, Integer.MAX_VALUE if unknown
*/
public int getNetworkId() {
return mNetworkId;
}
/**
- * @return System Id 0..32767
+ * @return System Id 0..32767, Integer.MAX_VALUE if unknown
*/
public int getSystemId() {
return mSystemId;
}
/**
- * @return Base Station Id 0..65535
+ * @return Base Station Id 0..65535, Integer.MAX_VALUE if unknown
*/
public int getBasestationId() {
return mBasestationId;
@@ -118,7 +118,7 @@
* specified in 3GPP2 C.S0005-A v6.0. It is represented in units
* of 0.25 seconds and ranges from -2592000 to 2592000, both
* values inclusive (corresponding to a range of -180
- * to +180 degrees).
+ * to +180 degrees). Integer.MAX_VALUE if unknown.
*/
public int getLongitude() {
return mLongitude;
@@ -129,7 +129,7 @@
* specified in 3GPP2 C.S0005-A v6.0. It is represented in units
* of 0.25 seconds and ranges from -1296000 to 1296000, both
* values inclusive (corresponding to a range of -90
- * to +90 degrees).
+ * to +90 degrees). Integer.MAX_VALUE if unknown.
*/
public int getLatitude() {
return mLatitude;
@@ -162,7 +162,7 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("CellIdentitiyCdma:{");
+ StringBuilder sb = new StringBuilder("CellIdentityCdma:{");
sb.append(" mNetworkId="); sb.append(mNetworkId);
sb.append(" mSystemId="); sb.append(mSystemId);
sb.append(" mBasestationId="); sb.append(mBasestationId);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 98113e7..6f8cc91 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -21,7 +21,7 @@
import android.telephony.Rlog;
/**
- * CellIdentity to represent a unique GSM or UMTS cell
+ * CellIdentity to represent a unique GSM cell
*/
public final class CellIdentityGsm implements Parcelable {
@@ -35,10 +35,7 @@
// 16-bit Location Area Code, 0..65535
private final int mLac;
// 16-bit GSM Cell Identity described in TS 27.007, 0..65535
- // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
private final int mCid;
- // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
- private final int mPsc;
/**
* @hide
@@ -48,7 +45,6 @@
mMnc = Integer.MAX_VALUE;
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
- mPsc = Integer.MAX_VALUE;
}
/**
* public constructor
@@ -56,16 +52,14 @@
* @param mnc 2 or 3-digit Mobile Network Code, 0..999
* @param lac 16-bit Location Area Code, 0..65535
* @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
- * @param psc 9-bit UMTS Primary Scrambling Code
*
* @hide
*/
- public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int psc) {
+ public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
mMcc = mcc;
mMnc = mnc;
mLac = lac;
mCid = cid;
- mPsc = psc;
}
private CellIdentityGsm(CellIdentityGsm cid) {
@@ -73,7 +67,6 @@
mMnc = cid.mMnc;
mLac = cid.mLac;
mCid = cid.mCid;
- mPsc = cid.mPsc;
}
CellIdentityGsm copy() {
@@ -81,21 +74,21 @@
}
/**
- * @return 3-digit Mobile Country Code, 0..999
+ * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
*/
public int getMcc() {
return mMcc;
}
/**
- * @return 2 or 3-digit Mobile Network Code, 0..999
+ * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
*/
public int getMnc() {
return mMnc;
}
/**
- * @return 16-bit Location Area Code, 0..65535
+ * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
*/
public int getLac() {
return mLac;
@@ -104,27 +97,24 @@
/**
* @return CID
* Either 16-bit GSM Cell Identity described
- * in TS 27.007, 0..65535
- * or 28-bit UMTS Cell Identity described
- * in TS 25.331, 0..268435455
+ * in TS 27.007, 0..65535, Integer.MAX_VALUE if unknown
*/
public int getCid() {
return mCid;
}
/**
- * @return 9-bit UMTS Primary Scrambling Code described in
- * TS 25.331, 0..511
+ * @return Integer.MAX_VALUE, undefined for GSM
*/
+ @Deprecated
public int getPsc() {
- return mPsc;
+ return Integer.MAX_VALUE;
}
@Override
public int hashCode() {
int primeNum = 31;
- return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
- (mPsc * primeNum);
+ return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum);
}
@Override
@@ -135,8 +125,7 @@
return mMcc == o.mMcc &&
mMnc == o.mMnc &&
mLac == o.mLac &&
- mCid == o.mCid &&
- mPsc == o.mPsc;
+ mCid == o.mCid;
} catch (ClassCastException e) {
return false;
}
@@ -147,12 +136,11 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("CellIdentitiyGsm:{");
+ StringBuilder sb = new StringBuilder("CellIdentityGsm:{");
sb.append(" mMcc=").append(mMcc);
sb.append(" mMnc=").append(mMnc);
sb.append(" mLac=").append(mLac);
sb.append(" mCid=").append(mCid);
- sb.append(" mPsc=").append(mPsc);
sb.append("}");
return sb.toString();
@@ -172,7 +160,6 @@
dest.writeInt(mMnc);
dest.writeInt(mLac);
dest.writeInt(mCid);
- dest.writeInt(mPsc);
}
/** Construct from Parcel, type has already been processed */
@@ -181,7 +168,6 @@
mMnc = in.readInt();
mLac = in.readInt();
mCid = in.readInt();
- mPsc = in.readInt();
if (DBG) log("CellIdentityGsm(Parcel): " + toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 86924bd..13b39c9 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -81,35 +81,35 @@
}
/**
- * @return 3-digit Mobile Country Code, 0..999
+ * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
*/
public int getMcc() {
return mMcc;
}
/**
- * @return 2 or 3-digit Mobile Network Code, 0..999
+ * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
*/
public int getMnc() {
return mMnc;
}
/**
- * @return 28-bit Cell Identity
+ * @return 28-bit Cell Identity, Integer.MAX_VALUE if unknown
*/
public int getCi() {
return mCi;
}
/**
- * @return Physical Cell Id 0..503
+ * @return Physical Cell Id 0..503, Integer.MAX_VALUE if unknown
*/
public int getPci() {
return mPci;
}
/**
- * @return 16-bit Tracking Area Code
+ * @return 16-bit Tracking Area Code, Integer.MAX_VALUE if unknown
*/
public int getTac() {
return mTac;
@@ -142,7 +142,7 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("CellIdentitiyLte:{");
+ StringBuilder sb = new StringBuilder("CellIdentityLte:{");
sb.append(" mMcc="); sb.append(mMcc);
sb.append(" mMnc="); sb.append(mMnc);
sb.append(" mCi="); sb.append(mCi);
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
new file mode 100644
index 0000000..2f8fa42
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * CellIdentity to represent a unique UMTS cell
+ */
+public final class CellIdentityWcdma implements Parcelable {
+
+ private static final String LOG_TAG = "CellIdentityWcdma";
+ private static final boolean DBG = false;
+
+ // 3-digit Mobile Country Code, 0..999
+ private final int mMcc;
+ // 2 or 3-digit Mobile Network Code, 0..999
+ private final int mMnc;
+ // 16-bit Location Area Code, 0..65535
+ private final int mLac;
+ // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
+ private final int mCid;
+ // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
+ private final int mPsc;
+
+ /**
+ * @hide
+ */
+ public CellIdentityWcdma() {
+ mMcc = Integer.MAX_VALUE;
+ mMnc = Integer.MAX_VALUE;
+ mLac = Integer.MAX_VALUE;
+ mCid = Integer.MAX_VALUE;
+ mPsc = Integer.MAX_VALUE;
+ }
+ /**
+ * public constructor
+ * @param mcc 3-digit Mobile Country Code, 0..999
+ * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+ * @param lac 16-bit Location Area Code, 0..65535
+ * @param cid 28-bit UMTS Cell Identity
+ * @param psc 9-bit UMTS Primary Scrambling Code
+ *
+ * @hide
+ */
+ public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+ mMcc = mcc;
+ mMnc = mnc;
+ mLac = lac;
+ mCid = cid;
+ mPsc = psc;
+ }
+
+ private CellIdentityWcdma(CellIdentityWcdma cid) {
+ mMcc = cid.mMcc;
+ mMnc = cid.mMnc;
+ mLac = cid.mLac;
+ mCid = cid.mCid;
+ mPsc = cid.mPsc;
+ }
+
+ CellIdentityWcdma copy() {
+ return new CellIdentityWcdma(this);
+ }
+
+ /**
+ * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
+ */
+ public int getMcc() {
+ return mMcc;
+ }
+
+ /**
+ * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
+ */
+ public int getMnc() {
+ return mMnc;
+ }
+
+ /**
+ * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
+ */
+ public int getLac() {
+ return mLac;
+ }
+
+ /**
+ * @return CID
+ * 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, Integer.MAX_VALUE if unknown
+ */
+ public int getCid() {
+ return mCid;
+ }
+
+ /**
+ * @return 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, Integer.MAX_VALUE
+ * if unknown
+ */
+ public int getPsc() {
+ return mPsc;
+ }
+
+ @Override
+ public int hashCode() {
+ int primeNum = 31;
+ return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
+ (mPsc * primeNum);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (super.equals(other)) {
+ try {
+ CellIdentityWcdma o = (CellIdentityWcdma)other;
+ return mMcc == o.mMcc &&
+ mMnc == o.mMnc &&
+ mLac == o.mLac &&
+ mCid == o.mCid &&
+ mPsc == o.mPsc;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("CellIdentityWcdma:{");
+ sb.append(" mMcc=").append(mMcc);
+ sb.append(" mMnc=").append(mMnc);
+ sb.append(" mLac=").append(mLac);
+ sb.append(" mCid=").append(mCid);
+ sb.append(" mPsc=").append(mPsc);
+ sb.append("}");
+
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (DBG) log("writeToParcel(Parcel, int): " + toString());
+ dest.writeInt(mMcc);
+ dest.writeInt(mMnc);
+ dest.writeInt(mLac);
+ dest.writeInt(mCid);
+ dest.writeInt(mPsc);
+ }
+
+ /** Construct from Parcel, type has already been processed */
+ private CellIdentityWcdma(Parcel in) {
+ mMcc = in.readInt();
+ mMnc = in.readInt();
+ mLac = in.readInt();
+ mCid = in.readInt();
+ mPsc = in.readInt();
+ if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
+ }
+
+ /** Implement the Parcelable interface */
+ @SuppressWarnings("hiding")
+ public static final Creator<CellIdentityWcdma> CREATOR =
+ new Creator<CellIdentityWcdma>() {
+ @Override
+ public CellIdentityWcdma createFromParcel(Parcel in) {
+ return new CellIdentityWcdma(in);
+ }
+
+ @Override
+ public CellIdentityWcdma[] newArray(int size) {
+ return new CellIdentityWcdma[size];
+ }
+ };
+
+ /**
+ * log
+ */
+ private static void log(String s) {
+ Rlog.w(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index fe3c68b..bfa0942 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -31,6 +31,8 @@
protected static final int TYPE_CDMA = 2;
/** @hide */
protected static final int TYPE_LTE = 3;
+ /** @hide */
+ protected static final int TYPE_WCDMA = 4;
// Type to distinguish where time stamp gets recorded.
@@ -201,6 +203,7 @@
case TYPE_GSM: return CellInfoGsm.createFromParcelBody(in);
case TYPE_CDMA: return CellInfoCdma.createFromParcelBody(in);
case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
+ case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
default: throw new RuntimeException("Bad CellInfo Parcel");
}
}
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
new file mode 100644
index 0000000..0615702
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Immutable cell information from a point in time.
+ */
+public final class CellInfoWcdma extends CellInfo implements Parcelable {
+
+ private static final String LOG_TAG = "CellInfoWcdma";
+ private static final boolean DBG = false;
+
+ private CellIdentityWcdma mCellIdentityWcdma;
+ private CellSignalStrengthWcdma mCellSignalStrengthWcdma;
+
+ /** @hide */
+ public CellInfoWcdma() {
+ super();
+ mCellIdentityWcdma = new CellIdentityWcdma();
+ mCellSignalStrengthWcdma = new CellSignalStrengthWcdma();
+ }
+
+ /** @hide */
+ public CellInfoWcdma(CellInfoWcdma ci) {
+ super(ci);
+ this.mCellIdentityWcdma = ci.mCellIdentityWcdma.copy();
+ this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
+ }
+
+ public CellIdentityWcdma getCellIdentity() {
+ return mCellIdentityWcdma;
+ }
+ /** @hide */
+ public void setCellIdentity(CellIdentityWcdma cid) {
+ mCellIdentityWcdma = cid;
+ }
+
+ public CellSignalStrengthWcdma getCellSignalStrength() {
+ return mCellSignalStrengthWcdma;
+ }
+ /** @hide */
+ public void setCellSignalStrength(CellSignalStrengthWcdma css) {
+ mCellSignalStrengthWcdma = css;
+ }
+
+ /**
+ * @return hash code
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode() + mCellIdentityWcdma.hashCode() + mCellSignalStrengthWcdma.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!super.equals(other)) {
+ return false;
+ }
+ try {
+ CellInfoWcdma o = (CellInfoWcdma) other;
+ return mCellIdentityWcdma.equals(o.mCellIdentityWcdma)
+ && mCellSignalStrengthWcdma.equals(o.mCellSignalStrengthWcdma);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("CellInfoWcdma:{");
+ sb.append(super.toString());
+ sb.append(" ").append(mCellIdentityWcdma);
+ sb.append(" ").append(mCellSignalStrengthWcdma);
+ sb.append("}");
+
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags, TYPE_WCDMA);
+ mCellIdentityWcdma.writeToParcel(dest, flags);
+ mCellSignalStrengthWcdma.writeToParcel(dest, flags);
+ }
+
+ /**
+ * Construct a CellInfoWcdma object from the given parcel
+ * where the token is already been processed.
+ */
+ private CellInfoWcdma(Parcel in) {
+ super(in);
+ mCellIdentityWcdma = CellIdentityWcdma.CREATOR.createFromParcel(in);
+ mCellSignalStrengthWcdma = CellSignalStrengthWcdma.CREATOR.createFromParcel(in);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<CellInfoWcdma> CREATOR = new Creator<CellInfoWcdma>() {
+ @Override
+ public CellInfoWcdma createFromParcel(Parcel in) {
+ in.readInt(); // Skip past token, we know what it is
+ return createFromParcelBody(in);
+ }
+
+ @Override
+ public CellInfoWcdma[] newArray(int size) {
+ return new CellInfoWcdma[size];
+ }
+ };
+
+ /** @hide */
+ protected static CellInfoWcdma createFromParcelBody(Parcel in) {
+ return new CellInfoWcdma(in);
+ }
+
+ /**
+ * log
+ */
+ private static void log(String s) {
+ Rlog.w(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 2c36344..d27fcec 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -21,7 +21,7 @@
import android.telephony.Rlog;
/**
- * LTE signal strength related information.
+ * GSM signal strength related information.
*/
public final class CellSignalStrengthGsm extends CellSignalStrength implements Parcelable {
@@ -30,7 +30,7 @@
private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
- private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8;
+ private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
@@ -67,7 +67,8 @@
/**
* Initialize all the values
*
- * @param SignalStrength
+ * @param ss SignalStrength as ASU value
+ * @param ber is Bit Error Rate
*
* @hide
*/
@@ -139,7 +140,7 @@
}
/**
- * Get the LTE signal level as an asu value between 0..97, 99 is unknown
+ * Get the signal level as an asu value between 0..31, 99 is unknown
* Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
*/
@Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
new file mode 100644
index 0000000..b94b01d
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2012 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Wcdma signal strength related information.
+ */
+public final class CellSignalStrengthWcdma extends CellSignalStrength implements Parcelable {
+
+ private static final String LOG_TAG = "CellSignalStrengthWcdma";
+ private static final boolean DBG = false;
+
+ private static final int WCDMA_SIGNAL_STRENGTH_GREAT = 12;
+ private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
+ private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
+
+ private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
+ private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+
+ /**
+ * Empty constructor
+ *
+ * @hide
+ */
+ public CellSignalStrengthWcdma() {
+ setDefaultValues();
+ }
+
+ /**
+ * Constructor
+ *
+ * @hide
+ */
+ public CellSignalStrengthWcdma(int ss, int ber) {
+ initialize(ss, ber);
+ }
+
+ /**
+ * Copy constructors
+ *
+ * @param s Source SignalStrength
+ *
+ * @hide
+ */
+ public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
+ copyFrom(s);
+ }
+
+ /**
+ * Initialize all the values
+ *
+ * @param ss SignalStrength as ASU value
+ * @param ber is Bit Error Rate
+ *
+ * @hide
+ */
+ public void initialize(int ss, int ber) {
+ mSignalStrength = ss;
+ mBitErrorRate = ber;
+ }
+
+ /**
+ * @hide
+ */
+ protected void copyFrom(CellSignalStrengthWcdma s) {
+ mSignalStrength = s.mSignalStrength;
+ mBitErrorRate = s.mBitErrorRate;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public CellSignalStrengthWcdma copy() {
+ return new CellSignalStrengthWcdma(this);
+ }
+
+ /** @hide */
+ @Override
+ public void setDefaultValues() {
+ mSignalStrength = Integer.MAX_VALUE;
+ mBitErrorRate = Integer.MAX_VALUE;
+ }
+
+ /**
+ * Get signal level as an int from 0..4
+ */
+ @Override
+ public int getLevel() {
+ int level;
+
+ // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+ // asu = 0 (-113dB or less) is very weak
+ // signal, its better to show 0 bars to the user in such cases.
+ // asu = 99 is a special case, where the signal strength is unknown.
+ int asu = mSignalStrength;
+ if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ else if (asu >= WCDMA_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
+ else if (asu >= WCDMA_SIGNAL_STRENGTH_GOOD) level = SIGNAL_STRENGTH_GOOD;
+ else if (asu >= WCDMA_SIGNAL_STRENGTH_MODERATE) level = SIGNAL_STRENGTH_MODERATE;
+ else level = SIGNAL_STRENGTH_POOR;
+ if (DBG) log("getLevel=" + level);
+ return level;
+ }
+
+ /**
+ * Get the signal strength as dBm
+ */
+ @Override
+ public int getDbm() {
+ int dBm;
+
+ int level = mSignalStrength;
+ int asu = (level == 99 ? Integer.MAX_VALUE : level);
+ if (asu != Integer.MAX_VALUE) {
+ dBm = -113 + (2 * asu);
+ } else {
+ dBm = Integer.MAX_VALUE;
+ }
+ if (DBG) log("getDbm=" + dBm);
+ return dBm;
+ }
+
+ /**
+ * Get the signal level as an asu value between 0..31, 99 is unknown
+ * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+ */
+ @Override
+ public int getAsuLevel() {
+ // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+ // asu = 0 (-113dB or less) is very weak
+ // signal, its better to show 0 bars to the user in such cases.
+ // asu = 99 is a special case, where the signal strength is unknown.
+ int level = mSignalStrength;
+ if (DBG) log("getAsuLevel=" + level);
+ return level;
+ }
+
+ @Override
+ public int hashCode() {
+ int primeNum = 31;
+ return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
+ }
+
+ @Override
+ public boolean equals (Object o) {
+ CellSignalStrengthWcdma s;
+
+ try {
+ s = (CellSignalStrengthWcdma) o;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ if (o == null) {
+ return false;
+ }
+
+ return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+ }
+
+ /**
+ * @return string representation.
+ */
+ @Override
+ public String toString() {
+ return "CellSignalStrengthWcdma:"
+ + " ss=" + mSignalStrength
+ + " ber=" + mBitErrorRate;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (DBG) log("writeToParcel(Parcel, int): " + toString());
+ dest.writeInt(mSignalStrength);
+ dest.writeInt(mBitErrorRate);
+ }
+
+ /**
+ * Construct a SignalStrength object from the given parcel
+ * where the token is already been processed.
+ */
+ private CellSignalStrengthWcdma(Parcel in) {
+ mSignalStrength = in.readInt();
+ mBitErrorRate = in.readInt();
+ if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString());
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<CellSignalStrengthWcdma> CREATOR =
+ new Parcelable.Creator<CellSignalStrengthWcdma>() {
+ @Override
+ public CellSignalStrengthWcdma createFromParcel(Parcel in) {
+ return new CellSignalStrengthWcdma(in);
+ }
+
+ @Override
+ public CellSignalStrengthWcdma[] newArray(int size) {
+ return new CellSignalStrengthWcdma[size];
+ }
+ };
+
+ /**
+ * log
+ */
+ private static void log(String s) {
+ Rlog.w(LOG_TAG, s);
+ }
+}
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index 1cb8c37..b55e290 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -15,8 +15,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.hwuicompare" >
- <!-- for perfhud -->
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:label="@string/app_name"
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
index e0ff1dc..1ed4723 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
@@ -16,11 +16,20 @@
package com.android.test.hwuicompare;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.TreeSet;
-import com.android.test.hwuicompare.R;
+import org.json.JSONException;
+import org.json.JSONObject;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Trace;
import android.util.Log;
import android.widget.ImageView;
@@ -31,20 +40,31 @@
private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
protected static final boolean DRAW_BITMAPS = false;
+ /**
+ * Threshold of error change required to consider a test regressed/improved
+ */
+ private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
+
+ private static final float[] ERROR_CUTOFFS = {
+ 0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
+ };
+
+ private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
+ private float mTotalTests = 0;
+ private float mTotalError = 0;
+ private int mTestsRegressed = 0;
+ private int mTestsImproved = 0;
+
private ImageView mSoftwareImageView = null;
private ImageView mHardwareImageView = null;
- private static final float[] ERROR_CUTOFFS = {0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f};
- private float[] mErrorRates = new float[ERROR_CUTOFFS.length];
- private float mTotalTests = 0;
- private float mTotalError = 0;
- public abstract static class TestCallback {
+ public abstract static class FinalCallback {
abstract void report(String name, float value);
- void complete() {}
+ void complete() {};
}
- private ArrayList<TestCallback> mTestCallbacks = new ArrayList<TestCallback>();
+ private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
Runnable mRunnable = new Runnable() {
@Override
@@ -64,32 +84,11 @@
float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
- if (error > ERROR_DISPLAY_THRESHOLD) {
- String modname = "";
- for (String s : DisplayModifier.getLastAppliedModifications()) {
- modname = modname.concat(s + ".");
- }
- Log.d(LOG_TAG, String.format("error for %s was %2.9f", modname, error));
- }
- for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
- if (error <= ERROR_CUTOFFS[i]) break;
- mErrorRates[i]++;
- }
- mTotalError += error;
- mTotalTests++;
+ final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
+ handleError(modifierNames, error);
if (DisplayModifier.step()) {
- for (TestCallback c : mTestCallbacks) {
- c.report("averageError", (mTotalError / mTotalTests));
- for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
- c.report(String.format("error over %1.3f", ERROR_CUTOFFS[i]),
- mErrorRates[i]/mTotalTests);
- }
- c.complete();
- }
-
- Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
- finish();
+ finishTest();
} else {
mHardwareView.invalidate();
if (DRAW_BITMAPS) {
@@ -116,11 +115,186 @@
mHardwareImageView = (ImageView) findViewById(R.id.hardware_image_view);
onCreateCommon(mRunnable);
- mTestCallbacks.add(new TestCallback() {
+ beginTest();
+ }
+
+ private static class TestResult {
+ TestResult(String label, float error) {
+ mLabel = label;
+ mTotalError = error;
+ mCount = 1;
+ }
+ public void addInto(float error) {
+ mTotalError += error;
+ mCount++;
+ }
+ public float getAverage() {
+ return mTotalError / mCount;
+ }
+ final String mLabel;
+ float mTotalError;
+ int mCount;
+ }
+
+ JSONObject mOutputJson = null;
+ JSONObject mInputJson = null;
+ final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
+ final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
+ private void beginTest() {
+ mFinalCallbacks.add(new FinalCallback() {
+ @Override
void report(String name, float value) {
Log.d(LOG_TAG, name + " " + value);
};
});
+
+ File inputFile = new File(Environment.getExternalStorageDirectory(),
+ "CanvasCompareInput.json");
+ if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
+ try {
+ FileInputStream inputStream = new FileInputStream(inputFile);
+ Log.d(LOG_TAG, "Parsing input file...");
+ StringBuffer content = new StringBuffer((int)inputFile.length());
+ byte[] buffer = new byte[1024];
+ while (inputStream.read(buffer) != -1) {
+ content.append(new String(buffer));
+ }
+ mInputJson = new JSONObject(content.toString());
+ inputStream.close();
+ Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "error parsing input json", e);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "error reading input json from sd", e);
+ }
+ }
+
+ mOutputJson = new JSONObject();
+ }
+
+ private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
+ Log.d(LOG_TAG, "---------------");
+ Log.d(LOG_TAG, label + ":");
+ Log.d(LOG_TAG, "---------------");
+ TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
+ @Override
+ public int compare(TestResult lhs, TestResult rhs) {
+ if (lhs == rhs) return 0; // don't need to worry about complex equality
+
+ int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
+ if (cmp != 0) {
+ return cmp;
+ }
+ return lhs.mLabel.compareTo(rhs.mLabel);
+ }
+ });
+
+ for (TestResult t : map.values()) {
+ set.add(t);
+ }
+
+ for (TestResult t : set.descendingSet()) {
+ if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
+ Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
+ }
+ }
+ Log.d(LOG_TAG, "");
+ }
+
+ private void finishTest() {
+ for (FinalCallback c : mFinalCallbacks) {
+ c.report("averageError", (mTotalError / mTotalTests));
+ for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
+ c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
+ mErrorRates[i]);
+ }
+ if (mInputJson != null) {
+ c.report("tests regressed", mTestsRegressed);
+ c.report("tests improved", mTestsImproved);
+ }
+ c.complete();
+ }
+
+ try {
+ if (mOutputJson != null) {
+ String outputString = mOutputJson.toString(4);
+ File outputFile = new File(Environment.getExternalStorageDirectory(),
+ "CanvasCompareOutput.json");
+ FileOutputStream outputStream = new FileOutputStream(outputFile);
+ outputStream.write(outputString.getBytes());
+ outputStream.close();
+ Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
+ }
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "error during JSON stringify", e);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "error storing JSON output on sd", e);
+ }
+
+ logTestResultHash("Modifier change vs previous", mModifierDiffResults);
+ logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
+ logTestResultHash("Modifier average test results", mModifierResults);
+ logTestResultHash("Individual test results", mIndividualResults);
+
+ Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ /**
+ * Inserts the error value into all TestResult objects, associated with each of its modifiers
+ */
+ private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
+ HashMap<String, TestResult> modifierResults) {
+ for (String modifierName : modifierNames) {
+ TestResult r = modifierResults.get(fullName);
+ if (r == null) {
+ modifierResults.put(modifierName, new TestResult(modifierName, error));
+ } else {
+ r.addInto(error);
+ }
+ }
+ }
+
+ private void handleError(final String[] modifierNames, final float error) {
+ String fullName = "";
+ for (String s : modifierNames) {
+ fullName = fullName.concat("." + s);
+ }
+ fullName = fullName.substring(1);
+
+ float deltaError = 0;
+ if (mInputJson != null) {
+ try {
+ deltaError = error - (float)mInputJson.getDouble(fullName);
+ } catch (JSONException e) {
+ Log.w(LOG_TAG, "Warning: unable to read from input json", e);
+ }
+ if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
+ if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
+ mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
+ addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
+ }
+
+ mIndividualResults.put(fullName, new TestResult(fullName, error));
+ addForAllModifiers(fullName, error, modifierNames, mModifierResults);
+
+ try {
+ if (mOutputJson != null) {
+ mOutputJson.put(fullName, error);
+ }
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "exception during JSON recording", e);
+ mOutputJson = null;
+ }
+
+ for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
+ if (error <= ERROR_CUTOFFS[i]) break;
+ mErrorRates[i]++;
+ }
+ mTotalError += error;
+ mTotalTests++;
}
@Override
@@ -130,7 +304,7 @@
}
// FOR TESTING
- public void setCallback(TestCallback c) {
- mTestCallbacks.add(c);
+ public void setFinalCallback(FinalCallback c) {
+ mFinalCallbacks.add(c);
}
}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
index 6ea8237..1ff153c 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
@@ -1,6 +1,6 @@
package com.android.test.hwuicompare;
-import com.android.test.hwuicompare.AutomaticActivity.TestCallback;
+import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
@@ -18,7 +18,7 @@
super.setUp();
mBundle = new Bundle();
mActivity = getActivity();
- mActivity.setCallback(new TestCallback() {
+ mActivity.setFinalCallback(new FinalCallback() {
@Override
void report(String key, float value) {