Merge "Sliding drawer for roots, move sorting, search."
diff --git a/Android.mk b/Android.mk
index f5b1cd9..9adf434 100644
--- a/Android.mk
+++ b/Android.mk
@@ -121,8 +121,8 @@
core/java/android/hardware/ICameraClient.aidl \
core/java/android/hardware/IProCameraUser.aidl \
core/java/android/hardware/IProCameraCallbacks.aidl \
- core/java/android/hardware/photography/ICameraDeviceUser.aidl \
- core/java/android/hardware/photography/ICameraDeviceCallbacks.aidl \
+ core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
+ core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/display/IDisplayManager.aidl \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
@@ -623,7 +623,7 @@
## SDK version identifiers used in the published docs
# major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=4.2
+framework_docs_SDK_VERSION:=4.3
# release version (ie "Release x") (full releases only)
framework_docs_SDK_REL_ID:=1
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c696aa1..73e8fa4 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -165,6 +165,8 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libandroidfw_intermediates/import_includes)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index 09c2385..f3aff2b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7446,6 +7446,7 @@
field public static final int KEYBOARD_NOKEYS = 1; // 0x1
field public static final int KEYBOARD_QWERTY = 2; // 0x2
field public static final int KEYBOARD_UNDEFINED = 0; // 0x0
+ field public static final int MNC_ZERO = 65535; // 0xffff
field public static final int NAVIGATIONHIDDEN_NO = 1; // 0x1
field public static final int NAVIGATIONHIDDEN_UNDEFINED = 0; // 0x0
field public static final int NAVIGATIONHIDDEN_YES = 2; // 0x2
@@ -9432,6 +9433,8 @@
method public void moveTo(float, float);
method public void offset(float, float, android.graphics.Path);
method public void offset(float, float);
+ method public boolean op(android.graphics.Path, android.graphics.Path.Op);
+ method public boolean op(android.graphics.Path, android.graphics.Path, android.graphics.Path.Op);
method public void quadTo(float, float, float, float);
method public void rCubicTo(float, float, float, float, float, float);
method public void rLineTo(float, float);
@@ -9463,6 +9466,16 @@
enum_constant public static final android.graphics.Path.FillType WINDING;
}
+ public static final class Path.Op extends java.lang.Enum {
+ method public static android.graphics.Path.Op valueOf(java.lang.String);
+ method public static final android.graphics.Path.Op[] values();
+ enum_constant public static final android.graphics.Path.Op DIFFERENCE;
+ enum_constant public static final android.graphics.Path.Op INTERSECT;
+ enum_constant public static final android.graphics.Path.Op REVERSE_DIFFERENCE;
+ enum_constant public static final android.graphics.Path.Op UNION;
+ enum_constant public static final android.graphics.Path.Op XOR;
+ }
+
public class PathDashPathEffect extends android.graphics.PathEffect {
ctor public PathDashPathEffect(android.graphics.Path, float, float, android.graphics.PathDashPathEffect.Style);
}
@@ -10064,6 +10077,7 @@
ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
method public void draw(android.graphics.Canvas);
+ method public android.graphics.drawable.Drawable getDrawable();
method public int getOpacity();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -10636,6 +10650,142 @@
}
+package android.hardware.camera2 {
+
+ public class CameraAccessException extends android.util.AndroidException {
+ ctor public CameraAccessException(int);
+ ctor public CameraAccessException(int, java.lang.String);
+ ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable);
+ ctor public CameraAccessException(int, java.lang.Throwable);
+ method public final int getReason();
+ field public static final int CAMERA_DISABLED = 3; // 0x3
+ field public static final int CAMERA_DISCONNECTED = 4; // 0x4
+ field public static final int CAMERA_IN_USE = 1; // 0x1
+ field public static final int MAX_CAMERAS_IN_USE = 2; // 0x2
+ }
+
+ public abstract interface CameraDevice implements java.lang.AutoCloseable {
+ method public abstract void capture(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void close() throws java.lang.Exception;
+ method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.camera2.CameraAccessException;
+ method public abstract android.hardware.camera2.CaptureRequest createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
+ method public abstract android.hardware.camera2.CameraProperties getProperties() throws android.hardware.camera2.CameraAccessException;
+ method public abstract void setErrorListener(android.hardware.camera2.CameraDevice.ErrorListener);
+ method public abstract void setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraDevice.CaptureListener) throws android.hardware.camera2.CameraAccessException;
+ method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
+ method public abstract void waitUntilIdle() throws android.hardware.camera2.CameraAccessException;
+ field public static final int TEMPLATE_MANUAL = 5; // 0x5
+ field public static final int TEMPLATE_PREVIEW = 1; // 0x1
+ field public static final int TEMPLATE_RECORD = 3; // 0x3
+ field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
+ field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
+ }
+
+ public static abstract interface CameraDevice.CaptureListener {
+ method public abstract void onCaptureComplete(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
+ method public abstract void onCaptureFailed(android.hardware.camera2.CameraDevice, android.hardware.camera2.CaptureRequest);
+ }
+
+ public static abstract interface CameraDevice.ErrorListener {
+ method public abstract void onCameraDeviceError(android.hardware.camera2.CameraDevice, int);
+ field public static final int DEVICE_DISCONNECTED = 1; // 0x1
+ field public static final int DEVICE_ERROR = 2; // 0x2
+ field public static final int SERVICE_ERROR = 3; // 0x3
+ }
+
+ public final class CameraManager {
+ method public android.hardware.camera2.CameraProperties getCameraProperties(java.lang.String) throws android.hardware.camera2.CameraAccessException;
+ method public java.lang.String[] getDeviceIdList() throws android.hardware.camera2.CameraAccessException;
+ method public android.hardware.camera2.CameraDevice openCamera(java.lang.String) throws android.hardware.camera2.CameraAccessException;
+ method public void registerCameraListener(android.hardware.camera2.CameraManager.CameraListener);
+ method public void unregisterCameraListener(android.hardware.camera2.CameraManager.CameraListener);
+ }
+
+ public static abstract interface CameraManager.CameraListener {
+ method public abstract void onCameraAvailable(java.lang.String);
+ method public abstract void onCameraUnavailable(java.lang.String);
+ }
+
+ public class CameraMetadata implements java.lang.AutoCloseable android.os.Parcelable {
+ ctor public CameraMetadata();
+ method public void close() throws java.lang.Exception;
+ method public int describeContents();
+ method public T get(android.hardware.camera2.CameraMetadata.Key<T>);
+ method public void readFromParcel(android.os.Parcel);
+ method public void set(android.hardware.camera2.CameraMetadata.Key<T>, T);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static class CameraMetadata.Key {
+ ctor public CameraMetadata.Key(java.lang.String, java.lang.Class<T>);
+ method public final boolean equals(java.lang.Object);
+ method public final java.lang.String getName();
+ method public final int hashCode();
+ }
+
+ public final class CameraProperties extends android.hardware.camera2.CameraMetadata {
+ ctor public CameraProperties();
+ field public static final android.hardware.camera2.CameraMetadata.Key INFO_IDENTIFIER;
+ field public static final android.hardware.camera2.CameraMetadata.Key INFO_MODEL;
+ field public static final android.hardware.camera2.CameraMetadata.Key INFO_REMOVABLE;
+ field public static final android.hardware.camera2.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL;
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_RAW_SIZES;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ACTIVE_ARRAY_SIZE;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PIXEL_ARRAY_SIZE;
+ }
+
+ public final class CaptureRequest extends android.hardware.camera2.CameraMetadata implements android.os.Parcelable {
+ method public void addTarget(android.view.Surface);
+ method public void removeTarget(android.view.Surface);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
+ }
+
+ public final class CaptureResult extends android.hardware.camera2.CameraMetadata {
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
+ field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
+ field public static final int CONTROL_AE_STATE_FLASH_REQUIRED = 4; // 0x4
+ field public static final int CONTROL_AE_STATE_INACTIVE = 0; // 0x0
+ field public static final int CONTROL_AE_STATE_LOCKED = 3; // 0x3
+ field public static final int CONTROL_AE_STATE_PRECAPTURE = 5; // 0x5
+ field public static final int CONTROL_AE_STATE_SEARCHING = 1; // 0x1
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_DETECTED_FACES;
+ }
+
+ public static class CaptureResult.Face {
+ ctor public CaptureResult.Face();
+ method public android.graphics.Rect getBounds();
+ method public int getId();
+ method public android.graphics.Point getLeftEye();
+ method public android.graphics.Point getMouth();
+ method public android.graphics.Point getRightEye();
+ method public int getScore();
+ }
+
+ public final class Rational {
+ ctor public Rational(int, int);
+ method public int getDenominator();
+ method public int getNumerator();
+ }
+
+ public final class Size {
+ ctor public Size(int, int);
+ method public final int getHeight();
+ method public final int getWidth();
+ }
+
+}
+
package android.hardware.display {
public final class DisplayManager {
@@ -10738,142 +10888,6 @@
}
-package android.hardware.photography {
-
- public class CameraAccessException extends android.util.AndroidException {
- ctor public CameraAccessException(int);
- ctor public CameraAccessException(int, java.lang.String);
- ctor public CameraAccessException(int, java.lang.String, java.lang.Throwable);
- ctor public CameraAccessException(int, java.lang.Throwable);
- method public final int getReason();
- field public static final int CAMERA_DISABLED = 3; // 0x3
- field public static final int CAMERA_DISCONNECTED = 4; // 0x4
- field public static final int CAMERA_IN_USE = 1; // 0x1
- field public static final int MAX_CAMERAS_IN_USE = 2; // 0x2
- }
-
- public abstract interface CameraDevice implements java.lang.AutoCloseable {
- method public abstract void capture(android.hardware.photography.CaptureRequest, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
- method public abstract void captureBurst(java.util.List<android.hardware.photography.CaptureRequest>, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
- method public abstract void close() throws java.lang.Exception;
- method public abstract void configureOutputs(java.util.List<android.view.Surface>) throws android.hardware.photography.CameraAccessException;
- method public abstract android.hardware.photography.CaptureRequest createCaptureRequest(int) throws android.hardware.photography.CameraAccessException;
- method public abstract android.hardware.photography.CameraProperties getProperties() throws android.hardware.photography.CameraAccessException;
- method public abstract void setErrorListener(android.hardware.photography.CameraDevice.ErrorListener);
- method public abstract void setRepeatingBurst(java.util.List<android.hardware.photography.CaptureRequest>, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
- method public abstract void setRepeatingRequest(android.hardware.photography.CaptureRequest, android.hardware.photography.CameraDevice.CaptureListener) throws android.hardware.photography.CameraAccessException;
- method public abstract void stopRepeating() throws android.hardware.photography.CameraAccessException;
- method public abstract void waitUntilIdle() throws android.hardware.photography.CameraAccessException;
- field public static final int TEMPLATE_MANUAL = 5; // 0x5
- field public static final int TEMPLATE_PREVIEW = 1; // 0x1
- field public static final int TEMPLATE_RECORD = 3; // 0x3
- field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
- field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
- }
-
- public static abstract interface CameraDevice.CaptureListener {
- method public abstract void onCaptureComplete(android.hardware.photography.CameraDevice, android.hardware.photography.CaptureRequest, android.hardware.photography.CaptureResult);
- method public abstract void onCaptureFailed(android.hardware.photography.CameraDevice, android.hardware.photography.CaptureRequest);
- }
-
- public static abstract interface CameraDevice.ErrorListener {
- method public abstract void onCameraDeviceError(android.hardware.photography.CameraDevice, int);
- field public static final int DEVICE_DISCONNECTED = 1; // 0x1
- field public static final int DEVICE_ERROR = 2; // 0x2
- field public static final int SERVICE_ERROR = 3; // 0x3
- }
-
- public final class CameraManager {
- method public android.hardware.photography.CameraProperties getCameraProperties(java.lang.String) throws android.hardware.photography.CameraAccessException;
- method public java.lang.String[] getDeviceIdList() throws android.hardware.photography.CameraAccessException;
- method public android.hardware.photography.CameraDevice openCamera(java.lang.String) throws android.hardware.photography.CameraAccessException;
- method public void registerCameraListener(android.hardware.photography.CameraManager.CameraListener);
- method public void unregisterCameraListener(android.hardware.photography.CameraManager.CameraListener);
- }
-
- public static abstract interface CameraManager.CameraListener {
- method public abstract void onCameraAvailable(java.lang.String);
- method public abstract void onCameraUnavailable(java.lang.String);
- }
-
- public class CameraMetadata implements java.lang.AutoCloseable android.os.Parcelable {
- ctor public CameraMetadata();
- method public void close() throws java.lang.Exception;
- method public int describeContents();
- method public T get(android.hardware.photography.CameraMetadata.Key<T>);
- method public void readFromParcel(android.os.Parcel);
- method public void set(android.hardware.photography.CameraMetadata.Key<T>, T);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static class CameraMetadata.Key {
- ctor public CameraMetadata.Key(java.lang.String, java.lang.Class<T>);
- method public final boolean equals(java.lang.Object);
- method public final java.lang.String getName();
- method public final int hashCode();
- }
-
- public final class CameraProperties extends android.hardware.photography.CameraMetadata {
- ctor public CameraProperties();
- field public static final android.hardware.photography.CameraMetadata.Key INFO_IDENTIFIER;
- field public static final android.hardware.photography.CameraMetadata.Key INFO_MODEL;
- field public static final android.hardware.photography.CameraMetadata.Key INFO_REMOVABLE;
- field public static final android.hardware.photography.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL;
- field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
- field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
- field public static final android.hardware.photography.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
- field public static final android.hardware.photography.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
- field public static final android.hardware.photography.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
- field public static final android.hardware.photography.CameraMetadata.Key SCALER_AVAILABLE_RAW_SIZES;
- field public static final android.hardware.photography.CameraMetadata.Key SENSOR_ACTIVE_ARRAY_SIZE;
- field public static final android.hardware.photography.CameraMetadata.Key SENSOR_PIXEL_ARRAY_SIZE;
- }
-
- public final class CaptureRequest extends android.hardware.photography.CameraMetadata implements android.os.Parcelable {
- method public void addTarget(android.view.Surface);
- method public void removeTarget(android.view.Surface);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final android.hardware.photography.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
- field public static final android.hardware.photography.CameraMetadata.Key SENSOR_SENSITIVITY;
- }
-
- public final class CaptureResult extends android.hardware.photography.CameraMetadata {
- field public static final android.hardware.photography.CameraMetadata.Key CONTROL_AE_STATE;
- field public static final int CONTROL_AE_STATE_CONVERGED = 2; // 0x2
- field public static final int CONTROL_AE_STATE_FLASH_REQUIRED = 4; // 0x4
- field public static final int CONTROL_AE_STATE_INACTIVE = 0; // 0x0
- field public static final int CONTROL_AE_STATE_LOCKED = 3; // 0x3
- field public static final int CONTROL_AE_STATE_PRECAPTURE = 5; // 0x5
- field public static final int CONTROL_AE_STATE_SEARCHING = 1; // 0x1
- field public static final android.hardware.photography.CameraMetadata.Key SENSOR_TIMESTAMP;
- field public static final android.hardware.photography.CameraMetadata.Key STATISTICS_DETECTED_FACES;
- }
-
- public static class CaptureResult.Face {
- ctor public CaptureResult.Face();
- method public android.graphics.Rect getBounds();
- method public int getId();
- method public android.graphics.Point getLeftEye();
- method public android.graphics.Point getMouth();
- method public android.graphics.Point getRightEye();
- method public int getScore();
- }
-
- public final class Rational {
- ctor public Rational(int, int);
- method public int getDenominator();
- method public int getNumerator();
- }
-
- public final class Size {
- ctor public Size(int, int);
- method public final int getHeight();
- method public final int getWidth();
- }
-
-}
-
package android.hardware.usb {
public class UsbAccessory implements android.os.Parcelable {
@@ -18528,7 +18542,6 @@
method public void clear();
method public int describeContents();
method public int getColorMode();
- method public int getCopies();
method public int getDuplexMode();
method public int getFittingMode();
method public android.print.PrintAttributes.Tray getInputTray();
@@ -18554,7 +18567,6 @@
ctor public PrintAttributes.Builder();
method public android.print.PrintAttributes create();
method public android.print.PrintAttributes.Builder setColorMode(int);
- method public android.print.PrintAttributes.Builder setCopyCount(int);
method public android.print.PrintAttributes.Builder setDuplexMode(int);
method public android.print.PrintAttributes.Builder setFittingMode(int);
method public android.print.PrintAttributes.Builder setInputTray(android.print.PrintAttributes.Tray);
@@ -18640,18 +18652,20 @@
method public void onFinish();
method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle);
method public void onStart();
- method public abstract void onWrite(java.util.List<android.print.PageRange>, java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
+ method public abstract void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback);
field public static final java.lang.String METADATA_KEY_PRINT_PREVIEW = "KEY_METADATA_PRINT_PREVIEW";
}
public static abstract class PrintDocumentAdapter.LayoutResultCallback {
+ method public void onLayoutCancelled();
method public void onLayoutFailed(java.lang.CharSequence);
method public void onLayoutFinished(android.print.PrintDocumentInfo, boolean);
}
public static abstract class PrintDocumentAdapter.WriteResultCallback {
+ method public void onWriteCancelled();
method public void onWriteFailed(java.lang.CharSequence);
- method public void onWriteFinished(java.util.List<android.print.PageRange>);
+ method public void onWriteFinished(android.print.PageRange[]);
}
public final class PrintDocumentInfo implements android.os.Parcelable {
@@ -18682,6 +18696,7 @@
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
method public android.print.PrintAttributes getAttributes();
+ method public int getCopies();
method public int getId();
method public java.lang.CharSequence getLabel();
method public android.print.PageRange[] getPages();
@@ -18726,6 +18741,7 @@
method public java.util.List<android.print.PrintAttributes.Tray> getOutputTrays();
method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions();
method public int getStatus();
+ method public boolean hasAllRequiredAttributes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int STATUS_READY = 1; // 0x1
@@ -18811,9 +18827,11 @@
method protected void onDisconnected();
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected void onRequestCancelPrintJob(android.printservice.PrintJob);
+ method protected void onRequestUpdatePrinters(java.util.List<android.print.PrinterId>);
method protected abstract void onStartPrinterDiscovery();
method protected abstract void onStopPrinterDiscovery();
method public final void removeDiscoveredPrinters(java.util.List<android.print.PrinterId>);
+ method public final void updateDiscoveredPrinters(java.util.List<android.print.PrinterInfo>);
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
}
@@ -21765,8 +21783,11 @@
public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic {
method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element);
+ method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript);
method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation);
method public android.renderscript.Script.KernelID getKernelID();
+ method public void setAdd(android.renderscript.Float4);
+ method public void setAdd(float, float, float, float);
method public void setColorMatrix(android.renderscript.Matrix4f);
method public void setColorMatrix(android.renderscript.Matrix3f);
method public void setGreyscale();
@@ -29537,6 +29558,7 @@
method public android.webkit.WebBackForwardList copyBackForwardList();
method public void destroy();
method public void documentHasImages(android.os.Message);
+ method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
method public static java.lang.String findAddress(java.lang.String);
method public deprecated int findAll(java.lang.String);
method public void findAllAsync(java.lang.String);
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index d9c3775..b73fbff 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -257,6 +257,16 @@
private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
PendingIntent operation) {
+ if (triggerAtMillis < 0) {
+ /* NOTYET
+ if (mAlwaysExact) {
+ // Fatal error for KLP+ apps to use negative trigger times
+ throw new IllegalArgumentException("Invalid alarm trigger time "
+ + triggerAtMillis);
+ }
+ */
+ triggerAtMillis = 0;
+ }
try {
mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation);
} catch (RemoteException ex) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eeee57d..ab11903 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -50,7 +50,7 @@
import android.hardware.ISerialManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
-import android.hardware.photography.CameraManager;
+import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 613450b..809f900 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -161,10 +161,13 @@
if (mAutoInitialize
&& extras != null
&& extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
- if (ContentResolver.getIsSyncable(account, authority) < 0) {
- ContentResolver.setIsSyncable(account, authority, 1);
+ try {
+ if (ContentResolver.getIsSyncable(account, authority) < 0) {
+ ContentResolver.setIsSyncable(account, authority, 1);
+ }
+ } finally {
+ syncContextClient.onFinished(new SyncResult());
}
- syncContextClient.onFinished(new SyncResult());
return;
}
SyncThread syncThread = new SyncThread(
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aa326ad..0b1127c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2292,7 +2292,7 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.hardware.photography.CameraManager} for interacting with
+ * {@link android.hardware.camera2.CameraManager} for interacting with
* camera devices.
*
* @see #getSystemService
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 68db33a..6318e38 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -54,10 +54,17 @@
/**
* IMSI MNC (Mobile Network Code), corresponding to
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
- * resource qualifier. 0 if undefined.
+ * resource qualifier. 0 if undefined. Note that the actual MNC may be 0; in order to check
+ * for this use the {@link #MNC_ZERO} symbol.
*/
public int mnc;
-
+
+ /**
+ * Constant used to to represent MNC (Mobile Network Code) zero.
+ * 0 cannot be used, since it is used to represent an undefined MNC.
+ */
+ public static final int MNC_ZERO = 0xffff;
+
/**
* Current user preference for the locale, corresponding to
* <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 842a482..220b40d 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -97,7 +97,9 @@
}
/*
- * Handle introductory packet.
+ * Handle introductory packet. This is called during JNI_CreateJavaVM
+ * before frameworks native methods are registered, so be careful not
+ * to call any APIs that depend on frameworks native code.
*/
private Chunk handleHELO(Chunk request) {
if (false)
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 2d0c099..81e564e 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -20,8 +20,8 @@
import android.hardware.ICameraClient;
import android.hardware.IProCameraUser;
import android.hardware.IProCameraCallbacks;
-import android.hardware.photography.ICameraDeviceUser;
-import android.hardware.photography.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.ICameraServiceListener;
import android.hardware.CameraInfo;
diff --git a/core/java/android/hardware/photography/CameraAccessException.java b/core/java/android/hardware/camera2/CameraAccessException.java
similarity index 98%
rename from core/java/android/hardware/photography/CameraAccessException.java
rename to core/java/android/hardware/camera2/CameraAccessException.java
index fac5086..0089f26 100644
--- a/core/java/android/hardware/photography/CameraAccessException.java
+++ b/core/java/android/hardware/camera2/CameraAccessException.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.util.AndroidException;
diff --git a/core/java/android/hardware/photography/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
similarity index 99%
rename from core/java/android/hardware/photography/CameraDevice.java
rename to core/java/android/hardware/camera2/CameraDevice.java
index 0852025..422d827 100644
--- a/core/java/android/hardware/photography/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.view.Surface;
diff --git a/core/java/android/hardware/photography/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
similarity index 96%
rename from core/java/android/hardware/photography/CameraManager.java
rename to core/java/android/hardware/camera2/CameraManager.java
index c1c9435..1370654 100644
--- a/core/java/android/hardware/photography/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.content.Context;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraUser;
-import android.hardware.photography.utils.CameraBinderDecorator;
-import android.hardware.photography.utils.CameraRuntimeException;
-import android.os.Binder;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -42,7 +41,7 @@
* <pre>CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);</pre>
*
* <p>For more details about communicating with camera devices, read the Camera
- * developer guide or the {@link android.hardware.photography photography}
+ * developer guide or the {@link android.hardware.camera2 camera2}
* package documentation.</p>
*/
public final class CameraManager {
@@ -190,8 +189,8 @@
ICameraDeviceUser cameraUser;
- android.hardware.photography.impl.CameraDevice device =
- new android.hardware.photography.impl.CameraDevice(cameraId);
+ android.hardware.camera2.impl.CameraDevice device =
+ new android.hardware.camera2.impl.CameraDevice(cameraId);
cameraUser = mCameraService.connectDevice(device.getCallbacks(),
Integer.parseInt(cameraId),
@@ -279,7 +278,7 @@
// TODO: this class needs unit tests
// TODO: extract class into top level
- private class CameraServiceListener extends Binder implements ICameraServiceListener {
+ private class CameraServiceListener extends ICameraServiceListener.Stub {
// Keep up-to-date with ICameraServiceListener.h
diff --git a/core/java/android/hardware/photography/CameraMetadata.aidl b/core/java/android/hardware/camera2/CameraMetadata.aidl
similarity index 94%
rename from core/java/android/hardware/photography/CameraMetadata.aidl
rename to core/java/android/hardware/camera2/CameraMetadata.aidl
index b4dc9ac..71dd471 100644
--- a/core/java/android/hardware/photography/CameraMetadata.aidl
+++ b/core/java/android/hardware/camera2/CameraMetadata.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
/** @hide */
parcelable CameraMetadata;
diff --git a/core/java/android/hardware/photography/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
similarity index 98%
rename from core/java/android/hardware/photography/CameraMetadata.java
rename to core/java/android/hardware/camera2/CameraMetadata.java
index c024c05..e7f34d8 100644
--- a/core/java/android/hardware/photography/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
-import android.hardware.photography.impl.MetadataMarshalClass;
-import android.hardware.photography.impl.MetadataMarshalRect;
-import android.hardware.photography.impl.MetadataMarshalSize;
-import android.hardware.photography.impl.MetadataMarshalString;
+import android.hardware.camera2.impl.MetadataMarshalClass;
+import android.hardware.camera2.impl.MetadataMarshalRect;
+import android.hardware.camera2.impl.MetadataMarshalSize;
+import android.hardware.camera2.impl.MetadataMarshalString;
import android.os.Parcelable;
import android.os.Parcel;
import android.util.Log;
diff --git a/core/java/android/hardware/photography/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
similarity index 99%
rename from core/java/android/hardware/photography/CameraProperties.java
rename to core/java/android/hardware/camera2/CameraProperties.java
index 2ed4e3a..89e1f2a 100644
--- a/core/java/android/hardware/photography/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.graphics.Rect;
diff --git a/core/java/android/hardware/photography/CameraPropertiesKeys.java b/core/java/android/hardware/camera2/CameraPropertiesKeys.java
similarity index 88%
rename from core/java/android/hardware/photography/CameraPropertiesKeys.java
rename to core/java/android/hardware/camera2/CameraPropertiesKeys.java
index db8ab44..41b31ff 100644
--- a/core/java/android/hardware/photography/CameraPropertiesKeys.java
+++ b/core/java/android/hardware/camera2/CameraPropertiesKeys.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
-import static android.hardware.photography.CameraMetadata.Key;
+import static android.hardware.camera2.CameraMetadata.Key;
/**
* ! Do not edit this file directly !
@@ -71,8 +71,8 @@
}
public static final class Jpeg {
- public static final Key<android.hardware.photography.Size[]> AVAILABLE_THUMBNAIL_SIZES =
- new Key<android.hardware.photography.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.photography.Size[].class);
+ public static final Key<android.hardware.camera2.Size[]> AVAILABLE_THUMBNAIL_SIZES =
+ new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
}
@@ -90,8 +90,8 @@
new Key<Float>("android.lens.info.hyperfocalDistance", float.class);
public static final Key<Float> MINIMUM_FOCUS_DISTANCE =
new Key<Float>("android.lens.info.minimumFocusDistance", float.class);
- public static final Key<android.hardware.photography.Size> SHADING_MAP_SIZE =
- new Key<android.hardware.photography.Size>("android.lens.info.shadingMapSize", android.hardware.photography.Size.class);
+ public static final Key<android.hardware.camera2.Size> SHADING_MAP_SIZE =
+ new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
}
public static final class FacingKey extends Key<Lens.FacingKey.Enum> {
@@ -161,14 +161,14 @@
new AvailableFormatsKey("android.scaler.availableFormats");
public static final Key<long[]> AVAILABLE_JPEG_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
- public static final Key<android.hardware.photography.Size[]> AVAILABLE_JPEG_SIZES =
- new Key<android.hardware.photography.Size[]>("android.scaler.availableJpegSizes", android.hardware.photography.Size[].class);
+ public static final Key<android.hardware.camera2.Size[]> AVAILABLE_JPEG_SIZES =
+ new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
public static final Key<Float> AVAILABLE_MAX_DIGITAL_ZOOM =
new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
public static final Key<long[]> AVAILABLE_PROCESSED_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
- public static final Key<android.hardware.photography.Size[]> AVAILABLE_PROCESSED_SIZES =
- new Key<android.hardware.photography.Size[]>("android.scaler.availableProcessedSizes", android.hardware.photography.Size[].class);
+ public static final Key<android.hardware.camera2.Size[]> AVAILABLE_PROCESSED_SIZES =
+ new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
}
@@ -182,8 +182,8 @@
new Key<long[]>("android.sensor.info.exposureTimeRange", long[].class);
public static final Key<Long> MAX_FRAME_DURATION =
new Key<Long>("android.sensor.info.maxFrameDuration", long.class);
- public static final Key<android.hardware.photography.Size> PHYSICAL_SIZE =
- new Key<android.hardware.photography.Size>("android.sensor.info.physicalSize", android.hardware.photography.Size.class);
+ public static final Key<android.hardware.camera2.Size> PHYSICAL_SIZE =
+ new Key<android.hardware.camera2.Size>("android.sensor.info.physicalSize", android.hardware.camera2.Size.class);
}
public static final Key<Rational> BASE_GAIN_FACTOR =
new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
diff --git a/core/java/android/hardware/photography/CaptureRequest.aidl b/core/java/android/hardware/camera2/CaptureRequest.aidl
similarity index 94%
rename from core/java/android/hardware/photography/CaptureRequest.aidl
rename to core/java/android/hardware/camera2/CaptureRequest.aidl
index 64fb6f2..0b7d5ba 100644
--- a/core/java/android/hardware/photography/CaptureRequest.aidl
+++ b/core/java/android/hardware/camera2/CaptureRequest.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
/** @hide */
parcelable CaptureRequest;
diff --git a/core/java/android/hardware/photography/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
similarity index 98%
rename from core/java/android/hardware/photography/CaptureRequest.java
rename to core/java/android/hardware/camera2/CaptureRequest.java
index d4a7a3c..15ba12c 100644
--- a/core/java/android/hardware/photography/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/hardware/photography/CaptureRequestKeys.java b/core/java/android/hardware/camera2/CaptureRequestKeys.java
similarity index 98%
rename from core/java/android/hardware/photography/CaptureRequestKeys.java
rename to core/java/android/hardware/camera2/CaptureRequestKeys.java
index ca6d487..17de8f0 100644
--- a/core/java/android/hardware/photography/CaptureRequestKeys.java
+++ b/core/java/android/hardware/camera2/CaptureRequestKeys.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
-import static android.hardware.photography.CameraMetadata.Key;
+import static android.hardware.camera2.CameraMetadata.Key;
/**
* ! Do not edit this file directly !
@@ -449,8 +449,8 @@
new Key<Byte>("android.jpeg.quality", byte.class);
public static final Key<Byte> THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
- public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE =
- new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class);
+ public static final Key<android.hardware.camera2.Size> THUMBNAIL_SIZE =
+ new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
}
diff --git a/core/java/android/hardware/photography/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
similarity index 99%
rename from core/java/android/hardware/photography/CaptureResult.java
rename to core/java/android/hardware/camera2/CaptureResult.java
index 2fdd466..11c991a 100644
--- a/core/java/android/hardware/photography/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.graphics.Point;
import android.graphics.Rect;
diff --git a/core/java/android/hardware/photography/CaptureResultKeys.java b/core/java/android/hardware/camera2/CaptureResultKeys.java
similarity index 98%
rename from core/java/android/hardware/photography/CaptureResultKeys.java
rename to core/java/android/hardware/camera2/CaptureResultKeys.java
index 4931564..dd3ed83 100644
--- a/core/java/android/hardware/photography/CaptureResultKeys.java
+++ b/core/java/android/hardware/camera2/CaptureResultKeys.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
-import static android.hardware.photography.CameraMetadata.Key;
+import static android.hardware.camera2.CameraMetadata.Key;
/**
* ! Do not edit this file directly !
@@ -310,8 +310,8 @@
new Key<Byte>("android.jpeg.quality", byte.class);
public static final Key<Byte> THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
- public static final Key<android.hardware.photography.Size> THUMBNAIL_SIZE =
- new Key<android.hardware.photography.Size>("android.jpeg.thumbnailSize", android.hardware.photography.Size.class);
+ public static final Key<android.hardware.camera2.Size> THUMBNAIL_SIZE =
+ new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
}
diff --git a/core/java/android/hardware/photography/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
similarity index 68%
rename from core/java/android/hardware/photography/ICameraDeviceCallbacks.aidl
rename to core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index c506800..4172238 100644
--- a/core/java/android/hardware/photography/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
-import android.hardware.photography.CameraMetadata;
+import android.hardware.camera2.CameraMetadata;
/** @hide */
interface ICameraDeviceCallbacks
{
/**
- * Keep up-to-date with frameworks/av/include/camera/photography/ICameraDeviceCallbacks.h
+ * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
*/
- void notifyCallback(int msgType, int ext1, int ext2);
- void onResultReceived(int frameId, in CameraMetadata result);
+ oneway void notifyCallback(int msgType, int ext1, int ext2);
+ oneway void onResultReceived(int frameId, in CameraMetadata result);
}
diff --git a/core/java/android/hardware/photography/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
similarity index 84%
rename from core/java/android/hardware/photography/ICameraDeviceUser.aidl
rename to core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 571f50a..5a9b72f 100644
--- a/core/java/android/hardware/photography/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
import android.view.Surface;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.CaptureRequest;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
/** @hide */
interface ICameraDeviceUser
{
/**
- * Keep up-to-date with frameworks/av/include/camera/photography/ICameraDeviceUser.h
+ * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h
*/
void disconnect();
diff --git a/core/java/android/hardware/photography/Rational.java b/core/java/android/hardware/camera2/Rational.java
similarity index 98%
rename from core/java/android/hardware/photography/Rational.java
rename to core/java/android/hardware/camera2/Rational.java
index 66e533e..7ccc555 100644
--- a/core/java/android/hardware/photography/Rational.java
+++ b/core/java/android/hardware/camera2/Rational.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
/**
* The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
diff --git a/core/java/android/hardware/photography/Size.java b/core/java/android/hardware/camera2/Size.java
similarity index 97%
rename from core/java/android/hardware/photography/Size.java
rename to core/java/android/hardware/camera2/Size.java
index 499fd56..45aaeae 100644
--- a/core/java/android/hardware/photography/Size.java
+++ b/core/java/android/hardware/camera2/Size.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography;
+package android.hardware.camera2;
/**
* A simple immutable class for describing the dimensions of camera image
diff --git a/core/java/android/hardware/photography/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
similarity index 90%
rename from core/java/android/hardware/photography/impl/CameraDevice.java
rename to core/java/android/hardware/camera2/impl/CameraDevice.java
index 5cb7525..fa79051 100644
--- a/core/java/android/hardware/photography/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-package android.hardware.photography.impl;
+package android.hardware.camera2.impl;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.CaptureResult;
-import android.hardware.photography.ICameraDeviceUser;
-import android.hardware.photography.ICameraDeviceCallbacks;
-import android.hardware.photography.CameraAccessException;
-import android.hardware.photography.CameraProperties;
-import android.hardware.photography.CaptureRequest;
-import android.hardware.photography.utils.CameraRuntimeException;
-import android.os.Binder;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraProperties;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -37,9 +36,10 @@
/**
* HAL2.1+ implementation of CameraDevice Use CameraManager#open to instantiate
*/
-public class CameraDevice implements android.hardware.photography.CameraDevice {
+public class CameraDevice implements android.hardware.camera2.CameraDevice {
private final String TAG;
+ private final boolean DEBUG;
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
private ICameraDeviceUser mRemoteDevice;
@@ -59,6 +59,7 @@
public CameraDevice(String cameraId) {
mCameraId = cameraId;
TAG = String.format("CameraDevice-%s-JV", mCameraId);
+ DEBUG = Log.isLoggable(TAG, Log.DEBUG);
}
public CameraDeviceCallbacks getCallbacks() {
@@ -288,7 +289,7 @@
}
// TODO: unit tests
- public class CameraDeviceCallbacks extends Binder implements ICameraDeviceCallbacks {
+ public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
@Override
public IBinder asBinder() {
@@ -298,14 +299,17 @@
// TODO: consider rename to onMessageReceived
@Override
public void notifyCallback(int msgType, int ext1, int ext2) throws RemoteException {
- Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
+ if (DEBUG) {
+ Log.d(TAG, "Got message " + msgType + " ext1: " + ext1 + " , ext2: " + ext2);
+ }
// TODO implement rest
}
@Override
- public void onResultReceived(int frameId, CameraMetadata result) throws RemoteException {
- Log.d(TAG, "Received result for frameId " + frameId);
-
+ public void onResultReceived(int requestId, CameraMetadata result) throws RemoteException {
+ if (DEBUG) {
+ Log.d(TAG, "Received result for id " + requestId);
+ }
CaptureListenerHolder holder;
synchronized (mLock) {
@@ -313,7 +317,7 @@
// exposing the methods necessary like subscribeToRequest, unsubscribe..
// TODO: make class static class
- holder = CameraDevice.this.mCaptureListenerMap.get(frameId);
+ holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
// Clean up listener once we no longer expect to see it.
@@ -321,7 +325,7 @@
// we probably want cancelRequest to return # of times it already enqueued and
// keep a counter.
if (holder != null && !holder.isRepeating()) {
- CameraDevice.this.mCaptureListenerMap.remove(frameId);
+ CameraDevice.this.mCaptureListenerMap.remove(requestId);
}
}
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
similarity index 85%
rename from core/java/android/hardware/photography/impl/MetadataMarshalClass.java
rename to core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
index a70784d..a934d75 100644
--- a/core/java/android/hardware/photography/impl/MetadataMarshalClass.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography.impl;
+package android.hardware.camera2.impl;
import java.nio.ByteBuffer;
@@ -26,7 +26,7 @@
* @param value the value of type T that we wish to write into the byte buffer
* @param buffer the byte buffer into which the marshalled object will be written
* @param nativeType the native type, e.g.
- * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
* @return the size that needs to be written to the byte buffer
@@ -37,7 +37,7 @@
* Unmarshal a new object instance from the byte buffer.
* @param buffer the byte buffer, from which we will read the object
* @param nativeType the native type, e.g.
- * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
+ * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}.
* Guaranteed to be one for which isNativeTypeSupported returns true.
* @return a new instance of type T read from the byte buffer
*/
@@ -50,7 +50,7 @@
* will are likely to only support one type.
*
* @param nativeType the native type, e.g.
- * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
* @return true if it supports, false otherwise
*/
boolean isNativeTypeSupported(int nativeType);
@@ -60,7 +60,7 @@
/**
* How many bytes T will take up if marshalled to/from nativeType
* @param nativeType the native type, e.g.
- * {@link android.hardware.photography.CameraMetadata#TYPE_BYTE TYPE_BYTE}
+ * {@link android.hardware.camera2.CameraMetadata#TYPE_BYTE TYPE_BYTE}
* @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
*/
int getNativeSize(int nativeType);
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
similarity index 94%
rename from core/java/android/hardware/photography/impl/MetadataMarshalRect.java
rename to core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
index d6636ac..384223c 100644
--- a/core/java/android/hardware/photography/impl/MetadataMarshalRect.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.photography.impl;
+package android.hardware.camera2.impl;
import android.graphics.Rect;
-import android.hardware.photography.CameraMetadata;
+import android.hardware.camera2.CameraMetadata;
import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
similarity index 91%
rename from core/java/android/hardware/photography/impl/MetadataMarshalSize.java
rename to core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
index 430219c..793bba7 100644
--- a/core/java/android/hardware/photography/impl/MetadataMarshalSize.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.photography.impl;
+package android.hardware.camera2.impl;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.Size;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Size;
import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/photography/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
similarity index 95%
rename from core/java/android/hardware/photography/impl/MetadataMarshalString.java
rename to core/java/android/hardware/camera2/impl/MetadataMarshalString.java
index 81123ee..50b3347 100644
--- a/core/java/android/hardware/photography/impl/MetadataMarshalString.java
+++ b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.photography.impl;
+package android.hardware.camera2.impl;
-import android.hardware.photography.CameraMetadata;
+import android.hardware.camera2.CameraMetadata;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
diff --git a/core/java/android/hardware/photography/impl/package.html b/core/java/android/hardware/camera2/impl/package.html
similarity index 100%
rename from core/java/android/hardware/photography/impl/package.html
rename to core/java/android/hardware/camera2/impl/package.html
diff --git a/core/java/android/hardware/photography/package.html b/core/java/android/hardware/camera2/package.html
similarity index 83%
rename from core/java/android/hardware/photography/package.html
rename to core/java/android/hardware/camera2/package.html
index 578bdf5..e9d9cea 100644
--- a/core/java/android/hardware/photography/package.html
+++ b/core/java/android/hardware/camera2/package.html
@@ -14,7 +14,7 @@
-->
<HTML>
<BODY>
-<p>The android.hardware.photography package provides an interface to
+<p>The android.hardware.camera2 package provides an interface to
individual camera devices connected to an Android device. It replaces
the deprecated {@link android.hardware.Camera} class.</p>
@@ -28,18 +28,18 @@
framerate on most Android devices.</p>
<p>To enumerate, query, and open available camera devices, obtain a
-{@link android.hardware.photography.CameraManager} instance.</p>
+{@link android.hardware.camera2.CameraManager} instance.</p>
-<p>Individual {@link android.hardware.photography.CameraDevice
+<p>Individual {@link android.hardware.camera2.CameraDevice
CameraDevices} provide a set of static property information that
describes the hardware device and the available settings and output
parameters for the device. This information is provided through the
-{@link android.hardware.photography.CameraProperties} object.</p>
+{@link android.hardware.camera2.CameraProperties} object.</p>
<p>To capture or stream images from a camera device, the application
must first configure a set of output Surfaces for use with the camera
device, with {@link
-android.hardware.photography.CameraDevice#configureOutputs}. Each
+android.hardware.camera2.CameraDevice#configureOutputs}. Each
Surface has to be pre-configured with an appropriate size and format
(if applicable) to match the sizes and formats available from the
camera device. A target Surface can be obtained from a variety of
@@ -50,19 +50,19 @@
</p>
<p>The application then needs to construct a {@link
-android.hardware.photography.CaptureRequest}, which defines all the
+android.hardware.camera2.CaptureRequest}, which defines all the
capture parameters needed by a camera device to capture a single
image. The request also lists which of the configured output Surfaces
should be used as targets for this capture. The CameraDevice has a
-{@link android.hardware.photography.CameraDevice#createCaptureRequest
+{@link android.hardware.camera2.CameraDevice#createCaptureRequest
convenience factory method} for creating a request for a given use
case which is optimized for the Android device the application is
running on.</p>
<p>Once the request has been set up, it can be handed to the
CameraDevice either for a one-shot {@link
-android.hardware.photography.CameraDevice#capture} or for an endlessly
-{@link android.hardware.photography.CameraDevice#setRepeatingRequest
+android.hardware.camera2.CameraDevice#capture} or for an endlessly
+{@link android.hardware.camera2.CameraDevice#setRepeatingRequest
repeating} use. Both methods also accept a list of requests to use as
a burst capture / repeating burst. Repeating requests have a lower
priority than captures, so a request submitted
@@ -71,7 +71,7 @@
capture completes.</p>
<p>After processing a request, the camera device will produce a {@link
-android.hardware.photography.CaptureResult} object, which contains
+android.hardware.camera2.CaptureResult} object, which contains
information about the state of the camera device at time of capture,
and the final settings used. These may vary somewhat from the request,
if rounding or resolving contradictory parameters was necessary. The
diff --git a/core/java/android/hardware/photography/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
similarity index 93%
rename from core/java/android/hardware/photography/utils/CameraBinderDecorator.java
rename to core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 1a44b97f..586c759 100644
--- a/core/java/android/hardware/photography/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.hardware.photography.utils;
+package android.hardware.camera2.utils;
-import static android.hardware.photography.CameraAccessException.CAMERA_DISABLED;
-import static android.hardware.photography.CameraAccessException.CAMERA_DISCONNECTED;
-import static android.hardware.photography.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import android.os.DeadObjectException;
import android.os.RemoteException;
@@ -28,7 +28,7 @@
/**
* Translate camera service status_t return values into exceptions.
*
- * @see android.hardware.photography.utils.CameraBinderDecorator#newInstance
+ * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
* @hide
*/
public class CameraBinderDecorator {
diff --git a/core/java/android/hardware/photography/utils/CameraRuntimeException.java b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
similarity index 93%
rename from core/java/android/hardware/photography/utils/CameraRuntimeException.java
rename to core/java/android/hardware/camera2/utils/CameraRuntimeException.java
index 25dfc62..9ed88a9 100644
--- a/core/java/android/hardware/photography/utils/CameraRuntimeException.java
+++ b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
@@ -1,6 +1,6 @@
-package android.hardware.photography.utils;
+package android.hardware.camera2.utils;
-import android.hardware.photography.CameraAccessException;
+import android.hardware.camera2.CameraAccessException;
/**
* @hide
diff --git a/core/java/android/hardware/photography/utils/Decorator.java b/core/java/android/hardware/camera2/utils/Decorator.java
similarity index 96%
rename from core/java/android/hardware/photography/utils/Decorator.java
rename to core/java/android/hardware/camera2/utils/Decorator.java
index ed05dd2..5826497 100644
--- a/core/java/android/hardware/photography/utils/Decorator.java
+++ b/core/java/android/hardware/camera2/utils/Decorator.java
@@ -1,12 +1,12 @@
-package android.hardware.photography.utils;
+package android.hardware.camera2.utils;
import java.lang.reflect.*;
/**
* This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
*
- * @see android.hardware.photography.utils.Decorator#newInstance
+ * @see android.hardware.camera2.utils.Decorator#newInstance
*
* @hide
*/
diff --git a/core/java/android/hardware/photography/utils/UncheckedThrow.java b/core/java/android/hardware/camera2/utils/UncheckedThrow.java
similarity index 96%
rename from core/java/android/hardware/photography/utils/UncheckedThrow.java
rename to core/java/android/hardware/camera2/utils/UncheckedThrow.java
index 8eed6b1..8224fed 100644
--- a/core/java/android/hardware/photography/utils/UncheckedThrow.java
+++ b/core/java/android/hardware/camera2/utils/UncheckedThrow.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.photography.utils;
+package android.hardware.camera2.utils;
/**
* @hide
diff --git a/core/java/android/hardware/photography/utils/package.html b/core/java/android/hardware/camera2/utils/package.html
similarity index 100%
rename from core/java/android/hardware/photography/utils/package.html
rename to core/java/android/hardware/camera2/utils/package.html
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8bbe6c8..1dbe34e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -355,11 +355,17 @@
*/
public static final int TYPE_WIFI_P2P = 13;
- /** {@hide} */
- public static final int MAX_RADIO_TYPE = TYPE_WIFI_P2P;
+ /**
+ * The network to use for initially attaching to the network
+ * {@hide}
+ */
+ public static final int TYPE_MOBILE_IA = 14;
/** {@hide} */
- public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P;
+ public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA;
+
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA;
/**
* If you want to set the default network preference,you can directly
@@ -436,6 +442,8 @@
return "MOBILE_CBS";
case TYPE_WIFI_P2P:
return "WIFI_P2P";
+ case TYPE_MOBILE_IA:
+ return "MOBILE_IA";
default:
return Integer.toString(type);
}
@@ -458,6 +466,7 @@
case TYPE_MOBILE_FOTA:
case TYPE_MOBILE_IMS:
case TYPE_MOBILE_CBS:
+ case TYPE_MOBILE_IA:
return true;
default:
return false;
@@ -489,6 +498,7 @@
case TYPE_MOBILE_MMS:
case TYPE_MOBILE_SUPL:
case TYPE_MOBILE_HIPRI:
+ case TYPE_MOBILE_IA:
return true;
default:
return false;
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 5a1daed..54273ee 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -51,7 +51,7 @@
public class MobileDataStateTracker implements NetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
private static final boolean VDBG = false;
private PhoneConstants.DataState mMobileDataState;
@@ -597,6 +597,8 @@
return PhoneConstants.APN_TYPE_IMS;
case ConnectivityManager.TYPE_MOBILE_CBS:
return PhoneConstants.APN_TYPE_CBS;
+ case ConnectivityManager.TYPE_MOBILE_IA:
+ return PhoneConstants.APN_TYPE_IA;
default:
sloge("Error mapping networkType " + netType + " to apnType.");
return null;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 1d482dc..ab0543d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -27,6 +27,8 @@
import java.io.OutputStreamWriter;
import java.util.ArrayList;
+import libcore.io.Libcore;
+
/*package*/ class ZygoteStartFailedEx extends Exception {
/**
* Something prevented the zygote process startup from happening normally
@@ -647,19 +649,25 @@
* Returns the identifier of this process, which can be used with
* {@link #killProcess} and {@link #sendSignal}.
*/
- public static final native int myPid();
+ public static final int myPid() {
+ return Libcore.os.getpid();
+ }
/**
* Returns the identifier of this process' parent.
* @hide
*/
- public static native int myPpid();
+ public static final int myPpid() {
+ return Libcore.os.getppid();
+ }
/**
* Returns the identifier of the calling thread, which be used with
* {@link #setThreadPriority(int, int)}.
*/
- public static final native int myTid();
+ public static final int myTid() {
+ return Libcore.os.gettid();
+ }
/**
* Returns the identifier of this process's uid. This is the kernel uid
@@ -667,7 +675,9 @@
* app-specific sandbox. It is different from {@link #myUserHandle} in that
* a uid identifies a specific app sandbox in a specific user.
*/
- public static final native int myUid();
+ public static final int myUid() {
+ return Libcore.os.getuid();
+ }
/**
* Returns this process's user handle. This is the
diff --git a/core/java/android/print/FileDocumentAdapter.java b/core/java/android/print/FileDocumentAdapter.java
index c7011f4..d642a61 100644
--- a/core/java/android/print/FileDocumentAdapter.java
+++ b/core/java/android/print/FileDocumentAdapter.java
@@ -34,8 +34,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
/**
* Adapter for printing files.
@@ -69,7 +67,7 @@
}
@Override
- public void onWrite(List<PageRange> pages, FileDescriptor destination,
+ public void onWrite(PageRange[] pages, FileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback) {
mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
@@ -127,9 +125,7 @@
@Override
protected void onPostExecute(Void result) {
- List<PageRange> pages = new ArrayList<PageRange>();
- pages.add(PageRange.ALL_PAGES);
- mResultCallback.onWriteFinished(pages);
+ mResultCallback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
}
@Override
diff --git a/core/java/android/print/ILayoutResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl
index e4d79f3..43b8c30 100644
--- a/core/java/android/print/ILayoutResultCallback.aidl
+++ b/core/java/android/print/ILayoutResultCallback.aidl
@@ -16,7 +16,6 @@
package android.print;
-import android.os.ICancellationSignal;
import android.print.PrintDocumentInfo;
/**
@@ -25,7 +24,6 @@
* @hide
*/
oneway interface ILayoutResultCallback {
- void onLayoutStarted(ICancellationSignal cancellationSignal);
- void onLayoutFinished(in PrintDocumentInfo info, boolean changed);
- void onLayoutFailed(CharSequence error);
+ void onLayoutFinished(in PrintDocumentInfo info, boolean changed, int sequence);
+ void onLayoutFailed(CharSequence error, int sequence);
}
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
index 04da157..b12c922 100644
--- a/core/java/android/print/IPrintDocumentAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -31,8 +31,8 @@
oneway interface IPrintDocumentAdapter {
void start();
void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes,
- ILayoutResultCallback callback, in Bundle metadata);
- void write(in List<PageRange> pages, in ParcelFileDescriptor fd,
- IWriteResultCallback callback);
+ ILayoutResultCallback callback, in Bundle metadata, int sequence);
+ void write(in PageRange[] pages, in ParcelFileDescriptor fd,
+ IWriteResultCallback callback, int sequence);
void finish();
}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index a466e74..37ae2ca 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -33,5 +33,4 @@
in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
int appId, int userId);
void cancelPrintJob(int printJobId, int appId, int userId);
-
}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 7912964..51b5439 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -28,9 +28,9 @@
*/
oneway interface IPrintSpoolerCallbacks {
void onGetPrintJobInfosResult(in List<PrintJobInfo> printJob, int sequence);
- void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
void onCreatePrintJobResult(in PrintJobInfo printJob, int sequence);
void onCancelPrintJobResult(boolean canceled, int sequence);
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
+ void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
}
diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl
index 47975e1..46857e4 100644
--- a/core/java/android/print/IPrintSpoolerClient.aidl
+++ b/core/java/android/print/IPrintSpoolerClient.aidl
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.print.IPrinterDiscoveryObserver;
+import android.print.PrinterId;
import android.print.PrintJobInfo;
@@ -30,6 +31,7 @@
void onPrintJobQueued(in PrintJobInfo printJob);
void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer);
void onStopPrinterDiscovery();
+ void onRequestUpdatePrinters(in List<PrinterId> printerIds);
void onAllPrintJobsForServiceHandled(in ComponentName printService);
void onAllPrintJobsHandled();
}
diff --git a/core/java/android/print/IPrintSpoolerObserver.aidl b/core/java/android/print/IPrintSpoolerObserver.aidl
deleted file mode 100644
index 7b8f40e..0000000
--- a/core/java/android/print/IPrintSpoolerObserver.aidl
+++ /dev/null
@@ -1,31 +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.print;
-
-import android.print.PrinterId;
-import android.print.PrinterInfo;
-
-/**
- * Interface for observing the state of the print spooler.
- *
- * @hide
- */
-oneway interface IPrinterDiscoveryObserver {
- void onPrintJobQueued(in PrinterId printerId, in PrintJobInfo printJob);
- void onAllPrintJobsHandled(in ComponentName printService);
- void onAllPrintJobsHandled();
-}
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
index 39aeb8c..deabbcb 100644
--- a/core/java/android/print/IPrinterDiscoveryObserver.aidl
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -25,6 +25,7 @@
* @hide
*/
oneway interface IPrinterDiscoveryObserver {
- void addDiscoveredPrinters(in List<PrinterInfo> printers);
- void removeDiscoveredPrinters(in List<PrinterId> printers);
+ void onPrintersAdded(in List<PrinterInfo> printers);
+ void onPrintersRemoved(in List<PrinterId> printers);
+ void onPrintersUpdated(in List<PrinterInfo> printers);
}
diff --git a/core/java/android/print/IWriteResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl
index d5428b1..8281c4e 100644
--- a/core/java/android/print/IWriteResultCallback.aidl
+++ b/core/java/android/print/IWriteResultCallback.aidl
@@ -16,7 +16,6 @@
package android.print;
-import android.os.ICancellationSignal;
import android.print.PageRange;
/**
@@ -25,7 +24,6 @@
* @hide
*/
oneway interface IWriteResultCallback {
- void onWriteStarted(ICancellationSignal cancellationSignal);
- void onWriteFinished(in List<PageRange> pages);
- void onWriteFailed(CharSequence error);
+ void onWriteFinished(in PageRange[] pages, int sequence);
+ void onWriteFailed(CharSequence error, int sequence);
}
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 9257a04..ba455f6 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -93,8 +93,38 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mEnd;
+ result = prime * result + mStart;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PageRange other = (PageRange) obj;
+ if (mEnd != other.mEnd) {
+ return false;
+ }
+ if (mStart != other.mStart) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
- if (this == ALL_PAGES) {
+ if (mStart == 0 && mEnd == Integer.MAX_VALUE) {
return "PageRange[<all pages>]";
}
StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 87d75c0..911e380 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -77,7 +77,6 @@
private int mColorMode;
private int mFittingMode;
private int mOrientation;
- private int mCopies;
PrintAttributes() {
/* hide constructor */
@@ -93,7 +92,6 @@
mColorMode = parcel.readInt();
mFittingMode = parcel.readInt();
mOrientation = parcel.readInt();
- mCopies = parcel.readInt();
}
/**
@@ -302,29 +300,6 @@
mOrientation = orientation;
}
- /**
- * Gets the number of copies.
- *
- * @return The number of copies or zero if not set.
- */
- public int getCopies() {
- return mCopies;
- }
-
- /**
- * Sets the number of copies.
- *
- * @param copyCount The number of copies.
- *
- * @hide
- */
- public void setCopies(int copyCount) {
- if (copyCount < 1) {
- throw new IllegalArgumentException("Copies must be more than one.");
- }
- mCopies = copyCount;
- }
-
@Override
public void writeToParcel(Parcel parcel, int flags) {
if (mMediaSize != null) {
@@ -361,7 +336,6 @@
parcel.writeInt(mColorMode);
parcel.writeInt(mFittingMode);
parcel.writeInt(mOrientation);
- parcel.writeInt(mCopies);
}
@Override
@@ -369,6 +343,101 @@
return 0;
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mColorMode;
+ result = prime * result + mDuplexMode;
+ result = prime * result + mFittingMode;
+ result = prime * result + mOrientation;
+ result = prime * result + ((mInputTray == null) ? 0 : mInputTray.hashCode());
+ result = prime * result + ((mMargins == null) ? 0 : mMargins.hashCode());
+ result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
+ result = prime * result + ((mOutputTray == null) ? 0 : mOutputTray.hashCode());
+ result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrintAttributes other = (PrintAttributes) obj;
+ if (mColorMode != other.mColorMode) {
+ return false;
+ }
+ if (mDuplexMode != other.mDuplexMode) {
+ return false;
+ }
+ if (mFittingMode != other.mFittingMode) {
+ return false;
+ }
+ if (mOrientation != other.mOrientation) {
+ return false;
+ }
+ if (mInputTray == null) {
+ if (other.mInputTray != null) {
+ return false;
+ }
+ } else if (!mInputTray.equals(other.mInputTray)) {
+ return false;
+ }
+ if (mOutputTray == null) {
+ if (other.mOutputTray != null) {
+ return false;
+ }
+ } else if (!mOutputTray.equals(other.mOutputTray)) {
+ return false;
+ }
+ if (mMargins == null) {
+ if (other.mMargins != null) {
+ return false;
+ }
+ } else if (!mMargins.equals(other.mMargins)) {
+ return false;
+ }
+ if (mMediaSize == null) {
+ if (other.mMediaSize != null) {
+ return false;
+ }
+ } else if (!mMediaSize.equals(other.mMediaSize)) {
+ return false;
+ }
+ if (mResolution == null) {
+ if (other.mResolution != null) {
+ return false;
+ }
+ } else if (!mResolution.equals(other.mResolution)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PrintAttributes{");
+ builder.append("mediaSize: ").append(mMediaSize);
+ builder.append(", resolution: ").append(mResolution);
+ builder.append(", margins: ").append(mMargins);
+ builder.append(", inputTray: ").append(mInputTray);
+ builder.append(", outputTray: ").append(mOutputTray);
+ builder.append(", colorMode: ").append(colorModeToString(mColorMode));
+ builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
+ builder.append(", fittingMode: ").append(fittingModeToString(mFittingMode));
+ builder.append(", orientation: ").append(orientationToString(mOrientation));
+ builder.append("}");
+ return builder.toString();
+ }
+
/** hide */
public void clear() {
mMediaSize = null;
@@ -380,7 +449,6 @@
mColorMode = 0;
mFittingMode = 0;
mOrientation = 0;
- mCopies = 0;
}
/**
@@ -396,7 +464,6 @@
mColorMode = other.mColorMode;
mFittingMode = other.mFittingMode;
mOrientation = other.mOrientation;
- mCopies = other.mCopies;
}
/**
@@ -954,6 +1021,44 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mId == null) ? 0 : mId.hashCode());
+ result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
+ result = prime * result + mWidthMils;
+ result = prime * result + mHeightMils;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ MediaSize other = (MediaSize) obj;
+ if (!TextUtils.equals(mId, other.mId)) {
+ return false;
+ }
+ if (!TextUtils.equals(mLabel, other.mLabel)) {
+ return false;
+ }
+ if (mWidthMils != other.mWidthMils) {
+ return false;
+ }
+ if (mHeightMils != other.mHeightMils) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MediaSize{");
@@ -1061,6 +1166,44 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mId == null) ? 0 : mId.hashCode());
+ result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
+ result = prime * result + mHorizontalDpi;
+ result = prime * result + mVerticalDpi;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Resolution other = (Resolution) obj;
+ if (!TextUtils.equals(mId, other.mId)) {
+ return false;
+ }
+ if (!TextUtils.equals(mLabel, other.mLabel)) {
+ return false;
+ }
+ if (mHorizontalDpi != other.mHorizontalDpi) {
+ return false;
+ }
+ if (mVerticalDpi != other.mVerticalDpi) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Resolution{");
@@ -1166,6 +1309,44 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mBottomMils;
+ result = prime * result + mLeftMils;
+ result = prime * result + mRightMils;
+ result = prime * result + mTopMils;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Margins other = (Margins) obj;
+ if (mBottomMils != other.mBottomMils) {
+ return false;
+ }
+ if (mLeftMils != other.mLeftMils) {
+ return false;
+ }
+ if (mRightMils != other.mRightMils) {
+ return false;
+ }
+ if (mTopMils != other.mTopMils) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Margins{");
@@ -1235,6 +1416,36 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mId == null) ? 0 : mId.hashCode());
+ result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Tray other = (Tray) obj;
+ if (!TextUtils.equals(mId, other.mId)) {
+ return false;
+ }
+ if (!TextUtils.equals(mLabel, other.mLabel)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Tray{");
@@ -1246,21 +1457,6 @@
}
}
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("PrintAttributes{");
- builder.append("mediaSize: ").append(mMediaSize);
- builder.append(", resolution: ").append(mResolution);
- builder.append(", margins: ").append(mMargins);
- builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
- builder.append(", colorMode: ").append(colorModeToString(mColorMode));
- builder.append(", fittingMode: ").append(fittingModeToString(mFittingMode));
- builder.append(", orientation: ").append(orientationToString(mOrientation));
- builder.append(", copies: ").append(mCopies);
- return builder.toString();
- }
-
private static String duplexModeToString(int duplexMode) {
switch (duplexMode) {
case DUPLEX_MODE_NONE: {
@@ -1412,7 +1608,7 @@
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
*/
public Builder setDuplexMode(int duplexMode) {
- if (Integer.bitCount(duplexMode) != 1) {
+ if (Integer.bitCount(duplexMode) > 1) {
throw new IllegalArgumentException("can specify at most one duplexMode bit.");
}
mAttributes.setDuplexMode(duplexMode);
@@ -1471,17 +1667,6 @@
}
/**
- * Sets the number of copies.
- *
- * @param copyCount A greater or equal to zero copy count.
- * @return This builder.
- */
- public Builder setCopyCount(int copyCount) {
- mAttributes.setCopies(copyCount);
- return this;
- }
-
- /**
* Creates a new {@link PrintAttributes} instance.
*
* @return The new instance.
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 1f83a45..d320226 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -41,7 +41,7 @@
* <li>
* After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
* CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
- * {@link #onWrite(List, FileDescriptor, CancellationSignal, WriteResultCallback)}
+ * {@link #onWrite(PageRange[], FileDescriptor, CancellationSignal, WriteResultCallback)}
* asking you to write a PDF file with the content for specific pages.
* </li>
* <li>
@@ -64,7 +64,7 @@
* PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on
* the UI thread (assuming onStart initializes resources needed for layout).
* This will ensure that the UI does not change while you are laying out the
- * printed content. Then you can handle {@link #onWrite(List, FileDescriptor,
+ * printed content. Then you can handle {@link #onWrite(PageRange[], FileDescriptor,
* CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
* thread. This will ensure that the UI is frozen for the minimal amount of
* time. Also this assumes that you will generate the printed content in
@@ -141,7 +141,7 @@
* made on the main thread.
* </p>
*
- * @param pages The pages whose content to print.
+ * @param pages The pages whose content to print - non-overlapping in ascending order.
* @param destination The destination file descriptor to which to write.
* @param cancellationSignal Signal for observing cancel writing requests.
* @param callback Callback to inform the system for the write result.
@@ -149,7 +149,7 @@
* @see WriteResultCallback
* @see CancellationSignal
*/
- public abstract void onWrite(List<PageRange> pages, FileDescriptor destination,
+ public abstract void onWrite(PageRange[] pages, FileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback);
/**
@@ -163,7 +163,7 @@
/**
* Base class for implementing a callback for the result of {@link
- * PrintDocumentAdapter#onWrite(List, FileDescriptor, CancellationSignal,
+ * PrintDocumentAdapter#onWrite(PageRange[], FileDescriptor, CancellationSignal,
* WriteResultCallback)}.
*/
public static abstract class WriteResultCallback {
@@ -178,9 +178,9 @@
/**
* Notifies that all the data was written.
*
- * @param pages The pages that were written.
+ * @param pages The pages that were written. Cannot be null or empty.
*/
- public void onWriteFinished(List<PageRange> pages) {
+ public void onWriteFinished(PageRange[] pages) {
/* do nothing - stub */
}
@@ -192,6 +192,13 @@
public void onWriteFailed(CharSequence error) {
/* do nothing - stub */
}
+
+ /**
+ * Notifies that write was cancelled as a result of a cancellation request.
+ */
+ public void onWriteCancelled() {
+ /* do nothing - stub */
+ }
}
/**
@@ -211,7 +218,7 @@
/**
* Notifies that the layout finished and whether the content changed.
*
- * @param info An info object describing the document.
+ * @param info An info object describing the document. Cannot be null.
* @param changed Whether the layout changed.
*
* @see PrintDocumentInfo
@@ -228,5 +235,12 @@
public void onLayoutFailed(CharSequence error) {
/* do nothing - stub */
}
+
+ /**
+ * Notifies that layout was cancelled as a result of a cancellation request.
+ */
+ public void onLayoutCancelled() {
+ /* do nothing - stub */
+ }
}
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 7d42b3a..29e8e7c 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -111,6 +111,36 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mContentType;
+ result = prime * result + mPageCount;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrintDocumentInfo other = (PrintDocumentInfo) obj;
+ if (mContentType != other.mContentType) {
+ return false;
+ }
+ if (mPageCount != other.mPageCount) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrintDocumentInfo{");
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index a5e0b79..de28bd3 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -55,6 +55,9 @@
* @return The print job info.
*/
public PrintJobInfo getInfo() {
+ if (isInImmutableState()) {
+ return mCachedInfo;
+ }
PrintJobInfo info = mPrintManager.getPrintJobInfo(mId);
if (info != null) {
mCachedInfo = info;
@@ -66,7 +69,15 @@
* Cancels this print job.
*/
public void cancel() {
- mPrintManager.cancelPrintJob(mId);
+ if (!isInImmutableState()) {
+ mPrintManager.cancelPrintJob(mId);
+ }
+ }
+
+ private boolean isInImmutableState() {
+ final int state = mCachedInfo.getState();
+ return state == PrintJobInfo.STATE_COMPLETED
+ || state == PrintJobInfo.STATE_CANCELED;
}
@Override
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 97384d9..39546f3 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+
/**
* This class represents the description of a print job.
*/
@@ -119,6 +121,9 @@
/** Optional tag assigned by a print service.*/
private String mTag;
+ /** How many copies to print. */
+ private int mCopies;
+
/** The pages to print */
private PageRange[] mPageRanges;
@@ -142,6 +147,8 @@
mAppId = other.mAppId;
mUserId = other.mUserId;
mTag = other.mTag;
+ mCopies = other.mCopies;
+ mPageRanges = other.mPageRanges;
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
}
@@ -154,8 +161,13 @@
mAppId = parcel.readInt();
mUserId = parcel.readInt();
mTag = parcel.readString();
+ mCopies = parcel.readInt();
if (parcel.readInt() == 1) {
- mPageRanges = (PageRange[]) parcel.readParcelableArray(null);
+ Parcelable[] parcelables = parcel.readParcelableArray(null);
+ mPageRanges = new PageRange[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ mPageRanges[i] = (PageRange) parcelables[i];
+ }
}
if (parcel.readInt() == 1) {
mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel);
@@ -310,6 +322,29 @@
}
/**
+ * Gets the number of copies.
+ *
+ * @return The number of copies or zero if not set.
+ */
+ public int getCopies() {
+ return mCopies;
+ }
+
+ /**
+ * Sets the number of copies.
+ *
+ * @param copyCount The number of copies.
+ *
+ * @hide
+ */
+ public void setCopies(int copyCount) {
+ if (copyCount < 1) {
+ throw new IllegalArgumentException("Copies must be more than one.");
+ }
+ mCopies = copyCount;
+ }
+
+ /**
* Gets the included pages.
*
* @return The included pages or <code>null</code> if not set.
@@ -385,6 +420,7 @@
parcel.writeInt(mAppId);
parcel.writeInt(mUserId);
parcel.writeString(mTag);
+ parcel.writeInt(mCopies);
if (mPageRanges != null) {
parcel.writeInt(1);
parcel.writeParcelableArray(mPageRanges, flags);
@@ -413,10 +449,14 @@
builder.append(", id: ").append(mId);
builder.append(", status: ").append(stateToString(mState));
builder.append(", printer: " + mPrinterId);
+ builder.append(", tag: ").append(mTag);
+ builder.append(", copies: ").append(mCopies);
builder.append(", attributes: " + (mAttributes != null
? mAttributes.toString() : null));
builder.append(", documentInfo: " + (mDocumentInfo != null
? mDocumentInfo.toString() : null));
+ builder.append(", pages: " + (mPageRanges != null
+ ? Arrays.toString(mPageRanges) : null));
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index f9f53f6..9e8cfad 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -22,7 +22,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
-import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -223,6 +222,11 @@
}
private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
+
+ private final Object mLock = new Object();
+
+ private CancellationSignal mLayoutOrWriteCancellation;
+
private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish()
private Handler mHandler; // Strong reference OK - cleared in finish()
@@ -239,22 +243,36 @@
@Override
public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
- ILayoutResultCallback callback, Bundle metadata) {
+ ILayoutResultCallback callback, Bundle metadata, int sequence) {
+ synchronized (mLock) {
+ if (mLayoutOrWriteCancellation != null) {
+ mLayoutOrWriteCancellation.cancel();
+ }
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = oldAttributes;
args.arg2 = newAttributes;
args.arg3 = callback;
args.arg4 = metadata;
+ args.argi1 = sequence;
+ mHandler.removeMessages(MyHandler.MSG_LAYOUT);
mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget();
}
@Override
- public void write(List<PageRange> pages, ParcelFileDescriptor fd,
- IWriteResultCallback callback) {
+ public void write(PageRange[] pages, ParcelFileDescriptor fd,
+ IWriteResultCallback callback, int sequence) {
+ synchronized (mLock) {
+ if (mLayoutOrWriteCancellation != null) {
+ mLayoutOrWriteCancellation.cancel();
+ }
+ }
SomeArgs args = SomeArgs.obtain();
args.arg1 = pages;
args.arg2 = fd.getFileDescriptor();
args.arg3 = callback;
+ args.argi1 = sequence;
+ mHandler.removeMessages(MyHandler.MSG_WRITE);
mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget();
}
@@ -283,7 +301,6 @@
}
@Override
- @SuppressWarnings("unchecked")
public void handleMessage(Message message) {
if (isFinished()) {
return;
@@ -295,42 +312,116 @@
case MSG_LAYOUT: {
SomeArgs args = (SomeArgs) message.obj;
- PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
- PrintAttributes newAttributes = (PrintAttributes) args.arg2;
- ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
- Bundle metadata = (Bundle) args.arg4;
+ final PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
+ final PrintAttributes newAttributes = (PrintAttributes) args.arg2;
+ final ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
+ final Bundle metadata = (Bundle) args.arg4;
+ final int sequence = args.argi1;
args.recycle();
- try {
- ICancellationSignal remoteSignal = CancellationSignal.createTransport();
- callback.onLayoutStarted(remoteSignal);
-
- mDocumentAdapter.onLayout(oldAttributes, newAttributes,
- CancellationSignal.fromTransport(remoteSignal),
- new LayoutResultCallbackWrapper(callback), metadata);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error printing", re);
+ CancellationSignal cancellation = new CancellationSignal();
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = cancellation;
}
+
+ mDocumentAdapter.onLayout(oldAttributes, newAttributes,
+ cancellation, new LayoutResultCallback() {
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ if (info == null) {
+ throw new IllegalArgumentException("info cannot be null");
+ }
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ try {
+ callback.onLayoutFinished(info, changed, sequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error) {
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ try {
+ callback.onLayoutFailed(error, sequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+ }
+ }
+
+ @Override
+ public void onLayoutCancelled() {
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ }
+ }, metadata);
} break;
case MSG_WRITE: {
SomeArgs args = (SomeArgs) message.obj;
- List<PageRange> pages = (List<PageRange>) args.arg1;
- FileDescriptor fd = (FileDescriptor) args.arg2;
- IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
+ final PageRange[] pages = (PageRange[]) args.arg1;
+ final FileDescriptor fd = (FileDescriptor) args.arg2;
+ final IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
+ final int sequence = args.argi1;
args.recycle();
- try {
- ICancellationSignal remoteSignal = CancellationSignal.createTransport();
- callback.onWriteStarted(remoteSignal);
-
- mDocumentAdapter.onWrite(pages, fd,
- CancellationSignal.fromTransport(remoteSignal),
- new WriteResultCallbackWrapper(callback, fd));
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error printing", re);
- IoUtils.closeQuietly(fd);
+ CancellationSignal cancellation = new CancellationSignal();
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = cancellation;
}
+
+ mDocumentAdapter.onWrite(pages, fd, cancellation,
+ new WriteResultCallback() {
+ @Override
+ public void onWriteFinished(PageRange[] pages) {
+ if (pages == null) {
+ throw new IllegalArgumentException("pages cannot be null");
+ }
+ if (pages.length == 0) {
+ throw new IllegalArgumentException("pages cannot be empty");
+ }
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ // Close before notifying the other end. We want
+ // to be ready by the time we announce it.
+ IoUtils.closeQuietly(fd);
+ try {
+ callback.onWriteFinished(pages, sequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFinished", re);
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ // Close before notifying the other end. We want
+ // to be ready by the time we announce it.
+ IoUtils.closeQuietly(fd);
+ try {
+ callback.onWriteFailed(error, sequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFailed", re);
+ }
+ }
+
+ @Override
+ public void onWriteCancelled() {
+ synchronized (mLock) {
+ mLayoutOrWriteCancellation = null;
+ }
+ // Just close the fd for now.
+ IoUtils.closeQuietly(fd);
+ }
+ });
} break;
case MSG_FINISH: {
@@ -346,67 +437,4 @@
}
}
}
-
- private static final class WriteResultCallbackWrapper extends WriteResultCallback {
-
- private final IWriteResultCallback mWrappedCallback;
- private final FileDescriptor mFd;
-
- public WriteResultCallbackWrapper(IWriteResultCallback callback,
- FileDescriptor fd) {
- mWrappedCallback = callback;
- mFd = fd;
- }
-
- @Override
- public void onWriteFinished(List<PageRange> pages) {
- try {
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(mFd);
- mWrappedCallback.onWriteFinished(pages);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFinished", re);
- }
- }
-
- @Override
- public void onWriteFailed(CharSequence error) {
- try {
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(mFd);
- mWrappedCallback.onWriteFailed(error);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFailed", re);
- }
- }
- }
-
- private static final class LayoutResultCallbackWrapper extends LayoutResultCallback {
-
- private final ILayoutResultCallback mWrappedCallback;
-
- public LayoutResultCallbackWrapper(ILayoutResultCallback callback) {
- mWrappedCallback = callback;
- }
-
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- try {
- mWrappedCallback.onLayoutFinished(info, changed);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error) {
- try {
- mWrappedCallback.onLayoutFailed(error);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
- }
- }
- }
}
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index e884026..e27fbb2 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
/**
* This class represents the unique id of a printer.
@@ -98,7 +99,7 @@
} else if (!mServiceComponentName.equals(other.mServiceComponentName)) {
return false;
}
- if (mLocalId != other.mLocalId) {
+ if (!TextUtils.equals(mLocalId, other.mLocalId)) {
return false;
}
return true;
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index da3b6bc..15bcb73 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -23,9 +23,9 @@
import android.print.PrintAttributes.Resolution;
import android.print.PrintAttributes.Tray;
import android.text.TextUtils;
-import android.util.SparseIntArray;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -41,8 +41,6 @@
*/
public static final int DEFAULT_UNDEFINED = -1;
- private static final int MIN_COPIES = 1;
-
private static final int PROPERTY_MEDIA_SIZE = 0;
private static final int PROPERTY_RESOLUTION = 1;
private static final int PROPERTY_INPUT_TRAY = 2;
@@ -51,19 +49,22 @@
private static final int PROPERTY_COLOR_MODE = 5;
private static final int PROPERTY_FITTING_MODE = 6;
private static final int PROPERTY_ORIENTATION = 7;
+ private static final int PROPERTY_COUNT = 8;
/** Printer status: the printer is ready to print. */
public static final int STATUS_READY = 1;
+ private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
+
// TODO: Add printer status constants.
private PrinterId mId;
private CharSequence mLabel;
private int mStatus;
- private Margins mMinMargins;
- private final List<MediaSize> mMediaSizes = new ArrayList<MediaSize>(); // required
- private final List<Resolution> mResolutions = new ArrayList<Resolution>(); // required
+ private Margins mMinMargins = DEFAULT_MARGINS;
+ private List<MediaSize> mMediaSizes;
+ private List<Resolution> mResolutions;
private List<Tray> mInputTrays;
private List<Tray> mOutputTrays;
@@ -72,43 +73,83 @@
private int mFittingModes;
private int mOrientations;
- private final SparseIntArray mDefaults = new SparseIntArray();
- private Margins mDefaultMargins;
+ private final int[] mDefaults = new int[PROPERTY_COUNT];
+ private Margins mDefaultMargins = DEFAULT_MARGINS;
- private PrinterInfo() {
- mDefaults.put(PROPERTY_MEDIA_SIZE, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_RESOLUTION, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_INPUT_TRAY, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_OUTPUT_TRAY, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_DUPLEX_MODE, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_COLOR_MODE, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_FITTING_MODE, DEFAULT_UNDEFINED);
- mDefaults.put(PROPERTY_ORIENTATION, DEFAULT_UNDEFINED);
+ /**
+ * @hide
+ */
+ public PrinterInfo() {
+ Arrays.fill(mDefaults, DEFAULT_UNDEFINED);
}
private PrinterInfo(PrinterInfo prototype) {
- mId = prototype.mId;
- mLabel = prototype.mLabel;
- mStatus = prototype.mStatus;
+ copyFrom(prototype);
+ }
- mMinMargins = prototype.mMinMargins;
- mMediaSizes.addAll(prototype.mMediaSizes);
- mResolutions.addAll(prototype.mResolutions);
- mInputTrays = (prototype.mInputTrays != null)
- ? new ArrayList<Tray>(prototype.mInputTrays) : null;
- mOutputTrays = (prototype.mOutputTrays != null)
- ? new ArrayList<Tray>(prototype.mOutputTrays) : null;
+ /**
+ * @hide
+ */
+ public void copyFrom(PrinterInfo other) {
+ mId = other.mId;
+ mLabel = other.mLabel;
+ mStatus = other.mStatus;
- mDuplexModes = prototype.mDuplexModes;
- mColorModes = prototype.mColorModes;
- mFittingModes = prototype.mFittingModes;
- mOrientations = prototype.mOrientations;
-
- final int defaultCount = prototype.mDefaults.size();
- for (int i = 0; i < defaultCount; i++) {
- mDefaults.put(prototype.mDefaults.keyAt(i), prototype.mDefaults.valueAt(i));
+ mMinMargins = other.mMinMargins;
+ if (other.mMediaSizes != null) {
+ if (mMediaSizes != null) {
+ mMediaSizes.clear();
+ mMediaSizes.addAll(other.mMediaSizes);
+ } else {
+ mMediaSizes = new ArrayList<MediaSize>(other.mMediaSizes);
+ }
+ } else {
+ mMediaSizes = null;
}
- mDefaultMargins = prototype.mDefaultMargins;
+
+ if (other.mResolutions != null) {
+ if (mResolutions != null) {
+ mResolutions.clear();
+ mResolutions.addAll(other.mResolutions);
+ } else {
+ mResolutions = new ArrayList<Resolution>(other.mResolutions);
+ }
+ } else {
+ mResolutions = null;
+ }
+
+ if (other.mInputTrays != null) {
+ if (mInputTrays != null) {
+ mInputTrays.clear();
+ mInputTrays.addAll(other.mInputTrays);
+ } else {
+ mInputTrays = new ArrayList<Tray>(other.mInputTrays);
+ }
+ } else {
+ mInputTrays = null;
+ }
+
+ if (other.mOutputTrays != null) {
+ if (mOutputTrays != null) {
+ mOutputTrays.clear();
+ mOutputTrays.addAll(other.mOutputTrays);
+ } else {
+ mOutputTrays = new ArrayList<Tray>(other.mOutputTrays);
+ }
+ } else {
+ mOutputTrays = null;
+ }
+
+ mDuplexModes = other.mDuplexModes;
+ mColorModes = other.mColorModes;
+ mFittingModes = other.mFittingModes;
+ mOrientations = other.mOrientations;
+
+ final int defaultCount = other.mDefaults.length;
+ for (int i = 0; i < defaultCount; i++) {
+ mDefaults[i] = other.mDefaults[i];
+ }
+ mDefaultMargins = other.mDefaultMargins;
}
/**
@@ -240,52 +281,66 @@
public void getDefaults(PrintAttributes outAttributes) {
outAttributes.clear();
- // TODO: Do we want a printer to specify default copies?
- outAttributes.setCopies(MIN_COPIES);
-
outAttributes.setMargins(mDefaultMargins);
- final int mediaSizeIndex = mDefaults.get(PROPERTY_MEDIA_SIZE);
+ final int mediaSizeIndex = mDefaults[PROPERTY_MEDIA_SIZE];
if (mediaSizeIndex >= 0) {
outAttributes.setMediaSize(mMediaSizes.get(mediaSizeIndex));
}
- final int resolutionIndex = mDefaults.get(PROPERTY_RESOLUTION);
+ final int resolutionIndex = mDefaults[PROPERTY_RESOLUTION];
if (resolutionIndex >= 0) {
outAttributes.setResolution(mResolutions.get(resolutionIndex));
}
- final int inputTrayIndex = mDefaults.get(PROPERTY_INPUT_TRAY);
+ final int inputTrayIndex = mDefaults[PROPERTY_INPUT_TRAY];
if (inputTrayIndex >= 0) {
outAttributes.setInputTray(mInputTrays.get(inputTrayIndex));
}
- final int outputTrayIndex = mDefaults.get(PROPERTY_OUTPUT_TRAY);
+ final int outputTrayIndex = mDefaults[PROPERTY_OUTPUT_TRAY];
if (outputTrayIndex >= 0) {
outAttributes.setOutputTray(mOutputTrays.get(outputTrayIndex));
}
- final int duplexMode = mDefaults.get(PROPERTY_DUPLEX_MODE);
+ final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE];
if (duplexMode > 0) {
outAttributes.setDuplexMode(duplexMode);
}
- final int colorMode = mDefaults.get(PROPERTY_COLOR_MODE);
+ final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
if (colorMode > 0) {
outAttributes.setColorMode(mColorModes & colorMode);
}
- final int fittingMode = mDefaults.get(PROPERTY_FITTING_MODE);
+ final int fittingMode = mDefaults[PROPERTY_FITTING_MODE];
if (fittingMode > 0) {
outAttributes.setFittingMode(fittingMode);
}
- final int orientation = mDefaults.get(PROPERTY_ORIENTATION);
+ final int orientation = mDefaults[PROPERTY_ORIENTATION];
if (orientation > 0) {
outAttributes.setOrientation(orientation);
}
}
+ /**
+ * Gets whether this printer info is fully-populated, i.e. whether
+ * all required attributes are specified. See the {@link Builder}
+ * documentation for which attributes are required.
+ *
+ * @return Whether this info has all required attributes.
+ */
+ public boolean hasAllRequiredAttributes() {
+ return (mMediaSizes != null && !mMediaSizes.isEmpty()
+ && mResolutions != null && !mResolutions.isEmpty()
+ && mColorModes != 0 || mOrientations != 0
+ && mDefaults[PROPERTY_MEDIA_SIZE] != DEFAULT_UNDEFINED
+ && mDefaults[PROPERTY_RESOLUTION] != DEFAULT_UNDEFINED
+ && mDefaults[PROPERTY_COLOR_MODE] != DEFAULT_UNDEFINED
+ && mDefaults[PROPERTY_ORIENTATION] != DEFAULT_UNDEFINED);
+ }
+
private PrinterInfo(Parcel parcel) {
mId = parcel.readParcelable(null);
mLabel = parcel.readCharSequence();
@@ -333,6 +388,112 @@
}
@Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mId == null) ? 0 : mId.hashCode());
+ result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
+ result = prime * result + mStatus;
+ result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
+ result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
+ result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
+ result = prime * result + ((mInputTrays == null) ? 0 : mInputTrays.hashCode());
+ result = prime * result + ((mOutputTrays == null) ? 0 : mOutputTrays.hashCode());
+ result = prime * result + mDuplexModes;
+ result = prime * result + mColorModes;
+ result = prime * result + mFittingModes;
+ result = prime * result + mOrientations;
+ result = prime * result + Arrays.hashCode(mDefaults);
+ result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PrinterInfo other = (PrinterInfo) obj;
+ if (mId == null) {
+ if (other.mId != null) {
+ return false;
+ }
+ } else if (!mId.equals(other.mId)) {
+ return false;
+ }
+ if (!TextUtils.equals(mLabel, other.mLabel)) {
+ return false;
+ }
+ if (mStatus != other.mStatus) {
+ return false;
+ }
+ if (mMinMargins == null) {
+ if (other.mMinMargins != null) {
+ return false;
+ }
+ } else if (!mMinMargins.equals(other.mMinMargins)) {
+ return false;
+ }
+ if (mMediaSizes == null) {
+ if (other.mMediaSizes != null) {
+ return false;
+ }
+ } else if (!mMediaSizes.equals(other.mMediaSizes)) {
+ return false;
+ }
+ if (mResolutions == null) {
+ if (other.mResolutions != null) {
+ return false;
+ }
+ } else if (!mResolutions.equals(other.mResolutions)) {
+ return false;
+ }
+ if (mInputTrays == null) {
+ if (other.mInputTrays != null) {
+ return false;
+ }
+ } else if (!mInputTrays.equals(other.mInputTrays)) {
+ return false;
+ }
+ if (mOutputTrays == null) {
+ if (other.mOutputTrays != null) {
+ return false;
+ }
+ } else if (!mOutputTrays.equals(other.mOutputTrays)) {
+ return false;
+ }
+ if (mDuplexModes != other.mDuplexModes) {
+ return false;
+ }
+ if (mColorModes != other.mColorModes) {
+ return false;
+ }
+ if (mFittingModes != other.mFittingModes) {
+ return false;
+ }
+ if (mOrientations != other.mOrientations) {
+ return false;
+ }
+ if (!Arrays.equals(mDefaults, other.mDefaults)) {
+ return false;
+ }
+ if (mDefaultMargins == null) {
+ if (other.mDefaultMargins != null) {
+ return false;
+ }
+ } else if (!mDefaultMargins.equals(other.mDefaultMargins)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrinterInfo{");
@@ -356,12 +517,19 @@
private void readMediaSizes(Parcel parcel) {
final int mediaSizeCount = parcel.readInt();
+ if (mediaSizeCount > 0 && mMediaSizes == null) {
+ mMediaSizes = new ArrayList<MediaSize>();
+ }
for (int i = 0; i < mediaSizeCount; i++) {
mMediaSizes.add(MediaSize.createFromParcel(parcel));
}
}
private void writeResolutions(Parcel parcel) {
+ if (mResolutions == null) {
+ parcel.writeInt(0);
+ return;
+ }
final int resolutionCount = mResolutions.size();
parcel.writeInt(resolutionCount);
for (int i = 0; i < resolutionCount; i++) {
@@ -371,6 +539,9 @@
private void readResolutions(Parcel parcel) {
final int resolutionCount = parcel.readInt();
+ if (resolutionCount > 0 && mResolutions == null) {
+ mResolutions = new ArrayList<Resolution>();
+ }
for (int i = 0; i < resolutionCount; i++) {
mResolutions.add(Resolution.createFromParcel(parcel));
}
@@ -440,15 +611,15 @@
private void readDefaults(Parcel parcel) {
final int defaultCount = parcel.readInt();
for (int i = 0; i < defaultCount; i++) {
- mDefaults.append(mDefaults.size(), parcel.readInt());
+ mDefaults[i] = parcel.readInt();
}
}
private void writeDefaults(Parcel parcel) {
- final int defaultCount = mDefaults.size();
+ final int defaultCount = mDefaults.length;
parcel.writeInt(defaultCount);
for (int i = 0; i < defaultCount; i++) {
- parcel.writeInt(mDefaults.valueAt(i));
+ parcel.writeInt(mDefaults[i]);
}
}
@@ -467,11 +638,11 @@
/**
* Creates a new instance.
*
- * @param printerId The printer id.
- * @param label The human readable printer label.
+ * @param printerId The printer id. Cannot be null.
+ * @param label The human readable printer label. Cannot be null or empty.
*
- * @throws IllegalArgumentException IF the printer id is null.
- * @throws IllegalArgumentException IF the label is empty.
+ * @throws IllegalArgumentException If the printer id is null.
+ * @throws IllegalArgumentException If the label is empty.
*/
public Builder(PrinterId printerId, CharSequence label) {
if (printerId == null) {
@@ -514,11 +685,14 @@
* @see PrintAttributes.MediaSize
*/
public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
+ if (mPrototype.mMediaSizes == null) {
+ mPrototype.mMediaSizes = new ArrayList<MediaSize>();
+ }
final int insertionIndex = mPrototype.mMediaSizes.size();
mPrototype.mMediaSizes.add(mediaSize);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
- mPrototype.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex);
+ mPrototype.mDefaults[PROPERTY_MEDIA_SIZE] = insertionIndex;
}
return this;
}
@@ -539,11 +713,14 @@
* @see PrintAttributes.Resolution
*/
public Builder addResolution(Resolution resolution, boolean isDefault) {
+ if (mPrototype.mResolutions == null) {
+ mPrototype.mResolutions = new ArrayList<Resolution>();
+ }
final int insertionIndex = mPrototype.mResolutions.size();
mPrototype.mResolutions.add(resolution);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
- mPrototype.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex);
+ mPrototype.mDefaults[PROPERTY_RESOLUTION] = insertionIndex;
}
return this;
}
@@ -596,7 +773,7 @@
mPrototype.mInputTrays.add(inputTray);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY);
- mPrototype.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex);
+ mPrototype.mDefaults[PROPERTY_INPUT_TRAY] = insertionIndex;
}
return this;
}
@@ -624,7 +801,7 @@
mPrototype.mOutputTrays.add(outputTray);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY);
- mPrototype.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex);
+ mPrototype.mDefaults[PROPERTY_OUTPUT_TRAY] = insertionIndex;
}
return this;
}
@@ -657,7 +834,7 @@
}
PrintAttributes.enforceValidColorMode(colorModes);
mPrototype.mColorModes = colorModes;
- mPrototype.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode);
+ mPrototype.mDefaults[PROPERTY_COLOR_MODE] = defaultColorMode;
return this;
}
@@ -690,7 +867,7 @@
}
PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
mPrototype.mDuplexModes = duplexModes;
- mPrototype.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode);
+ mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
return this;
}
@@ -722,7 +899,7 @@
}
PrintAttributes.enfoceValidFittingMode(defaultFittingMode);
mPrototype.mFittingModes = fittingModes;
- mPrototype.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode);
+ mPrototype.mDefaults[PROPERTY_FITTING_MODE] = defaultFittingMode;
return this;
}
@@ -754,55 +931,21 @@
}
PrintAttributes.enforceValidOrientation(defaultOrientation);
mPrototype.mOrientations = orientations;
- mPrototype.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation);
+ mPrototype.mDefaults[PROPERTY_ORIENTATION] = defaultOrientation;
return this;
}
/**
- * Crates a new {@link PrinterInfo} enforcing that all required properties
- * have need specified. See individual methods in this class for reference
- * about required attributes.
+ * Crates a new {@link PrinterInfo}.
*
* @return A new {@link PrinterInfo}.
- *
- * @throws IllegalStateException If a required attribute was not specified.
*/
public PrinterInfo create() {
- if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
- throw new IllegalStateException("No media size specified.");
- }
- if (mPrototype.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) {
- throw new IllegalStateException("No default media size specified.");
- }
- if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
- throw new IllegalStateException("No resolution specified.");
- }
- if (mPrototype.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) {
- throw new IllegalStateException("No default resolution specified.");
- }
- if (mPrototype.mColorModes == 0) {
- throw new IllegalStateException("No color mode specified.");
- }
- if (mPrototype.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) {
- throw new IllegalStateException("No default color mode specified.");
- }
- if (mPrototype.mOrientations == 0) {
- throw new IllegalStateException("No oprientation specified.");
- }
- if (mPrototype.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) {
- throw new IllegalStateException("No default orientation specified.");
- }
- if (mPrototype.mMinMargins == null) {
- mPrototype.mMinMargins = new Margins(0, 0, 0, 0);
- }
- if (mPrototype.mDefaultMargins == null) {
- mPrototype.mDefaultMargins = mPrototype.mMinMargins;
- }
return new PrinterInfo(mPrototype);
}
private void throwIfDefaultAlreadySpecified(int propertyIndex) {
- if (mPrototype.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults[propertyIndex] != DEFAULT_UNDEFINED) {
throw new IllegalArgumentException("Default already specified.");
}
}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
index c72385a..e6fdbf9 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -29,8 +29,9 @@
*/
oneway interface IPrintService {
void setClient(IPrintServiceClient client);
- void requestCancelPrintJob(in PrintJobInfo printJobInfo);
+ void onRequestUpdatePrinters(in List<PrinterId> printerIds);
+ void onRequestCancelPrintJob(in PrintJobInfo printJobInfo);
void onPrintJobQueued(in PrintJobInfo printJobInfo);
- void startPrinterDiscovery(IPrinterDiscoveryObserver observer);
- void stopPrinterDiscovery();
+ void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer);
+ void onStopPrinterDiscovery();
}
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 80530a7..0ac5a13 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -61,6 +61,9 @@
* @return The print job info.
*/
public PrintJobInfo getInfo() {
+ if (isInImmutableState()) {
+ return mCachedInfo;
+ }
PrintJobInfo info = null;
try {
info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
@@ -182,6 +185,9 @@
* @return True if the tag was set, false otherwise.
*/
public boolean setTag(String tag) {
+ if (isInImmutableState()) {
+ return false;
+ }
try {
return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
} catch (RemoteException re) {
@@ -210,6 +216,12 @@
return mCachedInfo.getId();
}
+ private boolean isInImmutableState() {
+ final int state = mCachedInfo.getState();
+ return state == PrintJobInfo.STATE_COMPLETED
+ || state == PrintJobInfo.STATE_CANCELED;
+ }
+
private boolean setState(int state) {
try {
if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state)) {
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index dde31d2..15e1b73 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -207,13 +207,14 @@
* Callback requesting from this service to start printer discovery.
* At the end of the printer discovery period the system will call
* {@link #onStopPrinterDiscovery()}. Discovered printers should be
- * reported by calling #addDiscoveredPrinters(List) and reported ones
- * that disappear should be reported by calling
+ * reported by calling {@link #addDiscoveredPrinters(List)} and reported
+ * ones that disappear should be reported by calling
* {@link #removeDiscoveredPrinters(List)}.
*
* @see #onStopPrinterDiscovery()
* @see #addDiscoveredPrinters(List)
* @see #removeDiscoveredPrinters(List)
+ * @see #updateDiscoveredPrinters(List)
*/
protected abstract void onStartPrinterDiscovery();
@@ -223,6 +224,7 @@
* @see #onStartPrinterDiscovery()
* @see #addDiscoveredPrinters(List)
* @see #removeDiscoveredPrinters(List)
+ * @see #updateDiscoveredPrinters(List)
*/
protected abstract void onStopPrinterDiscovery();
@@ -236,12 +238,23 @@
* printers have to be added. You can call this method as many times as
* necessary during the discovery period but should not pass in already
* added printers. If a printer is already added in the same printer
- * discovery period, it will be ignored. If you want to update an already
- * added printer, you should removed it and then re-add it.
+ * discovery period, it will be ignored.
* </p>
+ * <p>
+ * A {@link PrinterInfo} can have all of its required attributes specified,
+ * or not. Whether all attributes are specified can be verified by calling
+ * {@link PrinterInfo#hasAllRequiredAttributes()}. You can add printers
+ * regardless if all required attributes are specified. When the system
+ * (and the user) needs to interact with a printer, you will receive a
+ * call to {@link #onRequestUpdatePrinters(List)}. If you fail to update
+ * a printer that was added without all required attributes via calling
+ * {@link #updateDiscoveredPrinters(List)}, then this printer will be
+ * ignored, i.e. considered unavailable.
+ * <p>
*
* @param printers A list with discovered printers.
*
+ * @see #updateDiscoveredPrinters(List)
* @see #removeDiscoveredPrinters(List)
* @see #onStartPrinterDiscovery()
* @see #onStopPrinterDiscovery()
@@ -253,7 +266,7 @@
}
if (observer != null) {
try {
- observer.addDiscoveredPrinters(printers);
+ observer.onPrintersAdded(printers);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error adding discovered printers", re);
}
@@ -271,14 +284,13 @@
* period by a call to {@link #addDiscoveredPrinters(List)}. You can call
* this method as many times as necessary during the discovery period
* but should not pass in already removed printer ids. If a printer with
- * a given id is already removed in the same discovery period, it will
- * be ignored. If you want to update an already added printer, you should
- * removed it and then re-add it.
+ * a given id is already removed, it will be ignored.
* </p>
*
* @param printerIds A list with disappeared printer ids.
*
* @see #addDiscoveredPrinters(List)
+ * @see #updateDiscoveredPrinters(List)
* @see #onStartPrinterDiscovery()
* @see #onStopPrinterDiscovery()
*/
@@ -289,7 +301,7 @@
}
if (observer != null) {
try {
- observer.removeDiscoveredPrinters(printerIds);
+ observer.onPrintersRemoved(printerIds);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error removing discovered printers", re);
}
@@ -297,6 +309,65 @@
}
/**
+ * Updates discovered printers that are already added. This method should
+ * be called during a printer discovery period, i.e. after a call to
+ * {@link #onStartPrinterDiscovery()} and before the corresponding
+ * call to {@link #onStopPrinterDiscovery()}, otherwise it does nothing.
+ * <p>
+ * For every printer discovery period all printers have to be added. You
+ * should update only printers that were added in this printer discovery
+ * period by a call to {@link #addDiscoveredPrinters(List)}. You can call
+ * this method as many times as necessary during the discovery period
+ * but should not try to update already removed or never added printers.
+ * If a printer is already removed or never added, it will be ignored.
+ * </p>
+ *
+ * @param printers A list with updated printers.
+ *
+ * @see #addDiscoveredPrinters(List)
+ * @see #removeDiscoveredPrinters(List)
+ * @see #onStartPrinterDiscovery()
+ * @see #onStopPrinterDiscovery()
+ */
+ public final void updateDiscoveredPrinters(List<PrinterInfo> printers) {
+ final IPrinterDiscoveryObserver observer;
+ synchronized (mLock) {
+ observer = mDiscoveryObserver;
+ }
+ if (observer != null) {
+ try {
+ observer.onPrintersUpdated(printers);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error updating discovered printers", re);
+ }
+ }
+ }
+
+ /**
+ * Called when the system will start interacting with a printer
+ * giving you a change to update it in case some of its capabilities
+ * have changed. For example, this method will be called when the
+ * user selects a printer. Hence, it updating this printer should
+ * be done as quickly as possible in order to achieve maximally
+ * smooth user experience.
+ * <p>
+ * A {@link PrinterInfo} can have all of its required attributes specified,
+ * or not. Whether all attributes are specified can be verified by calling
+ * {@link PrinterInfo#hasAllRequiredAttributes()}. You can add printers
+ * regardless if all required attributes are specified. When the system
+ * (and the user) needs to interact with a printer, you will receive a
+ * call to this method. If you fail to update a printer that was added
+ * without all required attributes via calling
+ * {@link #updateDiscoveredPrinters(List)}, then this printer will be
+ * ignored, i.e. considered unavailable.
+ * </p>
+ *
+ * @param printerIds The printers to be updated.
+ */
+ protected void onRequestUpdatePrinters(List<PrinterId> printerIds) {
+ }
+
+ /**
* Called when canceling of a print job is requested. The service
* should do best effort to fulfill the request. After the cancellation
* is performed, the print job should be set to a cancelled state by
@@ -373,74 +444,87 @@
return new IPrintService.Stub() {
@Override
public void setClient(IPrintServiceClient client) {
- mHandler.obtainMessage(MyHandler.MESSAGE_SET_CLEINT, client).sendToTarget();
+ mHandler.obtainMessage(MyHandler.MSG_SET_CLEINT, client).sendToTarget();
}
@Override
- public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
- mHandler.obtainMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY,
+ public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_START_PRINTER_DISCOVERY,
observer).sendToTarget();
}
@Override
- public void stopPrinterDiscovery() {
- mHandler.sendEmptyMessage(MyHandler.MESSAGE_STOP_PRINTER_DISCOVERY);
+ public void onStopPrinterDiscovery() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_ON_STOP_PRINTER_DISCOVERY);
}
@Override
- public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
- mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB,
+ public void onRequestUpdatePrinters(List<PrinterId> printerIds) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_UPDATE_PRINTERS,
+ printerIds).sendToTarget();
+ }
+
+ @Override
+ public void onRequestCancelPrintJob(PrintJobInfo printJobInfo) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINTJOB,
printJobInfo).sendToTarget();
}
@Override
public void onPrintJobQueued(PrintJobInfo printJobInfo) {
- mHandler.obtainMessage(MyHandler.MESSAGE_ON_PRINTJOB_QUEUED,
+ mHandler.obtainMessage(MyHandler.MSG_ON_PRINTJOB_QUEUED,
printJobInfo).sendToTarget();
}
};
}
private final class MyHandler extends Handler {
- public static final int MESSAGE_START_PRINTER_DISCOVERY = 1;
- public static final int MESSAGE_STOP_PRINTER_DISCOVERY = 2;
- public static final int MESSAGE_CANCEL_PRINTJOB = 3;
- public static final int MESSAGE_ON_PRINTJOB_QUEUED = 4;
- public static final int MESSAGE_SET_CLEINT = 5;
+ public static final int MSG_ON_START_PRINTER_DISCOVERY = 1;
+ public static final int MSG_ON_STOP_PRINTER_DISCOVERY = 2;
+ public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 3;
+ public static final int MSG_ON_REQUEST_UPDATE_PRINTERS = 4;
+ public static final int MSG_ON_PRINTJOB_QUEUED = 5;
+ public static final int MSG_SET_CLEINT = 6;
public MyHandler(Looper looper) {
super(looper, null, true);
}
@Override
+ @SuppressWarnings("unchecked")
public void handleMessage(Message message) {
final int action = message.what;
switch (action) {
- case MESSAGE_START_PRINTER_DISCOVERY: {
+ case MSG_ON_START_PRINTER_DISCOVERY: {
synchronized (mLock) {
mDiscoveryObserver = (IPrinterDiscoveryObserver) message.obj;
}
onStartPrinterDiscovery();
} break;
- case MESSAGE_STOP_PRINTER_DISCOVERY: {
+ case MSG_ON_STOP_PRINTER_DISCOVERY: {
synchronized (mLock) {
mDiscoveryObserver = null;
}
onStopPrinterDiscovery();
} break;
- case MESSAGE_CANCEL_PRINTJOB: {
+ case MSG_ON_REQUEST_CANCEL_PRINTJOB: {
PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
} break;
- case MESSAGE_ON_PRINTJOB_QUEUED: {
+ case MSG_ON_REQUEST_UPDATE_PRINTERS: {
+ List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+ onRequestUpdatePrinters(printerIds);
+ } break;
+
+ case MSG_ON_PRINTJOB_QUEUED: {
PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
onPrintJobQueued(new PrintJob(printJobInfo, mClient));
} break;
- case MESSAGE_SET_CLEINT: {
+ case MSG_SET_CLEINT: {
IPrintServiceClient client = (IPrintServiceClient) message.obj;
synchronized (mLock) {
mClient = client;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e59f5b1..d87a36e 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -825,6 +825,14 @@
public static final String STARRED = "starred";
/**
+ * The position at which the contact is pinned. If {@link PinnedPositions.UNPINNED},
+ * the contact is not pinned. Also see {@link PinnedPositions}.
+ * <P>Type: INTEGER </P>
+ * @hide
+ */
+ public static final String PINNED = "pinned";
+
+ /**
* URI for a custom ringtone associated with the contact. If null or missing,
* the default ringtone is used.
* <P>Type: TEXT (URI to the ringtone)</P>
@@ -7714,6 +7722,107 @@
}
/**
+ * <p>
+ * API allowing applications to send pinning information for specified contacts to the
+ * Contacts Provider.
+ * </p>
+ *
+ * <p>
+ * This pinning information can be used by individual applications to customize how
+ * they order particular pinned contacts. For example, a Dialer application could
+ * use pinned information to order user-pinned contacts in a top row of favorites.
+ * </p>
+ *
+ * <p>
+ * It is possible for two or more contacts to occupy the same pinned position (due
+ * to aggregation and sync), so this pinning information should be used on a best-effort
+ * basis to order contacts in-application rather than an absolute guide on where a contact
+ * should be positioned. Contacts returned by the ContactsProvider will not be ordered based
+ * on this information, so it is up to the client application to reorder these contacts within
+ * their own UI adhering to (or ignoring as appropriate) information stored in the pinned
+ * column.
+ * </p>
+ *
+ * <p>
+ * By default, unpinned contacts will have a pinned position of
+ * {@link PinnedPositions#UNPINNED}, or {@link Integer#MAX_VALUE} (2^31 - 1). Client-provided
+ * pinned positions can be positive integers that range anywhere from 0 to
+ * {@link PinnedPositions#UNPINNED}.
+ * </p>
+ *
+ * <p>
+ * When using {@link PinnedPositions#UPDATE_URI} to update the pinned positions of
+ * certain contacts, it may make sense for your application to star any pinned contacts
+ * by default. To specify this behavior, set the boolean query parameter
+ * {@link PinnedPositions#STAR_WHEN_PINNING} to true to force all pinned and unpinned
+ * contacts to be automatically starred and unstarred.
+ * </p>
+ * @hide
+ */
+ public static final class PinnedPositions {
+
+ /**
+ * <p>
+ * This URI allows applications to update pinned positions for a provided set of contacts.
+ * </p>
+ *
+ * <p>
+ * The list of contactIds to pin and their corresponding pinned positions should be
+ * provided in key-value pairs stored in a {@link ContentValues} object where the key
+ * is a valid contactId, while each pinned position is a positive integer.
+ * </p>
+ *
+ * <p>
+ * Example:
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put("10", 20);
+ * values.put("12", 2);
+ * values.put("15", PinnedPositions.UNPINNED);
+ * int count = resolver.update(PinnedPositions.UPDATE_URI, values, null, null);
+ * </pre>
+ *
+ * This pins the contact with id 10 at position 20, the contact with id 12 at position 2,
+ * and unpins the contact with id 15.
+ * </p>
+ */
+ public static final Uri UPDATE_URI = Uri.withAppendedPath(AUTHORITY_URI,
+ "pinned_position_update");
+
+ /**
+ * Default value for the pinned position of an unpinned contact. Also equal to
+ * {@link Integer#MAX_VALUE}.
+ */
+ public static final int UNPINNED = 0x7FFFFFFF;
+
+ /**
+ * <p>
+ * A boolean query parameter that can be used with {@link #UPDATE_URI}.
+ * If "1" or "true", any contact that is pinned or unpinned will be correspondingly
+ * starred or unstarred. Otherwise, starring information will not be affected by pinned
+ * updates. This is false by default.
+ * </p>
+ *
+ * <p>
+ * Example:
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put("10", 20);
+ * values.put("15", PinnedPositions.UNPINNED);
+ * int count = resolver.update(ContactsContract.PinnedPositions.UPDATE_URI.buildUpon()
+ * .appendQueryParameter(PinnedPositions.FORCE_STAR_WHEN_PINNING, "true").build(),
+ * values, null, null);
+ * </pre>
+ *
+ * This will pin the contact with id 10 at position 20 and star it automatically if not
+ * already starred, and unpin the contact with id 15, and unstar it automatically if not
+ * already unstarred.
+ * </p>
+ */
+ public static final String STAR_WHEN_PINNING = "star_when_pinning";
+ }
+
+ /**
* Helper methods to display QuickContact dialogs that allow users to pivot on
* a specific {@link Contacts} entry.
*/
diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java
index f29fb65..09f1f8e 100644
--- a/core/java/android/util/MapCollections.java
+++ b/core/java/android/util/MapCollections.java
@@ -183,13 +183,27 @@
}
@Override
- public boolean contains(Object object) {
- throw new UnsupportedOperationException();
+ public boolean contains(Object o) {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
+ int index = colIndexOfKey(e.getKey());
+ if (index < 0) {
+ return false;
+ }
+ Object foundVal = colGetEntry(index, 1);
+ return Objects.equal(foundVal, e.getValue());
}
@Override
public boolean containsAll(Collection<?> collection) {
- throw new UnsupportedOperationException();
+ Iterator<?> it = collection.iterator();
+ while (it.hasNext()) {
+ if (!contains(it.next())) {
+ return false;
+ }
+ }
+ return true;
}
@Override
@@ -231,6 +245,23 @@
public <T> T[] toArray(T[] array) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public boolean equals(Object object) {
+ return equalsSetHelper(this, object);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ for (int i=colGetSize()-1; i>=0; i--) {
+ final Object key = colGetEntry(i, 0);
+ final Object value = colGetEntry(i, 1);
+ result += ( (key == null ? 0 : key.hashCode()) ^
+ (value == null ? 0 : value.hashCode()) );
+ }
+ return result;
+ }
};
final class KeySet implements Set<K> {
@@ -257,7 +288,7 @@
@Override
public boolean containsAll(Collection<?> collection) {
- return removeAllHelper(colGetMap(), collection);
+ return containsAllHelper(colGetMap(), collection);
}
@Override
@@ -304,6 +335,21 @@
public <T> T[] toArray(T[] array) {
return toArrayHelper(array, 1);
}
+
+ @Override
+ public boolean equals(Object object) {
+ return equalsSetHelper(this, object);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ for (int i=colGetSize()-1; i>=0; i--) {
+ Object obj = colGetEntry(i, 0);
+ result += obj == null ? 0 : obj.hashCode();
+ }
+ return result;
+ }
};
final class ValuesCollection implements Collection<V> {
@@ -437,7 +483,6 @@
return oldSize != map.size();
}
-
public Object[] toArrayHelper(int offset) {
final int N = colGetSize();
Object[] result = new Object[N];
@@ -463,6 +508,24 @@
return array;
}
+ public static <T> boolean equalsSetHelper(Set<T> set, Object object) {
+ if (set == object) {
+ return true;
+ }
+ if (object instanceof Set) {
+ Set<?> s = (Set<?>) object;
+
+ try {
+ return set.size() == s.size() && set.containsAll(s);
+ } catch (NullPointerException ignored) {
+ return false;
+ } catch (ClassCastException ignored) {
+ return false;
+ }
+ }
+ return false;
+ }
+
public Set<Map.Entry<K, V>> getEntrySet() {
if (mEntrySet == null) {
mEntrySet = new EntrySet();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4f501e7..a6e68d0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -862,7 +862,6 @@
* @param resultCallback A callback to be invoked when the script execution
* completes with the result of the execution (if any).
* May be null if no notificaion of the result is required.
- * @hide pending API council approval and CTS test coverage.
*/
public void evaluateJavascript(String script, ValueCallback<String> resultCallback) {
checkThread();
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 2ee0961..d924447 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -28,8 +28,15 @@
* @hide
*/
public final class WebViewFactory {
- public static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = false;
- public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp";
+ private static final boolean DEFAULT_TO_EXPERIMENTAL_WEBVIEW = false;
+ private static final String EXPERIMENTAL_PROPERTY_DEFAULT_OFF = "persist.sys.webview.exp";
+ private static final String EXPERIMENTAL_PROPERTY_DEFAULT_ON = "persist.sys.webview.exp_on";
+
+ // Modify the persisted property name when the experiment is on-by-default, so that any user
+ // setting override lives in a different property namespace.
+ private static final String WEBVIEW_EXPERIMENTAL_PROPERTY = DEFAULT_TO_EXPERIMENTAL_WEBVIEW ?
+ EXPERIMENTAL_PROPERTY_DEFAULT_ON : EXPERIMENTAL_PROPERTY_DEFAULT_OFF;
+
private static final String FORCE_PROVIDER_PROPERTY = "webview.force_provider";
private static final String FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM = "chromium";
private static final String FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC = "classic";
@@ -71,6 +78,20 @@
}
}
+ /** @hide */
+ public static void setUseExperimentalWebView(boolean enable) {
+ SystemProperties.set(WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY,
+ enable ? "true" : "false");
+ Log.i(LOGTAG, "Use Experimental WebView changed: "
+ + SystemProperties.get(WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY, ""));
+ }
+
+ /** @hide */
+ public static boolean useExperimentalWebView() {
+ return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY,
+ DEFAULT_TO_EXPERIMENTAL_WEBVIEW);
+ }
+
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
@@ -112,17 +133,15 @@
// WebView. This enables us to switch between implementations at runtime.
private static boolean isExperimentalWebViewEnabled() {
if (!isExperimentalWebViewAvailable()) return false;
- boolean use_experimental_webview = SystemProperties.getBoolean(
- WEBVIEW_EXPERIMENTAL_PROPERTY, DEFAULT_TO_EXPERIMENTAL_WEBVIEW);
String forceProviderName = SystemProperties.get(FORCE_PROVIDER_PROPERTY);
- if (forceProviderName.isEmpty()) return use_experimental_webview;
+ if (forceProviderName.isEmpty()) return useExperimentalWebView();
Log.i(LOGTAG, String.format("Provider overridden by property: %s=%s",
FORCE_PROVIDER_PROPERTY, forceProviderName));
if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CHROMIUM)) return true;
if (forceProviderName.equals(FORCE_PROVIDER_PROPERTY_VALUE_CLASSIC)) return false;
Log.e(LOGTAG, String.format("Unrecognized provider: %s", forceProviderName));
- return use_experimental_webview;
+ return useExperimentalWebView();
}
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9842aba..d8a2eda 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -923,9 +923,9 @@
* the choice mode has not been set to {@link #CHOICE_MODE_NONE}.
*
* @return A SparseBooleanArray which will return true for each call to
- * get(int position) where position is a position in the list,
- * or <code>null</code> if the choice mode is set to
- * {@link #CHOICE_MODE_NONE}.
+ * get(int position) where position is a checked position in the
+ * list and false otherwise, or <code>null</code> if the choice
+ * mode is set to {@link #CHOICE_MODE_NONE}.
*/
public SparseBooleanArray getCheckedItemPositions() {
if (mChoiceMode != CHOICE_MODE_NONE) {
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 789d263a..eec15a9 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -937,6 +937,9 @@
}
public void show(int textDirection, int textAlignment) {
+ if (mListAdapter == null) {
+ return;
+ }
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
if (mPrompt != null) {
builder.setTitle(mPrompt);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 345a39e..c7b5697 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -57,6 +57,45 @@
// This utility class is not publicly instantiable.
}
+ // ----------------------------------------------------------------------
+ // Utilities for debug
+ public static String getStackTrace() {
+ final StringBuilder sb = new StringBuilder();
+ try {
+ throw new RuntimeException();
+ } catch (RuntimeException e) {
+ final StackTraceElement[] frames = e.getStackTrace();
+ // Start at 1 because the first frame is here and we don't care about it
+ for (int j = 1; j < frames.length; ++j) {
+ sb.append(frames[j].toString() + "\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String getApiCallStack() {
+ String apiCallStack = "";
+ try {
+ throw new RuntimeException();
+ } catch (RuntimeException e) {
+ final StackTraceElement[] frames = e.getStackTrace();
+ for (int j = 1; j < frames.length; ++j) {
+ final String tempCallStack = frames[j].toString();
+ if (TextUtils.isEmpty(apiCallStack)) {
+ // Overwrite apiCallStack if it's empty
+ apiCallStack = tempCallStack;
+ } else if (tempCallStack.indexOf("Transact(") < 0) {
+ // Overwrite apiCallStack if it's not a binder call
+ apiCallStack = tempCallStack;
+ } else {
+ break;
+ }
+ }
+ }
+ return apiCallStack;
+ }
+ // ----------------------------------------------------------------------
+
public static boolean isSystemIme(InputMethodInfo inputMethod) {
return (inputMethod.getServiceInfo().applicationInfo.flags
& ApplicationInfo.FLAG_SYSTEM) != 0;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 4bb6d0694..ff9678c 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -16,9 +16,6 @@
package com.android.internal.view.menu;
-import com.android.internal.view.ActionBarPolicy;
-import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
-
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -27,11 +24,18 @@
import android.util.SparseBooleanArray;
import android.view.ActionProvider;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
+import android.widget.AbsListView;
import android.widget.ImageButton;
+import android.widget.ListPopupWindow;
+
+import com.android.internal.view.ActionBarPolicy;
+import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
import java.util.ArrayList;
@@ -559,6 +563,7 @@
setFocusable(true);
setVisibility(VISIBLE);
setEnabled(true);
+ setOnTouchListener(new OverflowForwardListener(context));
}
@Override
@@ -572,10 +577,12 @@
return true;
}
+ @Override
public boolean needsDividerBefore() {
return false;
}
+ @Override
public boolean needsDividerAfter() {
return false;
}
@@ -675,4 +682,45 @@
mPostedOpenRunnable = null;
}
}
+
+ private class OverflowForwardListener extends TouchForwardingListener {
+ /** Scaled touch slop, used for detecting movement outside bounds. */
+ private final float mScaledTouchSlop;
+
+ private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+ public OverflowForwardListener(Context context) {
+ mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ }
+
+ @Override
+ public boolean onTouchObserved(View v, MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_MOVE && v.isEnabled()
+ && !v.pointInView(ev.getX(), ev.getY(), mScaledTouchSlop)) {
+ mActivePointerId = ev.getPointerId(0);
+ v.performClick();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean onTouchForwarded(View v, MotionEvent ev) {
+ if (!v.isEnabled() || mOverflowPopup == null || !mOverflowPopup.isShowing()) {
+ return false;
+ }
+
+ if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) {
+ if (mOverflowPopup.forwardMotionEvent(v, ev, mActivePointerId)) {
+ return true;
+ }
+
+ mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+ }
+
+ mOverflowPopup.dismiss();
+ return false;
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 6d39860..945f42b 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -22,10 +22,12 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
@@ -46,6 +48,8 @@
static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
+ private final int[] mTempLocation = new int[2];
+
private final Context mContext;
private final LayoutInflater mInflater;
private final MenuBuilder mMenu;
@@ -158,6 +162,69 @@
return mPopup != null && mPopup.isShowing();
}
+ public boolean forwardMotionEvent(View v, MotionEvent ev, int activePointerId) {
+ if (mPopup == null || !mPopup.isShowing()) {
+ return false;
+ }
+
+ final AbsListView dstView = mPopup.getListView();
+ if (dstView == null || !dstView.isShown()) {
+ return false;
+ }
+
+ boolean cancelForwarding = false;
+ final int actionMasked = ev.getActionMasked();
+ switch (actionMasked) {
+ case MotionEvent.ACTION_CANCEL:
+ cancelForwarding = true;
+ break;
+ case MotionEvent.ACTION_UP:
+ cancelForwarding = true;
+ // $FALL-THROUGH$
+ case MotionEvent.ACTION_MOVE:
+ final int activeIndex = ev.findPointerIndex(activePointerId);
+ if (activeIndex < 0) {
+ return false;
+ }
+
+ final int[] location = mTempLocation;
+ int x = (int) ev.getX(activeIndex);
+ int y = (int) ev.getY(activeIndex);
+
+ // Convert to global coordinates.
+ v.getLocationOnScreen(location);
+ x += location[0];
+ y += location[1];
+
+ // Convert to local coordinates.
+ dstView.getLocationOnScreen(location);
+ x -= location[0];
+ y -= location[1];
+
+ final int position = dstView.pointToPosition(x, y);
+ if (position >= 0) {
+ final int childCount = dstView.getChildCount();
+ final int firstVisiblePosition = dstView.getFirstVisiblePosition();
+ final int index = position - firstVisiblePosition;
+ if (index < childCount) {
+ final View child = dstView.getChildAt(index);
+ if (actionMasked == MotionEvent.ACTION_UP) {
+ // Touch ended, click highlighted item.
+ final long id = dstView.getItemIdAtPosition(position);
+ dstView.performItemClick(child, position, id);
+ } else if (actionMasked == MotionEvent.ACTION_MOVE) {
+ // TODO: Highlight touched item, activate after
+ // long-hover. Consider forwarding events as HOVER and
+ // letting ListView handle this.
+ }
+ }
+ }
+ break;
+ }
+
+ return true;
+ }
+
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
MenuAdapter adapter = mAdapter;
diff --git a/core/java/com/android/internal/view/menu/TouchForwardingListener.java b/core/java/com/android/internal/view/menu/TouchForwardingListener.java
new file mode 100644
index 0000000..d1086de
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/TouchForwardingListener.java
@@ -0,0 +1,72 @@
+/*
+ * 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 com.android.internal.view.menu;
+
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Touch listener used to intercept touches and forward them out of a view.
+ */
+abstract class TouchForwardingListener implements View.OnTouchListener {
+ /** Whether this listener is currently forwarding touch events. */
+ private boolean mForwarding;
+
+ @Override
+ public boolean onTouch(View v, MotionEvent ev) {
+ final int actionMasked = ev.getActionMasked();
+
+ if (mForwarding) {
+ // Rejecting the event or ending the stream stops forwarding.
+ if (!onTouchForwarded(v, ev) || actionMasked == MotionEvent.ACTION_UP
+ || actionMasked == MotionEvent.ACTION_CANCEL) {
+ stopForwarding();
+ }
+ } else {
+ if (onTouchObserved(v, ev)) {
+ startForwarding();
+ }
+ }
+
+ return mForwarding;
+ }
+
+ public void startForwarding() {
+ mForwarding = true;
+ }
+
+ public void stopForwarding() {
+ mForwarding = false;
+ }
+
+ /**
+ * Attempts to start forwarding motion events.
+ *
+ * @param v The view that triggered forwarding.
+ * @return True to start forwarding motion events, or false to cancel.
+ */
+ public abstract boolean onTouchObserved(View v, MotionEvent ev);
+
+ /**
+ * Handles forwarded motion events.
+ *
+ * @param v The view from which the event was forwarded.
+ * @param ev The forwarded motion event.
+ * @return True to continue forwarding motion events, or false to cancel.
+ */
+ public abstract boolean onTouchForwarded(View v, MotionEvent ev);
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 84c28e6..4fc885c 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -130,7 +130,7 @@
android_media_RemoteDisplay.cpp \
android_media_ToneGenerator.cpp \
android_hardware_Camera.cpp \
- android_hardware_photography_CameraMetadata.cpp \
+ android_hardware_camera2_CameraMetadata.cpp \
android_hardware_SensorManager.cpp \
android_hardware_SerialPort.cpp \
android_hardware_UsbDevice.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 71395c7..91fdcc2 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -76,7 +76,7 @@
extern int register_android_opengl_jni_GLES30(JNIEnv* env);
extern int register_android_hardware_Camera(JNIEnv *env);
-extern int register_android_hardware_photography_CameraMetadata(JNIEnv *env);
+extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
@@ -1190,7 +1190,7 @@
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
- REG_JNI(register_android_hardware_photography_CameraMetadata),
+ REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_SensorManager),
REG_JNI(register_android_hardware_SerialPort),
REG_JNI(register_android_hardware_UsbDevice),
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index eb9e004..ab7f1dc 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -25,6 +25,7 @@
#include <android_runtime/AndroidRuntime.h>
#include "SkPath.h"
+#include "pathops/SkPathOps.h"
#include <Caches.h>
@@ -67,8 +68,7 @@
return obj->getFillType();
}
- static void setFillType(JNIEnv* env, jobject clazz, SkPath* path,
- SkPath::FillType ft) {
+ static void setFillType(JNIEnv* env, jobject clazz, SkPath* path, SkPath::FillType ft) {
path->setFillType(ft);
}
@@ -200,7 +200,7 @@
}
static void addRoundRectXY(JNIEnv* env, jobject clazz, SkPath* obj, jobject rect,
- jfloat rx, jfloat ry, SkPath::Direction dir) {
+ jfloat rx, jfloat ry, SkPath::Direction dir) {
SkRect rect_;
GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
SkScalar rx_ = SkFloatToScalar(rx);
@@ -209,7 +209,7 @@
}
static void addRoundRect8(JNIEnv* env, jobject, SkPath* obj, jobject rect,
- jfloatArray array, SkPath::Direction dir) {
+ jfloatArray array, SkPath::Direction dir) {
SkRect rect_;
GraphicsJNI::jrectf_to_rect(env, rect, &rect_);
AutoJavaFloatArray afa(env, array, 8);
@@ -261,7 +261,10 @@
static void transform__Matrix(JNIEnv* env, jobject clazz, SkPath* obj, SkMatrix* matrix) {
obj->transform(*matrix);
}
-
+
+ static jboolean op(JNIEnv* env, jobject clazz, SkPath* p1, SkPath* p2, SkPathOp op, SkPath* r) {
+ return Op(*p1, *p2, op, r);
+ }
};
static JNINativeMethod methods[] = {
@@ -301,7 +304,8 @@
{"native_offset","(IFF)V", (void*) SkPathGlue::offset__FF},
{"native_setLastPoint","(IFF)V", (void*) SkPathGlue::setLastPoint},
{"native_transform","(III)V", (void*) SkPathGlue::transform__MatrixPath},
- {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix}
+ {"native_transform","(II)V", (void*) SkPathGlue::transform__Matrix},
+ {"native_op","(IIII)Z", (void*) SkPathGlue::op}
};
int register_android_graphics_Path(JNIEnv* env) {
diff --git a/core/jni/android_hardware_photography_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
similarity index 98%
rename from core/jni/android_hardware_photography_CameraMetadata.cpp
rename to core/jni/android_hardware_camera2_CameraMetadata.cpp
index 5190a37..852c4d4 100644
--- a/core/jni/android_hardware_photography_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -38,7 +38,7 @@
#endif
// fully-qualified class name
-#define CAMERA_METADATA_CLASS_NAME "android/hardware/photography/CameraMetadata"
+#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/CameraMetadata"
using namespace android;
@@ -418,7 +418,7 @@
}
// Get all the required offsets in java class and register native functions
-int register_android_hardware_photography_CameraMetadata(JNIEnv *env)
+int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
{
// Register native functions
return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 32f6ecf..2c23f9d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -586,7 +586,7 @@
}
ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, &name)) {
+ if (!am->getResources().getResourceName(resid, true, &name)) {
return NULL;
}
@@ -594,19 +594,27 @@
if (name.package != NULL) {
str.setTo(name.package, name.packageLen);
}
- if (name.type != NULL) {
+ if (name.type8 != NULL || name.type != NULL) {
if (str.size() > 0) {
char16_t div = ':';
str.append(&div, 1);
}
- str.append(name.type, name.typeLen);
+ if (name.type8 != NULL) {
+ str.append(String16(name.type8, name.typeLen));
+ } else {
+ str.append(name.type, name.typeLen);
+ }
}
- if (name.name != NULL) {
+ if (name.name8 != NULL || name.name != NULL) {
if (str.size() > 0) {
char16_t div = '/';
str.append(&div, 1);
}
- str.append(name.name, name.nameLen);
+ if (name.name8 != NULL) {
+ str.append(String16(name.name8, name.nameLen));
+ } else {
+ str.append(name.name, name.nameLen);
+ }
}
return env->NewString((const jchar*)str.string(), str.size());
@@ -621,7 +629,7 @@
}
ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, &name)) {
+ if (!am->getResources().getResourceName(resid, true, &name)) {
return NULL;
}
@@ -641,10 +649,14 @@
}
ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, &name)) {
+ if (!am->getResources().getResourceName(resid, true, &name)) {
return NULL;
}
+ if (name.type8 != NULL) {
+ return env->NewStringUTF(name.type8);
+ }
+
if (name.type != NULL) {
return env->NewString((const jchar*)name.type, name.typeLen);
}
@@ -661,10 +673,14 @@
}
ResTable::resource_name name;
- if (!am->getResources().getResourceName(resid, &name)) {
+ if (!am->getResources().getResourceName(resid, true, &name)) {
return NULL;
}
+ if (name.name8 != NULL) {
+ return env->NewStringUTF(name.name8);
+ }
+
if (name.name != NULL) {
return env->NewString((const jchar*)name.name, name.nameLen);
}
@@ -680,7 +696,7 @@
{
if (outValue == NULL) {
jniThrowNullPointerException(env, "outValue");
- return NULL;
+ return 0;
}
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 6d97d01..8325217 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -95,26 +95,6 @@
}
}
-jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
-{
- return getpid();
-}
-
-jint android_os_Process_myPpid(JNIEnv* env, jobject clazz)
-{
- return getppid();
-}
-
-jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
-{
- return getuid();
-}
-
-jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
-{
- return androidGetTid();
-}
-
jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
{
if (name == NULL) {
@@ -349,8 +329,7 @@
void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
jint pri)
{
- jint tid = android_os_Process_myTid(env, clazz);
- android_os_Process_setThreadPriority(env, clazz, tid, pri);
+ android_os_Process_setThreadPriority(env, clazz, androidGetTid(), pri);
}
jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
@@ -1034,10 +1013,6 @@
}
static const JNINativeMethod methods[] = {
- {"myPid", "()I", (void*)android_os_Process_myPid},
- {"myPpid", "()I", (void*)android_os_Process_myPpid},
- {"myTid", "()I", (void*)android_os_Process_myTid},
- {"myUid", "()I", (void*)android_os_Process_myUid},
{"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
{"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
{"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c99fcf5..0414b01 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"voeg \'n toesteladministrateur by of verwyder een"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Laat die houer aktiewe toesteladministrateurs byvoeg of verwyder. Behoort nooit nodig te wees vir normale programme nie."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"verander skermoriëntasie"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Laat die program toe om die skerm se rotasie te eniger tyd te verander. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"verander wyserspoed"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ac6f57f..f4f8881 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"በማንኛውም ጊዜ የማሳያውን መሽከርከር ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"የጠቋሚ ፍጥነት ለውጥ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6bcfde8..63c8f74 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"إضافة مشرف جهاز أو إزالته"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"للسماح بحامل البطاقة بإضافة مشرفي أجهزة نشطين أو إزالتهم. لا يلزم ذلك أبدًا للتطبيقات العادية."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"تغيير اتجاه الشاشة"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"للسماح للتطبيق بتغيير تدوير الشاشة في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغيير سرعة المؤشر"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index bcc803e..32c786c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Разрешава на приложението да променя ориентацията на екрана по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промяна на скоростта на курсор"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 76f243e..782d27e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"afegeix un administrador al dispositiu o suprimeix-lo"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet que el titular afegeixi administradors actius al dispositiu o en suprimeixi. No s\'hauria de necessitar per a les aplicacions normals."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"canviar l\'orientació de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permet que l\'aplicació canviï el gir de la pantalla en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"canvi de velocitat del punter"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8e28050..aa74e3c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikaci kdykoli změnit otočení obrazovky. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"změna rychlosti kurzoru"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 088f2ac..a18b4df 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tilføje eller fjerne en enhedsadministrator"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillader, at man tilføjer eller fjerner aktive enhedsadministratorer. Dette burde aldrig være nødvendigt til normale apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"skift skærmretning"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Tillader, at appen kan ændre skærmretningen på et hvilket som helst tidspunkt. Bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ændre markørens hastighed"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 17f96cf..3597f94 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ermöglicht der App, die Bildschirmdrehung jederzeit zu ändern. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Zeigergeschwindigkeit ändern"</string>
@@ -652,13 +650,13 @@
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Tablet sperren oder alle Daten auf dem Tablet löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Bildschirms überwachen und Telefon sperren oder alle Daten auf dem Telefon löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string>
- <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Displays ändern"</string>
- <string name="policydesc_resetPassword" msgid="605963962301904458">"Passwort zum Entsperren des Bildschirms ändern"</string>
+ <string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Bildschirms ändern"</string>
+ <string name="policydesc_resetPassword" msgid="605963962301904458">"Ändern Sie das Passwort zum Entsperren des Bildschirms."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Display sperren"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Legen Sie fest, wie und wann der Bildschirm gesperrt wird."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index bc379c5..de2f255 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"προσθήκη ή κατάργηση ενός διαχειριστή συσκευής"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Επιτρέπει στον κάτοχο να προσθέτει ή να καταργεί ενεργούς διαχειριστές συσκευών. Δεν θα πρέπει να ζητείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"αλλαγή προσανατολισμού οθόνης"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Επιτρέπει στην εφαρμογή την αλλαγή της περιστροφής της οθόνης ανά πάσα στιγμή. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"αλλαγή ταχύτητας δείκτη"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 0222b1b..4abcade 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"add or remove a device admin"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Allows the holder to add or remove active device administrators. Should never be needed for normal apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"change screen orientation"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Allows the app to change the rotation of the screen at any time. Should never be needed for normal apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"change pointer speed"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index cde265f..d93d5da 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0c45c10..3e0eb84 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4332cab..31ccf47 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"seadme administraatori lisamine või eemaldamine"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Võimaldab omanikul lisada või eemaldada aktiivseid seadme administraatoreid. Tavarakenduste puhul ei tohiks see kunagi vajalik olla."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"muuda ekraani paigutust"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Võimaldab rakendusel muuta ekraani pööramist mis tahes ajal. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"kursorikiiruse muutmine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e5c230f..8ea169f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"به دارنده اجازه میدهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامههای معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه میدهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"به برنامه اجازه میدهد تا چرخش صفحه را هر وقت بخواهد تغییر دهد. برای برنامههای عادی نیاز نیست."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغییر سرعت اشارهگر"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7badf31..d4f9922 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Antaa sovelluksen muuttaa näytön kiertoa milloin tahansa. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"muuta osoittimen nopeutta"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e002539..ab3748c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permet à l\'application de changer l\'orientation de l\'écran à tout moment. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"changer la vitesse du pointeur"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a91c0aa..249623e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"उपकरण व्यवस्थापक को जोड़ें या निकालें"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"धारक को सक्रिय डिवाइस व्यवस्थापकों को जोड़ने या निकालने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"स्क्रीन अभिविन्यास बदलें"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्लिकेशन को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 836906a..31e1271 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodavanje ili uklanjanje administratora uređaja"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Omogućuje nositelju dodavanje ili uklanjanje administratora aktivnih uređaja. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"promjena orijentacije zaslona"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Omogućuje aplikaciji promjenu rotacije zaslona u bilo kojem trenutku. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"promjena brzine pokazivača"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5836c228..590cd50 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Lehetővé teszi az alkalmazás számára a képernyő elforgatásának bármikori módosítását. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"mutató sebességének módosítása"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e77dd17..c03ff0c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"menambah atau menghapus admin perangkat"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Memungkinkan pemegang menambahkan atau menghapus administrator perangkat aktif. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ubah orientasi layar"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Mengizinkan apl mengubah rotasi layar kapan saja. Tidak pernah dibutuhkan oleh apl normal."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ubah kecepatan penunjuk"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0156181..cc09561 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Consente all\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambio velocità del puntatore"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 30ee51b..96d873e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"הוספה או הסרה של מנהלי מכשיר"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"מאפשרת לבעלים להוסיף או להסיר מנהלי מכשיר פעילים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"שנה את כיוון המסך"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"מאפשר ליישום לשנות את הסיבוב של המסך בכל עת. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"שינוי מהירות המצביע"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index a4c7acb..7b995bf 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"いつでも画面の向きを変更することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ポインタの速度の変更"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index afee089..f897fc9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"앱이 언제든지 화면 회전을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"포인터 속도 변경"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8ed428d..2b7f59c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridėti arba pašalinti įrenginio administratorių"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Savininkui leidžiama pridėti aktyvių įrenginio administratorių arba juos pašalinti. Neturėtų reikėti įprastoms programoms."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"keisti ekrano padėtį"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Leidžiama programai bet kada kaitalioti ekraną. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"keisti žymiklio greitį"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 82d0038..c39e5972 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pievienot vai noņemt ierīces administratoru"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ļauj īpašniekam pievienot vai noņemt aktīvos ierīces administratorus. Nekad nav nepieciešama parastām lietotnēm."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"mainīt ekrāna orientāciju"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ļauj lietotnei jebkurā laikā mainīt ekrāna pozīciju. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Rādītāja ātruma mainīšana"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index db81e01..581e8cb0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -279,8 +279,8 @@
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"Membenarkan apl memindahkan tugasan ke latar depan dan latar belakang. Apl boleh melakukan ini tanpa input anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
- <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"urus susunan aktiviti"</string>
- <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Membenarkan apl menambah, membuang dan mengubah suai susunan aktiviti tempat apl lain berjalan. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
+ <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"urus tindanan aktiviti"</string>
+ <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Membenarkan apl menambah, mengalih keluar dan mengubah suai tindanan aktiviti tempat apl lain berjalan. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"mulakan sebarang aktiviti"</string>
<string name="permdesc_startAnyActivity" msgid="997823695343584001">"Membenarkan apl untuk memulakan apa-apa aktiviti, tanpa mengira perlindungan kebenaran atau keadaan eksport."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"tetapkan keserasian skrin"</string>
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Membenarkan apl untuk menukar putaran skrin pada bila-bila masa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"tukar kelajuan penuding"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index be87452..892abfc 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommuniser med enhetsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Gir appen tillatelse til når som helst å endre rotasjonen av skjermen. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"endre pekerhastighet"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 12ec61f..9058386 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Hiermee kan de app de rotatie van het scherm op elk moment wijzigen. Nooit vereist voor normale apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"aanwijzersnelheid wijzigen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 64227ed..5d92367 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Pozwala aplikacji na zmianę obrotu ekranu w dowolnym momencie. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmiana szybkości wskaźnika"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 35e10bc..c005ab5 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador de dispositivos"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o titular adicione ou remova administradores de dispositivos ativos. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"mudar orientação do ecrã"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que a aplicação altere a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar a veloc. do ponteiro"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5910c9b..f321d55 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que o aplicativo gire a tela a qualquer momento. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar velocidade do ponteiro"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 46fa378..72727ac1 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -279,10 +279,8 @@
<string name="permdesc_reorderTasks" msgid="7734217754877439351">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţia poate face acest lucru fără aportul dvs."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
- <!-- no translation found for permlab_manageActivityStacks (7391191384027303065) -->
- <skip />
- <!-- no translation found for permdesc_manageActivityStacks (1615881933034084440) -->
- <skip />
+ <string name="permlab_manageActivityStacks" msgid="7391191384027303065">"gestionarea grupurilor de activități"</string>
+ <string name="permdesc_manageActivityStacks" msgid="1615881933034084440">"Permite aplicației să adauge, să elimine și să modifice grupuri de activități în care rulează alte aplicații. Aplicațiile rău-intenționate pot perturba comportamentul altor aplicații."</string>
<string name="permlab_startAnyActivity" msgid="2918768238045206456">"începe orice activitate"</string>
<string name="permdesc_startAnyActivity" msgid="997823695343584001">"Permite aplicaţiei să înceapă orice activitate, indiferent de protecţia permisiunii şi de starea de export."</string>
<string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setaţi compatibilitatea ecranului"</string>
@@ -360,14 +358,10 @@
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei metode de introducere. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"conectare la un serviciu de accesibilitate"</string>
<string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu de accesibilitate. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <!-- no translation found for permlab_bindPrintService (8462815179572748761) -->
- <skip />
- <!-- no translation found for permdesc_bindPrintService (7960067623209111135) -->
- <skip />
- <!-- no translation found for permlab_accessAllPrintJobs (1120792468465711159) -->
- <skip />
- <!-- no translation found for permdesc_accessAllPrintJobs (2978185311041864762) -->
- <skip />
+ <string name="permlab_bindPrintService" msgid="8462815179572748761">"conectarea la un serviciu de printare"</string>
+ <string name="permdesc_bindPrintService" msgid="7960067623209111135">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de printare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+ <string name="permlab_accessAllPrintJobs" msgid="1120792468465711159">"acces la toate procesele de printare"</string>
+ <string name="permdesc_accessAllPrintJobs" msgid="2978185311041864762">"Permite proprietarului să acceseze procesele de printare create de o altă aplicație. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"conectare la un serviciu text"</string>
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Permite proprietarului să se conecteze la o interfaţă de nivel superior a unui serviciu text (de ex., SpellCheckerService). Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"conectare la un serviciu VPN"</string>
@@ -378,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite aplicaţiei să modifice rotaţia ecranului în orice moment. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"modifică viteza indicatorului"</string>
@@ -474,10 +466,8 @@
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite aplicaţiei să utilizeze funcţiile de nivel redus SurfaceFlinger."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"citire zonă tampon de cadre"</string>
<string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permite aplicaţiei să citească conţinutul zonei-tampon a cadrului."</string>
- <!-- no translation found for permlab_accessInputFlinger (5348635270689553857) -->
- <skip />
- <!-- no translation found for permdesc_accessInputFlinger (2104864941201226616) -->
- <skip />
+ <string name="permlab_accessInputFlinger" msgid="5348635270689553857">"acces la InputFlinger"</string>
+ <string name="permdesc_accessInputFlinger" msgid="2104864941201226616">"Permite aplicației să utilizeze funcțiile de nivel redus InputFlinger."</string>
<string name="permlab_configureWifiDisplay" msgid="5595661694746742168">"configurează afişaje Wi-Fi"</string>
<string name="permdesc_configureWifiDisplay" msgid="7916815158690218065">"Permite aplicaţiei să configureze şi să se conecteze la afişaje Wi-Fi."</string>
<string name="permlab_controlWifiDisplay" msgid="393641276723695496">"controlează afişaje Wi-Fi"</string>
@@ -647,18 +637,14 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite aplicaţiei să gestioneze politicile de reţea şi să definească regulile specifice aplicaţiilor."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificaţi modul de calcul al utilizării reţelei"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
- <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
- <skip />
- <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
- <skip />
+ <string name="permlab_markNetworkSocket" msgid="3658527214914959749">"modificarea mărcilor socketurilor"</string>
+ <string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permite aplicației să modifice mărcile socketurilor pentru rutare."</string>
<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. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
- <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
- <skip />
- <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
- <skip />
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</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>
@@ -768,8 +754,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <!-- no translation found for imProtocolGoogleTalk (493902321140277304) -->
- <skip />
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1531,102 +1516,56 @@
<string name="app_no_restricted_accounts" msgid="5739463249673727736">"Această aplicație nu acceptă conturi pentru profilurile cu permisiuni limitate"</string>
<string name="app_not_found" msgid="3429141853498927379">"Nicio aplicație pentru gestionarea acestei acțiuni"</string>
<string name="revoke" msgid="5404479185228271586">"Revocați"</string>
- <!-- no translation found for mediaSize_iso_a0 (7875427489420821793) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a1 (3760734499050875356) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a2 (5973266378020144382) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a3 (1373407105687300884) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a4 (6689772807982597254) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a5 (5353549652015741040) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a6 (8585038048674911907) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a7 (6641836716963839119) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a8 (7571139437465693355) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a9 (1378455891957115079) -->
- <skip />
- <!-- no translation found for mediaSize_iso_a10 (2480747457429475344) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b0 (3965935097661108039) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b1 (2505753285010115437) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b2 (8763874709859458453) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b3 (4210506688191764076) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b4 (5749404165888526034) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b5 (7640627414621904733) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b6 (7342988864712748544) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b7 (5069844065235382429) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b8 (7316818922278779774) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b9 (5414727094026532341) -->
- <skip />
- <!-- no translation found for mediaSize_iso_b10 (5251253731832048185) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c0 (4003138342671964217) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c1 (1935188063393553008) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c2 (3197307969712069904) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c3 (4335826087321913508) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c4 (3745639598281015005) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c5 (8269457765822791013) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c6 (566666105260346930) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c7 (8678413180782608498) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c8 (8392376206627041730) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c9 (9191613372324845405) -->
- <skip />
- <!-- no translation found for mediaSize_iso_c10 (7327709699184920822) -->
- <skip />
- <!-- no translation found for mediaSize_na_letter (4191805615829472953) -->
- <skip />
- <!-- no translation found for mediaSize_na_gvrnmt_letter (7853382192649405507) -->
- <skip />
- <!-- no translation found for mediaSize_na_legal (6697982988283823150) -->
- <skip />
- <!-- no translation found for mediaSize_na_junior_legal (3727743969902758948) -->
- <skip />
- <!-- no translation found for mediaSize_na_ledger (281871464896601236) -->
- <skip />
- <!-- no translation found for mediaSize_na_tabloid (5775966416333578127) -->
- <skip />
- <!-- no translation found for write_fail_reason_cancelled (7091258378121627624) -->
- <skip />
- <!-- no translation found for write_fail_reason_cannot_write (8132505417935337724) -->
- <skip />
- <!-- no translation found for restr_pin_enter_pin (3395953421368476103) -->
- <skip />
- <!-- no translation found for restr_pin_enter_old_pin (1462206225512910757) -->
- <skip />
- <!-- no translation found for restr_pin_enter_new_pin (5959606691619959184) -->
- <skip />
- <!-- no translation found for restr_pin_confirm_pin (8501523829633146239) -->
- <skip />
- <!-- no translation found for restr_pin_create_pin (8017600000263450337) -->
- <skip />
- <!-- no translation found for restr_pin_error_doesnt_match (2224214190906994548) -->
- <skip />
- <!-- no translation found for restr_pin_error_too_short (8173982756265777792) -->
- <skip />
- <!-- no translation found for restr_pin_countdown:one (4835639969503729874) -->
- <!-- no translation found for restr_pin_countdown:other (8030607343223287654) -->
+ <string name="mediaSize_iso_a0" msgid="7875427489420821793">"ISO A0"</string>
+ <string name="mediaSize_iso_a1" msgid="3760734499050875356">"ISO A1"</string>
+ <string name="mediaSize_iso_a2" msgid="5973266378020144382">"ISO A2"</string>
+ <string name="mediaSize_iso_a3" msgid="1373407105687300884">"ISO A3"</string>
+ <string name="mediaSize_iso_a4" msgid="6689772807982597254">"ISO A4"</string>
+ <string name="mediaSize_iso_a5" msgid="5353549652015741040">"ISO A5"</string>
+ <string name="mediaSize_iso_a6" msgid="8585038048674911907">"ISO A6"</string>
+ <string name="mediaSize_iso_a7" msgid="6641836716963839119">"ISO A7"</string>
+ <string name="mediaSize_iso_a8" msgid="7571139437465693355">"ISO A8"</string>
+ <string name="mediaSize_iso_a9" msgid="1378455891957115079">"ISO A9"</string>
+ <string name="mediaSize_iso_a10" msgid="2480747457429475344">"ISO A10"</string>
+ <string name="mediaSize_iso_b0" msgid="3965935097661108039">"ISO B0"</string>
+ <string name="mediaSize_iso_b1" msgid="2505753285010115437">"ISO B1"</string>
+ <string name="mediaSize_iso_b2" msgid="8763874709859458453">"ISO B2"</string>
+ <string name="mediaSize_iso_b3" msgid="4210506688191764076">"ISO B3"</string>
+ <string name="mediaSize_iso_b4" msgid="5749404165888526034">"ISO B4"</string>
+ <string name="mediaSize_iso_b5" msgid="7640627414621904733">"ISO B5"</string>
+ <string name="mediaSize_iso_b6" msgid="7342988864712748544">"ISO B6"</string>
+ <string name="mediaSize_iso_b7" msgid="5069844065235382429">"ISO B7"</string>
+ <string name="mediaSize_iso_b8" msgid="7316818922278779774">"ISO B8"</string>
+ <string name="mediaSize_iso_b9" msgid="5414727094026532341">"ISO B9"</string>
+ <string name="mediaSize_iso_b10" msgid="5251253731832048185">"ISO B10"</string>
+ <string name="mediaSize_iso_c0" msgid="4003138342671964217">"ISO C0"</string>
+ <string name="mediaSize_iso_c1" msgid="1935188063393553008">"ISO C1"</string>
+ <string name="mediaSize_iso_c2" msgid="3197307969712069904">"ISO C2"</string>
+ <string name="mediaSize_iso_c3" msgid="4335826087321913508">"ISO C3"</string>
+ <string name="mediaSize_iso_c4" msgid="3745639598281015005">"ISO C4"</string>
+ <string name="mediaSize_iso_c5" msgid="8269457765822791013">"ISO C5"</string>
+ <string name="mediaSize_iso_c6" msgid="566666105260346930">"ISO C6"</string>
+ <string name="mediaSize_iso_c7" msgid="8678413180782608498">"ISO C7"</string>
+ <string name="mediaSize_iso_c8" msgid="8392376206627041730">"ISO C8"</string>
+ <string name="mediaSize_iso_c9" msgid="9191613372324845405">"ISO C9"</string>
+ <string name="mediaSize_iso_c10" msgid="7327709699184920822">"ISO C10"</string>
+ <string name="mediaSize_na_letter" msgid="4191805615829472953">"Letter"</string>
+ <string name="mediaSize_na_gvrnmt_letter" msgid="7853382192649405507">"Government Letter"</string>
+ <string name="mediaSize_na_legal" msgid="6697982988283823150">"Legal"</string>
+ <string name="mediaSize_na_junior_legal" msgid="3727743969902758948">"Junior Legal"</string>
+ <string name="mediaSize_na_ledger" msgid="281871464896601236">"Ledger"</string>
+ <string name="mediaSize_na_tabloid" msgid="5775966416333578127">"Tabloid"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Anulat"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Eroare la scrierea conținutului"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Introduceți codul PIN"</string>
+ <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Codul PIN actual"</string>
+ <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Codul PIN nou"</string>
+ <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Confirmați noul cod PIN"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"Creați un cod PIN pentru modificarea restricțiilor"</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"Codurile PIN nu se potrivesc. Încercați din nou."</string>
+ <string name="restr_pin_error_too_short" msgid="8173982756265777792">"Codul PIN este prea scurt. Trebuie să aibă cel puțin 4 cifre."</string>
+ <plurals name="restr_pin_countdown">
+ <item quantity="one" msgid="4835639969503729874">"PIN incorect. Reîncercați în 1 sec."</item>
+ <item quantity="other" msgid="8030607343223287654">"PIN incorect. Reîncercați în <xliff:g id="COUNT">%d</xliff:g> sec."</item>
+ </plurals>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index aa11bb7..b3f1f94 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Приложение сможет менять ориентацию экрана. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Изменение скорости указателя"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e424e17..3ef8c86 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"pridanie alebo odstránenie správcu zariadenia"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umožňuje držiteľovi pridať alebo odstrániť správcov aktívnych zariadení. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"zmena orientácie obrazovky"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikácii kedykoľvek zmeniť otáčanie obrazovky. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmena rýchlosti ukazovateľa"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ca56c78..d93be86 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Programu omogoča, da kadar koli zasuka zaslon. Ne uporabljajte za navadne programe."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"spreminjanje hitrosti kazalca"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 39965849..2ae2103 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавање или уклањање администратора уређаја"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозвољава власнику да додаје или уклања активне администраторе уређаја. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"промена положаја екрана"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозвољава апликацији да у сваком тренутку промени ротацију екрана. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промена брзине показивача"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 96729f4..4f370b4 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lägga till eller ta bort en enhetsadministratör"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Innehavaren får lägga till eller ta bort aktiva enhetsadministratörer. Detta ska normalt inte behövas för vanliga appar."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Gör att appen när som helst kan ändra skärmläget. Behövs inte för vanliga appar."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ändra markörens hastighet"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d66a966..cbbdbf9 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Inaruhusu programu kubadilisha mzunguko wa skrini wakati wowote. Kamwe hazihitajiki kwa programu za kawaida."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Badilisha kasi ya pointa"</string>
@@ -1190,7 +1188,7 @@
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Usiruhusu Kamwe"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM kadi imeondolewa"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na SIM kadi halali iliyoingizwa."</string>
- <string name="sim_done_button" msgid="827949989369963775">"Kwisha"</string>
+ <string name="sim_done_button" msgid="827949989369963775">"Nimemaliza"</string>
<string name="sim_added_title" msgid="3719670512889674693">"SIM kadi imeongezwa"</string>
<string name="sim_added_message" msgid="6599945301141050216">"Anzisha upya kifaa chako ili kufikia mtandao wa simu."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Anza upya"</string>
@@ -1283,7 +1281,7 @@
<string name="ime_action_search" msgid="658110271822807811">"Tafuta"</string>
<string name="ime_action_send" msgid="2316166556349314424">"Tuma"</string>
<string name="ime_action_next" msgid="3138843904009813834">"Ifuatayo"</string>
- <string name="ime_action_done" msgid="8971516117910934605">"Kwisha"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"Nimemaliza"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"Iliyotangulia"</string>
<string name="ime_action_default" msgid="2840921885558045721">"Tekeleza"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Piga nambari "\n" kwa kutumia <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -1330,7 +1328,7 @@
<item quantity="one" msgid="8167147081136579439">"Linganisho 1"</item>
<item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ya <xliff:g id="TOTAL">%d</xliff:g>"</item>
</plurals>
- <string name="action_mode_done" msgid="7217581640461922289">"Kwisha"</string>
+ <string name="action_mode_done" msgid="7217581640461922289">"Nimemaliza"</string>
<string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Inaondoa hifadhi ya USB..."</string>
<string name="progress_unmounting" product="default" msgid="1327894998409537190">"Inaondoa kadi ya SD..."</string>
<string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Inafuta hifadhi ya USB..."</string>
@@ -1381,7 +1379,7 @@
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
- <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Imefanyika"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Nimemaliza"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -1456,7 +1454,7 @@
<string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
<string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
- <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string>
+ <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Nimemaliza"</string>
<string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Inatambaza..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Inaunganisha..."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3024e0d..9f194af 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"อนุญาตให้แอปพลิเคชันเปลี่ยนการหมุนของหน้าจอได้ตลอดเวลา ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"เปลี่ยนความเร็วของตัวชี้"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d338759..92369ff 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Pinapayagan ang app na baguhin ang pag-ikot ng screen anumang oras. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"baguhin ang bilis ng pointer"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 1fd4a36..fa0ee82 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Uygulamaya, istediği zaman ekran dönüşünü değiştirme izni verir. Normal uygulamalar için gerekli değildir."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"işaretçi hızını değiştir"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 23d01b1..cbe8a26 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозволяє програмі будь-коли змінювати обертання екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змінювати швидкість указівника"</string>
@@ -1567,7 +1565,7 @@
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-коди не збігаються. Повторіть спробу."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN-код закороткий. Має бути принаймні 4 цифри."</string>
<plurals name="restr_pin_countdown">
- <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с"</item>
- <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с"</item>
+ <item quantity="one" msgid="4835639969503729874">"Неправильний PIN. Повторіть через 1 с."</item>
+ <item quantity="other" msgid="8030607343223287654">"Неправильний PIN. Повторіть через <xliff:g id="COUNT">%d</xliff:g> с."</item>
</plurals>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e25b3a6..348b17e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Cho phép ứng dụng thay đổi độ xoay màn hình bất cứ lúc nào. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"thay đổi tốc độ con trỏ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0ff3456..8615b8b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"允许应用随时更改屏幕的旋转状态。普通应用绝不需要此权限。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"更改指针速度"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 009bb5c..b576c84 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"允許應用程式隨時變更螢幕旋轉狀態 (一般應用程式不需使用)。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"變更指標速度"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ccab02f..019a74a 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -372,10 +372,8 @@
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
- <!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
- <skip />
- <!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
- <skip />
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"engeza noma susa umlawuli wedivayisi"</string>
+ <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ivumela umnikazi ukuthi angeze noma asuse abalawuli bedivayisi esebenzayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"shintsha ukujikeleza kwesikrini"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela insiza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinsiza ezejwayelekile."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"guqula isivinini sesikhombi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8e86950..580a337 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -196,6 +196,7 @@
<item>"mobile_ims,11,0,2,60000,true"</item>
<item>"mobile_cbs,12,0,2,60000,true"</item>
<item>"wifi_p2p,13,1,0,-1,true"</item>
+ <item>"mobile_ia,14,0,2,-1,true"</item>
</string-array>
<!-- Array of ConnectivityManager.TYPE_xxxx constants for networks that may only
@@ -204,6 +205,7 @@
<item>10</item>
<item>11</item>
<item>12</item>
+ <item>14</item>
</integer-array>
<!-- This string array should be overridden by the device to present a list of radio
@@ -226,6 +228,7 @@
<item>10</item> <!-- TYPE_MOBILE_FOTA -->
<item>11</item> <!-- TYPE_MOBILE_IMS -->
<item>12</item> <!-- TYPE_MOBILE_CBS -->
+ <item>14</item> <!-- TYPE_MOBILE_IA -->
</integer-array>
<!-- The maximum duration (in milliseconds) we expect a network transition to take -->
@@ -535,7 +538,6 @@
<integer name="config_shutdownBatteryTemperature">680</integer>
<!-- Display low battery warning when battery level dips to this value -->
- <!-- Display low battery warning when battery level dips to this value -->
<integer name="config_lowBatteryWarningLevel">15</integer>
<!-- Close low battery warning when battery level reaches this value -->
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
deleted file mode 100644
index 0084969..0000000
--- a/data/keyboards/Vendor_0a5c_Product_8502.kl
+++ /dev/null
@@ -1,33 +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.
-
-# 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/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 2169c8e..c23ee10 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -299,6 +299,9 @@
# ------------------- TRAINING -------------------
+- from: /guide/topics/ui/layout/tabs.html
+ to: /training/implementing-navigation/lateral.html
+
- from: /training/cloudsync/aesync.html
to: /google/gcm/index.html
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index 985a266..5deb190 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -7,14 +7,7 @@
tab3.link=#android-41
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
+
<style>
#android-41 {display:none;}
diff --git a/docs/html/channels/io2013.jd b/docs/html/channels/io2013.jd
index b2bde31..977eb2f 100644
--- a/docs/html/channels/io2013.jd
+++ b/docs/html/channels/io2013.jd
@@ -1,15 +1,7 @@
fullpage=true
page.title=Google I/O 13
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
-
+
<style>
#ioplayer-frame {
z-index:10;
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index ab6bb1b..00f4467 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -1,13 +1,5 @@
page.title=Downloads
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div class="layout-content-row">
<div class="layout-content-col span-9">
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index d4ef07f..1e6b40c 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -2,14 +2,6 @@
header.hide=1
footer.hide=1
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<style>
#landing-graphic-container {
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 7e2337c..1833f24 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -4,14 +4,6 @@
carousel=1
tabbedList=1
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<style>
#noplayer-message {
@@ -140,7 +132,7 @@
<li><a href="//android-developers.blogspot.com/2013/07/beautiful-design-collection-summer-2013.html">
<div class="feed-image" style="background:url('//1.bp.blogspot.com/-k8DZYu0daT4/UdRt1AzstvI/AAAAAAAAAFM/CvEkb2yh-i0/s965/beautifulapps_4.png') no-repeat 0 0"></div>
<h4>The Beautiful Design Summer 2013 Collection</h4>
- <p>See the apps chosen by the Android Design for their masterfully crafted design details...</p>
+ <p>See the apps chosen by the Android Design team for their masterfully crafted design details...</p>
</a></li>
<li><a href="//android-developers.blogspot.com/2013/06/google-play-developer-8-step-checkup.html">
<div class="feed-image" style="background:url('//4.bp.blogspot.com/-LeK74UYY1eM/UbD8L-2DpFI/AAAAAAAACZA/YMjwndr-ZgM/s400/DoctorDroidV2.png') no-repeat 0 0;background-size:130px;background-position:8px -4px;"></div>
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
index 75cf9f9..ecdf2a8 100644
--- a/docs/html/distribute/distribute_toc.cs
+++ b/docs/html/distribute/distribute_toc.cs
@@ -80,6 +80,7 @@
<div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
<ul>
<li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
+ <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/games.html">Game Stories</a></li>
</ul>
</li>
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/googleplay/promote/badges.jd
index 93092bf..9a32921 100644
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ b/docs/html/distribute/googleplay/promote/badges.jd
@@ -1,13 +1,5 @@
page.title=Google Play Badges
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<p itemprop="description">Google Play badges allow you to promote your app with official branding
in your online ads, promotional materials, or anywhere else you want a link to your app.</p>
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/googleplay/promote/brand.jd
index a047b1f..265584f 100644
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ b/docs/html/distribute/googleplay/promote/brand.jd
@@ -1,13 +1,6 @@
page.title=Brand Guidelines
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
+
<p>We encourage you to use the Android and Google Play brands with your Android app
diff --git a/docs/html/distribute/googleplay/promote/index.jd b/docs/html/distribute/googleplay/promote/index.jd
index 14f37c4..6882990 100644
--- a/docs/html/distribute/googleplay/promote/index.jd
+++ b/docs/html/distribute/googleplay/promote/index.jd
@@ -3,14 +3,6 @@
header.hide=0
footer.hide=0
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<!--
<style>
diff --git a/docs/html/distribute/googleplay/promote/linking.jd b/docs/html/distribute/googleplay/promote/linking.jd
index 014582a..4fdc5db 100644
--- a/docs/html/distribute/googleplay/promote/linking.jd
+++ b/docs/html/distribute/googleplay/promote/linking.jd
@@ -1,13 +1,5 @@
page.title=Linking to Your Products
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div class="sidebox-wrapper">
<div class="sidebox">
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index dd35b25..5593f4f 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -1,14 +1,6 @@
page.title=Launch Checklist
page.tags="publishing","launch","Google Play", "Developer Console"
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div id="qv-wrapper"><div id="qv">
<h2>Checklist</h2>
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
index 3fd221c..9e23bcc 100644
--- a/docs/html/distribute/googleplay/quality/core.jd
+++ b/docs/html/distribute/googleplay/quality/core.jd
@@ -1,13 +1,5 @@
page.title=Core App Quality Guidelines
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div id="qv-wrapper"><div id="qv">
<h2>Quality Criteria</h2>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
index def42e5..ef537b1 100644
--- a/docs/html/distribute/googleplay/quality/index.jd
+++ b/docs/html/distribute/googleplay/quality/index.jd
@@ -1,13 +1,5 @@
page.title=App Quality
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<p>App quality directly influences the long-term success of your app—in
terms of installs, user rating and reviews, engagement, and user retention.
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
index c80c3cc..36e7345 100644
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ b/docs/html/distribute/googleplay/quality/tablet.jd
@@ -1,13 +1,5 @@
page.title=Tablet App Quality Checklist
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div id="qv-wrapper"><div id="qv">
<h2>Checklist</h2>
@@ -312,7 +304,7 @@
<td>144x144 px</td>
<td>96x96 px</td>
<td>48x48 px</td>
-<td>74x74 px</td>
+<td>72x72 px</td>
</tr>
</table>
diff --git a/docs/html/distribute/googleplay/spotlight/games.jd b/docs/html/distribute/googleplay/spotlight/games.jd
new file mode 100644
index 0000000..4e356db
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/games.jd
@@ -0,0 +1,245 @@
+page.title=Developer Stories: Google Play Game Services
+walkthru=0
+header.hide=0
+
+@jd:body
+
+<p>One of the goals of <a href="https://developers.google.com/games/">Google
+Play game services</a> is to allow developers to focus on what they’re good at
+as game developers — creating great gaming experiences for their users, by
+building on top of what Google is good at: mobile and cloud services. Integral
+to that is an easy integration process, one that provides a whole host of
+features with little engineering work required.</p>
+
+<p>The gaming studios below understood the opportunity that Google Play game
+services unlocked, and are starting to see real results following their
+successful integrations. </p>
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Concrete Software — Straightforward, easy to implement</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;"
+ src="//lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>,
+ makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
+ Bowling Challenge</a></li>
+ <li>Added support for multiplayer, leaderboards and achievements through Google Play game
+ services</li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>Session lengths have increased more than 15%</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
+ <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
+features from Google Play game services into one of their top titles,
+<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
+Bowling Challenge</a>, including support for multiplayer, leaderboards, and
+achievements.</p>
+
+<p>So far, their users have loved the new additions: average session length
+is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
+
+<p>"The Google Play game services were straightforward and easy to implement. We
+had been researching options for multiplayer services, so when Google Play game
+services came out, it was an easy decision for us. Not only were they easy to
+integrate, but the features have worked flawlessly. </p>
+
+<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
+were thrilled with; you can see in the reviews how people immediately raved about
+the new game experience. </p>
+
+<p>"We also included achievements, leaderboards, and most recently cloud
+synchronization from the Google Play game services as well. Using the game
+services in PBA Bowling Challenge was a huge success, enough so that we are now
+going back to our other titles, adding the features to them as well."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
+ After adding support for multiplayer with Google Play game services, Concrete
+ Software saw an increase in session lengths of more than 15% for PBA Bowling
+ Challenge.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+<h3>Glu: It’s a must-have for all titles</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 30px 20px;"
+ src="//lh5.ggpht.com/l20dR2HYLV8vECoC35q_0NdfaAGTe4lZIFy_wCJRDqZjeQqSgneLRpXi3qOnnCaLXA=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
+ Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+ Warriors 2</a></li>
+ <li>Has already integrated 5 titles with Google Play game services</li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
+ <li>20% increase in play sessions per day as well</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
+ <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
+to integrate Google Play game services, with
+<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+Warriors 2</a>. Based on this first success, Glu has integrated game services
+into several more games, including Samurai vs. Zombies 2, Frontline Commando:
+D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
+
+<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
+user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
+Vice President of Android Development, explains:</p>
+
+<p>“Multiplayer, leaderboards, achievements — these are all things that we
+had to build individually for our titles. The availability of these features in
+Google Play game services helps us make our games stickier, and it’s awesome that
+it comes directly from Google. </p>
+
+<p>"It’s flexible enough that we were able to make it interoperable with our
+in-house systems. We look forward to utilizing game services extensively across
+our portfolio."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
+ Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
+ integrating with Google Play game services.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Vector-Unit: An awesome multiplayer experience</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
+ Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+ GP2</a></li>
+ <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>With an easy multiplayer solution, they were able to focus on the
+ gameplay</li>
+ <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
+ cherries on top!”</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
+ <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
+latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+GP2</a>, with Google Play game services integration, and it has one of the strongest
+integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
+cherries on top!”.</p>
+
+<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
+services:</p>
+
+<p>“We wanted to provide a really compelling multiplayer experience for our users, and
+Google Play game services allowed us to do just that. With multiplayer, you can show off
+your skills and your custom-tuned hydro jet in 4-way online battles with friends and
+players around the world. </p>
+
+<p>"By providing an easy way to power this multiplayer experience, we were able to focus
+on making the gameplay come alive — like the stunts, which are more daring and
+slicker than ever (with more of them to master), or the realistic detail of the water
+splashing against the camera lens.”</p>
+
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
+ Google Play game services helped Vector Unit pack an awesome multiplayer experience
+ into Riptide GP 2, so they could focus on building a great gaming experience.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index 7004b0a..c599628 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -3,14 +3,7 @@
header.hide=0
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
+
<p>Android developers, their apps, and their successes with Android and Google Play. </p>
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 8e7c6e1..54f9301 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -2,14 +2,6 @@
header.hide=1
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div class="marquee">
diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/promote/device-art.jd
index 09a3941..89231b2 100644
--- a/docs/html/distribute/promote/device-art.jd
+++ b/docs/html/distribute/promote/device-art.jd
@@ -1,13 +1,5 @@
page.title=Device Art Generator
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<p>The device art generator allows you to quickly wrap your app screenshots in real device artwork.
This provides better visual context for your app screenshots on your web site or in other
@@ -47,7 +39,9 @@
</p>
</div>
<div class="layout-content-col span-10">
- <div id="output">No input image.</div>
+ <!-- position:relative fixes an issue where dragging an image out of a inline-block container
+ produced no drag feedback image in Chrome 28. -->
+ <div id="output" style="position:relative">No input image.</div>
</div>
</div>
@@ -143,6 +137,8 @@
// Global variables
var g_currentImage;
var g_currentDevice;
+ var g_currentObjectURL;
+ var g_currentBlob;
// Global constants
var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
@@ -267,14 +263,15 @@
return;
}
+ polyfillCanvasToBlob();
setupUI();
// Set up Chrome drag-out
$.event.props.push("dataTransfer");
document.body.addEventListener('dragstart', function(e) {
- var a = e.target;
- if (a.classList.contains('dragout')) {
- e.dataTransfer.setData('DownloadURL', a.dataset.downloadurl);
+ var target = e.target;
+ if (target.classList.contains('dragout')) {
+ e.dataTransfer.setData('DownloadURL', target.dataset.downloadurl);
}
}, false);
});
@@ -419,7 +416,7 @@
ctx.translate(-h, 0);
ctx.drawImage(g_currentImage, 0, 0);
- loadImageFromUri(canvas.toDataURL(), function(img) {
+ loadImageFromUri(canvas.toDataURL('image/png'), function(img) {
g_currentImage = img;
createFrame();
});
@@ -459,10 +456,10 @@
var resourceImages = {};
loadImageResources(resList, function(r) {
resourceImages = r;
- continuation_();
+ continueWithResources_();
});
- function continuation_() {
+ function continueWithResources_() {
var width = resourceImages['back'].naturalWidth;
var height = resourceImages['back'].naturalHeight;
var offset = port ? g_currentDevice.portOffset : g_currentDevice.landOffset;
@@ -486,17 +483,46 @@
ctx.drawImage(resourceImages['fore'], 0, 0);
}
- var dataUrl = canvas.toDataURL();
+ window.URL = window.URL || window.webkitURL;
+ if (canvas.toBlob && window.URL.createObjectURL) {
+ if (g_currentObjectURL) {
+ window.URL.revokeObjectURL(g_currentObjectURL);
+ g_currentObjectURL = null;
+ }
+ if (g_currentBlob) {
+ if (g_currentBlob.close) {
+ g_currentBlob.close();
+ }
+ g_currentBlob = null;
+ }
+
+ canvas.toBlob(function(blob) {
+ if (!blob) {
+ continueWithFinalUrl_(canvas.toDataURL('image/png'));
+ return;
+ }
+ g_currentBlob = blob;
+ g_currentObjectURL = window.URL.createObjectURL(blob);
+ continueWithFinalUrl_(g_currentObjectURL);
+ }, 'image/png');
+ } else {
+ continueWithFinalUrl_(canvas.toDataURL('image/png'));
+ }
+ }
+
+ function continueWithFinalUrl_(imageUrl) {
var filename = g_currentFilename
- ? ('framed_' + g_currentFilename)
+ ? g_currentFilename.replace(/^(.+?)(\.\w+)?$/, '$1_framed.png')
: 'framed_screenshot.png';
var $link = $('<a>')
.attr('download', filename)
- .attr('href', dataUrl)
- .attr('draggable', true)
- .attr('data-downloadurl', ['image/png', filename, dataUrl].join(':'))
- .append($('<img>').attr('src', dataUrl))
+ .attr('href', imageUrl)
+ .append($('<img>')
+ .addClass('dragout')
+ .attr('src', imageUrl)
+ .attr('draggable', true)
+ .attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
.appendTo($('#output').empty());
$('#frame-customizations').show();
@@ -566,14 +592,14 @@
var file = null;
for (var i = 0; i < fileList.length; i++) {
- if (fileList[i].type.toLowerCase().match(/^image\/png/)) {
+ if (fileList[i].type.toLowerCase().match(/^image\/(png|jpeg|jpg)/)) {
file = fileList[i];
break;
}
}
if (!file) {
- alert('Please use a valid screenshot file (PNG format).');
+ alert('Please use a valid screenshot file (PNG or JPEG format).');
callback(null);
return;
}
@@ -609,4 +635,28 @@
fileReader.readAsDataURL(file);
}
+
+ /**
+ * Adds a simple version of Canvas.toBlob if toBlob isn't available.
+ */
+ function polyfillCanvasToBlob() {
+ if (!HTMLCanvasElement.prototype.toBlob && window.Blob) {
+ HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, quality) {
+ if (typeof callback != 'function') {
+ throw new TypeError('Function expected');
+ }
+ var dataURL = this.toDataURL(mimeType, quality);
+ mimeType = dataURL.split(';')[0].split(':')[1];
+ var bs = window.atob(dataURL.split(',')[1]);
+ if (dataURL == 'data:,' || !bs.length) {
+ callback(null);
+ return;
+ }
+ for (var ui8arr = new Uint8Array(bs.length), i = 0; i < bs.length; ++i) {
+ ui8arr[i] = bs.charCodeAt(i);
+ }
+ callback(new Blob([ui8arr.buffer /* req'd for Safari */ || ui8arr], {type: mimeType}));
+ };
+ }
+ }
</script>
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index 095388e..4020cf4 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -1,14 +1,6 @@
page.title=Google Services
header.hide=1
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<style>
div.landing-cell,
diff --git a/docs/html/google/play-services/auth.jd b/docs/html/google/play-services/auth.jd
index 3ccc81a..7acaf1c 100644
--- a/docs/html/google/play-services/auth.jd
+++ b/docs/html/google/play-services/auth.jd
@@ -23,7 +23,7 @@
</p>
<p>For implementation details, see the sample in <code><android-sdk>/extras/google-play-services/samples/auth</code>,
-which shows you how to carry out these basic steps for obtaining an acesss token.</p>
+which shows you how to carry out these basic steps for obtaining an access token.</p>
<h2 id="choose">Choosing an Account</h2>
<p>
diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd
index d6b251e..c5b8461 100644
--- a/docs/html/google/play/billing/gp-purchase-status-api.jd
+++ b/docs/html/google/play/billing/gp-purchase-status-api.jd
@@ -118,13 +118,13 @@
the purchase itself using the Purchase Status API.</p>
<p>If the backend server determines that the purchase is valid, it notifies the
-app and grant access to the content. For improved performance, the backend servers
-should store the purchase details and order status in a local database, updated a
+app and grants access to the content. For improved performance, the backend servers
+should store the purchase details and order status in a local database, updated at
intervals or as-needed.</p>
-<p>Keep in mind that users will want to be able to use your app at any time, including
+<p>Keep in mind that users will want the ability to use your app at any time, including
when there may be no network connection available. Make sure that your approach to
-purchase verification takes account of the offline use-case.</p>
+purchase verification accounts for the offline use-case.</p>
<h2 id="practices">Using the API Efficiently</h2>
@@ -154,7 +154,7 @@
query each day to check the status of expiring subscriptions, then update the database.
Note that:
<ul>
- <li>Your servers should not query all subscriptions every day</li>
+ <li>Your servers should not query all subscriptions every day.</li>
<li>Your servers should never query subscription status dynamically, based on
individual requests from your Android application.</li>
</ul>
@@ -162,5 +162,6 @@
</ul>
<p>By following those general guidelines, your implementation will offer the
-best possible performance for users and minimize use of the Google Play Android
-Developer API.</p>
+best possible performance for users and minimize use of the <a
+href="https://developers.google.com/android-publisher/v1_1/">Google Play Android
+Developer API</a>.</p>
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index 0818514..481a79c 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -1,13 +1,5 @@
page.title=Google Play In-app Billing
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<p>In-app Billing is a Google Play service that lets you sell digital content from inside
your applications. You can use the service to sell a wide range of content, including downloadable
diff --git a/docs/html/guide/components/index.jd b/docs/html/guide/components/index.jd
index 6ede873..87bae53 100644
--- a/docs/html/guide/components/index.jd
+++ b/docs/html/guide/components/index.jd
@@ -4,14 +4,6 @@
page.landing.image=images/develop/app_components.png
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div class="landing-docs">
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index db08c3e..2a31374 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -146,9 +146,6 @@
<li><a href="<?cs var:toroot ?>guide/topics/ui/layout/grid.html">
<span class="en">Grid Layout</span>
</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/ui/layout/tabs.html">
- <span class="en">Tab Layout</span>
- </a></li>
-->
<li><a href="<?cs var:toroot ?>guide/topics/ui/layout/listview.html">
<span class="en">List View</span>
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 6398646..6586c2f 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -359,23 +359,6 @@
<p>Enables you to specify the location of child objects relative to each other (child A to
the left of child B) or to the parent (aligned to the top of the parent).</p>
</div>
-
-<!--
-<div class="layout">
- <h4><a href="layout/tabs.html">Tabs</a></h4>
- <a href="layout/tabs.html"><img src="{@docRoot}images/ui/tabs-small.png" alt="" /></a>
- <p>Provides a tab selection list that monitors clicks and enables the application to change
-the screen whenever a tab is clicked.</p>
-</div>
-
-<div class="layout first">
- <h4><a href="layout/grid.html">Table Layout</a></h4>
- <a href="layout/table.html"><img src="{@docRoot}images/ui/gridlayout-small.png" alt="" /></a>
- <p>A tabular layout with an arbitrary number of rows and columns, each cell holding the
-widget of your choice. The rows resize to fit the largest column. The cell borders are not
-visible.</p>
-</div>
--->
<div class="layout">
<h4><a href="{@docRoot}guide/webapps/webview.html">Web View</a></h4>
diff --git a/docs/html/guide/topics/ui/layout/tabs.jd b/docs/html/guide/topics/ui/layout/tabs.jd
deleted file mode 100644
index 62663de..0000000
--- a/docs/html/guide/topics/ui/layout/tabs.jd
+++ /dev/null
@@ -1,219 +0,0 @@
-page.title=Tabbed
-parent.title=Layouts
-parent.link=layout-objects.html
-@jd:body
-<div id="qv-wrapper">
-<div id="qv">
-<h2>In this document</h2>
- <ol>
- <li><a href="#example">Example</a></li>
- </ol>
- <h2>Key classes</h2>
- <ol>
-<li>{@link android.widget.TabWidget}</li>
-<li>{@link android.widget.TabHost}</li>
-<li>{@link android.widget.TabHost.TabSpec}</li>
-<li>{@link android.widget.FrameLayout}</li>
- </ol>
-</div>
-</div>
-<p>To create a tabbed UI, you need to use a {@link android.widget.TabHost} and a {@link
-android.widget.TabWidget}. The {@link android.widget.TabHost} must be the root node for the layout,
-which contains both the {@link android.widget.TabWidget} for displaying the tabs and a {@link
-android.widget.FrameLayout} for displaying the tab content.</p>
-
-<img src="{@docRoot}images/ui/tabs.png" alt="" />
-
-<p>You can implement your tab content in one of two ways: use the tabs to swap
-{@link android.view.View}s within the same {@link android.app.Activity}, or use the tabs to change
-between entirely separate activities. Which method you want for your application will depend on your
-demands, but if each tab provides a distinct user activity, then it probably makes sense to use
-a separate {@link android.app.Activity} for each tab, so that you can better manage the application
-in discrete groups, rather than one massive application and layout.</p>
-<h2 id="example">Example</h2>
-<p>In this tutorial, you'll create a tabbed UI that uses a separate {@link
-android.app.Activity} for each tab.</p>
-
-<ol>
- <li>Start a new project named <em>HelloTabWidget</em>.</li>
- <li>First, create three separate {@link android.app.Activity} classes in your project:
-<code>ArtistsActivity</code>, <code>AlbumsActivity</code>, and <code>SongsActivity</code>. These
-will each represent a separate tab. For now, make each one display a simple message using a {@link
-android.widget.TextView}. For example:
-<pre>
-public class ArtistsActivity extends Activity {
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- TextView textview = new TextView(this);
- textview.setText("This is the Artists tab");
- setContentView(textview);
- }
-}
-</pre>
- <p>Notice that this doesn't use a layout file. Just create a {@link
-android.widget.TextView}, give it some text and set that as the content. Duplicate this for
-each of the three activities, and add the corresponding <code><activity/></code> tags to the Android Manifest file.</p>
-
- <li>You need an icon for each of your tabs. For each icon, you should create two versions: one
-for when the tab is selected and one for when it is unselected. The
-general design recommendation is for the selected icon to be a dark color (grey), and the
-unselected icon to be a light color (white). (See the <a
-href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#tabstructure">Icon Design
-Guidelines</a>.) For example:
- <p>
- <img src="images/ic_tab_artists_white.png" title="unselected tab icon" alt="" />
- <img src="images/ic_tab_artists_grey.png" title="selected tab icon" alt="" />
- </p>
- <p>For this tutorial, you can copy these images and use them for all three tabs. (When you
-create tabs in your own application, you should create customized tab icons.)</p>
- <p>Now create a <a
-href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">state-list drawable</a>
-that specifies which image to use for each tab state:</p>
- <ol>
- <li>Save the icon images in your project <code>res/drawable/</code> directory.</li>
- <li>Create a new XML file in <code>res/drawable/</code>
-named <code>ic_tab_artists.xml</code> and insert the following:
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- When selected, use grey -->
- <item android:drawable="@drawable/ic_tab_artists_grey"
- android:state_selected="true" />
- <!-- When not selected, use white-->
- <item android:drawable="@drawable/ic_tab_artists_white" />
-</selector>
-</pre>
- <p>This is a <a
-href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">state-list drawable</a>,
-which you will apply as the tab image. When the tab state changes, the tab icon will
-automatically switch between the images defined here.</p>
- </li>
- </ol>
- </li>
-
- <li>Open the <code>res/layout/main.xml</code> file and insert the following:
- <pre>
-<?xml version="1.0" encoding="utf-8"?>
-<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/tabhost"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <LinearLayout
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp">
- <TabWidget
- android:id="@android:id/tabs"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
- <FrameLayout
- android:id="@android:id/tabcontent"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:padding="5dp" />
- </LinearLayout>
-</TabHost>
-</pre>
- <p>This is the layout that will display the tabs and provide navigation between each {@link
- android.app.Activity} created above.</p>
- <p>The {@link android.widget.TabHost} requires that a {@link android.widget.TabWidget} and a
-{@link android.widget.FrameLayout} both live somewhere within it. To position the {@link
-android.widget.TabWidget} and {@link android.widget.FrameLayout} vertically, a {@link
-android.widget.LinearLayout} is used. The {@link android.widget.FrameLayout} is where the content
-for each tab goes, which is empty now because the {@link android.widget.TabHost} will automatically
-embed each {@link android.app.Activity} within it.</p>
- <p>Notice that the {@link android.widget.TabWidget} and the {@link android.widget.FrameLayout}
- elements have the IDs {@code tabs} and {@code tabcontent}, respectively. These names
- must be used so that the {@link android.widget.TabHost} can retrieve references to each of
- them. It expects exactly these names.</p>
- </li>
-
- <li>Now open <code>HelloTabWidget.java</code> and make it extend {@link
- android.app.TabActivity}:</p>
-<pre>
-public class HelloTabWidget extends TabActivity {
-</pre>
- </li>
- <li>Use the following code for the {@link android.app.Activity#onCreate(Bundle) onCreate()}
- method:
-<pre>
-public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- Resources res = getResources(); // Resource object to get Drawables
- TabHost tabHost = getTabHost(); // The activity TabHost
- TabHost.TabSpec spec; // Resusable TabSpec for each tab
- Intent intent; // Reusable Intent for each tab
-
- // Create an Intent to launch an Activity for the tab (to be reused)
- intent = new Intent().setClass(this, ArtistsActivity.class);
-
- // Initialize a TabSpec for each tab and add it to the TabHost
- spec = tabHost.newTabSpec("artists").setIndicator("Artists",
- res.getDrawable(R.drawable.ic_tab_artists))
- .setContent(intent);
- tabHost.addTab(spec);
-
- // Do the same for the other tabs
- intent = new Intent().setClass(this, AlbumsActivity.class);
- spec = tabHost.newTabSpec("albums").setIndicator("Albums",
- res.getDrawable(R.drawable.ic_tab_albums))
- .setContent(intent);
- tabHost.addTab(spec);
-
- intent = new Intent().setClass(this, SongsActivity.class);
- spec = tabHost.newTabSpec("songs").setIndicator("Songs",
- res.getDrawable(R.drawable.ic_tab_songs))
- .setContent(intent);
- tabHost.addTab(spec);
-
- tabHost.setCurrentTab(2);
-}
-</pre>
- <p>This sets up each tab with their text and icon, and assigns each one an {@link
-android.app.Activity}.</p>
- <p>A reference to the {@link android.widget.TabHost} is first captured with {@link
-android.app.TabActivity#getTabHost()}. Then, for
-each tab, a {@link android.widget.TabHost.TabSpec} is created to define the tab properties. The
-{@link android.widget.TabHost#newTabSpec(String)} method creates a new {@link
-android.widget.TabHost.TabSpec} identified by the given string tag. For each
-{@link android.widget.TabHost.TabSpec}, {@link
-android.widget.TabHost.TabSpec#setIndicator(CharSequence,Drawable)} is called to set the text and
-icon for the tab, and {@link android.widget.TabHost.TabSpec#setContent(Intent)} is called to specify
-the {@link android.content.Intent} to open the appropriate {@link android.app.Activity}. Each
-{@link android.widget.TabHost.TabSpec} is then added to the {@link android.widget.TabHost} by
-calling {@link android.widget.TabHost#addTab(TabHost.TabSpec)}.</p>
-
- <p>At the very end, {@link
- android.widget.TabHost#setCurrentTab(int)} opens the tab to be displayed by default, specified
- by the index position of the tab.</p>
-
- <p>Notice that not once was the {@link android.widget.TabWidget} object referenced. This is
- because a {@link android.widget.TabWidget} must always be a child of a {@link
- android.widget.TabHost}, which is what you use for almost all interaction with the tabs. So when
- a tab is added to the {@link android.widget.TabHost}, it's automatically added to the child
- {@link android.widget.TabWidget}.</p>
- </li>
-
- <li>Now open the Android Manifest file and add the <code>NoTitleBar</code> theme to the
-<em>HelloTabWidget</em>'s
- <code><activity></code> tag. This will remove the default application title from the top
- of the layout, leaving more space for the tabs, which effectively operate as their own titles.
- The <code><activity></code> tag should look like this:
-<pre>
-<activity android:name=".HelloTabWidget" android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar">
-</pre>
- </li>
-
- <li>Run the application.</li>
-</ol>
-
-
-<p>Your application should look like this (though your icons may be different):</p>
-<img src="images/hello-tabwidget.png" width="150px" />
-
-
diff --git a/docs/html/images/distribute/concrete-pbc-gpgames.jpg b/docs/html/images/distribute/concrete-pbc-gpgames.jpg
new file mode 100644
index 0000000..c97ba8e
--- /dev/null
+++ b/docs/html/images/distribute/concrete-pbc-gpgames.jpg
Binary files differ
diff --git a/docs/html/images/distribute/glu-ew-gpgames.jpg b/docs/html/images/distribute/glu-ew-gpgames.jpg
new file mode 100644
index 0000000..8d97f8d
--- /dev/null
+++ b/docs/html/images/distribute/glu-ew-gpgames.jpg
Binary files differ
diff --git a/docs/html/images/distribute/vector-unit-rt-gpgames.jpg b/docs/html/images/distribute/vector-unit-rt-gpgames.jpg
new file mode 100644
index 0000000..323f188
--- /dev/null
+++ b/docs/html/images/distribute/vector-unit-rt-gpgames.jpg
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index a945f0a7..bbb6a16 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -3,14 +3,6 @@
carousel=true
page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
<div class="wrap">
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index aa3b2ec..4ea3752 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,43 +5,43 @@
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.linux32_bundle_download=adt-bundle-linux-x86-20130717.zip
-sdk.linux32_bundle_bytes=440035305
-sdk.linux32_bundle_checksum=ecfacb91df1ee63cce1edd4f1a5cda5a
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130729.zip
+sdk.linux32_bundle_bytes=457716139
+sdk.linux32_bundle_checksum=b3686d10dc1cbceba1074404d4386283
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130717.zip
-sdk.linux64_bundle_bytes=440322117
-sdk.linux64_bundle_checksum=ab177a06784340b8f1d136651e3dc62a
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130729.zip
+sdk.linux64_bundle_bytes=458006784
+sdk.linux64_bundle_checksum=1fabcc3f772ba8b2fc194d6e0449da17
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130717.zip
-sdk.mac64_bundle_bytes=411609229
-sdk.mac64_bundle_checksum=07c891212a49b5f8495ea9d8d47ba3fe
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130729.zip
+sdk.mac64_bundle_bytes=428792424
+sdk.mac64_bundle_checksum=6c42b9966abcfa8a75c0ee83d0d95882
-sdk.win32_bundle_download=adt-bundle-windows-x86-20130717.zip
-sdk.win32_bundle_bytes=446783216
-sdk.win32_bundle_checksum=0dd91095999d3539ca1ec4033d83d935
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130729.zip
+sdk.win32_bundle_bytes=463931746
+sdk.win32_bundle_checksum=51faf4e5fdf9c5b4a176179a99ce3511
-sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130717.zip
-sdk.win64_bundle_bytes=446911629
-sdk.win64_bundle_checksum=61ec74995b39166db7f079017a028cec
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130729.zip
+sdk.win64_bundle_bytes=464064756
+sdk.win64_bundle_checksum=e8f05c1fddb8e609e880de23113c7426
-sdk.linux_download=android-sdk_r22.0.4-linux.tgz
-sdk.linux_bytes=105640988
-sdk.linux_checksum=4a5db98a58c68c24e66f04f07ac77da5
+sdk.linux_download=android-sdk_r22.0.5-linux.tgz
+sdk.linux_bytes=105641005
+sdk.linux_checksum=8201b10c21510f082c54f58a9bb082c8
-sdk.mac_download=android-sdk_r22.0.4-macosx.zip
-sdk.mac_bytes=77225662
-sdk.mac_checksum=384752505f4f2ba3627bd6aad0697f11
+sdk.mac_download=android-sdk_r22.0.5-macosx.zip
+sdk.mac_bytes=77225724
+sdk.mac_checksum=94f3cbe896c332b94ee0408ae610a4b8
-sdk.win_download=android-sdk_r22.0.4-windows.zip
-sdk.win_bytes=113507679
-sdk.win_checksum=320b11d1ed85fd3f5e937697c333d895
+sdk.win_download=android-sdk_r22.0.5-windows.zip
+sdk.win_bytes=113510621
+sdk.win_checksum=30695dffc41e0d7cf9ff948ab0c48920
-sdk.win_installer=installer_r22.0.4-windows.exe
-sdk.win_installer_bytes=93502726
-sdk.win_installer_checksum=96a8ae367d84ed219e1eb2cf473667d0
+sdk.win_installer=installer_r22.0.5-windows.exe
+sdk.win_installer_bytes=93505782
+sdk.win_installer_checksum=940849be19ac6151e3e35c8706c81d86
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 2a09636..bdc07d0 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.0.4
-adt.zip.download=ADT-22.0.4.zip
-adt.zip.bytes=16838756
-adt.zip.checksum=f0291f4bb9d78ec34a7751cd2402cc2a
+adt.zip.version=22.0.5
+adt.zip.download=ADT-22.0.5.zip
+adt.zip.bytes=16839757
+adt.zip.checksum=1097fccf32063e3638a9d27aa0f295ca
@jd:body
diff --git a/docs/html/tools/extras/oem-usb.jd b/docs/html/tools/extras/oem-usb.jd
index 5e0e893..e0bbf33 100644
--- a/docs/html/tools/extras/oem-usb.jd
+++ b/docs/html/tools/extras/oem-usb.jd
@@ -227,7 +227,7 @@
<tr>
<td style="font-variant:small-caps">alcatel one touch</td>
<td><a
-href="http://www.alcatel-mobilephones.com/global/Android-Downloads">http://www.alcatel-mobilephones.com/global/Android-Downloads</a></td>
+href="http://www.alcatelonetouch.com/global-en/support/faq/usbdriver.html">http://www.alcatelonetouch.com/global-en/support/faq/usbdriver.html</a></td>
</tr>
<tr>
<td>Asus</td>
diff --git a/docs/html/tools/index.jd b/docs/html/tools/index.jd
index e9094a7..f9d452c 100644
--- a/docs/html/tools/index.jd
+++ b/docs/html/tools/index.jd
@@ -1,13 +1,6 @@
page.title=Developer Tools
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
+
<img src="{@docRoot}images/tools-home.png" style="float:right;" height="415" width="763" />
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 7b0b5a8..e9c514e 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -57,6 +57,41 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.0.5</a> <em>(July 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.0.5</a>.
+ If you haven't already installed SDK Tools r22.0.5 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed Renderscript compilation issue for Windows platforms.</li>
+ <li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> report generation
+ in the Monitor and DDMS perspectives.</li>
+ </ul>
+ </dd>
+
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.0.4</a> <em>(July 2013)</em>
</p>
@@ -66,11 +101,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 22.0.4.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 22.0.4.</li>
- <li>ADT 22.0.4 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r22.0.4</a>. If you haven't already installed SDK Tools r22.0.4 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.0.4</a>.
+ If you haven't already installed SDK Tools r22.0.4 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -102,11 +138,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 22.0.1.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 22.0.1.</li>
- <li>ADT 22.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r22.0.1</a>. If you haven't already installed SDK Tools r22 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.0.1</a>.
+ If you haven't already installed SDK Tools r22.0.1 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -138,11 +175,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 22.0.0.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 22.0.0.</li>
- <li>ADT 22.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r22</a>. If you haven't already installed SDK Tools r22 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22</a>.
+ If you haven't already installed SDK Tools r22 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -181,11 +219,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 21.1.0.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.1.0.</li>
- <li>ADT 21.1.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r21.1</a>. If you haven't already installed SDK Tools r21.1 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r21.1</a>.
+ If you haven't already installed SDK Tools r21.1 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -238,11 +277,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 21.0.1.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.0.1.</li>
- <li>ADT 21.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r21.0.1</a>. If you haven't already installed SDK Tools r21.0.1 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r21.0.1</a>.
+ If you haven't already installed SDK Tools r21.0.1 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -357,11 +397,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 20.0.3.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.0.0.</li>
- <li>ADT 21.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r21</a>. If you haven't already installed SDK Tools r21.0.0 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r21</a>.
+ If you haven't already installed SDK Tools r21.0.0 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -478,11 +519,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 20.0.3.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 20.0.3.</li>
- <li>ADT 20.0.3 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r20.0.3</a>. If you haven't already installed SDK Tools r20.0.3 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r20.0.3</a>.
+ If you haven't already installed SDK Tools r20.0.3 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -512,11 +554,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 20.0.2.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 20.0.2.</li>
- <li>ADT 20.0.2 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r20.0.1</a>. If you haven't already installed SDK Tools r20.0.1 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r20.0.1</a>.
+ If you haven't already installed SDK Tools r20.0.1 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -547,11 +590,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 20.0.1.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 20.0.1.</li>
- <li>ADT 20.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r20.0.1</a>. If you haven't already installed SDK Tools r20.0.1 into your SDK, use the
- Android SDK Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r20.0.1</a>.
+ If you haven't already installed SDK Tools r20.0.1 into your SDK, use the
+ Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -588,11 +632,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 20.0.0.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 20.0.0.</li>
- <li>ADT 20.0.0 is designed for use with <a href="{@docRoot}sdk/tools-notes.html">SDK Tools
- r20</a>. If you haven't already installed SDK Tools r20 into your SDK, use the Android SDK
- Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}sdk/tools-notes.html">SDK Tools r20</a>.
+ If you haven't already installed SDK Tools r20 into your SDK, use the Android SDK
+ Manager to do so.</li>
</ul>
</dd>
@@ -711,11 +756,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 18.0.0.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 18.0.0.</li>
- <li>ADT 18.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools
- r18</a>. If you haven't already installed SDK Tools r18 into your SDK, use the Android SDK
- Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r18</a>.
+ If you haven't already installed SDK Tools r18 into your SDK, use the Android SDK
+ Manager to do so.</li>
</ul>
</dd>
@@ -746,11 +792,12 @@
<dd>
<ul>
- <li>Java 1.6 or higher is required for ADT 17.0.0.</li>
- <li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 17.0.0.</li>
- <li>ADT 17.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools
- r17</a>. If you haven't already installed SDK Tools r17 into your SDK, use the Android SDK
- Manager to do so.</li>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Helios (Version 3.6.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r17</a>.
+ If you haven't already installed SDK Tools r17 into your SDK, use the Android SDK
+ Manager to do so.</li>
</ul>
</dd>
@@ -848,9 +895,10 @@
<dd>
<ul>
- <li>Eclipse Helios (Version 3.6) or higher is required for ADT 16.0.1.</li>
- <li>ADT 16.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools
- r16</a>. If you haven't already installed SDK Tools r16 into your SDK, use the Android SDK
+ <li>Eclipse Helios (Version 3.6) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r16</a>.
+ If you haven't already installed SDK Tools r16 into your SDK, use the Android SDK
Manager to do so.</li>
</ul>
</dd>
@@ -882,11 +930,11 @@
<dd>
<ul>
- <li>Eclipse Helios (Version 3.6) or higher is required for ADT
-16.0.0.</li>
- <li>ADT 16.0.0 is designed for use with <a
-href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r16</a>. If you haven't already installed SDK Tools
-r16 into your SDK, use the Android SDK Manager to do so.</li>
+ <li>Eclipse Helios (Version 3.6) or higher is required for ADT 16.0.0.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r16</a>.
+ If you haven't already installed SDK Tools r16 into your SDK, use
+ the Android SDK Manager to do so.</li>
</ul>
</dd>
@@ -913,9 +961,10 @@
<dl>
<dt>Dependencies:</dt>
- <dd>ADT 15.0.1 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r15</a>.
- If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
- do so.</dd>
+ <dd>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r15</a>.
+ If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
+ do so.</dd>
<dt>Bug fixes:</dt>
<dd>
@@ -948,9 +997,10 @@
<dt>Dependencies:</dt>
-<dd>ADT 15.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r15</a>.
-If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
-do so.</dd>
+<dd>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r15</a>.
+ If you haven't already installed SDK Tools r15 into your SDK, use the Android SDK Manager to
+ do so.</dd>
<dt>Bug fixes:</dt>
<dd>
@@ -980,9 +1030,10 @@
<dt>Dependencies:</dt>
-<dd>ADT 14.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r14</a>.
-If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK Manager to
-do so.</dd>
+<dd>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r14</a>.
+ If you haven't already installed SDK Tools r14 into your SDK, use the Android SDK Manager to
+ do so.</dd>
<dt>Build system:</dt>
<dd>
@@ -1099,7 +1150,8 @@
<dt>Dependencies:</dt>
-<dd>ADT 12.0.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r12</a>. If you haven't
+<dd>This version of ADT is designed for use with
+<a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r12</a>. If you haven't
already installed SDK Tools r12 into your SDK, use
the Android SDK Manager to do so.</dd>
@@ -1152,7 +1204,7 @@
<dt>Dependencies:</dt>
-<dd>ADT 11.0.0 is designed for use with SDK Tools r11. If you haven't
+<dd>This version of ADT is designed for use with SDK Tools r11. If you haven't
already installed SDK Tools r11 into your SDK, use the Android SDK Manager to do
so.</dd>
@@ -1289,7 +1341,7 @@
<dt>Dependencies:</dt>
-<dd>ADT 10.0.1 is designed for use with SDK Tools r10. If you haven't
+<dd>This version of ADT is designed for use with SDK Tools r10. If you haven't
already installed SDK Tools r10 into your SDK, use the Android SDK Manager to do
so.</dd>
@@ -1319,7 +1371,7 @@
<dt>Dependencies:</dt>
-<dd>ADT 10.0.0 is designed for use with SDK Tools r10. If you haven't
+<dd>This version of ADT is designed for use with SDK Tools r10. If you haven't
already installed SDK Tools r10 into your SDK, use the Android SDK Manager to do
so.</dd>
@@ -1369,7 +1421,7 @@
<dt>Dependencies:</dt>
-<dd>ADT 9.0.0 is designed for use with SDK Tools r9. If you haven't
+<dd>This version of ADT is designed for use with SDK Tools r9. If you haven't
already installed SDK Tools r9 into your SDK, use the Android SDK Manager to do
so.</dd>
@@ -1478,7 +1530,7 @@
<dt>Dependencies:</dt>
-<p><p>ADT 8.0.1 is designed for use with SDK Tools r8. If you haven't
+<p>This version of ADT is designed for use with SDK Tools r8. If you haven't
already installed SDK Tools r8 into your SDK, use the Android SDK Manager to do
so.</p></dd>
@@ -1507,7 +1559,7 @@
<dt>Dependencies:</dt>
-<p><p>ADT 8.0.0 is designed for use with SDK Tools r8. If you haven't
+<p>This version of ADT is designed for use with SDK Tools r8. If you haven't
already installed SDK Tools r8 into your SDK, use the Android SDK Manager to do
so.</p></dd>
@@ -1656,7 +1708,7 @@
<dl>
<dt>Dependencies:</dt>
-<dd><p>ADT 0.9.6 is designed for use with SDK Tools r5 and later. Before
+<dd><p>This version of ADT is designed for use with SDK Tools r5 and later. Before
updating to ADT 0.9.6, we highly recommend that you use the Android SDK Manager to install SDK
Tools r5 into your SDK.</p></dd>
@@ -1725,7 +1777,7 @@
<dl>
<dt>Dependencies:</dt>
-<dd><p>ADT 0.9.5 requires features provided in SDK Tools r4 or higher. If you install
+<dd><p>This version of ADT requires features provided in SDK Tools r4 or higher. If you install
ADT 0.9.5, which is highly recommended, you should use the Android SDK
Manager to download the latest SDK Tools into your SDK. For more information,
see <a href="{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</p>
@@ -1755,7 +1807,7 @@
<dl>
<dt>Dependencies:</dt>
-<dd><p>ADT 0.9.4 requires features provided in SDK Tools r3 or higher. If you install
+<dd><p>This version of ADT requires features provided in SDK Tools r3 or higher. If you install
ADT 0.9.4, which is highly recommended, you should use the Android SDK
Manager to download the latest SDK Tools into your SDK. For more information,
see <a href="{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index 318764e..61a91a8 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -63,7 +63,7 @@
<div id="tos" style="display:none;width:760px;height:0;margin:0 auto">
-<div class="ndk" style="
+<div id="download" class="ndk" style="
z-index: 99;
width: 720px;
position: absolute;
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index cd2d986..4aef8a0 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -26,9 +26,50 @@
href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
+
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.0.5</a> <em>(July 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 16 or later.</li>
+ <li>If you are developing in Eclipse with the
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a>, note that this version of
+ SDK Tools is designed for use with ADT 22.0.5 and later. If you haven't already, update
+ ADT to 22.0.5.</li>
+ <li>If you are using <a href="{@docRoot}sdk/installing/studio.html">Android Studio</a>,
+ note that this version of the SDK Tools is designed to work with Android Studio
+ 0.2.x and later.</li>
+ <li>If you are developing without an integrated development environment (IDE), you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed Renderscript compilation issue for Windows platforms with ant.</li>
+ <li>Updated <a href="{@docRoot}tools/help/systrace.html">Systrace</a> to work with the
+ Android 4.3 platform image.</li>
+ <li>Fixed packaging of Renderscript compiler.</li>
+ <li>Build tools 18.0.0 is obsolete and 18.0.1 should be used instead.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.0.4</a> <em>(July 2013)</em>
</p>
@@ -75,7 +116,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r22.0.1 is
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 22.0.1 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.0.1.</li>
<li>If you are developing outside Eclipse, you must have
@@ -116,7 +157,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r22 is
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 22.0.0 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -171,7 +212,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1 is
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 21.1.0 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.1.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -206,7 +247,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.0.1 is
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 21.0.1 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.1.</li>
<li>If you are developing outside Eclipse, you must have
@@ -309,7 +350,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21 is designed
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed
for use with ADT 21.0.0 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -395,7 +436,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 12 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r20.0.3 is designed
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed
for use with ADT 20.0.3 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 20.0.3.</li>
<li>If you are developing outside Eclipse, you must have
@@ -426,7 +467,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 12 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r20.0.1 is designed
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed
for use with ADT 20.0.1 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 20.0.1.</li>
<li>If you are developing outside Eclipse, you must have
@@ -462,7 +503,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 12 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r20 is designed for
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for
use with ADT 20.0.0 and later. If you haven't already, we highly recommend updating your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 20.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -540,7 +581,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 9 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r19 is designed for
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for
use with ADT 18.0.0 and later. If you haven't already, we highly recommend updating your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 18.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -575,7 +616,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 9 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r18 is designed for
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for
use with ADT 18.0.0 and later. If you haven't already, we highly recommend updating your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 18.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -617,7 +658,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 9 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r17 is designed for
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for
use with ADT 17.0.0 and later. If you haven't already, we highly recommend updating your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 17.0.0.</li>
<li>If you are developing outside Eclipse, you must have
@@ -721,7 +762,7 @@
<dd>
<ul>
<li>Android SDK Platform-tools revision 9 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r16 is designed for use
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use
with ADT 16.0.0 and later. If you haven't already, we highly recommend updating your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 16.0.0.</li>
<li>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
@@ -769,7 +810,7 @@
<dt>Dependencies:</dt>
<dd>
<ul><li>Android SDK Platform-tools revision 9 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r15 is designed for use
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use
with ADT 15.0.0 and later. If you haven't already, we highly recommend updating your <a
href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 15.0.0.</li>
<li>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
@@ -817,7 +858,7 @@
<dt>Dependencies:</dt>
<dd>
<ul><li>Android SDK Platform-tools revision 8 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r14 is designed for use
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use
with ADT 14.0.0 and later. If you haven't already, we highly recommend updating your <a
href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 14.0.0.</li>
<li>If you are developing outside Eclipse, you must have <a href="http://ant.apache.org/">Apache
@@ -867,7 +908,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that the SDK Tools r13 is designed for use with
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use with
ADT 12.0.0 and later. If you haven't already, we highly recommend updating your <a
href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 12.0.0.</p>
@@ -898,7 +939,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that the SDK Tools r12 is designed for use with
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use with
ADT 12.0.0 and later. If you haven't already, we highly recommend updating your <a
href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 12.0.0.</p>
@@ -926,7 +967,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that the SDK Tools r11 is designed for use with
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is designed for use with
ADT 10.0.1 and later. If you haven't already, we highly recommend updating your <a
href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 10.0.1.</p>
@@ -954,7 +995,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that the SDK Tools r10 is
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 10.0.0 and later. After installing SDK Tools r10, we
highly recommend updating your ADT Plugin to 10.0.0.</p>
@@ -985,7 +1026,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that the SDK Tools r9 is
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 9.0.0 and later. After installing SDK Tools r9, we
highly recommend updating your ADT Plugin to 9.0.0.</p>
@@ -1044,7 +1085,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that SDK Tools r8 is
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 8.0.0 and later. After installing SDK Tools r8, we
highly recommend updating your ADT Plugin to 8.0.0.</p>
@@ -1112,7 +1153,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that SDK Tools r7 is
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 0.9.8 and later. After installing SDK Tools r7, we
highly recommend updating your ADT Plugin to 0.9.8.</p>
</dd>
@@ -1146,7 +1187,7 @@
<dl>
<dt>Dependencies:</dt>
<dd>
-<p>If you are developing in Eclipse with ADT, note that SDK Tools r6 is
+<p>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 0.9.7 and later. After installing SDK Tools r6, we
highly recommend updating your ADT Plugin to 0.9.7.</p>
</dd>
@@ -1177,7 +1218,7 @@
<dl>
<dt>Dependencies:</dt>
<dd><ul>
-<li>If you are developing in Eclipse with ADT, note that SDK Tools r5 is
+<li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
designed for use with ADT 0.9.6 and later. After installing SDK Tools r5, we
highly recommend updating your ADT Plugin to 0.9.6.</li>
<li>For Mac OS platforms, OS X 10.4.x (Tiger) is no longer
@@ -1225,7 +1266,7 @@
<div class="toggle-content-toggleme">
<dl>
<dt>Dependencies:</dt>
-<dd><p>SDK Tools r4 is compatible with ADT 0.9.5 and later, but not
+<dd><p>This version of SDK Tools is compatible with ADT 0.9.5 and later, but not
compatible with earlier versions. If you are developing in Eclipse with ADT, you
<strong>must</strong> update your ADT plugin to version 0.9.5 or higher if you
install SDK Tools r4 in your SDK. </p></dd>
@@ -1275,7 +1316,7 @@
<div class="toggle-content-toggleme">
<dl>
<dt>Dependencies:</dt>
-<dd><p>SDK Tools r3 is compatible with ADT 0.9.4 and later, but not
+<dd><p>This version of SDK Tools is compatible with ADT 0.9.4 and later, but not
compatible with earlier versions. If you are developing in Eclipse with ADT, you
<strong>must</strong> update your ADT plugin to version 0.9.4 or higher if you
install SDK Tools r3 in your SDK.</p>
@@ -1329,4 +1370,3 @@
</dl>
</div>
</div>
-
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 12fc0ae..8d25d96 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -12,6 +12,7 @@
<ol>
<li><a href="#v7-appcompat">v7 appcompat library</a></li>
<li><a href="#v7-gridlayout">v7 gridlayout library</a></li>
+ <li><a href="#v7-mediarouter">v7 mediarouter library</a></li>
</ol>
</li>
<li><a href="#v13">v13 Support Library</a></li>
@@ -148,7 +149,6 @@
<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
-
<h2 id="v7">v7 Libraries</h2>
<p>There are several libraries designed to be used with Android 2.1 (API level 7) and higher.
@@ -197,9 +197,7 @@
com.android.support:appcompat-v7:18.0.+
</pre>
-<p>This dependency notation specifies release version 18.0.0 or higher.</p>
-
-
+<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
<h3 id="v7-gridlayout">v7 gridlayout library</h3>
@@ -220,7 +218,48 @@
com.android.support:gridlayout-v7:18.0.+
</pre>
-<p>This dependency notation specifies release version 18.0.0 or higher.</p>
+<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
+
+<h3 id="v7-mediarouter">v7 mediarouter library</h3>
+
+<p>This library provides {@link android.support.v7.media.MediaRouter}, {@link
+android.support.v7.media.MediaRouteProvider}, and related media classes that
+support the <a href="https://developers.google.com/cast/">Google Cast
+developer preview</a>. </p>
+
+<p>In general, the APIs in the v7 mediarouter library provide a means of
+controlling the routing of media channels and streams from the current device to
+external screens, speakers, and other destination devices. The library includes
+APIs for publishing app-specific media route providers, for discovering and
+selecting destination devices, for checking media status, and more. For detailed
+information about the v7 mediarouter library APIs, see the
+{@link android.support.v7.media android.support.v7.media} package in the API
+reference.</p>
+
+<p>The v7 mediarouter library is located in the
+<code><sdk>/extras/android/support/v7/mediarouter/</code> directory after
+you download the Android Support Library. It's provided as a library project
+with a dependency on the v7 appcompat library, so you'll need to include both
+libraries in your build path when setting up your project. For more information
+on how to set up your project, follow the instructions in <a
+href="{@docRoot}tools/support-library/setup.html#libs-with-res">adding libraries
+with resources</a>. If you are developing in Eclipse/ADT, make sure to include
+both the <code>android-support-v7-mediarouter.jar</code> and
+<code>android-support-v7-appcompat.jar</code> files.</p>
+
+<p>If you are using Android Studio, all you need to do is specify the Gradle build
+script dependency identifier <code>com.android.support:support-v7-mediarouter:<revision></code>,
+where "18.0.0" is the minimum revision at which the library is available. For example:</p>
+
+<pre>
+com.android.support:support-v7-mediarouter:18.0.0
+</pre>
+
+<p class="caution">The v7 mediarouter library APIs introduced in Support Library
+r18 are subject to change in later revisions of the Support Library. At this
+time, we recommend using the library only in connection with the <a
+href="https://developers.google.com/cast/">Google Cast
+developer preview</a>. </p>
<h2 id="v13">v13 Support Library</h2>
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 87ed7f1..06c7a3f 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -22,8 +22,7 @@
</div>
</div>
-<p>The Android Support Library package is a set of code libraries that provide useful and important
- features for Android applications in addition to the framework APIs. These libraries provide
+<p>The Android Support Library package is a set of code libraries that provide
backward-compatible versions of Android framework APIs as well as features that are only available
through the library APIs. Each Support Library is backward-compatible to a specific Android API
level. This design means that your applications can use the libraries' features and still be
@@ -36,7 +35,8 @@
<h2 id="overview">Overview</h2>
<p>Including the Support Libraries in your Android project is considered a best practice for
- application developers. Using the features they provide can help you improve the look of your
+ application developers, depending on the range of platform versions your app is targeting
+ and the APIs that it uses. Using the features the libraries provide can help you improve the look of your
application, increase performance and broaden the reach of your application to more users.
If you use the Android
<a href="{@docRoot}tools/projects/templates.html">code template</a> tools, you will notice that
@@ -136,6 +136,24 @@
</ul>
</dd>
+ <dt>New v7 mediarouter library:</dt>
+ <dd>
+ <p>Added a new mediarouter library that provides support for the <a
+ href="https://developers.google.com/cast/">Google Cast developer preview</a>.
+ The v7 mediarouter library APIs provide a means of controlling the routing of
+ media channels and streams from the current device to external screens,
+ speakers, and other destination devices, with compatibility back to Android 2.1
+ (API level 7). See <a
+ href="{@docRoot}tools/support-library/features.html#v7-mediarouter">V7
+ mediarouter library</a> for more information. </p>
+
+ <p class="caution">The v7 mediarouter library APIs introduced in Support
+ Library r18 are subject to change in later revisions of the Support
+ Library. At this time, we recommend using the library only in connection
+ with the <a href="https://developers.google.com/cast/">Google Cast
+ developer preview</a>.</p>
+ </dd>
+
</dl>
</div>
</div>
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 37a06f1..1646b91 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -172,7 +172,7 @@
<h2 id="StartActivity">Start an Activity with the Intent</h2>
-<div class="figure" style="width:200px">
+<div class="figure" style="width:200px;margin-top:-10px">
<img src="{@docRoot}images/training/basics/intents-choice.png" alt="" />
<p class="img-caption"><strong>Figure 1.</strong> Example of the selection dialog that appears
when more than one app can handle an intent.</p>
@@ -211,11 +211,9 @@
<h2 id="AppChooser">Show an App Chooser</h2>
-<div class="figure" style="width:200px">
+<div class="figure" style="width:200px;margin-top:-10px">
<img src="{@docRoot}images/training/basics/intent-chooser.png" alt="" />
- <p class="img-caption"><strong>Figure 2.</strong> Example of the chooser dialog that appears
-when you use {@link android.content.Intent#createChooser createChooser()} to ensure
-that the user is always shown a list of apps that respond to your intent.</p>
+ <p class="img-caption"><strong>Figure 2.</strong> A chooser dialog.</p>
</div>
<p>Notice that when you start an activity by passing your {@link android.content.Intent} to {@link
@@ -223,11 +221,13 @@
the intent, the user can select which app to use by default (by selecting a checkbox at the bottom
of the dialog; see figure 1). This is nice when performing an action for which the user
generally wants to use the same app every time, such as when opening a web page (users
-likely use just one web browser) or taking a photo (users likely prefer one camera). However, if
-the action to be performed could be handled by multiple apps and the user might
+likely use just one web browser) or taking a photo (users likely prefer one camera).</p>
+
+<p>However, if the action to be performed could be handled by multiple apps and the user might
prefer a different app each time—such as a "share" action, for which users might have several
-apps through which they might share an item—you should explicitly show a chooser dialog,
-which forces the user to select which app to use for the action every time (the user cannot select a
+apps through which they might share an item—you should explicitly show a chooser dialog
+as shown in figure 2. The chooser dialog
+forces the user to select which app to use for the action every time (the user cannot select a
default app for the action).</p>
<p>To show the chooser, create an {@link android.content.Intent} using {@link
@@ -238,8 +238,9 @@
Intent intent = new Intent(Intent.ACTION_SEND);
...
-// Always use string resources for UI text. This says something like "Share this photo with"
-String title = getResources().getText(R.string.chooser_title);
+// Always use string resources for UI text.
+// This says something like "Share this photo with"
+String title = (String) getResources().getText(R.string.chooser_title);
// Create and start the chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index b1608c3..25efe1e 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -324,14 +324,14 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
...
- RetainFragment mRetainFragment =
+ RetainFragment retainFragment =
RetainFragment.findOrCreateRetainFragment(getFragmentManager());
- mMemoryCache = RetainFragment.mRetainedCache;
+ mMemoryCache = retainFragment.mRetainedCache;
if (mMemoryCache == null) {
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
... // Initialize cache here as usual
}
- mRetainFragment.mRetainedCache = mMemoryCache;
+ retainFragment.mRetainedCache = mMemoryCache;
}
...
}
diff --git a/docs/html/training/index.jd b/docs/html/training/index.jd
index 82fbd16..72ad018 100644
--- a/docs/html/training/index.jd
+++ b/docs/html/training/index.jd
@@ -3,14 +3,7 @@
page.metaDescription=Android Training provides a collection of classes that aim to help you build great apps for Android. Each class explains the steps required to solve a problem or implement a feature using code snippets and sample code for you to use in your apps.
@jd:body
-<div id="butterbar-wrapper" >
- <div id="butterbar" >
- <div id="butterbar-message">
-<a target="_blank" href="https://docs.google.com/a/google.com/forms/d/1EHLPGqhbxj2HungHRRN4_0K9TGpc-Izy-u46vBDgS8Q/viewform">
- Take the Android Developer Survey</a>
- </div>
- </div>
-</div>
+
<p>Welcome to Training for Android developers. Here you'll find sets of lessons within classes
that describe how to accomplish a specific task with code samples you can re-use in your app.
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index d64006d..7f2d9c1 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -90,13 +90,13 @@
* <pre> y_size = stride * height </pre>
*
* <p>For example, the {@link android.media.Image} object can provide data
- * in this format from a {@link android.hardware.photography.CameraDevice}
+ * in this format from a {@link android.hardware.camera2.CameraDevice}
* through a {@link android.media.ImageReader} object if this format is
- * supported by {@link android.hardware.photography.CameraDevice}.</p>
+ * supported by {@link android.hardware.camera2.CameraDevice}.</p>
*
* @see android.media.Image
* @see android.media.ImageReader
- * @see android.hardware.photography.CameraDevice
+ * @see android.hardware.camera2.CameraDevice
*
* @hide
*/
@@ -120,13 +120,13 @@
* <pre> y_size = stride * height </pre>
*
* <p>For example, the {@link android.media.Image} object can provide data
- * in this format from a {@link android.hardware.photography.CameraDevice}
+ * in this format from a {@link android.hardware.camera2.CameraDevice}
* through a {@link android.media.ImageReader} object if this format is
- * supported by {@link android.hardware.photography.CameraDevice}.</p>
+ * supported by {@link android.hardware.camera2.CameraDevice}.</p>
*
* @see android.media.Image
* @see android.media.ImageReader
- * @see android.hardware.photography.CameraDevice
+ * @see android.hardware.camera2.CameraDevice
*
* @hide
*/
@@ -172,12 +172,12 @@
* for each plane.</p>
*
* <p>For example, the {@link android.media.Image} object can provide data
- * in this format from a {@link android.hardware.photography.CameraDevice}
+ * in this format from a {@link android.hardware.camera2.CameraDevice}
* through a {@link android.media.ImageReader} object.</p>
*
* @see android.media.Image
* @see android.media.ImageReader
- * @see android.hardware.photography.CameraDevice
+ * @see android.hardware.camera2.CameraDevice
*/
public static final int YUV_420_888 = 0x23;
@@ -189,7 +189,7 @@
* <p>The layout of the color mosaic, the maximum and minimum encoding
* values of the raw pixel data, the color space of the image, and all other
* needed information to interpret a raw sensor image must be queried from
- * the {@link android.hardware.photography.CameraDevice} which produced the
+ * the {@link android.hardware.camera2.CameraDevice} which produced the
* image.</p>
*/
public static final int RAW_SENSOR = 0x20;
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 157c7d1..ef858eb 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -103,21 +103,106 @@
}
}
- /** Enum for the ways a path may be filled
- */
+ /**
+ * The logical operations that can be performed when combining two paths.
+ *
+ * @see #op(Path, android.graphics.Path.Op)
+ * @see #op(Path, Path, android.graphics.Path.Op)
+ */
+ public enum Op {
+ /**
+ * Subtract the second path from the first path.
+ */
+ DIFFERENCE,
+ /**
+ * Intersect the two paths.
+ */
+ INTERSECT,
+ /**
+ * Union (inclusive-or) the two paths.
+ */
+ UNION,
+ /**
+ * Exclusive-or the two paths.
+ */
+ XOR,
+ /**
+ * Subtract the first path from the second path.
+ */
+ REVERSE_DIFFERENCE
+ }
+
+ /**
+ * Set this path to the result of applying the Op to this path and the specified path.
+ * The resulting path will be constructed from non-overlapping contours.
+ * The curve order is reduced where possible so that cubics may be turned
+ * into quadratics, and quadratics maybe turned into lines.
+ *
+ * @param path The second operand (for difference, the subtrahend)
+ *
+ * @return True if operation succeeded, false otherwise and this path remains unmodified.
+ *
+ * @see Op
+ * @see #op(Path, Path, android.graphics.Path.Op)
+ */
+ public boolean op(Path path, Op op) {
+ return op(this, path, op);
+ }
+
+ /**
+ * Set this path to the result of applying the Op to the two specified paths.
+ * The resulting path will be constructed from non-overlapping contours.
+ * The curve order is reduced where possible so that cubics may be turned
+ * into quadratics, and quadratics maybe turned into lines.
+ *
+ * @param path1 The first operand (for difference, the minuend)
+ * @param path2 The second operand (for difference, the subtrahend)
+ *
+ * @return True if operation succeeded, false otherwise and this path remains unmodified.
+ *
+ * @see Op
+ * @see #op(Path, android.graphics.Path.Op)
+ */
+ public boolean op(Path path1, Path path2, Op op) {
+ if (native_op(path1.mNativePath, path2.mNativePath, op.ordinal(), this.mNativePath)) {
+ isSimplePath = false;
+ rects = null;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Enum for the ways a path may be filled.
+ */
public enum FillType {
// these must match the values in SkPath.h
+ /**
+ * Specifies that "inside" is computed by a non-zero sum of signed
+ * edge crossings.
+ */
WINDING (0),
+ /**
+ * Specifies that "inside" is computed by an odd number of edge
+ * crossings.
+ */
EVEN_ODD (1),
+ /**
+ * Same as {@link #WINDING}, but draws outside of the path, rather than inside.
+ */
INVERSE_WINDING (2),
+ /**
+ * Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
+ */
INVERSE_EVEN_ODD(3);
FillType(int ni) {
nativeInt = ni;
}
+
final int nativeInt;
}
-
+
// these must be in the same order as their native values
static final FillType[] sFillTypeArray = {
FillType.WINDING,
@@ -644,24 +729,20 @@
private static native void native_addRect(int nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addOval(int nPath, RectF oval, int dir);
- private static native void native_addCircle(int nPath, float x, float y,
- float radius, int dir);
+ private static native void native_addCircle(int nPath, float x, float y, float radius, int dir);
private static native void native_addArc(int nPath, RectF oval,
float startAngle, float sweepAngle);
private static native void native_addRoundRect(int nPath, RectF rect,
float rx, float ry, int dir);
- private static native void native_addRoundRect(int nPath, RectF r,
- float[] radii, int dir);
- private static native void native_addPath(int nPath, int src, float dx,
- float dy);
+ private static native void native_addRoundRect(int nPath, RectF r, float[] radii, int dir);
+ private static native void native_addPath(int nPath, int src, float dx, float dy);
private static native void native_addPath(int nPath, int src);
private static native void native_addPath(int nPath, int src, int matrix);
- private static native void native_offset(int nPath, float dx, float dy,
- int dst_path);
+ private static native void native_offset(int nPath, float dx, float dy, int dst_path);
private static native void native_offset(int nPath, float dx, float dy);
private static native void native_setLastPoint(int nPath, float dx, float dy);
- private static native void native_transform(int nPath, int matrix,
- int dst_path);
+ private static native void native_transform(int nPath, int matrix, int dst_path);
private static native void native_transform(int nPath, int matrix);
+ private static native boolean native_op(int path1, int path2, int op, int result);
private static native void finalizer(int nPath);
}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 6cc9d8f..e3a7e2b 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -261,6 +261,13 @@
return this;
}
+ /**
+ * Returns the drawable wrapped by this InsetDrawable. May be null.
+ */
+ public Drawable getDrawable() {
+ return mInsetState.mDrawable;
+ }
+
final static class InsetState extends ConstantState {
Drawable mDrawable;
int mChangingConfigurations;
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
index 77b9385..6881627 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
@@ -21,15 +21,27 @@
/**
* Intrinsic for applying a color matrix to allocations.
*
- * This has the same effect as loading each element and
- * converting it to a {@link Element#F32_4}, multiplying the
- * result by the 4x4 color matrix as performed by
- * rsMatrixMultiply() and writing it to the output after
- * conversion back to {@link Element#U8_4}.
+ * If the element type is {@link Element.DataType#UNSIGNED_8},
+ * it is converted to {@link Element.DataType#FLOAT_32} and
+ * normalized from (0-255) to (0-1). If the incoming vector size
+ * is less than four, a {@link Element#F32_4} is created by
+ * filling the missing vector channels with zero. This value is
+ * then multiplied by the 4x4 color matrix as performed by
+ * rsMatrixMultiply(), adding a {@link Element#F32_4}, and then
+ * writing it to the output {@link Allocation}.
+ *
+ * If the ouptut type is unsigned, the value is normalized from
+ * (0-1) to (0-255) and converted. If the output vector size is
+ * less than four, the unused channels are discarded.
+ *
+ * Supported elements types are {@link Element#U8}, {@link
+ * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
+ * {@link Element#F32}, {@link Element#F32_2}, {@link
+ * Element#F32_3}, and {@link Element#F32_4}.
**/
public final class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
private final Matrix4f mMatrix = new Matrix4f();
- private Allocation mInput;
+ private final Float4 mAdd = new Float4();
private ScriptIntrinsicColorMatrix(int id, RenderScript rs) {
super(id, rs);
@@ -39,18 +51,27 @@
* Create an intrinsic for applying a color matrix to an
* allocation.
*
- * Supported elements types are {@link Element#U8_4}
- *
* @param rs The RenderScript context
- * @param e Element type for intputs and outputs
+ * @param e Element type for inputs and outputs, As of API 19,
+ * this parameter is ignored. The Element type check is
+ * performed in the kernel launch.
*
* @return ScriptIntrinsicColorMatrix
*/
public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
- if (!e.isCompatible(Element.U8_4(rs))) {
- throw new RSIllegalArgumentException("Unsuported element type.");
- }
- int id = rs.nScriptIntrinsicCreate(2, e.getID(rs));
+ return create(rs);
+ }
+
+ /**
+ * Create an intrinsic for applying a color matrix to an
+ * allocation.
+ *
+ * @param rs The RenderScript context
+ *
+ * @return ScriptIntrinsicColorMatrix
+ */
+ public static ScriptIntrinsicColorMatrix create(RenderScript rs) {
+ int id = rs.nScriptIntrinsicCreate(2, 0);
return new ScriptIntrinsicColorMatrix(id, rs);
}
@@ -84,6 +105,49 @@
}
/**
+ * Set the value to be added after the color matrix has been
+ * applied. The default value is {0, 0, 0, 0}
+ *
+ * @param f The float4 value to be added.
+ */
+ public void setAdd(Float4 f) {
+ mAdd.x = f.x;
+ mAdd.y = f.y;
+ mAdd.z = f.z;
+ mAdd.w = f.w;
+
+ FieldPacker fp = new FieldPacker(4*4);
+ fp.addF32(f.x);
+ fp.addF32(f.y);
+ fp.addF32(f.z);
+ fp.addF32(f.w);
+ setVar(1, fp);
+ }
+
+ /**
+ * Set the value to be added after the color matrix has been
+ * applied. The default value is {0, 0, 0, 0}
+ *
+ * @param r The red add value.
+ * @param g The green add value.
+ * @param b The blue add value.
+ * @param a The alpha add value.
+ */
+ public void setAdd(float r, float g, float b, float a) {
+ mAdd.x = r;
+ mAdd.y = g;
+ mAdd.z = b;
+ mAdd.w = a;
+
+ FieldPacker fp = new FieldPacker(4*4);
+ fp.addF32(mAdd.x);
+ fp.addF32(mAdd.y);
+ fp.addF32(mAdd.z);
+ fp.addF32(mAdd.w);
+ setVar(1, fp);
+ }
+
+ /**
* Set a color matrix to convert from RGB to luminance. The alpha channel
* will be a copy.
*
@@ -142,13 +206,45 @@
/**
- * Invoke the kernel and apply the matrix to each cell of ain and copy to
- * aout.
+ * Invoke the kernel and apply the matrix to each cell of input
+ * {@link Allocation} and copy to the output {@link Allocation}.
+ *
+ * If the vector size of the input is less than four, the
+ * remaining components are treated as zero for the matrix
+ * multiply.
+ *
+ * If the output vector size is less than four, the unused
+ * vector components are discarded.
+ *
*
* @param ain Input allocation
* @param aout Output allocation
*/
public void forEach(Allocation ain, Allocation aout) {
+ if (!ain.getElement().isCompatible(Element.U8(mRS)) &&
+ !ain.getElement().isCompatible(Element.U8_2(mRS)) &&
+ !ain.getElement().isCompatible(Element.U8_3(mRS)) &&
+ !ain.getElement().isCompatible(Element.U8_4(mRS)) &&
+ !ain.getElement().isCompatible(Element.F32(mRS)) &&
+ !ain.getElement().isCompatible(Element.F32_2(mRS)) &&
+ !ain.getElement().isCompatible(Element.F32_3(mRS)) &&
+ !ain.getElement().isCompatible(Element.F32_4(mRS))) {
+
+ throw new RSIllegalArgumentException("Unsuported element type.");
+ }
+
+ if (!aout.getElement().isCompatible(Element.U8(mRS)) &&
+ !aout.getElement().isCompatible(Element.U8_2(mRS)) &&
+ !aout.getElement().isCompatible(Element.U8_3(mRS)) &&
+ !aout.getElement().isCompatible(Element.U8_4(mRS)) &&
+ !aout.getElement().isCompatible(Element.F32(mRS)) &&
+ !aout.getElement().isCompatible(Element.F32_2(mRS)) &&
+ !aout.getElement().isCompatible(Element.F32_3(mRS)) &&
+ !aout.getElement().isCompatible(Element.F32_4(mRS))) {
+
+ throw new RSIllegalArgumentException("Unsuported element type.");
+ }
+
forEach(0, ain, aout, null);
}
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index a305fc3..97afa59 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -479,7 +479,7 @@
const uint32_t* mEntries;
const uint32_t* mEntryStyles;
const void* mStrings;
- char16_t** mCache;
+ char16_t mutable** mCache;
uint32_t mStringPoolSize; // number of uint16_t
const uint32_t* mStyles;
uint32_t mStylePoolSize; // number of uint32_t
@@ -678,11 +678,15 @@
// Returns -1 if no namespace, -2 if idx out of range.
int32_t getAttributeNamespaceID(size_t idx) const;
const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
-
+
int32_t getAttributeNameID(size_t idx) const;
const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
uint32_t getAttributeNameResID(size_t idx) const;
-
+
+ // These will work only if the underlying string pool is UTF-8.
+ const char* getAttributeNamespace8(size_t idx, size_t* outLen) const;
+ const char* getAttributeName8(size_t idx, size_t* outLen) const;
+
int32_t getAttributeValueStringID(size_t idx) const;
const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
@@ -1294,12 +1298,14 @@
const char16_t* package;
size_t packageLen;
const char16_t* type;
+ const char* type8;
size_t typeLen;
const char16_t* name;
+ const char* name8;
size_t nameLen;
};
- bool getResourceName(uint32_t resID, resource_name* outName) const;
+ bool getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const;
/**
* Retrieve the value of a resource. If the resource is found, returns a
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1128e02..1cc3563 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -35,7 +35,7 @@
#define INT32_MAX ((int32_t)(2147483647))
#endif
-#define POOL_NOISY(x) //x
+#define STRING_POOL_NOISY(x) //x
#define XML_NOISY(x) //x
#define TABLE_NOISY(x) //x
#define TABLE_GETENTRY(x) //x
@@ -378,7 +378,6 @@
size_t charSize;
if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
charSize = sizeof(uint8_t);
- mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
} else {
charSize = sizeof(char16_t);
}
@@ -593,6 +592,23 @@
if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
AutoMutex lock(mDecodeLock);
+ if (mCache == NULL) {
+#ifndef HAVE_ANDROID_OS
+ STRING_POOL_NOISY(ALOGI("CREATING STRING CACHE OF %d bytes",
+ mHeader->stringCount*sizeof(char16_t**)));
+#else
+ // We do not want to be in this case when actually running Android.
+ ALOGW("CREATING STRING CACHE OF %d bytes",
+ mHeader->stringCount*sizeof(char16_t**));
+#endif
+ mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
+ if (mCache == NULL) {
+ ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
+ (int)(mHeader->stringCount*sizeof(char16_t**)));
+ return NULL;
+ }
+ }
+
if (mCache[idx] != NULL) {
return mCache[idx];
}
@@ -612,6 +628,7 @@
return NULL;
}
+ STRING_POOL_NOISY(ALOGI("Caching UTF8 string: %s", u8str));
utf8_to_utf16(u8str, u8len, u16str);
mCache[idx] = u16str;
return u16str;
@@ -633,20 +650,20 @@
const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
- const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
+ if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
+ return NULL;
+ }
+ const uint32_t off = mEntries[idx]/sizeof(char);
if (off < (mStringPoolSize-1)) {
- if (isUTF8) {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* str = strings+off;
- *outLen = decodeLength(&str);
- size_t encLen = decodeLength(&str);
- if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
- return (const char*)str;
- } else {
- ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
- }
+ const uint8_t* strings = (uint8_t*)mStrings;
+ const uint8_t* str = strings+off;
+ *outLen = decodeLength(&str);
+ size_t encLen = decodeLength(&str);
+ if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+ return (const char*)str;
+ } else {
+ ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+ (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
}
} else {
ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -695,45 +712,104 @@
size_t len;
- // TODO optimize searching for UTF-8 strings taking into account
- // the cache fill to determine when to convert the searched-for
- // string key to UTF-8.
+ if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
+ STRING_POOL_NOISY(ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string()));
- if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
- // Do a binary search for the string...
- ssize_t l = 0;
- ssize_t h = mHeader->stringCount-1;
+ // The string pool contains UTF 8 strings; we don't want to cause
+ // temporary UTF-16 strings to be created as we search.
+ if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+ // Do a binary search for the string... this is a little tricky,
+ // because the strings are sorted with strzcmp16(). So to match
+ // the ordering, we need to convert strings in the pool to UTF-16.
+ // But we don't want to hit the cache, so instead we will have a
+ // local temporary allocation for the conversions.
+ char16_t* convBuffer = (char16_t*)malloc(strLen+4);
+ ssize_t l = 0;
+ ssize_t h = mHeader->stringCount-1;
- ssize_t mid;
- while (l <= h) {
- mid = l + (h - l)/2;
- const char16_t* s = stringAt(mid, &len);
- int c = s ? strzcmp16(s, len, str, strLen) : -1;
- POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- String8(str).string(),
- String8(s).string(),
- c, (int)l, (int)mid, (int)h));
- if (c == 0) {
- return mid;
- } else if (c < 0) {
- l = mid + 1;
- } else {
- h = mid - 1;
+ ssize_t mid;
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const uint8_t* s = (const uint8_t*)string8At(mid, &len);
+ int c;
+ if (s != NULL) {
+ char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3);
+ *end = 0;
+ c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+ } else {
+ c = -1;
+ }
+ STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+ (const char*)s, c, (int)l, (int)mid, (int)h));
+ if (c == 0) {
+ STRING_POOL_NOISY(ALOGI("MATCH!"));
+ free(convBuffer);
+ return mid;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ free(convBuffer);
+ } else {
+ // It is unusual to get the ID from an unsorted string block...
+ // most often this happens because we want to get IDs for style
+ // span tags; since those always appear at the end of the string
+ // block, start searching at the back.
+ String8 str8(str, strLen);
+ const size_t str8Len = str8.size();
+ for (int i=mHeader->stringCount-1; i>=0; i--) {
+ const char* s = string8At(i, &len);
+ STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
+ String8(s).string(),
+ i));
+ if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
+ STRING_POOL_NOISY(ALOGI("MATCH!"));
+ return i;
+ }
}
}
+
} else {
- // It is unusual to get the ID from an unsorted string block...
- // most often this happens because we want to get IDs for style
- // span tags; since those always appear at the end of the string
- // block, start searching at the back.
- for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char16_t* s = stringAt(i, &len);
- POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
- String8(str, strLen).string(),
- String8(s).string(),
- i));
- if (s && strzcmp16(s, len, str, strLen) == 0) {
- return i;
+ STRING_POOL_NOISY(ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string()));
+
+ if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
+ // Do a binary search for the string...
+ ssize_t l = 0;
+ ssize_t h = mHeader->stringCount-1;
+
+ ssize_t mid;
+ while (l <= h) {
+ mid = l + (h - l)/2;
+ const char16_t* s = stringAt(mid, &len);
+ int c = s ? strzcmp16(s, len, str, strLen) : -1;
+ STRING_POOL_NOISY(ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
+ String8(s).string(),
+ c, (int)l, (int)mid, (int)h));
+ if (c == 0) {
+ STRING_POOL_NOISY(ALOGI("MATCH!"));
+ return mid;
+ } else if (c < 0) {
+ l = mid + 1;
+ } else {
+ h = mid - 1;
+ }
+ }
+ } else {
+ // It is unusual to get the ID from an unsorted string block...
+ // most often this happens because we want to get IDs for style
+ // span tags; since those always appear at the end of the string
+ // block, start searching at the back.
+ for (int i=mHeader->stringCount-1; i>=0; i--) {
+ const char16_t* s = stringAt(i, &len);
+ STRING_POOL_NOISY(ALOGI("Looking at %s, i=%d\n",
+ String8(s).string(),
+ i));
+ if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
+ STRING_POOL_NOISY(ALOGI("MATCH!"));
+ return i;
+ }
}
}
}
@@ -936,6 +1012,14 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
+const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
+{
+ int32_t id = getAttributeNamespaceID(idx);
+ //printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode);
+ //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
+ return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+}
+
int32_t ResXMLParser::getAttributeNameID(size_t idx) const
{
if (mEventCode == START_TAG) {
@@ -959,6 +1043,14 @@
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
}
+const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
+{
+ int32_t id = getAttributeNameID(idx);
+ //printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode);
+ //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
+ return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+}
+
uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
{
int32_t id = getAttributeNameID(idx);
@@ -1048,22 +1140,67 @@
const char16_t* attr, size_t attrLen) const
{
if (mEventCode == START_TAG) {
+ if (attr == NULL) {
+ return NAME_NOT_FOUND;
+ }
const size_t N = getAttributeCount();
- for (size_t i=0; i<N; i++) {
- size_t curNsLen, curAttrLen;
- const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
- const char16_t* curAttr = getAttributeName(i, &curAttrLen);
- //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
- // i, ns, attr, curNs, curAttr);
- //printf(" --> attr=%s, curAttr=%s\n",
- // String8(attr).string(), String8(curAttr).string());
- if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
- if (ns == NULL) {
- if (curNs == NULL) return i;
- } else if (curNs != NULL) {
- //printf(" --> ns=%s, curNs=%s\n",
- // String8(ns).string(), String8(curNs).string());
- if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
+ if (mTree.mStrings.isUTF8()) {
+ String8 ns8, attr8;
+ if (ns != NULL) {
+ ns8 = String8(ns, nsLen);
+ }
+ attr8 = String8(attr, attrLen);
+ STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF8 %s (%d) / %s (%d)", ns8.string(), nsLen,
+ attr8.string(), attrLen));
+ for (size_t i=0; i<N; i++) {
+ size_t curNsLen = 0, curAttrLen = 0;
+ const char* curNs = getAttributeNamespace8(i, &curNsLen);
+ const char* curAttr = getAttributeName8(i, &curAttrLen);
+ STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)", curNs, curNsLen,
+ curAttr, curAttrLen));
+ if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
+ && memcmp(attr8.string(), curAttr, attrLen) == 0) {
+ if (ns == NULL) {
+ if (curNs == NULL) {
+ STRING_POOL_NOISY(ALOGI(" FOUND!"));
+ return i;
+ }
+ } else if (curNs != NULL) {
+ //printf(" --> ns=%s, curNs=%s\n",
+ // String8(ns).string(), String8(curNs).string());
+ if (memcmp(ns8.string(), curNs, nsLen) == 0) {
+ STRING_POOL_NOISY(ALOGI(" FOUND!"));
+ return i;
+ }
+ }
+ }
+ }
+ } else {
+ STRING_POOL_NOISY(ALOGI("indexOfAttribute UTF16 %s (%d) / %s (%d)",
+ String8(ns, nsLen).string(), nsLen,
+ String8(attr, attrLen).string(), attrLen));
+ for (size_t i=0; i<N; i++) {
+ size_t curNsLen = 0, curAttrLen = 0;
+ const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
+ const char16_t* curAttr = getAttributeName(i, &curAttrLen);
+ STRING_POOL_NOISY(ALOGI(" curNs=%s (%d), curAttr=%s (%d)",
+ String8(curNs, curNsLen).string(), curNsLen,
+ String8(curAttr, curAttrLen).string(), curAttrLen));
+ if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
+ && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
+ if (ns == NULL) {
+ if (curNs == NULL) {
+ STRING_POOL_NOISY(ALOGI(" FOUND!"));
+ return i;
+ }
+ } else if (curNs != NULL) {
+ //printf(" --> ns=%s, curNs=%s\n",
+ // String8(ns).string(), String8(curNs).string());
+ if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
+ STRING_POOL_NOISY(ALOGI(" FOUND!"));
+ return i;
+ }
+ }
}
}
}
@@ -2940,7 +3077,7 @@
mHeaders.clear();
}
-bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
+bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
{
if (mError != NO_ERROR) {
return false;
@@ -2980,13 +3117,28 @@
outName->package = grp->name.string();
outName->packageLen = grp->name.size();
- outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
- outName->name = grp->basePackage->keyStrings.stringAt(
- dtohl(entry->key.index), &outName->nameLen);
-
- // If we have a bad index for some reason, we should abort.
- if (outName->type == NULL || outName->name == NULL) {
- return false;
+ if (allowUtf8) {
+ outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen);
+ outName->name8 = grp->basePackage->keyStrings.string8At(
+ dtohl(entry->key.index), &outName->nameLen);
+ } else {
+ outName->type8 = NULL;
+ outName->name8 = NULL;
+ }
+ if (outName->type8 == NULL) {
+ outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
+ // If we have a bad index for some reason, we should abort.
+ if (outName->type == NULL) {
+ return false;
+ }
+ }
+ if (outName->name8 == NULL) {
+ outName->name = grp->basePackage->keyStrings.stringAt(
+ dtohl(entry->key.index), &outName->nameLen);
+ // If we have a bad index for some reason, we should abort.
+ if (outName->name == NULL) {
+ return false;
+ }
}
return true;
@@ -4485,7 +4637,7 @@
while (cnt > 0) {
if (!Res_INTERNALID(bag->map.name.ident)) {
//printf("Trying attr #%08x\n", bag->map.name.ident);
- if (getResourceName(bag->map.name.ident, &rname)) {
+ if (getResourceName(bag->map.name.ident, false, &rname)) {
#if 0
printf("Matching %s against %s (0x%08x)\n",
String8(s, len).string(),
@@ -4538,7 +4690,7 @@
for (i=0; i<cnt; i++, bagi++) {
if (!Res_INTERNALID(bagi->map.name.ident)) {
//printf("Trying attr #%08x\n", bagi->map.name.ident);
- if (getResourceName(bagi->map.name.ident, &rname)) {
+ if (getResourceName(bagi->map.name.ident, false, &rname)) {
#if 0
printf("Matching %s against %s (0x%08x)\n",
String8(start,pos-start).string(),
@@ -5216,7 +5368,7 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- if (!this->getResourceName(resID, &resName)) {
+ if (!this->getResourceName(resID, true, &resName)) {
ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
// add dummy value, or trimming leading/trailing zeroes later will fail
vector.push(0);
@@ -5483,12 +5635,23 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- if (this->getResourceName(resID, &resName)) {
+ if (this->getResourceName(resID, true, &resName)) {
+ String8 type8;
+ String8 name8;
+ if (resName.type8 != NULL) {
+ type8 = String8(resName.type8, resName.typeLen);
+ } else {
+ type8 = String8(resName.type, resName.typeLen);
+ }
+ if (resName.name8 != NULL) {
+ name8 = String8(resName.name8, resName.nameLen);
+ } else {
+ name8 = String8(resName.name, resName.nameLen);
+ }
printf(" spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
resID,
CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen),
+ type8.string(), name8.string(),
dtohl(typeConfigs->typeSpecFlags[entryIndex]));
} else {
printf(" INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
@@ -5531,11 +5694,22 @@
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
- if (this->getResourceName(resID, &resName)) {
+ if (this->getResourceName(resID, true, &resName)) {
+ String8 type8;
+ String8 name8;
+ if (resName.type8 != NULL) {
+ type8 = String8(resName.type8, resName.typeLen);
+ } else {
+ type8 = String8(resName.type, resName.typeLen);
+ }
+ if (resName.name8 != NULL) {
+ name8 = String8(resName.name8, resName.nameLen);
+ } else {
+ name8 = String8(resName.name, resName.nameLen);
+ }
printf(" resource 0x%08x %s:%s/%s: ", resID,
CHAR16_TO_CSTR(resName.package, resName.packageLen),
- CHAR16_TO_CSTR(resName.type, resName.typeLen),
- CHAR16_TO_CSTR(resName.name, resName.nameLen));
+ type8.string(), name8.string());
} else {
printf(" INVALID RESOURCE 0x%08x: ", resID);
}
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
new file mode 100644
index 0000000..020f3e1
--- /dev/null
+++ b/media/java/android/media/FocusRequester.java
@@ -0,0 +1,246 @@
+/*
+ * 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.media;
+
+import android.media.MediaFocusControl.AudioFocusDeathHandler;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ * Class to handle all the information about a user of audio focus. The lifecycle of each
+ * instance is managed by android.media.MediaFocusControl, from its addition to the audio focus
+ * stack to its release.
+ */
+class FocusRequester {
+
+ /**
+ * Used to indicate no audio focus has been gained or lost.
+ */
+ private static final int AUDIOFOCUS_NONE = 0;
+
+ // on purpose not using this classe's name, as it will only be used from MediaFocusControl
+ private static final String TAG = "MediaFocusControl";
+ private static final boolean DEBUG = false;
+
+ private AudioFocusDeathHandler mDeathHandler;
+ private final IAudioFocusDispatcher mFocusDispatcher; // may be null
+ private final IBinder mSourceRef;
+ private final String mClientId;
+ private final String mPackageName;
+ private final int mCallingUid;
+ /**
+ * the audio focus gain request that caused the addition of this object in the focus stack.
+ */
+ private final int mFocusGainRequest;
+ /**
+ * the audio focus loss received my mFocusDispatcher, is MediaFocusControl.AUDIOFOCUS_NONE if
+ * it never lost focus.
+ */
+ private int mFocusLossReceived;
+ /**
+ * the stream type associated with the focus request
+ */
+ private final int mStreamType;
+
+ FocusRequester(int streamType, int focusRequest,
+ IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
+ String pn, int uid) {
+ mStreamType = streamType;
+ mFocusDispatcher = afl;
+ mSourceRef = source;
+ mClientId = id;
+ mDeathHandler = hdlr;
+ mPackageName = pn;
+ mCallingUid = uid;
+ mFocusGainRequest = focusRequest;
+ mFocusLossReceived = AUDIOFOCUS_NONE;
+ }
+
+
+ boolean hasSameClient(String otherClient) {
+ try {
+ return mClientId.compareTo(otherClient) == 0;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ boolean hasSameBinder(IBinder ib) {
+ return (mSourceRef != null) && mSourceRef.equals(ib);
+ }
+
+ boolean hasSamePackage(String pack) {
+ try {
+ return mPackageName.compareTo(pack) == 0;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ boolean hasSameUid(int uid) {
+ return mCallingUid == uid;
+ }
+
+
+ int getGainRequest() {
+ return mFocusGainRequest;
+ }
+
+ int getStreamType() {
+ return mStreamType;
+ }
+
+
+ private static String focusChangeToString(int focus) {
+ switch(focus) {
+ case AUDIOFOCUS_NONE:
+ return "none";
+ case AudioManager.AUDIOFOCUS_GAIN:
+ return "GAIN";
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+ return "GAIN_TRANSIENT";
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+ return "GAIN_TRANSIENT_MAY_DUCK";
+ case AudioManager.AUDIOFOCUS_LOSS:
+ return "LOSS";
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ return "LOSS_TRANSIENT";
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ return "LOSS_TRANSIENT_CAN_DUCK";
+ default:
+ return "[invalid focus change" + focus + "]";
+ }
+ }
+
+ private String focusGainToString() {
+ return focusChangeToString(mFocusGainRequest);
+ }
+
+ private String focusLossToString() {
+ return focusChangeToString(mFocusLossReceived);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" source:" + mSourceRef
+ + " -- pack: " + mPackageName
+ + " -- client: " + mClientId
+ + " -- gain: " + focusGainToString()
+ + " -- loss: " + focusLossToString()
+ + " -- uid: " + mCallingUid
+ + " -- stream: " + mStreamType);
+ }
+
+
+ void release() {
+ try {
+ if (mSourceRef != null && mDeathHandler != null) {
+ mSourceRef.unlinkToDeath(mDeathHandler, 0);
+ mDeathHandler = null;
+ }
+ } catch (java.util.NoSuchElementException e) {
+ Log.e(TAG, "FocusRequester.release() hit ", e);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ release();
+ super.finalize();
+ }
+
+ /**
+ * For a given audio focus gain request, return the audio focus loss type that will result
+ * from it, taking into account any previous focus loss.
+ * @param gainRequest
+ * @return the audio focus loss type that matches the gain request
+ */
+ private int focusLossForGainRequest(int gainRequest) {
+ switch(gainRequest) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ switch(mFocusLossReceived) {
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ case AudioManager.AUDIOFOCUS_LOSS:
+ case AUDIOFOCUS_NONE:
+ return AudioManager.AUDIOFOCUS_LOSS;
+ }
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+ switch(mFocusLossReceived) {
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ case AUDIOFOCUS_NONE:
+ return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+ case AudioManager.AUDIOFOCUS_LOSS:
+ return AudioManager.AUDIOFOCUS_LOSS;
+ }
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+ switch(mFocusLossReceived) {
+ case AUDIOFOCUS_NONE:
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ return AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
+ case AudioManager.AUDIOFOCUS_LOSS:
+ return AudioManager.AUDIOFOCUS_LOSS;
+ }
+ default:
+ Log.e(TAG, "focusLossForGainRequest() for invalid focus request "+ gainRequest);
+ return AUDIOFOCUS_NONE;
+ }
+ }
+
+ void handleExternalFocusGain(int focusGain) {
+ int focusLoss = focusLossForGainRequest(focusGain);
+ handleFocusLoss(focusLoss);
+ }
+
+ void handleFocusGain(int focusGain) {
+ try {
+ if (mFocusDispatcher != null) {
+ if (DEBUG) {
+ Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to "
+ + mClientId);
+ }
+ mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId);
+ }
+ mFocusLossReceived = AUDIOFOCUS_NONE;
+ } catch (android.os.RemoteException e) {
+ Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
+ }
+ }
+
+ void handleFocusLoss(int focusLoss) {
+ try {
+ if (focusLoss != mFocusLossReceived) {
+ if (mFocusDispatcher != null) {
+ if (DEBUG) {
+ Log.v(TAG, "dispatching " + focusChangeToString(focusLoss) + " to "
+ + mClientId);
+ }
+ mFocusDispatcher.dispatchAudioFocusChange(focusLoss, mClientId);
+ }
+ mFocusLossReceived = focusLoss;
+ }
+ } catch (android.os.RemoteException e) {
+ Log.e(TAG, "Failure to signal loss of audio focus due to:", e);
+ }
+ }
+
+}
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index f55756c..d06eeb31 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -23,7 +23,7 @@
/**
* <p>A single complete image buffer to use with a media source such as a
* {@link MediaCodec} or a
- * {@link android.hardware.photography.CameraDevice}.</p>
+ * {@link android.hardware.camera2.CameraDevice}.</p>
*
* <p>This class allows for efficient direct application access to the pixel
* data of the Image through one or more
@@ -80,7 +80,7 @@
* <td>A single plane of raw sensor image data, with 16 bits per color
* sample. The details of the layout need to be queried from the source of
* the raw sensor data, such as
- * {@link android.hardware.photography.CameraDevice}.
+ * {@link android.hardware.camera2.CameraDevice}.
* </td>
* </tr>
* </table>
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 8f09b54..90e01de 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -32,7 +32,7 @@
*
* <p>Several Android media API classes accept Surface objects as targets to
* render to, including {@link MediaPlayer}, {@link MediaCodec},
- * {@link android.hardware.photography.CameraDevice}, and
+ * {@link android.hardware.camera2.CameraDevice}, and
* {@link android.renderscript.Allocation RenderScript Allocations}. The image
* sizes and formats that can be used with each source vary, and should be
* checked in the documentation for the specific API.</p>
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index cc60d17..c5b1101 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -66,11 +66,6 @@
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
- /**
- * Used to indicate no audio focus has been gained or lost.
- */
- private static final int AUDIOFOCUS_NONE = 0;
-
/** Used to alter media button redirection when the phone is ringing. */
private boolean mIsRinging = false;
@@ -270,17 +265,11 @@
*/
protected void discardAudioFocusOwner() {
synchronized(mAudioFocusLock) {
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (!mFocusStack.empty()) {
// notify the current focus owner it lost focus after removing it from stack
- final FocusStackEntry exFocusOwner = mFocusStack.pop();
- try {
- exFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
- AudioManager.AUDIOFOCUS_LOSS, exFocusOwner.mClientId);
- } catch (RemoteException e) {
- Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
- e.printStackTrace();
- }
- exFocusOwner.unlinkToDeath();
+ final FocusRequester exFocusOwner = mFocusStack.pop();
+ exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
+ exFocusOwner.release();
// clear RCD
synchronized(mRCStack) {
clearRemoteControlDisplay_syncAfRcs();
@@ -291,97 +280,27 @@
private void notifyTopOfAudioFocusStack() {
// notify the top of the stack it gained focus
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ if (!mFocusStack.empty()) {
if (canReassignAudioFocus()) {
- final FocusStackEntry newFocusOwner = mFocusStack.peek();
- try {
- newFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
- AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
- newFocusOwner.mFocusLossReceived = AUDIOFOCUS_NONE;
- } catch (RemoteException e) {
- Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
- e.printStackTrace();
- }
+ mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
}
}
}
- private static class FocusStackEntry {
- public int mStreamType = -1;// no stream type
- public IAudioFocusDispatcher mFocusDispatcher = null;
- public IBinder mSourceRef = null;
- public String mClientId;
- /** the audio focus gain request that caused the addition of this entry in the stack */
- public int mFocusGainRequest;
- public int mFocusLossReceived;
- public AudioFocusDeathHandler mHandler;
- public String mPackageName;
- public int mCallingUid;
-
- private static String focusChangeToString(int focus) {
- switch(focus) {
- case AudioManager.AUDIOFOCUS_GAIN:
- return "GAIN";
- case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
- return "GAIN_TRANSIENT";
- case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
- return "GAIN_TRANSIENT_MAY_DUCK";
- case AudioManager.AUDIOFOCUS_LOSS:
- return "LOSS";
- case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
- return "LOSS_TRANSIENT";
- case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
- return "LOSS_TRANSIENT_CAN_DUCK";
- default:
- return "[invalid focus change" + focus + "]";
- }
- }
-
- String focusGainToString() {
- return focusChangeToString(mFocusGainRequest);
- }
-
- String focusLossToString() {
- if (mFocusLossReceived == 0) {
- return "none";
- } else {
- return focusChangeToString(mFocusLossReceived);
- }
- }
-
- FocusStackEntry(int streamType, int focusRequest,
- IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
- String pn, int uid) {
- mStreamType = streamType;
- mFocusDispatcher = afl;
- mSourceRef = source;
- mClientId = id;
- mFocusGainRequest = focusRequest;
- mFocusLossReceived = AUDIOFOCUS_NONE;
- mHandler = hdlr;
- mPackageName = pn;
- mCallingUid = uid;
- }
-
- public void unlinkToDeath() {
- try {
- if (mSourceRef != null && mHandler != null) {
- mSourceRef.unlinkToDeath(mHandler, 0);
- mHandler = null;
- }
- } catch (java.util.NoSuchElementException e) {
- Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- unlinkToDeath(); // unlink exception handled inside method
- super.finalize();
+ /**
+ * Focus is requested, propagate the associated loss throughout the stack.
+ * @param focusGain the new focus gain that will later be added at the top of the stack
+ */
+ private void propagateFocusLossFromGain_syncAf(int focusGain) {
+ // going through the audio focus stack to signal new focus, traversing order doesn't
+ // matter as all entries respond to the same external focus gain
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
+ while(stackIterator.hasNext()) {
+ stackIterator.next().handleExternalFocusGain(focusGain);
}
}
- private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
+ private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
/**
* Helper function:
@@ -390,16 +309,9 @@
private void dumpFocusStack(PrintWriter pw) {
pw.println("\nAudio Focus stack entries (last is top of stack):");
synchronized(mAudioFocusLock) {
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = stackIterator.next();
- pw.println(" source:" + fse.mSourceRef
- + " -- pack: " + fse.mPackageName
- + " -- client: " + fse.mClientId
- + " -- gain: " + fse.focusGainToString()
- + " -- loss: " + fse.focusLossToString()
- + " -- uid: " + fse.mCallingUid
- + " -- stream: " + fse.mStreamType);
+ stackIterator.next().dump(pw);
}
}
}
@@ -414,11 +326,11 @@
*/
private void removeFocusStackEntry(String clientToRemove, boolean signal) {
// is the current top of the focus stack abandoning focus? (because of request, not death)
- if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
+ if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
{
//Log.i(TAG, " removeFocusStackEntry() removing top of stack");
- FocusStackEntry fse = mFocusStack.pop();
- fse.unlinkToDeath();
+ FocusRequester fr = mFocusStack.pop();
+ fr.release();
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
@@ -432,14 +344,14 @@
// no need to update focus.
// (using an iterator on the stack so we can safely remove an entry after having
// evaluated it, traversal order doesn't matter here)
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if(fse.mClientId.equals(clientToRemove)) {
- Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for "
- + fse.mClientId);
+ FocusRequester fr = (FocusRequester)stackIterator.next();
+ if(fr.hasSameClient(clientToRemove)) {
+ Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
+ + clientToRemove);
stackIterator.remove();
- fse.unlinkToDeath();
+ fr.release();
}
}
}
@@ -453,15 +365,14 @@
private void removeFocusStackEntryForClient(IBinder cb) {
// is the owner of the audio focus part of the client to remove?
boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
- mFocusStack.peek().mSourceRef.equals(cb);
+ mFocusStack.peek().hasSameBinder(cb);
// (using an iterator on the stack so we can safely remove an entry after having
// evaluated it, traversal order doesn't matter here)
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
+ Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if(fse.mSourceRef.equals(cb)) {
- Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for "
- + fse.mClientId);
+ FocusRequester fr = (FocusRequester)stackIterator.next();
+ if(fr.hasSameBinder(cb)) {
+ Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " + cb);
stackIterator.remove();
// the client just died, no need to unlink to its death
}
@@ -484,7 +395,7 @@
private boolean canReassignAudioFocus() {
// focus requests are rejected during a phone call or when the phone is ringing
// this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
- if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
+ if (!mFocusStack.isEmpty() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
return false;
}
return true;
@@ -494,7 +405,7 @@
* Inner class to monitor audio focus client deaths, and remove them from the audio focus
* stack if necessary.
*/
- private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
+ protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
AudioFocusDeathHandler(IBinder cb) {
@@ -549,10 +460,10 @@
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
- if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
+ if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
// if focus is already owned by this client and the reason for acquiring the focus
// hasn't changed, don't do anything
- if (mFocusStack.peek().mFocusGainRequest == focusChangeHint) {
+ if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
// unlink death handler so it can be gc'ed.
// linkToDeath() creates a JNI global reference preventing collection.
cb.unlinkToDeath(afdh, 0);
@@ -560,29 +471,20 @@
}
// the reason for the audio focus request has changed: remove the current top of
// stack and respond as if we had a new focus owner
- FocusStackEntry fse = mFocusStack.pop();
- fse.unlinkToDeath();
- }
-
- // notify current top of stack it is losing focus
- if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
- final FocusStackEntry exFocusOwner = mFocusStack.peek();
- try {
- exFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
- -1 * focusChangeHint, // loss and gain codes are inverse of each other
- mFocusStack.peek().mClientId);
- exFocusOwner.mFocusLossReceived = -1 * focusChangeHint;
- } catch (RemoteException e) {
- Log.e(TAG, " Failure to signal loss of focus: ", e);
- e.printStackTrace();
- }
+ FocusRequester fr = mFocusStack.pop();
+ fr.release();
}
// focus requester might already be somewhere below in the stack, remove it
removeFocusStackEntry(clientId, false /* signal */);
+ // propagate the focus change through the stack
+ if (!mFocusStack.empty()) {
+ propagateFocusLossFromGain_syncAf(focusChangeHint);
+ }
+
// push focus requester at the top of the audio focus stack
- mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+ mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
clientId, afdh, callingPackageName, Binder.getCallingUid()));
// there's a new top of the stack, let the remote control know
@@ -600,7 +502,7 @@
try {
// this will take care of notifying the new focus owner if needed
synchronized(mAudioFocusLock) {
- removeFocusStackEntry(clientId, true);
+ removeFocusStackEntry(clientId, true /*signal*/);
}
} catch (java.util.ConcurrentModificationException cme) {
// Catching this exception here is temporary. It is here just to prevent
@@ -1593,13 +1495,13 @@
// characteristics:
// - focus gain on STREAM_MUSIC stream
// - non-transient focus gain on a stream other than music
- FocusStackEntry af = null;
+ FocusRequester af = null;
try {
for (int index = mFocusStack.size()-1; index >= 0; index--) {
- FocusStackEntry fse = mFocusStack.elementAt(index);
- if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
- || (fse.mFocusGainRequest == AudioManager.AUDIOFOCUS_GAIN)) {
- af = fse;
+ FocusRequester fr = mFocusStack.elementAt(index);
+ if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
+ || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
+ af = fr;
break;
}
}
@@ -1613,16 +1515,13 @@
}
// if the audio focus and RC owners belong to different packages, there is a mismatch, clear
- if ((mRCStack.peek().mCallingPackageName != null)
- && (af.mPackageName != null)
- && !(mRCStack.peek().mCallingPackageName.compareTo(
- af.mPackageName) == 0)) {
+ if (!af.hasSamePackage(mRCStack.peek().mCallingPackageName)) {
clearRemoteControlDisplay_syncAfRcs();
return;
}
// if the audio focus didn't originate from the same Uid as the one in which the remote
// control information will be retrieved, clear
- if (mRCStack.peek().mCallingUid != af.mCallingUid) {
+ if (!af.hasSameUid(mRCStack.peek().mCallingUid)) {
clearRemoteControlDisplay_syncAfRcs();
return;
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a2eb8d9..3fbaf69 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -40,7 +40,8 @@
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_WIDTH}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_HEIGHT}</td><td>Integer</td><td></td></tr>
- * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user
+ * for encoders, readable in the output format of decoders</b></td></tr>
* <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
* </table>
@@ -154,7 +155,7 @@
/**
* A key describing the AAC profile to be used (AAC audio formats only).
- * Constants are declared in {@link android.media.MediaCodecInfo.CodecCapabilities}.
+ * Constants are declared in {@link android.media.MediaCodecInfo.CodecProfileLevel}.
*/
public static final String KEY_AAC_PROFILE = "aac-profile";
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index bc3adc9..4053666 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -22,9 +22,9 @@
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraCallbacks;
import android.hardware.IProCameraUser;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.ICameraDeviceCallbacks;
-import android.hardware.photography.ICameraDeviceUser;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index a9a0757..acd76d5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -17,18 +17,18 @@
package com.android.mediaframeworktest.integration;
import android.graphics.SurfaceTexture;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.CameraPropertiesKeys;
-import android.hardware.photography.CaptureRequest;
-import android.hardware.photography.ICameraDeviceCallbacks;
-import android.hardware.photography.ICameraDeviceUser;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CameraPropertiesKeys;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraDeviceUser;
import android.os.RemoteException;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.view.Surface;
-import static android.hardware.photography.CameraDevice.TEMPLATE_PREVIEW;
+import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW;
import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner;
import com.android.mediaframeworktest.integration.CameraBinderTest.DummyBase;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 131441b..ecf01d9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -20,11 +20,11 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.graphics.ImageFormat;
import android.graphics.Rect;
-import android.hardware.photography.CameraMetadata;
-import android.hardware.photography.Rational;
-import android.hardware.photography.Size;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.Size;
-import static android.hardware.photography.CameraMetadata.*;
+import static android.hardware.camera2.CameraMetadata.*;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
index 7c48992..727af78 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
@@ -16,17 +16,17 @@
package com.android.mediaframeworktest.unit;
-import android.hardware.photography.CameraAccessException;
-import android.hardware.photography.utils.CameraBinderDecorator;
-import android.hardware.photography.utils.CameraRuntimeException;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.camera2.utils.CameraRuntimeException;
import android.os.DeadObjectException;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.test.suitebuilder.annotation.SmallTest;
import static org.mockito.Mockito.*;
-import static android.hardware.photography.utils.CameraBinderDecorator.*;
-import static android.hardware.photography.CameraAccessException.*;
+import static android.hardware.camera2.utils.CameraBinderDecorator.*;
+import static android.hardware.camera2.CameraAccessException.*;
import junit.framework.Assert;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
index bae17fa..c3b6006 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
@@ -17,8 +17,8 @@
package com.android.mediaframeworktest.unit;
import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.photography.utils.*;
-import android.hardware.photography.utils.Decorator.DecoratorListener;
+import android.hardware.camera2.utils.*;
+import android.hardware.camera2.utils.Decorator.DecoratorListener;
import junit.framework.Assert;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
index 8c2dd4d..02c9f2a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
@@ -16,9 +16,9 @@
package com.android.mediaframeworktest.unit;
-import android.hardware.photography.CameraAccessException;
-import android.hardware.photography.utils.CameraRuntimeException;
-import android.hardware.photography.utils.UncheckedThrow;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.UncheckedThrow;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.Assert;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
index cbe123c..b648763 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsUncheckedThrowTest.java
@@ -16,8 +16,8 @@
package com.android.mediaframeworktest.unit;
-import android.hardware.photography.CameraAccessException;
-import android.hardware.photography.utils.UncheckedThrow;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.utils.UncheckedThrow;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.Assert;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index c15d030..926719c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -17,7 +17,7 @@
package com.android.mediaframeworktest.unit;
import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.photography.Rational;
+import android.hardware.camera2.Rational;
/**
* <pre>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 014c732..6eb88bc 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -77,7 +77,7 @@
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
- <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Imefanyika"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Nimemaliza"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
index 32bc15a..a4105ea 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
@@ -34,12 +34,13 @@
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:layout_marginLeft="32dip"
+ android:layout_marginTop="32dip"
android:layout_marginRight="32dip"
android:layout_marginBottom="12dip"
android:layout_row="0"
android:layout_column="0"
android:layout_columnSpan="2"
- android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Spinner>
<!-- Copies -->
@@ -57,7 +58,8 @@
android:layout_gravity="bottom"
android:inputType="numberDecimal"
android:selectAllOnFocus="true"
- android:minWidth="150dip">
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</view>
<TextView
@@ -86,7 +88,8 @@
android:layout_marginBottom="12dip"
android:layout_row="2"
android:layout_column="1"
- android:minWidth="150dip">
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Spinner>
<TextView
@@ -114,7 +117,8 @@
android:layout_marginBottom="12dip"
android:layout_row="4"
android:layout_column="0"
- android:minWidth="150dip">
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Spinner>
<TextView
@@ -142,7 +146,8 @@
android:layout_marginBottom="12dip"
android:layout_row="4"
android:layout_column="1"
- android:minWidth="150dip">
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Spinner>
<TextView
@@ -169,7 +174,8 @@
android:layout_marginRight="12dip"
android:layout_row="6"
android:layout_column="0"
- android:minWidth="150dip">
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Spinner>
<view
@@ -186,10 +192,12 @@
android:minWidth="150dip"
android:hint="@string/pages_range_example"
android:inputType="textNoSuggestions"
- android:visibility="gone">
+ android:visibility="gone"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</view>
<TextView
+ android:id="@+id/page_range_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="32dip"
@@ -231,7 +239,8 @@
android:layout_columnSpan="2"
android:text="@string/print_preview"
android:gravity="left|center_vertical"
- android:background="?android:attr/selectableItemBackground">
+ android:background="?android:attr/selectableItemBackground"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Button>
<ImageView
@@ -269,7 +278,8 @@
android:layout_columnSpan="2"
android:padding="0dip"
android:text="@string/print_button"
- android:background="?android:attr/selectableItemBackground">
+ android:background="?android:attr/selectableItemBackground"
+ android:minHeight="?android:attr/listPreferredItemHeight">
</Button>
</GridLayout>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 27540d7..1762693 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title of the PrintSpooler application. [CHAR LIMIT=50] -->
<string name="app_label">Print Spooler</string>
@@ -38,7 +38,7 @@
<string name="label_orientation">ORIENTATION</string>
<!-- Label of the page selection widget. [CHAR LIMIT=20] -->
- <string name="label_pages">PAGES</string>
+ <string name="label_pages">PAGES (<xliff:g id="page_count" example="5">%1$s</xliff:g>)</string>
<!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=15] -->
<string name="pages_range_example">e.g. 1–5, 8</string>
@@ -52,6 +52,9 @@
<!-- Title of the message that the printing application crashed. [CHAR LIMIT=50] -->
<string name="printing_app_crashed">Printing app crashed</string>
+ <!-- Title if the number of pages in a printed document is unknown. [CHAR LIMIT=20] -->
+ <string name="page_count_unknown">unknown</string>
+
<!-- Color mode labels. -->
<string-array name="color_mode_labels">
<!-- Color modelabel: Monochrome color scheme, e.g. one color is used. [CHAR LIMIT=20] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 1e1cc24..d61fd2c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -24,9 +24,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -34,24 +32,27 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.UserHandle;
+import android.print.ILayoutResultCallback;
import android.print.IPrintDocumentAdapter;
import android.print.IPrinterDiscoveryObserver;
+import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintAttributes.MediaSize;
-import android.print.PrintDocumentAdapter.LayoutResultCallback;
-import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentAdapter;
import android.print.PrintDocumentInfo;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.text.Editable;
import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Choreographer;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -64,10 +65,13 @@
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
+import android.widget.Toast;
-import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -76,15 +80,31 @@
*/
public class PrintJobConfigActivity extends Activity {
- private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "PrintJobConfigActivity";
- private static final String LOG_TAG = PrintJobConfigActivity.class.getSimpleName();
+ private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
- public static final String EXTRA_PRINTABLE = "printable";
- public static final String EXTRA_APP_ID = "appId";
- public static final String EXTRA_ATTRIBUTES = "attributes";
+ private static final boolean LIVE_PREVIEW_SUPPORTED = false;
+
+ public static final String EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
+ public static final String EXTRA_PRINT_ATTRIBUTES = "printAttributes";
public static final String EXTRA_PRINT_JOB_ID = "printJobId";
+ private static final int CONTROLLER_STATE_INITIALIZED = 1;
+ private static final int CONTROLLER_STATE_STARTED = 2;
+ private static final int CONTROLLER_STATE_LAYOUT_STARTED = 3;
+ private static final int CONTROLLER_STATE_LAYOUT_COMPLETED = 4;
+ private static final int CONTROLLER_STATE_WRITE_STARTED = 5;
+ private static final int CONTROLLER_STATE_WRITE_COMPLETED = 6;
+ private static final int CONTROLLER_STATE_FINISHED = 7;
+ private static final int CONTROLLER_STATE_FAILED = 8;
+ private static final int CONTROLLER_STATE_CANCELLED = 9;
+
+ private static final int EDITOR_STATE_INITIALIZED = 1;
+ private static final int EDITOR_STATE_CONFIRMED_PRINT = 2;
+ private static final int EDITOR_STATE_CONFIRMED_PREVIEW = 3;
+ private static final int EDITOR_STATE_CANCELLED = 4;
+
private static final int MIN_COPIES = 1;
private static final Pattern PATTERN_DIGITS = Pattern.compile("\\d");
@@ -95,31 +115,12 @@
private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
"([0-9]+[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*[,]?[\\s]*)+");
- private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this);
-
- private Handler mHandler;
-
- private Editor mEditor;
-
- private IPrinterDiscoveryObserver mPrinterDiscoveryObserver;
-
- private int mAppId;
- private int mPrintJobId;
+ public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[] {PageRange.ALL_PAGES};
private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().create();
private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().create();
private final PrintAttributes mTempPrintAttributes = new PrintAttributes.Builder().create();
- private RemotePrintDocumentAdapter mRemotePrintAdapter;
-
- private boolean mPrintConfirmed;
-
- private boolean mStarted;
-
- private IBinder mIPrintDocumentAdapter;
-
- private PrintDocumentInfo mPrintDocumentInfo;
-
private final DeathRecipient mDeathRecipient = new DeathRecipient() {
@Override
public void binderDied() {
@@ -127,369 +128,492 @@
}
};
- @Override
- protected void onDestroy() {
- mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
- super.onDestroy();
- }
+ private PrintSpooler mSpooler;
+ private Editor mEditor;
+ private Document mDocument;
+ private PrintController mController;
+ private PrinterDiscoveryObserver mPrinterDiscoveryObserver;
+
+ private int mPrintJobId;
+
+ private IBinder mIPrintDocumentAdapter;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.print_job_config_activity);
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
- | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
- mHandler = new MyHandler(Looper.getMainLooper());
+ Bundle extras = getIntent().getExtras();
+
+ mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
+ if (mPrintJobId < 0) {
+ throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
+ }
+
+ mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
+ if (mIPrintDocumentAdapter == null) {
+ throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
+ }
+
+ PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_PRINT_ATTRIBUTES);
+ if (attributes != null) {
+ mCurrPrintAttributes.copyFrom(attributes);
+ }
+
+ mSpooler = PrintSpooler.getInstance(this);
mEditor = new Editor();
+ mDocument = new Document();
+ mController = new PrintController(new RemotePrintDocumentAdapter(
+ IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
+ mSpooler.generateFileForPrintJob(mPrintJobId)));
}
@Override
protected void onResume() {
super.onResume();
- mPrintSpooler.startPrinterDiscovery(mPrinterDiscoveryObserver);
- notifyPrintableStartIfNeeded();
+ try {
+ mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException re) {
+ finish();
+ return;
+ }
+ mController.initialize();
+ mEditor.initialize();
+ mPrinterDiscoveryObserver = new PrinterDiscoveryObserver(mEditor, getMainLooper());
+ mSpooler.startPrinterDiscovery(mPrinterDiscoveryObserver);
}
@Override
protected void onPause() {
- super.onPause();
- mPrintSpooler.stopPrinterDiscovery();
- notifyPrintableFinishIfNeeded();
- }
-
- private void notifyPrintableStartIfNeeded() {
- if (mEditor.getCurrentPrinter() == null
- || mStarted) {
- return;
- }
- mStarted = true;
- mRemotePrintAdapter.start();
- }
-
- private void updatePrintableContentIfNeeded() {
- if (!mStarted) {
- return;
- }
-
- mPrintSpooler.setPrintJobAttributes(mPrintJobId, mCurrPrintAttributes);
-
- mRemotePrintAdapter.cancel();
- mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FINISHED);
- mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT_FAILED);
-
- // TODO: Implement setting the print preview attribute
- mRemotePrintAdapter.layout(mOldPrintAttributes,
- mCurrPrintAttributes, new LayoutResultCallback() {
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
- 0, info).sendToTarget();
- }
-
- @Override
- public void onLayoutFailed(CharSequence error) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
- }
- }, new Bundle());
- }
-
- private void handleOnLayoutFinished(PrintDocumentInfo info, boolean changed) {
- mPrintDocumentInfo = info;
-
- mEditor.updateUiIfNeeded();
-
- // TODO: Handle the case of unchanged content
- mPrintSpooler.setPrintJobPrintDocumentInfo(mPrintJobId, info);
-
- // TODO: Implement page selector.
- final List<PageRange> pages = new ArrayList<PageRange>();
- pages.add(PageRange.ALL_PAGES);
-
- mRemotePrintAdapter.write(pages, new WriteResultCallback() {
- @Override
- public void onWriteFinished(List<PageRange> pages) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
- }
-
- @Override
- public void onWriteFailed(CharSequence error) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
- }
- });
- }
-
- private void handleOnLayoutFailed(CharSequence error) {
- Log.e(LOG_TAG, "Error during layout: " + error);
- finishActivity(Activity.RESULT_CANCELED);
- }
-
- private void handleOnWriteFinished(List<PageRange> pages) {
- // TODO: Now we have to allow the preview button
- mEditor.updatePrintPreview(mRemotePrintAdapter.getFile());
- }
-
- private void handleOnWriteFailed(CharSequence error) {
- Log.e(LOG_TAG, "Error write layout: " + error);
- finishActivity(Activity.RESULT_CANCELED);
- }
-
- private void notifyPrintableFinishIfNeeded() {
- if (!mStarted) {
- return;
- }
-
- if (!mPrintConfirmed) {
- mRemotePrintAdapter.cancel();
- }
- mRemotePrintAdapter.finish();
-
- PrinterInfo printer = mEditor.getCurrentPrinter();
- // If canceled or no printer, nothing to do.
- if (!mPrintConfirmed || printer == null) {
- // Update the print job's status.
- mPrintSpooler.setPrintJobState(mPrintJobId,
+ mSpooler.stopPrinterDiscovery();
+ mPrinterDiscoveryObserver.destroy();
+ mPrinterDiscoveryObserver = null;
+ if (mController.isCancelled() || mController.isFailed()) {
+ mSpooler.setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED);
- return;
- }
-
- // Update the print job's printer.
- mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printer.getId());
-
- // Update the print job's status.
- mPrintSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_QUEUED);
-
- if (DEBUG) {
- if (mPrintConfirmed) {
- File file = mRemotePrintAdapter.getFile();
- if (file.exists()) {
- new ViewSpooledFileAsyncTask(file).executeOnExecutor(
- AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ } else if (mController.hasStarted()) {
+ mController.finish();
+ if (mEditor.isPrintConfirmed()) {
+ if (mController.isFinished()) {
+ mSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_QUEUED);
+ } else {
+ mSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_CANCELED);
}
}
}
+ mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
+ super.onPause();
}
- private boolean hasPdfViewer() {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setType("application/pdf");
- return !getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
- }
-
- // Caution: Use this only for debugging
- private final class ViewSpooledFileAsyncTask extends AsyncTask<Void, Void, Void> {
-
- private final File mFile;
-
- public ViewSpooledFileAsyncTask(File file) {
- mFile = file;
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!mEditor.isPrintConfirmed() && !mEditor.isPreviewConfirmed()
+ && getWindow().shouldCloseOnTouch(this, event)) {
+ if (!mController.isWorking()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ mEditor.cancel();
+ return true;
}
-
- @Override
- protected Void doInBackground(Void... params) {
- mFile.setExecutable(true, false);
- mFile.setWritable(true, false);
- mFile.setReadable(true, false);
-
- final long identity = Binder.clearCallingIdentity();
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(Uri.fromFile(mFile), "application/pdf");
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityAsUser(intent, null, UserHandle.CURRENT);
- Binder.restoreCallingIdentity(identity);
- return null;
- }
+ return super.onTouchEvent(event);
}
- private final class PrintDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
- private static final int MESSAGE_ADD_DICOVERED_PRINTERS = 1;
- private static final int MESSAGE_REMOVE_DICOVERED_PRINTERS = 2;
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ && !event.isCanceled()) {
+ if (!mController.isWorking()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ mEditor.cancel();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ private boolean printAttributesChanged() {
+ return !mOldPrintAttributes.equals(mCurrPrintAttributes);
+ }
+
+ private class PrintController {
+ private final AtomicInteger mRequestCounter = new AtomicInteger();
+
+ private final RemotePrintDocumentAdapter mRemotePrintAdapter;
private final Handler mHandler;
- @SuppressWarnings("unchecked")
- public PrintDiscoveryObserver(Looper looper) {
- mHandler = new Handler(looper, null, true) {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MESSAGE_ADD_DICOVERED_PRINTERS: {
- List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
- mEditor.addPrinters(printers);
- } break;
- case MESSAGE_REMOVE_DICOVERED_PRINTERS: {
- List<PrinterId> printerIds = (List<PrinterId>) message.obj;
- mEditor.removePrinters(printerIds);
- } break;
- }
+ private int mControllerState = CONTROLLER_STATE_INITIALIZED;
+
+ private PageRange[] mRequestedPages;
+
+ private Bundle mMetadata = new Bundle();
+
+ private final ILayoutResultCallback mILayoutResultCallback =
+ new ILayoutResultCallback.Stub() {
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
+ if (mRequestCounter.get() == sequence) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
+ 0, info).sendToTarget();
}
- };
- }
-
- @Override
- public void addDiscoveredPrinters(List<PrinterInfo> printers) {
- mHandler.obtainMessage(MESSAGE_ADD_DICOVERED_PRINTERS, printers).sendToTarget();
- }
-
- @Override
- public void removeDiscoveredPrinters(List<PrinterId> printers) {
- mHandler.obtainMessage(MESSAGE_REMOVE_DICOVERED_PRINTERS, printers).sendToTarget();
- }
- }
-
- private final class SpinnerItem<T> {
- final T value;
- CharSequence label;
-
- public SpinnerItem(T value, CharSequence label) {
- this.value = value;
- this.label = label;
- }
-
- public String toString() {
- return label.toString();
- }
- }
-
- /**
- * An instance of this class class is intended to be the first focusable
- * in a layout to which the system automatically gives focus. It performs
- * some voodoo to avoid the first tap on it to start an edit mode, rather
- * to bring up the IME, i.e. to get the behavior as if the view was not
- * focused.
- */
- public static final class CustomEditText extends EditText {
- private boolean mClickedBeforeFocus;
-
- public CustomEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean performClick() {
- super.performClick();
- if (isFocused() && !mClickedBeforeFocus) {
- clearFocus();
- requestFocus();
}
- mClickedBeforeFocus = true;
- return true;
- }
- @Override
- public void setError(CharSequence error, Drawable icon) {
- setCompoundDrawables(null, null, icon, null);
- }
-
- protected void onFocusChanged(boolean gainFocus, int direction,
- Rect previouslyFocusedRect) {
- if (!gainFocus) {
- mClickedBeforeFocus = false;
+ @Override
+ public void onLayoutFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() == sequence) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
+ }
}
- super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- }
- }
+ };
- private final class MyHandler extends Handler {
- public static final int MSG_ON_LAYOUT_FINISHED = 1;
- public static final int MSG_ON_LAYOUT_FAILED = 2;
- public static final int MSG_ON_WRITE_FINISHED = 3;
- public static final int MSG_ON_WRITE_FAILED = 4;
+ private IWriteResultCallback mIWriteResultCallback = new IWriteResultCallback.Stub() {
+ @Override
+ public void onWriteFinished(PageRange[] pages, int sequence) {
+ if (mRequestCounter.get() == sequence) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
+ }
+ }
- public MyHandler(Looper looper) {
- super(looper, null, false);
+ @Override
+ public void onWriteFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() == sequence) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
+ }
+ }
+ };
+
+ public PrintController(RemotePrintDocumentAdapter adapter) {
+ mRemotePrintAdapter = adapter;
+ mHandler = new MyHandler(Looper.getMainLooper());
}
- @Override
- @SuppressWarnings("unchecked")
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_ON_LAYOUT_FINISHED: {
- PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
- final boolean changed = (message.arg1 == 1);
- handleOnLayoutFinished(info, changed);
- } break;
+ public void initialize() {
+ mControllerState = CONTROLLER_STATE_INITIALIZED;
+ }
- case MSG_ON_LAYOUT_FAILED: {
- CharSequence error = (CharSequence) message.obj;
- handleOnLayoutFailed(error);
- } break;
+ public void cancel() {
+ mControllerState = CONTROLLER_STATE_CANCELLED;
+ }
- case MSG_ON_WRITE_FINISHED: {
- List<PageRange> pages = (List<PageRange>) message.obj;
- handleOnWriteFinished(pages);
- } break;
+ public boolean isCancelled() {
+ return (mControllerState == CONTROLLER_STATE_CANCELLED);
+ }
- case MSG_ON_WRITE_FAILED: {
- CharSequence error = (CharSequence) message.obj;
- handleOnWriteFailed(error);
- } break;
+ public boolean isFinished() {
+ return (mControllerState == CONTROLLER_STATE_FINISHED);
+ }
+
+ public boolean isFailed() {
+ return (mControllerState == CONTROLLER_STATE_FAILED);
+ }
+
+ public boolean hasStarted() {
+ return mControllerState >= CONTROLLER_STATE_STARTED;
+ }
+
+ public boolean hasPerformedLayout() {
+ return mControllerState >= CONTROLLER_STATE_LAYOUT_COMPLETED;
+ }
+
+ public boolean isWorking() {
+ return mControllerState == CONTROLLER_STATE_LAYOUT_STARTED
+ || mControllerState == CONTROLLER_STATE_WRITE_STARTED;
+ }
+
+ public void start() {
+ mControllerState = CONTROLLER_STATE_STARTED;
+ mRemotePrintAdapter.start();
+ }
+
+ public void update() {
+ if (!printAttributesChanged()) {
+ // If the attributes changes, then we do not do a layout but may
+ // have to ask the app to write some pages. Hence, pretend layout
+ // completed and nothing changed, so we handle writing as usual.
+ handleOnLayoutFinished(mDocument.info, false);
+ } else {
+ mSpooler.setPrintJobAttributesNoPersistence(mPrintJobId, mCurrPrintAttributes);
+
+ mMetadata.putBoolean(PrintDocumentAdapter.METADATA_KEY_PRINT_PREVIEW,
+ !mEditor.isPrintConfirmed());
+
+ mControllerState = CONTROLLER_STATE_LAYOUT_STARTED;
+
+ mRemotePrintAdapter.layout(mOldPrintAttributes, mCurrPrintAttributes,
+ mILayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
+
+ mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
+ }
+ }
+
+ public void finish() {
+ mControllerState = CONTROLLER_STATE_FINISHED;
+ mRemotePrintAdapter.finish();
+ }
+
+ private void handleOnLayoutFinished(PrintDocumentInfo info, boolean layoutChanged) {
+ if (isCancelled()) {
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ return;
+ }
+
+ mControllerState = CONTROLLER_STATE_LAYOUT_COMPLETED;
+
+ // If the info changed, we update the document and the print job,
+ // and update the UI since the the page range selection may have
+ // become invalid.
+ final boolean infoChanged = !info.equals(mDocument.info);
+ if (infoChanged) {
+ mDocument.info = info;
+ mSpooler.setPrintJobPrintDocumentInfoNoPersistence(mPrintJobId, info);
+ mEditor.updateUi();
+ }
+
+ // If the document info or the layout changed, then
+ // drop the pages since we have to fetch them again.
+ if (infoChanged || layoutChanged) {
+ mDocument.pages = null;
+ }
+
+ // No pages means that the user selected an invalid range while we
+ // were doing a layout or the layout returned a document info for
+ // which the selected range is invalid. In such a case we do not
+ // write anything and wait for the user to fix the range which will
+ // trigger an update.
+ mRequestedPages = mEditor.getRequestedPages();
+ if (mRequestedPages == null) {
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ return;
+ }
+
+ // If the info and the layout did not change and we already have
+ // the requested pages, then nothing else to do.
+ if (!infoChanged && !layoutChanged
+ && PageRangeUtils.contains(mDocument.pages, mRequestedPages)) {
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ return;
+ }
+
+ // If we do not support live preview and the current layout is
+ // not for preview purposes, i.e. the user did not poke the
+ // preview button, then just skip the write.
+ if (!LIVE_PREVIEW_SUPPORTED && !mEditor.isPreviewConfirmed()
+ && mMetadata.getBoolean(PrintDocumentAdapter.METADATA_KEY_PRINT_PREVIEW)) {
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ return;
+ }
+
+ // Request a write of the pages of interest.
+ mControllerState = CONTROLLER_STATE_WRITE_STARTED;
+ mRemotePrintAdapter.write(mRequestedPages, mIWriteResultCallback,
+ mRequestCounter.incrementAndGet());
+ }
+
+ private void handleOnLayoutFailed(CharSequence error) {
+ mControllerState = CONTROLLER_STATE_FAILED;
+ // TODO: We need some UI for announcing an error.
+ Log.e(LOG_TAG, "Error during layout: " + error);
+ PrintJobConfigActivity.this.finish();
+ }
+
+ private void handleOnWriteFinished(PageRange[] pages) {
+ if (isCancelled()) {
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ return;
+ }
+
+ mControllerState = CONTROLLER_STATE_WRITE_COMPLETED;
+
+ // Update which pages we have fetched.
+ mDocument.pages = PageRangeUtils.normalize(pages);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Requested: " + Arrays.toString(mRequestedPages)
+ + " and got: " + Arrays.toString(mDocument.pages));
+ }
+
+ // Adjust the print job pages based on what was requested and written.
+ // The cases are ordered in the most expected to the least expected.
+ if (Arrays.equals(mDocument.pages, mRequestedPages)) {
+ // We got a document with exactly the pages we wanted. Hence,
+ // the printer has to print all pages in the data.
+ mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, ALL_PAGES_ARRAY);
+ } else if (Arrays.equals(mDocument.pages, ALL_PAGES_ARRAY)) {
+ // We requested specific pages but got all of them. Hence,
+ // the printer has to print only the requested pages.
+ mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mRequestedPages);
+ } else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) {
+ // We requested specific pages and got more but not all pages.
+ // Hence, we have to offset appropriately the printed pages to
+ // excle the pages we did not request. Note that pages is
+ // guaranteed to be not null and not empty.
+ final int offset = mDocument.pages[0].getStart() - pages[0].getStart();
+ PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length);
+ PageRangeUtils.offsetStart(offsetPages, offset);
+ mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, offsetPages);
+ } else if (Arrays.equals(mRequestedPages, ALL_PAGES_ARRAY)
+ && mDocument.pages.length == 1 && mDocument.pages[0].getStart() == 0
+ && mDocument.pages[0].getEnd() == mDocument.info.getPageCount() - 1) {
+ // We requested all pages via the special constant and got all
+ // of them as an explicit enumeration. Hence, the printer has
+ // to print only the requested pages.
+ mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mDocument.pages);
+ } else {
+ // We did not get the pages we requested, then the application
+ // misbehaves, so we fail quickly.
+ // TODO: We need some UI for announcing an error.
+ mControllerState = CONTROLLER_STATE_FAILED;
+ Log.e(LOG_TAG, "Received invalid pages from the app");
+ PrintJobConfigActivity.this.finish();
+ }
+
+ if (mEditor.isDone()) {
+ PrintJobConfigActivity.this.finish();
+ }
+ }
+
+ private void handleOnWriteFailed(CharSequence error) {
+ mControllerState = CONTROLLER_STATE_FAILED;
+ Log.e(LOG_TAG, "Error during write: " + error);
+ PrintJobConfigActivity.this.finish();
+ }
+
+ private final class MyHandler extends Handler {
+ public static final int MSG_ON_LAYOUT_FINISHED = 1;
+ public static final int MSG_ON_LAYOUT_FAILED = 2;
+ public static final int MSG_ON_WRITE_FINISHED = 3;
+ public static final int MSG_ON_WRITE_FAILED = 4;
+
+ public MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ON_LAYOUT_FINISHED: {
+ PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
+ final boolean changed = (message.arg1 == 1);
+ mController.handleOnLayoutFinished(info, changed);
+ } break;
+
+ case MSG_ON_LAYOUT_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ mController.handleOnLayoutFailed(error);
+ } break;
+
+ case MSG_ON_WRITE_FINISHED: {
+ PageRange[] pages = (PageRange[]) message.obj;
+ mController.handleOnWriteFinished(pages);
+ } break;
+
+ case MSG_ON_WRITE_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ mController.handleOnWriteFailed(error);
+ } break;
+ }
}
}
}
- private class Editor {
- private EditText mCopiesEditText;
+ private final class Editor {
+ private final EditText mCopiesEditText;
- private EditText mRangeEditText;
+ private final TextView mRangeTitle;
+ private final EditText mRangeEditText;
- private Spinner mDestinationSpinner;
- public ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
+ private final Spinner mDestinationSpinner;
+ private final ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
- private Spinner mMediaSizeSpinner;
- public ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
+ private final Spinner mMediaSizeSpinner;
+ private final ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
- private Spinner mColorModeSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
+ private final Spinner mColorModeSpinner;
+ private final ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
- private Spinner mOrientationSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
+ private final Spinner mOrientationSpinner;
+ private final ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
- private Spinner mRangeOptionsSpinner;
- public ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
+ private final Spinner mRangeOptionsSpinner;
+ private final ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
- private Button mPrintPreviewButton;
+ private final SimpleStringSplitter mStringCommaSplitter =
+ new SimpleStringSplitter(',');
- private Button mPrintButton;
+ private final Button mPrintPreviewButton;
+
+ private final Button mPrintButton;
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
if (spinner == mDestinationSpinner) {
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
mCurrPrintAttributes.clear();
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex >= 0) {
- mDestinationSpinnerAdapter.getItem(selectedIndex).value.getDefaults(
- mCurrPrintAttributes);
+ SpinnerItem<PrinterInfo> dstItem = mDestinationSpinnerAdapter.getItem(position);
+ if (dstItem != null) {
+ PrinterInfo printer = dstItem.value;
+ mSpooler.setPrintJobPrinterIdNoPersistence(mPrintJobId, printer.getId());
+ printer.getDefaults(mCurrPrintAttributes);
+ if (!printer.hasAllRequiredAttributes()) {
+ List<PrinterId> printerIds = new ArrayList<PrinterId>();
+ printerIds.add(printer.getId());
+ mSpooler.onReqeustUpdatePrinters(printerIds);
+ //TODO: We need a timeout for the update.
+ } else {
+ if (!mController.hasStarted()) {
+ mController.start();
+ }
+ if (!hasErrors()) {
+ mController.update();
+ }
+ }
}
- updateUiIfNeeded();
- notifyPrintableStartIfNeeded();
- updatePrintableContentIfNeeded();
+ updateUi();
} else if (spinner == mMediaSizeSpinner) {
SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
mCurrPrintAttributes.setMediaSize(mediaItem.value);
- updatePrintableContentIfNeeded();
+ if (!hasErrors()) {
+ mController.update();
+ }
} else if (spinner == mColorModeSpinner) {
SpinnerItem<Integer> colorModeItem =
mColorModeSpinnerAdapter.getItem(position);
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
mCurrPrintAttributes.setColorMode(colorModeItem.value);
- updatePrintableContentIfNeeded();
+ if (!hasErrors()) {
+ mController.update();
+ }
} else if (spinner == mOrientationSpinner) {
SpinnerItem<Integer> orientationItem =
mOrientationSpinnerAdapter.getItem(position);
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
mCurrPrintAttributes.setOrientation(orientationItem.value);
- updatePrintableContentIfNeeded();
+ if (!hasErrors()) {
+ mController.update();
+ }
} else if (spinner == mRangeOptionsSpinner) {
- updateUiIfNeeded();
- updatePrintableContentIfNeeded();
+ updateUi();
+ if (!hasErrors()) {
+ mController.update();
+ }
}
}
@@ -512,19 +636,28 @@
@Override
public void afterTextChanged(Editable editable) {
+ final boolean hadErrors = hasErrors();
+
if (editable.length() == 0) {
mCopiesEditText.setError("");
- mPrintButton.setEnabled(false);
+ updateUi();
return;
}
+
final int copies = Integer.parseInt(editable.toString());
if (copies < MIN_COPIES) {
mCopiesEditText.setError("");
- mPrintButton.setEnabled(false);
+ updateUi();
return;
}
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
- mCurrPrintAttributes.setCopies(copies);
+
+ mCopiesEditText.setError(null);
+ mSpooler.setPrintJobCopiesNoPersistence(mPrintJobId, copies);
+ updateUi();
+
+ if (hadErrors && !hasErrors() && printAttributesChanged()) {
+ mController.update();
+ }
}
};
@@ -541,18 +674,20 @@
@Override
public void afterTextChanged(Editable editable) {
+ final boolean hadErrors = hasErrors();
+
String text = editable.toString();
if (TextUtils.isEmpty(text)) {
mRangeEditText.setError("");
- mPrintButton.setEnabled(false);
+ updateUi();
return;
}
String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
mRangeEditText.setError("");
- mPrintButton.setEnabled(false);
+ updateUi();
return;
}
@@ -560,100 +695,36 @@
while (matcher.find()) {
String numericString = text.substring(matcher.start(), matcher.end());
final int pageIndex = Integer.parseInt(numericString);
- if (pageIndex < 1 || pageIndex > mPrintDocumentInfo.getPageCount()) {
+ if (pageIndex < 1 || pageIndex > mDocument.info.getPageCount()) {
mRangeEditText.setError("");
- mPrintButton.setEnabled(false);
+ updateUi();
return;
}
}
+ //TODO: Catch the error if start is less grater than the end.
+
mRangeEditText.setError(null);
mPrintButton.setEnabled(true);
+ updateUi();
+
+ if (hadErrors && !hasErrors() && printAttributesChanged()) {
+ updateUi();
+ }
}
};
+ private int mEditorState;
+
public Editor() {
- Bundle extras = getIntent().getExtras();
-
- mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
- if (mPrintJobId < 0) {
- throw new IllegalArgumentException("Invalid print job id: " + mPrintJobId);
- }
-
- mAppId = extras.getInt(EXTRA_APP_ID, -1);
- if (mAppId < 0) {
- throw new IllegalArgumentException("Invalid app id: " + mAppId);
- }
-
- PrintAttributes attributes = getIntent().getParcelableExtra(EXTRA_ATTRIBUTES);
- if (attributes == null) {
- mCurrPrintAttributes.copyFrom(attributes);
- }
-
- mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
- if (mIPrintDocumentAdapter == null) {
- throw new IllegalArgumentException("Printable cannot be null");
- }
- mRemotePrintAdapter = new RemotePrintDocumentAdapter(
- IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
- mPrintSpooler.generateFileForPrintJob(mPrintJobId));
-
- try {
- mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException re) {
- finish();
- }
-
- mPrinterDiscoveryObserver = new PrintDiscoveryObserver(getMainLooper());
-
- bindUi();
- }
-
- private void bindUi() {
// Copies
mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
- mCopiesEditText.setText(String.valueOf(MIN_COPIES));
mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
- mCopiesEditText.setText(String.valueOf(
- Math.max(mCurrPrintAttributes.getCopies(), MIN_COPIES)));
mCopiesEditText.selectAll();
// Destination.
mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
- mDestinationSpinnerAdapter = new ArrayAdapter<SpinnerItem<PrinterInfo>>(
- PrintJobConfigActivity.this, R.layout.spinner_dropdown_item) {
- @Override
- public View getDropDownView(int position, View convertView,
- ViewGroup parent) {
- return getView(position, convertView, parent);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = getLayoutInflater().inflate(
- R.layout.spinner_dropdown_item, parent, false);
- }
-
- PrinterInfo printerInfo = getItem(position).value;
- TextView title = (TextView) convertView.findViewById(R.id.title);
- title.setText(printerInfo.getLabel());
-
- try {
- TextView subtitle = (TextView)
- convertView.findViewById(R.id.subtitle);
- PackageManager pm = getPackageManager();
- PackageInfo packageInfo = pm.getPackageInfo(
- printerInfo.getId().getService().getPackageName(), 0);
- subtitle.setText(packageInfo.applicationInfo.loadLabel(pm));
- subtitle.setVisibility(View.VISIBLE);
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
-
- return convertView;
- }
- };
+ mDestinationSpinnerAdapter = new DestinationAdapter();
mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
@@ -682,6 +753,7 @@
mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
// Range
+ mRangeTitle = (TextView) findViewById(R.id.page_range_title);
mRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
mRangeEditText.addTextChangedListener(mRangeTextWatcher);
@@ -690,8 +762,6 @@
mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
PrintJobConfigActivity.this,
R.layout.spinner_dropdown_item, R.id.title);
- mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
- mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
final int[] rangeOptionsValues = getResources().getIntArray(
R.array.page_options_values);
String[] rangeOptionsLabels = getResources().getStringArray(
@@ -701,13 +771,29 @@
mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>(
rangeOptionsValues[i], rangeOptionsLabels[i]));
}
+ mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
mRangeOptionsSpinner.setSelection(0);
+ // Here is some voodoo to circumvent the weird behavior of AdapterView
+ // in which a selection listener may get a callback for an event that
+ // happened before the listener was registered. The reason for that is
+ // that the selection change is handled on the next layout pass.
+ Choreographer.getInstance().postCallbackDelayed(Choreographer.CALLBACK_TRAVERSAL,
+ new Runnable() {
+ @Override
+ public void run() {
+ mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ }
+ }, null, Choreographer.getFrameDelay() * 2);
mPrintPreviewButton = (Button) findViewById(R.id.print_preview_button);
mPrintPreviewButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- // TODO: Implement
+ mEditor.confirmPreview();
+ // TODO: Implement me
+ Toast.makeText(PrintJobConfigActivity.this,
+ "Stop poking me! Not implemented yet :)",
+ Toast.LENGTH_LONG).show();
}
});
@@ -715,21 +801,108 @@
mPrintButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- mPrintConfirmed = true;
- finish();
+ mEditor.confirmPrint();
+ updateUi();
+ mController.update();
}
});
}
- private void updateUiIfNeeded() {
+ public void initialize() {
+ mEditorState = EDITOR_STATE_INITIALIZED;
+ mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION);
+ }
+
+ public boolean isCancelled() {
+ return mEditorState == EDITOR_STATE_CANCELLED;
+ }
+
+ public void cancel() {
+ mEditorState = EDITOR_STATE_CANCELLED;
+ mController.cancel();
+ updateUi();
+ }
+
+ public boolean isDone() {
+ return isPrintConfirmed() || isPreviewConfirmed() || isCancelled();
+ }
+
+ public boolean isPrintConfirmed() {
+ return mEditorState == EDITOR_STATE_CONFIRMED_PRINT;
+ }
+
+ public void confirmPrint() {
+ mEditorState = EDITOR_STATE_CONFIRMED_PRINT;
+ }
+
+ public boolean isPreviewConfirmed() {
+ return mEditorState == EDITOR_STATE_CONFIRMED_PRINT;
+ }
+
+ public void confirmPreview() {
+ mEditorState = EDITOR_STATE_CONFIRMED_PREVIEW;
+ }
+
+ public PageRange[] getRequestedPages() {
+ if (hasErrors()) {
+ return null;
+ }
+ if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+ List<PageRange> pageRanges = new ArrayList<PageRange>();
+ mStringCommaSplitter.setString(mRangeEditText.getText().toString());
+
+ while (mStringCommaSplitter.hasNext()) {
+ String range = mStringCommaSplitter.next().trim();
+ final int dashIndex = range.indexOf('-');
+ final int fromIndex;
+ final int toIndex;
+
+ if (dashIndex > 0) {
+ fromIndex = Integer.parseInt(range.substring(0, dashIndex)) - 1;
+ toIndex = Integer.parseInt(range.substring(
+ dashIndex + 1, range.length())) - 1;
+ } else {
+ fromIndex = toIndex = Integer.parseInt(range);
+ }
+
+ PageRange pageRange = new PageRange(fromIndex, toIndex);
+ pageRanges.add(pageRange);
+ }
+
+ PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+ pageRanges.toArray(pageRangesArray);
+
+ return PageRangeUtils.normalize(pageRangesArray);
+ }
+
+ return ALL_PAGES_ARRAY;
+ }
+
+ public void updateUi() {
+ if (isPrintConfirmed() || isPreviewConfirmed() || isCancelled()) {
+ mDestinationSpinner.setEnabled(false);
+ mCopiesEditText.setEnabled(false);
+ mMediaSizeSpinner.setEnabled(false);
+ mColorModeSpinner.setEnabled(false);
+ mOrientationSpinner.setEnabled(false);
+ mRangeOptionsSpinner.setEnabled(false);
+ mRangeEditText.setEnabled(false);
+ mPrintPreviewButton.setEnabled(false);
+ mPrintButton.setEnabled(false);
+ return;
+ }
+
final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex < 0) {
+ if (selectedIndex < 0 || !mDestinationSpinnerAdapter.getItem(
+ selectedIndex).value.hasAllRequiredAttributes()) {
+
// Destination
mDestinationSpinner.setEnabled(false);
- // Copies
- mCopiesEditText.setText("1");
+ mCopiesEditText.removeTextChangedListener(mCopiesTextWatcher);
+ mCopiesEditText.setText(String.valueOf(MIN_COPIES));
+ mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
mCopiesEditText.setEnabled(false);
// Media size
@@ -751,7 +924,11 @@
mRangeOptionsSpinner.setOnItemSelectedListener(null);
mRangeOptionsSpinner.setSelection(0);
mRangeOptionsSpinner.setEnabled(false);
+ mRangeTitle.setText(getString(R.string.label_pages,
+ getString(R.string.page_count_unknown)));
+ mRangeEditText.removeTextChangedListener(mRangeTextWatcher);
mRangeEditText.setText("");
+ mRangeEditText.addTextChangedListener(mRangeTextWatcher);
mRangeEditText.setEnabled(false);
mRangeEditText.setVisibility(View.INVISIBLE);
@@ -884,46 +1061,65 @@
}
// Range options
- if (mPrintDocumentInfo != null && (mPrintDocumentInfo.getPageCount() > 1
- || mPrintDocumentInfo.getPageCount()
- == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) {
+ PrintDocumentInfo info = mDocument.info;
+ if (info != null && (info.getPageCount() > 1
+ || info.getPageCount() == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) {
mRangeOptionsSpinner.setEnabled(true);
if (mRangeOptionsSpinner.getSelectedItemPosition() > 0
&& !mRangeEditText.isEnabled()) {
mRangeEditText.setEnabled(true);
- mRangeEditText.setError("");
mRangeEditText.setVisibility(View.VISIBLE);
mRangeEditText.requestFocus();
InputMethodManager imm = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
imm.showSoftInput(mRangeEditText, 0);
}
+ final int pageCount = mDocument.info.getPageCount();
+ mRangeTitle.setText(getString(R.string.label_pages,
+ (pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
+ ? getString(R.string.page_count_unknown)
+ : String.valueOf(pageCount)));
} else {
mRangeOptionsSpinner.setOnItemSelectedListener(null);
mRangeOptionsSpinner.setSelection(0);
mRangeOptionsSpinner.setEnabled(false);
+ mRangeTitle.setText(getString(R.string.label_pages,
+ getString(R.string.page_count_unknown)));
mRangeEditText.setEnabled(false);
- mRangeEditText.setText("");
mRangeEditText.setVisibility(View.INVISIBLE);
}
- // Print preview
- mPrintPreviewButton.setEnabled(true);
- if (hasPdfViewer()) {
- mPrintPreviewButton.setText(getString(R.string.print_preview));
+ // Print/Print preview
+ if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1
+ && (TextUtils.isEmpty(mRangeEditText.getText()) || hasErrors()))
+ || (mRangeOptionsSpinner.getSelectedItemPosition() == 0
+ && (!mController.hasPerformedLayout() || hasErrors()))) {
+ mPrintPreviewButton.setEnabled(false);
+ mPrintButton.setEnabled(false);
} else {
- mPrintPreviewButton.setText(getString(R.string.install_for_print_preview));
+ mPrintPreviewButton.setEnabled(true);
+ if (hasPdfViewer()) {
+ mPrintPreviewButton.setText(getString(R.string.print_preview));
+ } else {
+ mPrintPreviewButton.setText(getString(R.string.install_for_print_preview));
+ }
+ mPrintButton.setEnabled(true);
}
- // Print
- mPrintButton.setEnabled(true);
+ // Copies
+ if (mCopiesEditText.getError() == null
+ && TextUtils.isEmpty(mCopiesEditText.getText())) {
+ mCopiesEditText.setText(String.valueOf(MIN_COPIES));
+ mCopiesEditText.selectAll();
+ mCopiesEditText.requestFocus();
+ }
}
// Here is some voodoo to circumvent the weird behavior of AdapterView
// in which a selection listener may get a callback for an event that
// happened before the listener was registered. The reason for that is
// that the selection change is handled on the next layout pass.
- Choreographer.getInstance().postCallback(Choreographer.CALLBACK_TRAVERSAL,
+ Choreographer.getInstance().postCallbackDelayed(Choreographer.CALLBACK_TRAVERSAL,
new Runnable() {
@Override
public void run() {
@@ -932,15 +1128,7 @@
mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
}
- }, null);
- }
-
- public PrinterInfo getCurrentPrinter() {
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex >= 0) {
- return mDestinationSpinnerAdapter.getItem(selectedIndex).value;
- }
- return null;
+ }, null, Choreographer.getFrameDelay() * 2);
}
public void addPrinters(List<PrinterInfo> addedPrinters) {
@@ -995,8 +1183,317 @@
}
}
- private void updatePrintPreview(File file) {
- // TODO: Implement
+ @SuppressWarnings("unchecked")
+ public void updatePrinters(List<PrinterInfo> pritners) {
+ SpinnerItem<PrinterInfo> selectedItem =
+ (SpinnerItem<PrinterInfo>) mDestinationSpinner.getSelectedItem();
+ PrinterId selectedPrinterId = (selectedItem != null)
+ ? selectedItem.value.getId() : null;
+
+ boolean updated = false;
+
+ final int printerCount = pritners.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterInfo updatedPrinter = pritners.get(i);
+ final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
+ for (int j = 0; j < existingPrinterCount; j++) {
+ PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
+ if (updatedPrinter.getId().equals(existingPrinter.getId())) {
+ existingPrinter.copyFrom(updatedPrinter);
+ updated = true;
+ if (selectedPrinterId != null
+ && selectedPrinterId.equals(updatedPrinter.getId())) {
+ // The selected printer was updated. We simulate a fake
+ // selection to reuse the normal printer change handling.
+ mOnItemSelectedListener.onItemSelected(mDestinationSpinner,
+ mDestinationSpinner.getSelectedView(),
+ mDestinationSpinner.getSelectedItemPosition(),
+ mDestinationSpinner.getSelectedItemId());
+ // TODO: This will reset the UI to the defaults for the
+ // printer. We may need to revisit this.
+
+ }
+ break;
+ }
+ }
+ }
+ if (updated) {
+ mDestinationSpinnerAdapter.notifyDataSetChanged();
+ }
+ }
+
+ private boolean hasErrors() {
+ return mRangeEditText.getError() != null
+ || mCopiesEditText.getError() != null;
+ }
+
+ private boolean hasPdfViewer() {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setType("application/pdf");
+ return !getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
+ }
+
+ private final class SpinnerItem<T> {
+ final T value;
+ CharSequence label;
+
+ public SpinnerItem(T value, CharSequence label) {
+ this.value = value;
+ this.label = label;
+ }
+
+ public String toString() {
+ return label.toString();
+ }
+ }
+
+ private final class DestinationAdapter extends ArrayAdapter<SpinnerItem<PrinterInfo>> {
+
+ public DestinationAdapter() {
+ super( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item);
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView,
+ ViewGroup parent) {
+ return getView(position, convertView, parent);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.spinner_dropdown_item, parent, false);
+ }
+
+ PrinterInfo printerInfo = getItem(position).value;
+ TextView title = (TextView) convertView.findViewById(R.id.title);
+ title.setText(printerInfo.getLabel());
+
+ try {
+ TextView subtitle = (TextView)
+ convertView.findViewById(R.id.subtitle);
+ PackageManager pm = getPackageManager();
+ PackageInfo packageInfo = pm.getPackageInfo(
+ printerInfo.getId().getService().getPackageName(), 0);
+ subtitle.setText(packageInfo.applicationInfo.loadLabel(pm));
+ subtitle.setVisibility(View.VISIBLE);
+ } catch (NameNotFoundException nnfe) {
+ /* ignore */
+ }
+
+ return convertView;
+ }
+ }
+ }
+
+ private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
+ private static final int MSG_ON_PRINTERS_ADDED = 1;
+ private static final int MSG_ON_PRINTERS_REMOVED = 2;
+ private static final int MSG_ON_PRINTERS_UPDATED = 3;
+
+ private Handler mHandler;
+ private Editor mEditor;
+
+ @SuppressWarnings("unchecked")
+ public PrinterDiscoveryObserver(Editor editor, Looper looper) {
+ mEditor = editor;
+ mHandler = new Handler(looper, null, true) {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ON_PRINTERS_ADDED: {
+ List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
+ mEditor.addPrinters(printers);
+ } break;
+
+ case MSG_ON_PRINTERS_REMOVED: {
+ List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+ mEditor.removePrinters(printerIds);
+ } break;
+
+ case MSG_ON_PRINTERS_UPDATED: {
+ List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
+ mEditor.updatePrinters(printers);
+ } break;
+ }
+ }
+ };
+ }
+
+ @Override
+ public void onPrintersAdded(List<PrinterInfo> printers) {
+ synchronized (this) {
+ if (mHandler != null) {
+ mHandler.obtainMessage(MSG_ON_PRINTERS_ADDED, printers)
+ .sendToTarget();
+ }
+ }
+ }
+
+ @Override
+ public void onPrintersRemoved(List<PrinterId> printers) {
+ synchronized (this) {
+ if (mHandler != null) {
+ mHandler.obtainMessage(MSG_ON_PRINTERS_REMOVED, printers)
+ .sendToTarget();
+ }
+ }
+ }
+
+ @Override
+ public void onPrintersUpdated(List<PrinterInfo> printers) {
+ synchronized (this) {
+ if (mHandler != null) {
+ mHandler.obtainMessage(MSG_ON_PRINTERS_UPDATED, printers)
+ .sendToTarget();
+ }
+ }
+ }
+
+ public void destroy() {
+ synchronized (this) {
+ mHandler = null;
+ mEditor = null;
+ }
+ }
+ }
+
+ /**
+ * An instance of this class class is intended to be the first focusable
+ * in a layout to which the system automatically gives focus. It performs
+ * some voodoo to avoid the first tap on it to start an edit mode, rather
+ * to bring up the IME, i.e. to get the behavior as if the view was not
+ * focused.
+ */
+ public static final class CustomEditText extends EditText {
+ private boolean mClickedBeforeFocus;
+ private CharSequence mError;
+
+ public CustomEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean performClick() {
+ super.performClick();
+ if (isFocused() && !mClickedBeforeFocus) {
+ clearFocus();
+ requestFocus();
+ }
+ mClickedBeforeFocus = true;
+ return true;
+ }
+
+ @Override
+ public CharSequence getError() {
+ return mError;
+ }
+
+ @Override
+ public void setError(CharSequence error, Drawable icon) {
+ setCompoundDrawables(null, null, icon, null);
+ mError = error;
+ }
+
+ protected void onFocusChanged(boolean gainFocus, int direction,
+ Rect previouslyFocusedRect) {
+ if (!gainFocus) {
+ mClickedBeforeFocus = false;
+ }
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ }
+ }
+
+ private static final class Document {
+ public PrintDocumentInfo info;
+ public PageRange[] pages;
+ }
+
+ private static final class PageRangeUtils {
+
+ private static final Comparator<PageRange> sComparator = new Comparator<PageRange>() {
+ @Override
+ public int compare(PageRange lhs, PageRange rhs) {
+ return lhs.getStart() - rhs.getStart();
+ }
+ };
+
+ private PageRangeUtils() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static boolean contains(PageRange[] ourPageRanges, PageRange[] otherPageRanges) {
+ if (ourPageRanges == null || otherPageRanges == null) {
+ return false;
+ }
+
+ otherPageRanges = normalize(otherPageRanges);
+
+ int otherPageIdx = 0;
+ final int myPageCount = ourPageRanges.length;
+ final int otherPageCount = otherPageRanges.length;
+ for (int i= 0; i < myPageCount; i++) {
+ PageRange myPage = ourPageRanges[i];
+ for (; otherPageIdx < otherPageCount; otherPageIdx++) {
+ PageRange otherPage = otherPageRanges[otherPageIdx];
+ if (otherPage.getStart() > myPage.getStart()) {
+ break;
+ }
+ if ((otherPage.getStart() < myPage.getStart()
+ && otherPage.getEnd() > myPage.getStart())
+ || (otherPage.getEnd() > myPage.getEnd()
+ && otherPage.getStart() < myPage.getEnd())
+ || (otherPage.getEnd() < myPage.getStart())) {
+ return false;
+ }
+ }
+ }
+ if (otherPageIdx < otherPageCount) {
+ return false;
+ }
+ return true;
+ }
+
+ public static PageRange[] normalize(PageRange[] pageRanges) {
+ if (pageRanges == null) {
+ return null;
+ }
+ final int oldPageCount = pageRanges.length;
+ if (oldPageCount <= 1) {
+ return pageRanges;
+ }
+ Arrays.sort(pageRanges, sComparator);
+ int newRangeCount = 0;
+ for (int i = 0; i < oldPageCount - 1; i++) {
+ newRangeCount++;
+ PageRange currentRange = pageRanges[i];
+ PageRange nextRange = pageRanges[i + 1];
+ if (currentRange.getEnd() >= nextRange.getStart()) {
+ newRangeCount--;
+ pageRanges[i] = null;
+ pageRanges[i + 1] = new PageRange(currentRange.getStart(),
+ nextRange.getEnd());
+ }
+ }
+ if (newRangeCount == oldPageCount) {
+ return pageRanges;
+ }
+ return Arrays.copyOfRange(pageRanges, oldPageCount - newRangeCount,
+ oldPageCount - 1);
+ }
+
+ public static void offsetStart(PageRange[] pageRanges, int offset) {
+ if (offset == 0) {
+ return;
+ }
+ final int pageRangeCount = pageRanges.length;
+ for (int i = 0; i < pageRangeCount; i++) {
+ final int start = pageRanges[i].getStart() + offset;
+ final int end = pageRanges[i].getEnd() + offset;
+ pageRanges[i] = new PageRange(start, end);
+ }
}
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
index 53ae1459..870bfffd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
@@ -19,6 +19,9 @@
import android.content.ComponentName;
import android.content.Context;
import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.IPrintClient;
@@ -39,6 +42,7 @@
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.os.SomeArgs;
import com.android.internal.util.FastXmlSerializer;
import libcore.io.IoUtils;
@@ -59,9 +63,9 @@
public class PrintSpooler {
- private static final String LOG_TAG = PrintSpooler.class.getSimpleName();
+ private static final String LOG_TAG = "PrintSpooler";
- private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
+ private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
private static final boolean DEBUG_PERSISTENCE = true;
@@ -81,6 +85,8 @@
private final PersistenceManager mPersistanceManager;
+ private final Handler mHandler;
+
private final Context mContext;
public IPrintSpoolerClient mClient;
@@ -97,6 +103,7 @@
private PrintSpooler(Context context) {
mContext = context;
mPersistanceManager = new PersistenceManager(context);
+ mHandler = new MyHandler(context.getMainLooper());
}
public void setCleint(IPrintSpoolerClient client) {
@@ -111,37 +118,36 @@
}
}
- public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
- IPrintSpoolerClient client = null;
+ public void onReqeustUpdatePrinters(List<PrinterId> printers) {
synchronized (mLock) {
- client = mClient;
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mClient;
+ args.arg2 = printers;
+ mHandler.obtainMessage(MyHandler.MSG_REQUEST_UPDATE_PRINTERS,
+ args).sendToTarget();
}
- if (client != null) {
- try {
- client.onStartPrinterDiscovery(observer);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error notifying start printer discovery.", re);
- }
+ }
+
+ public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ synchronized (mLock) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mClient;
+ args.arg2 = observer;
+ mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY,
+ args).sendToTarget();
}
}
public void stopPrinterDiscovery() {
- IPrintSpoolerClient client = null;
synchronized (mLock) {
- client = mClient;
- }
- if (client != null) {
- try {
- client.onStopPrinterDiscovery();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error notifying stop printer discovery.", re);
- }
+ mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY,
+ mClient).sendToTarget();
}
}
public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, int appId) {
+ List<PrintJobInfo> foundPrintJobs = null;
synchronized (mLock) {
- List<PrintJobInfo> foundPrintJobs = null;
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
@@ -162,8 +168,8 @@
foundPrintJobs.add(printJob);
}
}
- return foundPrintJobs;
}
+ return foundPrintJobs;
}
public PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
@@ -172,11 +178,12 @@
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (printJob.getId() == printJobId
- && (appId == PrintManager.APP_ID_ANY || appId == printJob.getAppId())) {
+ && (appId == PrintManager.APP_ID_ANY
+ || appId == printJob.getAppId())) {
return printJob;
}
}
- return null;
+ return null;
}
}
@@ -217,7 +224,7 @@
Map<ComponentName, List<PrintJobInfo>> activeJobsPerServiceMap =
new HashMap<ComponentName, List<PrintJobInfo>>();
- synchronized(mLock) {
+ synchronized (mLock) {
if (mClient == null) {
throw new IllegalStateException("Client cannot be null.");
}
@@ -265,16 +272,25 @@
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = printJobs.get(i);
if (printJob.getState() == PrintJobInfo.STATE_QUEUED) {
- callOnPrintJobQueuedQuietly(client, printJob);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = client;
+ args.arg2 = new PrintJobInfo(printJob);
+ mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED,
+ args).sendToTarget();
}
}
} else {
- callOnAllPrintJobsForServiceHandledQuietly(client, service);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = client;
+ args.arg2 = service;
+ mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED,
+ args).sendToTarget();
}
}
if (allPrintJobsHandled) {
- callOnAllPrintJobsHandledQuietly(client);
+ mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED,
+ client).sendToTarget();
}
}
@@ -297,37 +313,43 @@
return false;
}
- @SuppressWarnings("resource")
- public boolean writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ public void writePrintJobData(final ParcelFileDescriptor fd, final int printJobId) {
+ final PrintJobInfo printJob;
synchronized (mLock) {
- FileInputStream in = null;
- FileOutputStream out = null;
- try {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- File file = generateFileForPrintJob(printJobId);
- in = new FileInputStream(file);
- out = new FileOutputStream(fd.getFileDescriptor());
+ printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+ }
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ try {
+ if (printJob != null) {
+ File file = generateFileForPrintJob(printJobId);
+ in = new FileInputStream(file);
+ out = new FileOutputStream(fd.getFileDescriptor());
+ }
final byte[] buffer = new byte[8192];
while (true) {
final int readByteCount = in.read(buffer);
if (readByteCount < 0) {
- return true;
+ return null;
}
out.write(buffer, 0, readByteCount);
}
+ } catch (FileNotFoundException fnfe) {
+ Log.e(LOG_TAG, "Error writing print job data!", fnfe);
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error writing print job data!", ioe);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(fd);
}
- } catch (FileNotFoundException fnfe) {
- Log.e(LOG_TAG, "Error writing print job data!", fnfe);
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error writing print job data!", ioe);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(fd);
+ Log.i(LOG_TAG, "[END WRITE]");
+ return null;
}
- }
- return false;
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
public File generateFileForPrintJob(int printJobId) {
@@ -354,28 +376,24 @@
public boolean setPrintJobState(int printJobId, int state) {
boolean success = false;
- boolean allPrintJobsHandled = false;
- boolean allPrintJobsForServiceHandled = false;
-
- IPrintSpoolerClient client = null;
- PrintJobInfo queuedPrintJob = null;
- PrintJobInfo removedPrintJob = null;
-
synchronized (mLock) {
if (mClient == null) {
throw new IllegalStateException("Client cannot be null.");
}
- client = mClient;
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null && printJob.getState() < state) {
success = true;
printJob.setState(state);
+
+ if (DEBUG_PRINT_JOB_LIFECYCLE) {
+ Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
+ }
+
// TODO: Update notifications.
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED: {
- removedPrintJob = printJob;
removePrintJobLocked(printJob);
// No printer means creation of a print job was cancelled,
@@ -387,83 +405,46 @@
return true;
}
- allPrintJobsHandled = !hasActivePrintJobsLocked();
- allPrintJobsForServiceHandled = !hasActivePrintJobsForServiceLocked(
- printerId.getService());
+ ComponentName service = printerId.getService();
+ if (!hasActivePrintJobsForServiceLocked(service)) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mClient;
+ args.arg2 = service;
+ mHandler.obtainMessage(
+ MyHandler.MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED,
+ args).sendToTarget();
+ }
+
+ if (!hasActivePrintJobsLocked()) {
+ mHandler.obtainMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED,
+ mClient).sendToTarget();
+ }
} break;
case PrintJobInfo.STATE_QUEUED: {
- queuedPrintJob = new PrintJobInfo(printJob);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mClient;
+ args.arg2 = new PrintJobInfo(printJob);
+ mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED,
+ args).sendToTarget();
} break;
}
- if (DEBUG_PRINT_JOB_LIFECYCLE) {
- Slog.i(LOG_TAG, "[STATUS CHANGED] " + printJob);
+
+ if (shouldPersistPrintJob(printJob)) {
+ mPersistanceManager.writeStateLocked();
}
- mPersistanceManager.writeStateLocked();
}
}
- if (queuedPrintJob != null) {
- callOnPrintJobQueuedQuietly(client, queuedPrintJob);
- }
-
- if (allPrintJobsForServiceHandled) {
- callOnAllPrintJobsForServiceHandledQuietly(client,
- removedPrintJob.getPrinterId().getService());
- }
-
- if (allPrintJobsHandled) {
- callOnAllPrintJobsHandledQuietly(client);
- }
-
return success;
}
- private void callOnPrintJobQueuedQuietly(IPrintSpoolerClient client,
- PrintJobInfo printJob) {
- try {
- client.onPrintJobQueued(printJob);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
- }
- }
-
- private void callOnAllPrintJobsForServiceHandledQuietly(IPrintSpoolerClient client,
- ComponentName service) {
- try {
- client.onAllPrintJobsForServiceHandled(service);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error notify for all print jobs per service handled.", re);
- }
- }
-
- private void callOnAllPrintJobsHandledQuietly(final IPrintSpoolerClient client) {
- // This has to run on the tread that is persisting the current state
- // since this call may result in the system unbinding from the spooler
- // and as a result the spooler process may get killed before the write
- // completes.
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- try {
- client.onAllPrintJobsHandled();
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
- }
- return null;
- }
- }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
- }
-
private boolean hasActivePrintJobsLocked() {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
- switch (printJob.getState()) {
- case PrintJobInfo.STATE_QUEUED:
- case PrintJobInfo.STATE_STARTED: {
- return true;
- }
+ if (!isActiveState(printJob.getState())) {
+ return true;
}
}
return false;
@@ -473,72 +454,89 @@
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
- switch (printJob.getState()) {
- case PrintJobInfo.STATE_QUEUED:
- case PrintJobInfo.STATE_STARTED: {
- if (printJob.getPrinterId().getService().equals(service)) {
- return true;
- }
- } break;
+ if (!isActiveState(printJob.getState())
+ && printJob.getPrinterId().getService().equals(service)) {
+ return true;
}
}
return false;
}
+ private static boolean isActiveState(int printJobState) {
+ return printJobState != PrintJobInfo.STATE_CREATED
+ || printJobState != PrintJobInfo.STATE_QUEUED
+ || printJobState != PrintJobInfo.STATE_STARTED;
+ }
+
public boolean setPrintJobTag(int printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
+ String printJobTag = printJob.getTag();
+ if (printJobTag == null) {
+ if (tag == null) {
+ return false;
+ }
+ } else if (printJobTag.equals(tag)) {
+ return false;
+ }
printJob.setTag(tag);
- mPersistanceManager.writeStateLocked();
+ if (shouldPersistPrintJob(printJob)) {
+ mPersistanceManager.writeStateLocked();
+ }
return true;
}
}
return false;
}
- public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) {
+ public void setPrintJobCopiesNoPersistence(int printJobId, int copies) {
+ synchronized (mLock) {
+ PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
+ if (printJob != null) {
+ printJob.setCopies(copies);
+ }
+ }
+ }
+
+ public void setPrintJobPrintDocumentInfoNoPersistence(int printJobId, PrintDocumentInfo info) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setDocumentInfo(info);
- mPersistanceManager.writeStateLocked();
- return true;
}
}
- return false;
}
- public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) {
+ public void setPrintJobAttributesNoPersistence(int printJobId, PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setAttributes(attributes);
- mPersistanceManager.writeStateLocked();
}
}
}
- public void setPrintJobPrinterId(int printJobId, PrinterId printerId) {
+ public void setPrintJobPrinterIdNoPersistence(int printJobId, PrinterId printerId) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setPrinterId(printerId);
- mPersistanceManager.writeStateLocked();
}
}
}
- public boolean setPrintJobPages(int printJobId, PageRange[] pages) {
+ public void setPrintJobPagesNoPersistence(int printJobId, PageRange[] pages) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setPages(pages);
- mPersistanceManager.writeStateLocked();
- return true;
}
}
- return false;
+ }
+
+ private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
+ return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
}
private final class PersistenceManager {
@@ -558,6 +556,7 @@
private static final String ATTR_APP_ID = "appId";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_TAG = "tag";
+ private static final String ATTR_COPIES = "copies";
private static final String TAG_MEDIA_SIZE = "mediaSize";
private static final String TAG_RESOLUTION = "resolution";
@@ -620,6 +619,9 @@
}
private void doWriteStateLocked() {
+ if (DEBUG_PERSISTENCE) {
+ Log.i(LOG_TAG, "[PERSIST START]");
+ }
FileOutputStream out = null;
try {
out = mStatePersistFile.startWrite();
@@ -652,6 +654,7 @@
if (tag != null) {
serializer.attribute(null, ATTR_TAG, tag);
}
+ serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
@@ -775,6 +778,9 @@
serializer.endTag(null, TAG_SPOOLER);
serializer.endDocument();
mStatePersistFile.finishWrite(out);
+ if (DEBUG_PERSISTENCE) {
+ Log.i(LOG_TAG, "[PERSIST END]");
+ }
} catch (IOException e) {
Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
mStatePersistFile.failWrite(out);
@@ -861,6 +867,8 @@
printJob.setUserId(userId);
String tag = parser.getAttributeValue(null, ATTR_TAG);
printJob.setTag(tag);
+ String copies = parser.getAttributeValue(null, ATTR_TAG);
+ printJob.setCopies(Integer.parseInt(copies));
parser.next();
@@ -892,7 +900,9 @@
parser.next();
}
if (pageRanges != null) {
- printJob.setPages((PageRange[]) pageRanges.toArray());
+ PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+ pageRanges.toArray(pageRangesArray);
+ printJob.setPages(pageRangesArray);
}
skipEmptyTextTags(parser);
@@ -1054,4 +1064,108 @@
return true;
}
}
+
+ private final class MyHandler extends Handler {
+ public static final int MSG_START_PRINTER_DISCOVERY = 1;
+ public static final int MSG_STOP_PRINTER_DISCOVERY = 2;
+ public static final int MSG_PRINT_JOB_QUEUED = 3;
+ public static final int MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 4;
+ public static final int MSG_ALL_PRINT_JOBS_HANDLED = 5;
+ public static final int MSG_REQUEST_UPDATE_PRINTERS = 6;
+
+ public MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_START_PRINTER_DISCOVERY: {
+ SomeArgs args = (SomeArgs) message.obj;
+ IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1;
+ IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg2;
+ args.recycle();
+ if (client != null) {
+ try {
+ client.onStartPrinterDiscovery(observer);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error notifying start printer discovery.", re);
+ }
+ }
+ } break;
+
+ case MSG_STOP_PRINTER_DISCOVERY: {
+ IPrintSpoolerClient client = (IPrintSpoolerClient) message.obj;
+ if (client != null) {
+ try {
+ client.onStopPrinterDiscovery();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error notifying stop printer discovery.", re);
+ }
+ }
+ } break;
+
+ case MSG_PRINT_JOB_QUEUED: {
+ SomeArgs args = (SomeArgs) message.obj;
+ IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1;
+ PrintJobInfo printJob = (PrintJobInfo) args.arg2;
+ args.recycle();
+ if (client != null) {
+ try {
+ client.onPrintJobQueued(printJob);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
+ }
+ }
+ } break;
+
+ case MSG_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED: {
+ SomeArgs args = (SomeArgs) message.obj;
+ IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1;
+ ComponentName service = (ComponentName) args.arg2;
+ args.recycle();
+ if (client != null) {
+ try {
+ client.onAllPrintJobsForServiceHandled(service);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error notify for all print jobs per service"
+ + " handled.", re);
+ }
+ }
+ } break;
+
+ case MSG_ALL_PRINT_JOBS_HANDLED: {
+ final IPrintSpoolerClient client = (IPrintSpoolerClient) message.obj;
+ // This has to run on the tread that is persisting the current state
+ // since this call may result in the system unbinding from the spooler
+ // and as a result the spooler process may get killed before the write
+ // completes.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ client.onAllPrintJobsHandled();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ } break;
+
+ case MSG_REQUEST_UPDATE_PRINTERS: {
+ SomeArgs args = (SomeArgs) message.obj;
+ IPrintSpoolerClient client = (IPrintSpoolerClient) args.arg1;
+ List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
+ args.recycle();
+ try {
+ client.onRequestUpdatePrinters(printerIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error requesting to update pritners.", re);
+ }
+ } break;
+ }
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 26d2a33..5ff2aa6 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -114,12 +114,11 @@
attributes, appId);
if (printJob != null) {
Intent intent = mStartPrintJobConfigActivityIntent;
- intent.putExtra(PrintJobConfigActivity.EXTRA_PRINTABLE,
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
printAdapter.asBinder());
- intent.putExtra(PrintJobConfigActivity.EXTRA_APP_ID, appId);
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB_ID,
printJob.getId());
- intent.putExtra(PrintJobConfigActivity.EXTRA_ATTRIBUTES, attributes);
+ intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_ATTRIBUTES, attributes);
IntentSender sender = PendingIntent.getActivity(
PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 25bb37c..4006a5a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -17,8 +17,8 @@
package com.android.printspooler;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
-import android.os.ICancellationSignal;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.ILayoutResultCallback;
@@ -26,11 +26,7 @@
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
-import android.print.PrintDocumentAdapter.LayoutResultCallback;
-import android.print.PrintDocumentAdapter.WriteResultCallback;
-import android.print.PrintDocumentInfo;
import android.util.Log;
-import android.util.Slog;
import libcore.io.IoUtils;
@@ -40,8 +36,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
/**
* This class represents a remote print document adapter instance.
@@ -49,461 +43,99 @@
final class RemotePrintDocumentAdapter {
private static final String LOG_TAG = "RemotePrintDocumentAdapter";
- private static final boolean DEBUG = true;
-
- public static final int STATE_INITIALIZED = 0;
- public static final int STATE_START_COMPLETED = 1;
- public static final int STATE_LAYOUT_STARTED = 2;
- public static final int STATE_LAYOUT_COMPLETED = 3;
- public static final int STATE_WRITE_STARTED = 4;
- public static final int STATE_WRITE_COMPLETED = 5;
- public static final int STATE_FINISH_COMPLETED = 6;
- public static final int STATE_FAILED = 7;
-
- private final Object mLock = new Object();
-
- private final List<QueuedAsyncTask> mTaskQueue = new ArrayList<QueuedAsyncTask>();
+ private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
private final IPrintDocumentAdapter mRemoteInterface;
private final File mFile;
- private int mState = STATE_INITIALIZED;
-
public RemotePrintDocumentAdapter(IPrintDocumentAdapter printAdatper, File file) {
mRemoteInterface = printAdatper;
mFile = file;
}
- public File getFile() {
+ public void start() {
if (DEBUG) {
- Log.i(LOG_TAG, "getFile()");
+ Log.i(LOG_TAG, "start()");
}
- synchronized (mLock) {
- if (mState != STATE_WRITE_COMPLETED
- && mState != STATE_FINISH_COMPLETED) {
- throw new IllegalStateException("Write not completed");
- }
- return mFile;
+ try {
+ mRemoteInterface.start();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling start()", re);
}
}
- public void start() {
- QueuedAsyncTask task = new QueuedAsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- if (DEBUG) {
- Log.i(LOG_TAG, "start()");
- }
- synchronized (mLock) {
- if (mState != STATE_INITIALIZED) {
- throw new IllegalStateException("Invalid state: " + mState);
- }
- }
- try {
- mRemoteInterface.start();
- synchronized (mLock) {
- mState = STATE_START_COMPLETED;
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error reading file", re);
- }
- return null;
- }
-
- @Override
- public void cancel() {
- /* cannot be cancelled */
- }
- };
- synchronized (mLock) {
- mTaskQueue.add(task);
- }
- task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
- }
-
public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
- LayoutResultCallback callback, Bundle metadata) {
- LayoutAsyncTask task = new LayoutAsyncTask(oldAttributes, newAttributes, callback,
- metadata);
- synchronized (mLock) {
- mTaskQueue.add(task);
+ ILayoutResultCallback callback, Bundle metadata, int sequence) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "layout()");
}
- task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
- }
-
- public void write(List<PageRange> pages, WriteResultCallback callback) {
- WriteAsyncTask task = new WriteAsyncTask(pages, callback);
- synchronized (mLock) {
- mTaskQueue.add(task);
- }
- task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
- }
-
- public void cancel() {
- synchronized (mLock) {
- final int taskCount = mTaskQueue.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- mTaskQueue.remove(i).cancel();
- }
+ try {
+ mRemoteInterface.layout(oldAttributes, newAttributes, callback, metadata, sequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling layout()", re);
}
}
- public void finish() {
- QueuedAsyncTask task = new QueuedAsyncTask() {
+ public void write(final PageRange[] pages, final IWriteResultCallback callback,
+ final int sequence) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "write()");
+ }
+ new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- if (DEBUG) {
- Log.i(LOG_TAG, "finish()");
- }
- synchronized (mLock) {
- if (mState < STATE_START_COMPLETED) {
- return null;
- }
- }
+ InputStream in = null;
+ OutputStream out = null;
+ ParcelFileDescriptor source = null;
+ ParcelFileDescriptor sink = null;
try {
- mRemoteInterface.finish();
- synchronized (mLock) {
- mState = STATE_FINISH_COMPLETED;
+ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ source = pipe[0];
+ sink = pipe[1];
+
+ in = new FileInputStream(source.getFileDescriptor());
+ out = new FileOutputStream(mFile);
+
+ // Async call to initiate the other process writing the data.
+ mRemoteInterface.write(pages, sink, callback, sequence);
+
+ // Close the source. It is now held by the client.
+ sink.close();
+ sink = null;
+
+ // Read the data.
+ final byte[] buffer = new byte[8192];
+ while (true) {
+ final int readByteCount = in.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ out.write(buffer, 0, readByteCount);
}
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error reading file", re);
- mState = STATE_FAILED;
+ Log.e(LOG_TAG, "Error calling write()", re);
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error calling write()", ioe);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(sink);
+ IoUtils.closeQuietly(source);
}
return null;
}
-
- @Override
- public void cancel() {
- /* cannot be cancelled */
- }
- };
- synchronized (mLock) {
- mTaskQueue.add(task);
- }
- task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- private abstract class QueuedAsyncTask extends AsyncTask<Void, Void, Void> {
- public void cancel() {
- super.cancel(true);
+ public void finish() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "finish()");
}
- }
-
- private final class LayoutAsyncTask extends QueuedAsyncTask {
-
- private final PrintAttributes mOldAttributes;
-
- private final PrintAttributes mNewAttributes;
-
- private final LayoutResultCallback mCallback;
-
- private final Bundle mMetadata;
-
- private final ILayoutResultCallback mILayoutResultCallback =
- new ILayoutResultCallback.Stub() {
- @Override
- public void onLayoutStarted(ICancellationSignal cancellationSignal) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onLayoutStarted()");
- }
- synchronized (mLock) {
- mCancellationSignal = cancellationSignal;
- if (isCancelled()) {
- cancelSignalQuietlyLocked();
- }
- }
- }
-
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onLayoutFinished()");
- }
- final boolean cancelled;
- synchronized (mLock) {
- cancelled = isCancelled();
- mCancellationSignal = null;
- mState = STATE_LAYOUT_COMPLETED;
- mTaskQueue.remove(this);
- mLock.notifyAll();
- }
- if (!cancelled) {
- mCallback.onLayoutFinished(info, changed);
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onLayoutFailed()");
- }
- final boolean cancelled;
- synchronized (mLock) {
- cancelled = isCancelled();
- mCancellationSignal = null;
- mState = STATE_LAYOUT_COMPLETED;
- mTaskQueue.remove(this);
- mLock.notifyAll();
- }
- if (!cancelled) {
- mCallback.onLayoutFailed(error);
- }
- }
- };
-
- private ICancellationSignal mCancellationSignal;
-
- public LayoutAsyncTask(PrintAttributes oldAttributes, PrintAttributes newAttributes,
- LayoutResultCallback callback, Bundle metadata) {
- mOldAttributes = oldAttributes;
- mNewAttributes = newAttributes;
- mCallback = callback;
- mMetadata = metadata;
- }
-
- @Override
- public void cancel() {
- synchronized (mLock) {
- throwIfCancelledLocked();
- cancelSignalQuietlyLocked();
- }
- super.cancel();
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- synchronized (mLock) {
- if (DEBUG) {
- Log.i(LOG_TAG, "layout()");
- }
- if (mState != STATE_START_COMPLETED
- && mState != STATE_LAYOUT_COMPLETED
- && mState != STATE_WRITE_COMPLETED) {
- throw new IllegalStateException("Invalid state: " + mState);
- }
- mState = STATE_LAYOUT_STARTED;
- }
- try {
- mRemoteInterface.layout(mOldAttributes, mNewAttributes,
- mILayoutResultCallback, mMetadata);
- synchronized (mLock) {
- while (true) {
- if (mState == STATE_LAYOUT_COMPLETED) {
- break;
- }
- try {
- mLock.wait();
- } catch (InterruptedException ie) {
- /* ignore */
- }
- }
- }
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error calling layout", re);
- mState = STATE_FAILED;
- mTaskQueue.remove(this);
- notifyLayoutFailedQuietly();
- }
- return null;
- }
-
- private void cancelSignalQuietlyLocked() {
- if (mCancellationSignal != null) {
- try {
- mCancellationSignal.cancel();
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error cancelling layout", re);
- notifyLayoutFailedQuietly();
- }
- }
- }
-
- public void notifyLayoutFailedQuietly() {
- try {
- mILayoutResultCallback.onLayoutFailed(null);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
-
- private void throwIfCancelledLocked() {
- if (isCancelled()) {
- throw new IllegalStateException("Already cancelled");
- }
- }
- }
-
- private final class WriteAsyncTask extends QueuedAsyncTask {
-
- private final List<PageRange> mPages;
-
- private final WriteResultCallback mCallback;
-
- private final IWriteResultCallback mIWriteResultCallback =
- new IWriteResultCallback.Stub() {
- @Override
- public void onWriteStarted(ICancellationSignal cancellationSignal) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onWriteStarted()");
- }
- synchronized (mLock) {
- mCancellationSignal = cancellationSignal;
- if (isCancelled()) {
- cancelSignalQuietlyLocked();
- }
- }
- }
-
- @Override
- public void onWriteFinished(List<PageRange> pages) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onWriteFinished()");
- }
- synchronized (mLock) {
- mCancellationSignal = null;
- mState = STATE_WRITE_COMPLETED;
- mTaskQueue.remove(this);
- mLock.notifyAll();
- }
- mCallback.onWriteFinished(pages);
- }
-
- @Override
- public void onWriteFailed(CharSequence error) {
- if (DEBUG) {
- Log.i(LOG_TAG, "onWriteFailed()");
- }
- synchronized (mLock) {
- mCancellationSignal = null;
- mState = STATE_WRITE_COMPLETED;
- mTaskQueue.remove(this);
- mLock.notifyAll();
- }
- Slog.e(LOG_TAG, "Error writing print document: " + error);
- mCallback.onWriteFailed(error);
- }
- };
-
- private ICancellationSignal mCancellationSignal;
-
- private Thread mWriteThread;
-
- public WriteAsyncTask(List<PageRange> pages, WriteResultCallback callback) {
- mPages = pages;
- mCallback = callback;
- }
-
- @Override
- public void cancel() {
- synchronized (mLock) {
- throwIfCancelledLocked();
- cancelSignalQuietlyLocked();
- mWriteThread.interrupt();
- }
- super.cancel();
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- if (DEBUG) {
- Log.i(LOG_TAG, "write()");
- }
- synchronized (mLock) {
- if (mState != STATE_LAYOUT_COMPLETED
- && mState != STATE_WRITE_COMPLETED) {
- throw new IllegalStateException("Invalid state: " + mState);
- }
- mState = STATE_WRITE_STARTED;
- }
- InputStream in = null;
- OutputStream out = null;
- ParcelFileDescriptor source = null;
- ParcelFileDescriptor sink = null;
- synchronized (mLock) {
- mWriteThread = Thread.currentThread();
- }
- try {
- ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
- source = pipe[0];
- sink = pipe[1];
-
- in = new FileInputStream(source.getFileDescriptor());
- out = new FileOutputStream(mFile);
-
- // Async call to initiate the other process writing the data.
- mRemoteInterface.write(mPages, sink, mIWriteResultCallback);
-
- // Close the source. It is now held by the client.
- sink.close();
- sink = null;
-
- final byte[] buffer = new byte[8192];
- while (true) {
- if (Thread.currentThread().isInterrupted()) {
- Thread.currentThread().interrupt();
- break;
- }
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
- }
- synchronized (mLock) {
- while (true) {
- if (mState == STATE_WRITE_COMPLETED) {
- break;
- }
- try {
- mLock.wait();
- } catch (InterruptedException ie) {
- /* ignore */
- }
- }
- }
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error writing print document", re);
- mState = STATE_FAILED;
- mTaskQueue.remove(this);
- notifyWriteFailedQuietly();
- } catch (IOException ioe) {
- Slog.e(LOG_TAG, "Error writing print document", ioe);
- mState = STATE_FAILED;
- mTaskQueue.remove(this);
- notifyWriteFailedQuietly();
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(sink);
- IoUtils.closeQuietly(source);
- }
- return null;
- }
-
- private void cancelSignalQuietlyLocked() {
- if (mCancellationSignal != null) {
- try {
- mCancellationSignal.cancel();
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error cancelling layout", re);
- notifyWriteFailedQuietly();
- }
- }
- }
-
- private void notifyWriteFailedQuietly() {
- try {
- mIWriteResultCallback.onWriteFailed(null);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
-
- private void throwIfCancelledLocked() {
- if (isCancelled()) {
- throw new IllegalStateException("Already cancelled");
- }
+ try {
+ mRemoteInterface.finish();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling finish()", re);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index a8cb955..e8b8dc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -939,7 +939,8 @@
@Override
public void resetHeadsUpDecayTimer() {
mHandler.removeMessages(MSG_HIDE_HEADS_UP);
- if (mHeadsUpNotificationDecay > 0) {
+ if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
+ && !mHeadsUpNotificationView.isInsistent()) {
mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 038eba1..7a8ce4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -199,4 +200,9 @@
mHeadsUp.row.setUserLocked(userLocked);
}
}
+
+ public boolean isInsistent() {
+ return mHeadsUp != null
+ && (mHeadsUp.notification.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
+ }
}
\ No newline at end of file
diff --git a/preloaded-classes b/preloaded-classes
index 45d27ee..064ca3a 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1671,7 +1671,6 @@
com.android.org.bouncycastle.jce.provider.BouncyCastleProviderConfiguration
com.android.org.bouncycastle.jce.provider.CertBlacklist
com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities
-com.android.org.bouncycastle.jce.provider.JDKKeyStore
com.android.org.bouncycastle.jce.provider.PKIXCRLUtil
com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidator
@@ -2026,7 +2025,6 @@
java.net.ProxySelector
java.net.ProxySelectorImpl
java.net.ResponseCache
-java.net.ResponseSource
java.net.Socket
java.net.SocketAddress
java.net.SocketImpl
@@ -2463,7 +2461,6 @@
libcore.io.StructPasswd
libcore.io.StructPollfd
libcore.io.StructStat
-libcore.io.StructStatFs
libcore.io.StructTimeval
libcore.io.StructUcred
libcore.io.StructUtsname
@@ -2471,26 +2468,8 @@
libcore.net.MimeUtils
libcore.net.RawSocket
libcore.net.UriCodec
-libcore.net.http.AbstractHttpInputStream
-libcore.net.http.FixedLengthInputStream
-libcore.net.http.HeaderParser$CacheControlHandler
-libcore.net.http.HttpConnection
-libcore.net.http.HttpConnection$Address
-libcore.net.http.HttpConnectionPool
libcore.net.http.HttpDate
libcore.net.http.HttpDate$1
-libcore.net.http.HttpEngine
-libcore.net.http.HttpEngine$1
-libcore.net.http.HttpHandler
-libcore.net.http.HttpURLConnectionImpl
-libcore.net.http.HttpURLConnectionImpl$Retry
-libcore.net.http.HttpsHandler
-libcore.net.http.RawHeaders
-libcore.net.http.RawHeaders$1
-libcore.net.http.RequestHeaders
-libcore.net.http.RequestHeaders$1
-libcore.net.http.ResponseHeaders
-libcore.net.http.ResponseHeaders$1
libcore.net.url.FileHandler
libcore.net.url.FileURLConnection
libcore.net.url.JarHandler
@@ -2516,9 +2495,6 @@
org.apache.harmony.dalvik.ddmc.Chunk
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
-org.apache.harmony.lang.annotation.AnnotationFactory
-org.apache.harmony.lang.annotation.AnnotationMember
-org.apache.harmony.lang.annotation.AnnotationMember$DefaultValues
org.apache.harmony.luni.internal.util.TimezoneGetter
org.apache.harmony.security.asn1.ASN1Any
org.apache.harmony.security.asn1.ASN1BitString
@@ -2566,8 +2542,6 @@
org.apache.harmony.security.provider.cert.DRLCertFactory
org.apache.harmony.security.provider.cert.X509CertImpl
org.apache.harmony.security.provider.crypto.CryptoProvider
-org.apache.harmony.security.provider.crypto.RandomBitsSupplier
-org.apache.harmony.security.provider.crypto.SHA1_Data
org.apache.harmony.security.utils.AlgNameMapper
org.apache.harmony.security.utils.ObjectIdentifier
org.apache.harmony.security.x501.AttributeTypeAndValue
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index a2b4e12..dc8fab6 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -83,7 +83,7 @@
private static final String ClockReceiver_TAG = "ClockReceiver";
private static final boolean localLOGV = false;
private static final boolean DEBUG_BATCH = localLOGV || false;
- private static final boolean DEBUG_VALIDATE = localLOGV || true;
+ private static final boolean DEBUG_VALIDATE = localLOGV || false;
private static final int ALARM_EVENT = 1;
private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
@@ -521,6 +521,14 @@
throw new IllegalArgumentException("Invalid alarm type " + type);
}
+ if (triggerAtTime < 0) {
+ final long who = Binder.getCallingUid();
+ final long what = Binder.getCallingPid();
+ Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
+ + " pid=" + what);
+ triggerAtTime = 0;
+ }
+
final long nowElapsed = SystemClock.elapsedRealtime();
final long triggerElapsed = convertToElapsed(triggerAtTime, type);
final long maxElapsed;
@@ -567,7 +575,12 @@
}
if (DEBUG_VALIDATE) {
- if (doValidate && validateConsistencyLocked()) {
+ if (doValidate && !validateConsistencyLocked()) {
+ Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
+ + " when(hex)=" + Long.toHexString(when)
+ + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
+ + " interval=" + interval + " op=" + operation
+ + " standalone=" + isStandalone);
rebatchAllAlarmsLocked(false);
reschedule = true;
}
@@ -586,8 +599,9 @@
final int NZ = mAlarmBatches.size();
for (int iz = 0; iz < NZ; iz++) {
Batch bz = mAlarmBatches.get(iz);
- Slog.v(TAG, "Batch " + iz + ": " + bz);
+ pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC);
+ pw.flush();
Slog.v(TAG, bs.toString());
bs.reset();
}
@@ -626,15 +640,17 @@
private void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
- final Batch firstWakeup = findFirstWakeupBatchLocked();
- final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
- mNextWakeup = firstWakeup.start;
- setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
- }
- if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
- mNextNonWakeup = firstBatch.start;
- setLocked(ELAPSED_REALTIME, firstBatch.start);
+ if (mAlarmBatches.size() > 0) {
+ final Batch firstWakeup = findFirstWakeupBatchLocked();
+ final Batch firstBatch = mAlarmBatches.get(0);
+ if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+ mNextWakeup = firstWakeup.start;
+ setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+ }
+ if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+ mNextNonWakeup = firstBatch.start;
+ setLocked(ELAPSED_REALTIME, firstBatch.start);
+ }
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 2d42cd61..457539f 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -26,9 +26,12 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.BatteryManager;
+import android.os.BatteryProperties;
import android.os.Binder;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBatteryPropertiesListener;
+import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.DropBoxManager;
import android.os.RemoteException;
@@ -102,20 +105,8 @@
private final Object mLock = new Object();
- /* Begin native fields: All of these fields are set by native code. */
- private boolean mAcOnline;
- private boolean mUsbOnline;
- private boolean mWirelessOnline;
- private int mBatteryStatus;
- private int mBatteryHealth;
- private boolean mBatteryPresent;
- private int mBatteryLevel;
- private int mBatteryVoltage;
- private int mBatteryTemperature;
- private String mBatteryTechnology;
+ private BatteryProperties mBatteryProps;
private boolean mBatteryLevelCritical;
- /* End native fields. */
-
private int mLastBatteryStatus;
private int mLastBatteryHealth;
private boolean mLastBatteryPresent;
@@ -143,7 +134,8 @@
private boolean mSentLowBatteryBroadcast = false;
- private native void native_update();
+ private BatteryListener mBatteryPropertiesListener;
+ private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
public BatteryService(Context context, LightsService lights) {
mContext = context;
@@ -160,17 +152,21 @@
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
- mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
-
// watch for invalid charger messages if the invalid_charger switch exists
if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
mInvalidChargerObserver.startObserving(
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
- // set initial status
- synchronized (mLock) {
- updateLocked();
+ mBatteryPropertiesListener = new BatteryListener();
+
+ IBinder b = ServiceManager.getService("batterypropreg");
+ mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
+
+ try {
+ mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+ } catch (RemoteException e) {
+ // Should never happen.
}
}
@@ -194,16 +190,16 @@
private boolean isPoweredLocked(int plugTypeSet) {
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work.
- if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mAcOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mUsbOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mWirelessOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
return true;
}
return false;
@@ -223,7 +219,7 @@
*/
public int getBatteryLevel() {
synchronized (mLock) {
- return mBatteryLevel;
+ return mBatteryProps.batteryLevel;
}
}
@@ -232,7 +228,7 @@
*/
public boolean isBatteryLow() {
synchronized (mLock) {
- return mBatteryPresent && mBatteryLevel <= mLowBatteryWarningLevel;
+ return mBatteryProps.batteryPresent && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel;
}
}
@@ -248,7 +244,7 @@
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -267,7 +263,7 @@
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mBatteryTemperature > mShutdownBatteryTemperature) {
+ if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -282,13 +278,13 @@
}
}
- private void updateLocked() {
- if (!mUpdatesStopped) {
- // Update the values of mAcOnline, et. all.
- native_update();
-
- // Process the new values.
- processValuesLocked();
+ private void update(BatteryProperties props) {
+ synchronized (mLock) {
+ if (!mUpdatesStopped) {
+ mBatteryProps = props;
+ // Process the new values.
+ processValuesLocked();
+ }
}
}
@@ -296,12 +292,12 @@
boolean logOutlier = false;
long dischargeDuration = 0;
- mBatteryLevelCritical = (mBatteryLevel <= mCriticalBatteryLevel);
- if (mAcOnline) {
+ mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
+ if (mBatteryProps.chargerAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
- } else if (mUsbOnline) {
+ } else if (mBatteryProps.chargerUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- } else if (mWirelessOnline) {
+ } else if (mBatteryProps.chargerWirelessOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
@@ -309,25 +305,25 @@
if (DEBUG) {
Slog.d(TAG, "Processing new values: "
- + "mAcOnline=" + mAcOnline
- + ", mUsbOnline=" + mUsbOnline
- + ", mWirelessOnline=" + mWirelessOnline
- + ", mBatteryStatus=" + mBatteryStatus
- + ", mBatteryHealth=" + mBatteryHealth
- + ", mBatteryPresent=" + mBatteryPresent
- + ", mBatteryLevel=" + mBatteryLevel
- + ", mBatteryTechnology=" + mBatteryTechnology
- + ", mBatteryVoltage=" + mBatteryVoltage
- + ", mBatteryTemperature=" + mBatteryTemperature
+ + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
+ + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
+ + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
+ + ", batteryStatus=" + mBatteryProps.batteryStatus
+ + ", batteryHealth=" + mBatteryProps.batteryHealth
+ + ", batteryPresent=" + mBatteryProps.batteryPresent
+ + ", batteryLevel=" + mBatteryProps.batteryLevel
+ + ", batteryTechnology=" + mBatteryProps.batteryTechnology
+ + ", batteryVoltage=" + mBatteryProps.batteryVoltage
+ + ", batteryTemperature=" + mBatteryProps.batteryTemperature
+ ", mBatteryLevelCritical=" + mBatteryLevelCritical
+ ", mPlugType=" + mPlugType);
}
// Let the battery stats keep track of the current level.
try {
- mBatteryStats.setBatteryState(mBatteryStatus, mBatteryHealth,
- mPlugType, mBatteryLevel, mBatteryTemperature,
- mBatteryVoltage);
+ mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
+ mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
+ mBatteryProps.batteryVoltage);
} catch (RemoteException e) {
// Should never happen.
}
@@ -335,13 +331,13 @@
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (mBatteryStatus != mLastBatteryStatus ||
- mBatteryHealth != mLastBatteryHealth ||
- mBatteryPresent != mLastBatteryPresent ||
- mBatteryLevel != mLastBatteryLevel ||
+ if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+ mBatteryProps.batteryHealth != mLastBatteryHealth ||
+ mBatteryProps.batteryPresent != mLastBatteryPresent ||
+ mBatteryProps.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
- mBatteryVoltage != mLastBatteryVoltage ||
- mBatteryTemperature != mLastBatteryTemperature ||
+ mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
+ mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
mInvalidCharger != mLastInvalidCharger) {
if (mPlugType != mLastPlugType) {
@@ -350,33 +346,33 @@
// There's no value in this data unless we've discharged at least once and the
// battery level has changed; so don't log until it does.
- if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) {
+ if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
- mDischargeStartLevel, mBatteryLevel);
+ mDischargeStartLevel, mBatteryProps.batteryLevel);
// make sure we see a discharge event before logging again
mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
mDischargeStartTime = SystemClock.elapsedRealtime();
- mDischargeStartLevel = mBatteryLevel;
+ mDischargeStartLevel = mBatteryProps.batteryLevel;
}
}
- if (mBatteryStatus != mLastBatteryStatus ||
- mBatteryHealth != mLastBatteryHealth ||
- mBatteryPresent != mLastBatteryPresent ||
+ if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+ mBatteryProps.batteryHealth != mLastBatteryHealth ||
+ mBatteryProps.batteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
- mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0,
- mPlugType, mBatteryTechnology);
+ mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
+ mPlugType, mBatteryProps.batteryTechnology);
}
- if (mBatteryLevel != mLastBatteryLevel) {
+ if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
- mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
+ mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
@@ -396,8 +392,8 @@
* (becomes <= mLowBatteryWarningLevel).
*/
final boolean sendBatteryLow = !plugged
- && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
- && mBatteryLevel <= mLowBatteryWarningLevel
+ && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
sendIntentLocked();
@@ -456,13 +452,13 @@
logOutlierLocked(dischargeDuration);
}
- mLastBatteryStatus = mBatteryStatus;
- mLastBatteryHealth = mBatteryHealth;
- mLastBatteryPresent = mBatteryPresent;
- mLastBatteryLevel = mBatteryLevel;
+ mLastBatteryStatus = mBatteryProps.batteryStatus;
+ mLastBatteryHealth = mBatteryProps.batteryHealth;
+ mLastBatteryPresent = mBatteryProps.batteryPresent;
+ mLastBatteryLevel = mBatteryProps.batteryLevel;
mLastPlugType = mPlugType;
- mLastBatteryVoltage = mBatteryVoltage;
- mLastBatteryTemperature = mBatteryTemperature;
+ mLastBatteryVoltage = mBatteryProps.batteryVoltage;
+ mLastBatteryTemperature = mBatteryProps.batteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
@@ -474,29 +470,29 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
- int icon = getIconLocked(mBatteryLevel);
+ int icon = getIconLocked(mBatteryProps.batteryLevel);
- intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
- intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);
- intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);
- intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);
+ intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
+ intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
+ intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
+ intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
- intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);
- intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);
- intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
+ intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
+ intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
+ intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
if (DEBUG) {
- Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryLevel +
- ", scale:" + BATTERY_SCALE + ", status:" + mBatteryStatus +
- ", health:" + mBatteryHealth + ", present:" + mBatteryPresent +
- ", voltage: " + mBatteryVoltage +
- ", temperature: " + mBatteryTemperature +
- ", technology: " + mBatteryTechnology +
- ", AC powered:" + mAcOnline + ", USB powered:" + mUsbOnline +
- ", Wireless powered:" + mWirelessOnline +
+ Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel +
+ ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
+ ", health:" + mBatteryProps.batteryHealth + ", present:" + mBatteryProps.batteryPresent +
+ ", voltage: " + mBatteryProps.batteryVoltage +
+ ", temperature: " + mBatteryProps.batteryTemperature +
+ ", technology: " + mBatteryProps.batteryTechnology +
+ ", AC powered:" + mBatteryProps.chargerAcOnline + ", USB powered:" + mBatteryProps.chargerUsbOnline +
+ ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
", icon:" + icon + ", invalid charger:" + mInvalidCharger);
}
@@ -558,14 +554,14 @@
long durationThreshold = Long.parseLong(durationThresholdString);
int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
if (duration <= durationThreshold &&
- mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
+ mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
// If the discharge cycle is bad enough we want to know about it.
logBatteryStatsLocked();
}
if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
" discharge threshold: " + dischargeThreshold);
if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
- (mDischargeStartLevel - mBatteryLevel));
+ (mDischargeStartLevel - mBatteryProps.batteryLevel));
} catch (NumberFormatException e) {
Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
durationThresholdString + " or " + dischargeThresholdString);
@@ -575,14 +571,14 @@
}
private int getIconLocked(int level) {
- if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
+ if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
- } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+ } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
return com.android.internal.R.drawable.stat_sys_battery;
- } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
- || mBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
+ } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
+ || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
- && mBatteryLevel >= 100) {
+ && mBatteryProps.batteryLevel >= 100) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
} else {
return com.android.internal.R.drawable.stat_sys_battery;
@@ -609,32 +605,32 @@
if (mUpdatesStopped) {
pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
}
- pw.println(" AC powered: " + mAcOnline);
- pw.println(" USB powered: " + mUsbOnline);
- pw.println(" Wireless powered: " + mWirelessOnline);
- pw.println(" status: " + mBatteryStatus);
- pw.println(" health: " + mBatteryHealth);
- pw.println(" present: " + mBatteryPresent);
- pw.println(" level: " + mBatteryLevel);
+ pw.println(" AC powered: " + mBatteryProps.chargerAcOnline);
+ pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline);
+ pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline);
+ pw.println(" status: " + mBatteryProps.batteryStatus);
+ pw.println(" health: " + mBatteryProps.batteryHealth);
+ pw.println(" present: " + mBatteryProps.batteryPresent);
+ pw.println(" level: " + mBatteryProps.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
- pw.println(" voltage:" + mBatteryVoltage);
- pw.println(" temperature: " + mBatteryTemperature);
- pw.println(" technology: " + mBatteryTechnology);
+ pw.println(" voltage:" + mBatteryProps.batteryVoltage);
+ pw.println(" temperature: " + mBatteryProps.batteryTemperature);
+ pw.println(" technology: " + mBatteryProps.batteryTechnology);
} else if (args.length == 3 && "set".equals(args[0])) {
String key = args[1];
String value = args[2];
try {
boolean update = true;
if ("ac".equals(key)) {
- mAcOnline = Integer.parseInt(value) != 0;
+ mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
} else if ("usb".equals(key)) {
- mUsbOnline = Integer.parseInt(value) != 0;
+ mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
} else if ("wireless".equals(key)) {
- mWirelessOnline = Integer.parseInt(value) != 0;
+ mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
} else if ("status".equals(key)) {
- mBatteryStatus = Integer.parseInt(value);
+ mBatteryProps.batteryStatus = Integer.parseInt(value);
} else if ("level".equals(key)) {
- mBatteryLevel = Integer.parseInt(value);
+ mBatteryProps.batteryLevel = Integer.parseInt(value);
} else if ("invalid".equals(key)) {
mInvalidCharger = Integer.parseInt(value);
} else {
@@ -657,7 +653,6 @@
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = false;
- updateLocked();
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -669,15 +664,6 @@
}
}
- private final UEventObserver mPowerSupplyObserver = new UEventObserver() {
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- synchronized (mLock) {
- updateLocked();
- }
- }
- };
-
private final UEventObserver mInvalidChargerObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
@@ -685,7 +671,6 @@
synchronized (mLock) {
if (mInvalidCharger != invalidCharger) {
mInvalidCharger = invalidCharger;
- updateLocked();
}
}
}
@@ -719,8 +704,8 @@
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
- final int level = mBatteryLevel;
- final int status = mBatteryStatus;
+ final int level = mBatteryProps.batteryLevel;
+ final int status = mBatteryProps.batteryStatus;
if (level < mLowBatteryWarningLevel) {
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
// Solid red when battery is charging
@@ -745,4 +730,10 @@
}
}
}
+
+ private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+ public void batteryPropertiesChanged(BatteryProperties props) {
+ BatteryService.this.update(props);
+ }
+ }
}
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 058857d..0bf03b5 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -154,31 +154,36 @@
if (clip != null && clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
- if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, Binder.getCallingUid(),
+ final int callingUid = Binder.getCallingUid();
+ if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
- checkDataOwnerLocked(clip, Binder.getCallingUid());
+ checkDataOwnerLocked(clip, callingUid);
clearActiveOwnersLocked();
PerUserClipboard clipboard = getClipboard();
clipboard.primaryClip = clip;
+ final long ident = Binder.clearCallingIdentity();
final int n = clipboard.primaryClipListeners.beginBroadcast();
- for (int i = 0; i < n; i++) {
- try {
- ListenerInfo li = (ListenerInfo)
- clipboard.primaryClipListeners.getBroadcastCookie(i);
- if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid,
- li.mPackageName) == AppOpsManager.MODE_ALLOWED) {
- clipboard.primaryClipListeners.getBroadcastItem(i)
- .dispatchPrimaryClipChanged();
+ try {
+ for (int i = 0; i < n; i++) {
+ try {
+ ListenerInfo li = (ListenerInfo)
+ clipboard.primaryClipListeners.getBroadcastCookie(i);
+ if (mAppOps.checkOpNoThrow(AppOpsManager.OP_READ_CLIPBOARD, li.mUid,
+ li.mPackageName) == AppOpsManager.MODE_ALLOWED) {
+ clipboard.primaryClipListeners.getBroadcastItem(i)
+ .dispatchPrimaryClipChanged();
+ }
+ } catch (RemoteException e) {
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
}
- } catch (RemoteException e) {
-
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
}
+ } finally {
+ clipboard.primaryClipListeners.finishBroadcast();
+ Binder.restoreCallingIdentity(ident);
}
- clipboard.primaryClipListeners.finishBroadcast();
}
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b341693..cdf9f21 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -472,6 +472,7 @@
com.android.internal.R.array.radioAttributes);
for (String raString : raStrings) {
RadioAttributes r = new RadioAttributes(raString);
+ if (VDBG) log("raString=" + raString + " r=" + r);
if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
continue;
@@ -492,6 +493,7 @@
for (String naString : naStrings) {
try {
NetworkConfig n = new NetworkConfig(naString);
+ if (VDBG) log("naString=" + naString + " config=" + n);
if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
loge("Error in networkAttributes - ignoring attempt to define type " +
n.type);
@@ -518,6 +520,7 @@
// ignore it - leave the entry null
}
}
+ if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
mProtectedNetworks = new ArrayList<Integer>();
int[] protectedNetworks = context.getResources().getIntArray(
@@ -3906,8 +3909,10 @@
NetworkInfo.State state = mCs
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (state != NetworkInfo.State.CONNECTED) {
- log("isMobileOk: not connected ni=" +
+ if (VDBG) {
+ log("isMobileOk: not connected ni=" +
mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
+ }
sleep(1);
result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
continue;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 35656f8..da584e2 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -899,7 +899,8 @@
Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ " calling userId = " + userId + ", foreground user id = "
- + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
+ + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
+ + InputMethodUtils.getApiCallStack());
}
if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
return true;
@@ -919,7 +920,8 @@
}
return true;
}
- Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
+ Slog.w(TAG, "--- IPC called from background users. Ignore. \n"
+ + InputMethodUtils.getStackTrace());
return false;
}
@@ -2473,7 +2475,7 @@
HashMap<String, InputMethodInfo> map, boolean resetDefaultEnabledIme) {
if (DEBUG) {
Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
- + " \n ------ \n" + getStackTrace());
+ + " \n ------ \n" + InputMethodUtils.getStackTrace());
}
list.clear();
map.clear();
@@ -3468,22 +3470,6 @@
}
}
- // ----------------------------------------------------------------------
- // Utilities for debug
- private static String getStackTrace() {
- final StringBuilder sb = new StringBuilder();
- try {
- throw new RuntimeException();
- } catch (RuntimeException e) {
- final StackTraceElement[] frames = e.getStackTrace();
- // Start at 1 because the first frame is here and we don't care about it
- for (int j = 1; j < frames.length; ++j) {
- sb.append(frames[j].toString() + "\n");
- }
- }
- return sb.toString();
- }
-
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index f95532d..f3aabe2 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -68,6 +68,9 @@
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
+ // How long we wait for a service to finish executing.
+ static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
+
// How long a service needs to be running until restarting its process
// is no longer considered to be a relaunch of the service.
static final int SERVICE_RESTART_DURATION = 5*1000;
@@ -215,6 +218,7 @@
if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
+ final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
@@ -223,11 +227,15 @@
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
+ callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ } else {
+ callerFg = true;
}
+
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid, userId, true);
+ callingPid, callingUid, userId, true, callerFg);
if (res == null) {
return null;
}
@@ -253,7 +261,7 @@
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
- String error = bringUpServiceLocked(r, service.getFlags(), false);
+ String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
if (error != null) {
return new ComponentName("!!", error);
}
@@ -288,7 +296,7 @@
// If this service is active, make sure it is stopped.
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, false);
+ Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);
if (r != null) {
if (r.record != null) {
final long origId = Binder.clearCallingIdentity();
@@ -308,7 +316,7 @@
IBinder peekServiceLocked(Intent service, String resolvedType) {
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(),
- UserHandle.getCallingUserId(), false);
+ UserHandle.getCallingUserId(), false, false);
IBinder ret = null;
if (r != null) {
@@ -483,9 +491,11 @@
}
}
+ final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, true);
+ Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
if (res == null) {
return 0;
}
@@ -545,7 +555,7 @@
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
- if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
+ if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
@@ -575,10 +585,10 @@
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
- requestServiceBindingLocked(s, b.intent, true);
+ requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
- requestServiceBindingLocked(s, b.intent, false);
+ requestServiceBindingLocked(s, b.intent, callerFg, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -676,7 +686,16 @@
if (b.apps.size() > 0 && !inStopping) {
// Applications have already bound since the last
// unbind, so just rebind right here.
- requestServiceBindingLocked(r, b, true);
+ boolean inFg = false;
+ for (int i=b.apps.size()-1; i>=0; i--) {
+ ProcessRecord client = b.apps.valueAt(i).client;
+ if (client != null && client.setSchedGroup
+ != Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ inFg = true;
+ break;
+ }
+ }
+ requestServiceBindingLocked(r, b, inFg, true);
} else {
// Note to tell the service the next time there is
// a new client.
@@ -723,7 +742,7 @@
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, int callingPid, int callingUid, int userId,
- boolean createIfNeeded) {
+ boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
@@ -773,7 +792,7 @@
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
- r = new ServiceRecord(mAm, ss, name, filter, sInfo, res);
+ r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
@@ -817,13 +836,14 @@
return null;
}
- private final void bumpServiceExecutingLocked(ServiceRecord r, String why) {
+ private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
if (DEBUG_SERVICE) Log.v(TAG, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
else if (DEBUG_SERVICE_EXECUTING) Log.v(TAG, ">>> EXECUTING "
+ why + " of " + r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
+ r.executeFg = fg;
ProcessTracker.ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessTracker.getMemFactorLocked(), now);
@@ -833,24 +853,34 @@
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = r.app;
- mAm.mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
+ mAm.mHandler.sendMessageAtTime(msg,
+ fg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}
r.app.executingServices.add(r);
+ r.app.execServicesFg |= fg;
}
+ } else if (r.app != null && fg && !r.app.execServicesFg) {
+ mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG);
+ Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_TIMEOUT_MSG);
+ msg.obj = r.app;
+ mAm.mHandler.sendMessageAtTime(msg,now+SERVICE_TIMEOUT);
+ r.app.execServicesFg = true;
}
+ r.executeFg |= fg;
r.executeNesting++;
r.executingStart = now;
}
private final boolean requestServiceBindingLocked(ServiceRecord r,
- IntentBindRecord i, boolean rebind) {
+ IntentBindRecord i, boolean execInFg, boolean rebind) {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
- bumpServiceExecutingLocked(r, "bind");
+ bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
@@ -962,6 +992,7 @@
}
if (!mRestartingServices.contains(r)) {
+ r.createdFromFg = false;
mRestartingServices.add(r);
}
@@ -982,7 +1013,7 @@
if (!mRestartingServices.contains(r)) {
return;
}
- bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
+ bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
}
private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
@@ -996,12 +1027,12 @@
}
private final String bringUpServiceLocked(ServiceRecord r,
- int intentFlags, boolean whileRestarting) {
+ int intentFlags, boolean execInFg, boolean whileRestarting) {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
- sendServiceArgsLocked(r, false);
+ sendServiceArgsLocked(r, execInFg, false);
return null;
}
@@ -1049,7 +1080,7 @@
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, mAm.mProcessTracker);
- realStartServiceLocked(r, app);
+ realStartServiceLocked(r, app, execInFg);
return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
@@ -1093,17 +1124,17 @@
return null;
}
- private final void requestServiceBindingsLocked(ServiceRecord r) {
+ private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
- if (!requestServiceBindingLocked(r, ibr, false)) {
+ if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
private final void realStartServiceLocked(ServiceRecord r,
- ProcessRecord app) throws RemoteException {
+ ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
@@ -1114,7 +1145,7 @@
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
- bumpServiceExecutingLocked(r, "create");
+ bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, true);
boolean created = false;
@@ -1141,7 +1172,7 @@
}
}
- requestServiceBindingsLocked(r);
+ requestServiceBindingsLocked(r, execInFg);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
@@ -1151,10 +1182,10 @@
null, null));
}
- sendServiceArgsLocked(r, true);
+ sendServiceArgsLocked(r, execInFg, true);
}
- private final void sendServiceArgsLocked(ServiceRecord r,
+ private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) {
final int N = r.pendingStarts.size();
if (N == 0) {
@@ -1180,7 +1211,7 @@
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
- bumpServiceExecutingLocked(r, "start");
+ bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app);
@@ -1256,7 +1287,7 @@
+ ": hasBound=" + ibr.hasBound);
if (ibr.hasBound) {
try {
- bumpServiceExecutingLocked(r, "bring down unbind");
+ bumpServiceExecutingLocked(r, false, "bring down unbind");
mAm.updateOomAdjLocked(r.app);
ibr.hasBound = false;
r.app.thread.scheduleUnbindService(r,
@@ -1306,7 +1337,7 @@
r.app.services.remove(r);
if (r.app.thread != null) {
try {
- bumpServiceExecutingLocked(r, "stop");
+ bumpServiceExecutingLocked(r, false, "stop");
mStoppingServices.add(r);
mAm.updateOomAdjLocked(r.app);
r.app.thread.scheduleStopService(r);
@@ -1387,7 +1418,7 @@
if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
&& b.intent.hasBound) {
try {
- bumpServiceExecutingLocked(s, "unbind");
+ bumpServiceExecutingLocked(s, false, "unbind");
mAm.updateOomAdjLocked(s.app);
b.intent.hasBound = false;
// Assume the client doesn't want to know about a rebind;
@@ -1485,11 +1516,20 @@
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG,
"Nesting at 0 of " + r.shortName);
+ r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
"No more executingServices of " + r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
+ } else if (r.executeFg) {
+ // Need to re-evaluate whether the app still needs to be in the foreground.
+ for (int i=r.app.executingServices.size()-1; i>=0; i--) {
+ if (r.app.executingServices.valueAt(i).executeFg) {
+ r.app.execServicesFg = true;
+ break;
+ }
+ }
}
if (inStopping) {
if (DEBUG_SERVICE) Slog.v(TAG,
@@ -1499,6 +1539,7 @@
}
mAm.updateOomAdjLocked(r.app);
}
+ r.executeFg = false;
if (r.tracker != null) {
r.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
SystemClock.uptimeMillis());
@@ -1526,7 +1567,7 @@
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, mAm.mProcessTracker);
- realStartServiceLocked(sr, proc);
+ realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
}
} catch (Exception e) {
@@ -1639,7 +1680,9 @@
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
sr.makeNextStartId(), baseIntent, null));
if (sr.app != null && sr.app.thread != null) {
- sendServiceArgsLocked(sr, false);
+ // We always run in the foreground, since this is called as
+ // part of the "remove task" UI operation.
+ sendServiceArgsLocked(sr, true, false);
}
}
}
@@ -1880,7 +1923,8 @@
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
- long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
+ long maxTime = SystemClock.uptimeMillis() -
+ (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
for (int i=proc.executingServices.size()-1; i>=0; i--) {
@@ -1900,7 +1944,8 @@
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
- mAm.mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
+ mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
+ ? (nextTime+SERVICE_TIMEOUT) : (nextTime+ SERVICE_BACKGROUND_TIMEOUT));
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3eceff7..c7b2213f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4491,12 +4491,12 @@
app.thread = thread;
app.curAdj = app.setAdj = -100;
- app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
- app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
app.foregroundServices = false;
app.hasShownUi = false;
app.debugging = false;
+ app.cached = false;
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
@@ -10295,6 +10295,22 @@
return needSep;
}
+ void printOomLevel(PrintWriter pw, String name, int adj) {
+ pw.print(" ");
+ if (adj >= 0) {
+ pw.print(' ');
+ if (adj < 10) pw.print(' ');
+ } else {
+ if (adj > -10) pw.print(' ');
+ }
+ pw.print(adj);
+ pw.print(": ");
+ pw.print(name);
+ pw.print(" (");
+ pw.print(mProcessList.getMemLevel(adj)/1024);
+ pw.println(" kB)");
+ }
+
boolean dumpOomLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll) {
boolean needSep = false;
@@ -10303,19 +10319,19 @@
if (needSep) pw.println();
needSep = true;
pw.println(" OOM levels:");
- pw.print(" SYSTEM_ADJ: "); pw.println(ProcessList.SYSTEM_ADJ);
- pw.print(" PERSISTENT_PROC_ADJ: "); pw.println(ProcessList.PERSISTENT_PROC_ADJ);
- pw.print(" FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ);
- pw.print(" VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ);
- pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ);
- pw.print(" BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
- pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
- pw.print(" SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ);
- pw.print(" HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
- pw.print(" PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ);
- pw.print(" SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ);
- pw.print(" CACHED_APP_MIN_ADJ: "); pw.println(ProcessList.CACHED_APP_MIN_ADJ);
- pw.print(" CACHED_APP_MAX_ADJ: "); pw.println(ProcessList.CACHED_APP_MAX_ADJ);
+ printOomLevel(pw, "SYSTEM_ADJ", ProcessList.SYSTEM_ADJ);
+ printOomLevel(pw, "PERSISTENT_PROC_ADJ", ProcessList.PERSISTENT_PROC_ADJ);
+ printOomLevel(pw, "FOREGROUND_APP_ADJ", ProcessList.FOREGROUND_APP_ADJ);
+ printOomLevel(pw, "VISIBLE_APP_ADJ", ProcessList.VISIBLE_APP_ADJ);
+ printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", ProcessList.PERCEPTIBLE_APP_ADJ);
+ printOomLevel(pw, "BACKUP_APP_ADJ", ProcessList.BACKUP_APP_ADJ);
+ printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ printOomLevel(pw, "SERVICE_ADJ", ProcessList.SERVICE_ADJ);
+ printOomLevel(pw, "HOME_APP_ADJ", ProcessList.HOME_APP_ADJ);
+ printOomLevel(pw, "PREVIOUS_APP_ADJ", ProcessList.PREVIOUS_APP_ADJ);
+ printOomLevel(pw, "SERVICE_B_ADJ", ProcessList.SERVICE_B_ADJ);
+ printOomLevel(pw, "CACHED_APP_MIN_ADJ", ProcessList.CACHED_APP_MIN_ADJ);
+ printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ);
if (needSep) pw.println();
needSep = true;
@@ -11515,10 +11531,37 @@
pw.print(" "); pw.print(unshared); pw.print(" kB unshared; ");
pw.print(voltile); pw.println(" kB volatile");
}
+ pw.print(" Tuning: ");
+ pw.print(ActivityManager.staticGetMemoryClass());
+ pw.print(" (large ");
+ pw.print(ActivityManager.staticGetLargeMemoryClass());
+ pw.print("), oom ");
+ pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
+ pw.print(" kB");
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ pw.print(" (low-ram)");
+ }
+ if (ActivityManager.isHighEndGfx()) {
+ pw.print(" (high-end-gfx)");
+ }
+ pw.println();
} else {
pw.print("ksm,"); pw.print(sharing); pw.print(",");
pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
pw.println(voltile);
+ pw.print("tuning,");
+ pw.print(ActivityManager.staticGetMemoryClass());
+ pw.print(',');
+ pw.print(ActivityManager.staticGetLargeMemoryClass());
+ pw.print(',');
+ pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ pw.print(",low-ram");
+ }
+ if (ActivityManager.isHighEndGfx()) {
+ pw.print(",high-end-gfx");
+ }
+ pw.println();
}
}
}
@@ -13558,9 +13601,11 @@
// An app that is currently executing a service callback also
// counts as being in the foreground.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = app.execServicesFg ?
+ Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
+ //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
} else {
// As far as we know the process is empty. We may change our mind later.
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
@@ -14879,7 +14924,7 @@
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
- app.setProcessTrackerState(trackerMemFactor, now);
+ app.setProcessTrackerState(ProcessTracker.ADJ_MEM_FACTOR_NORMAL, now);
}
if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
|| app.systemNoUi) && app.pendingUiClean) {
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index ae5c652..884f280 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -194,10 +194,14 @@
float scaleMem = ((float)(mTotalMemMb-300))/(700-300);
// Scale buckets from screen size.
- int minSize = 320*480; // 153600
+ int minSize = 480*800; // 384000
int maxSize = 1280*800; // 1024000 230400 870400 .264
float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
- //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);
+ if (false) {
+ Slog.i("XXXXXX", "scaleMem=" + scaleMem);
+ Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth
+ + " dh=" + displayHeight);
+ }
StringBuilder adjString = new StringBuilder();
StringBuilder memString = new StringBuilder();
@@ -205,8 +209,13 @@
float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
if (scale < 0) scale = 0;
else if (scale > 1) scale = 1;
- int minfree_adj = Resources.getSystem().getInteger(com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAdjust);
- int minfree_abs = Resources.getSystem().getInteger(com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute);
+ int minfree_adj = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAdjust);
+ int minfree_abs = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute);
+ if (false) {
+ Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
+ }
for (int i=0; i<mOomAdj.length; i++) {
long low = mOomMinFreeLow[i];
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 1b45d30..cade2bb 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -39,7 +39,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashSet;
/**
* Full information about a particular process that
@@ -138,7 +137,8 @@
// All ContentProviderRecord process is using
final ArrayList<ContentProviderConnection> conProviders
= new ArrayList<ContentProviderConnection>();
-
+
+ boolean execServicesFg; // do we need to be executing services in the foreground?
boolean persistent; // always keep this application running?
boolean crashing; // are we in the process of crashing?
Dialog crashDialog; // dialog being displayed due to crash.
@@ -301,7 +301,8 @@
}
}
if (executingServices.size() > 0) {
- pw.print(prefix); pw.println("Executing Services:");
+ pw.print(prefix); pw.print("Executing Services (fg=");
+ pw.print(execServicesFg); pw.println(")");
for (int i=0; i<executingServices.size(); i++) {
pw.print(prefix); pw.print(" - "); pw.println(executingServices.valueAt(i));
}
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index f37351f..6b98b03 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -815,8 +815,7 @@
mRuntime = runtime;
}
}
- String webview = SystemProperties.getBoolean(
- WebViewFactory.WEBVIEW_EXPERIMENTAL_PROPERTY, false) ? "chromeview" : "webview";
+ String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
if (!Objects.equals(webview, mWebView)) {
changed = true;
if (update) {
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index fe9a71c..19dda2a 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -92,7 +92,9 @@
boolean stopIfKilled; // last onStart() said to stop if service killed?
boolean callStart; // last onStart() has asked to alway be called on restart.
int executeNesting; // number of outstanding operations keeping foreground.
+ boolean executeFg; // should we be executing in the foreground?
long executingStart; // start time of last execute request.
+ boolean createdFromFg; // was this service last created due to a foreground process call?
int crashCount; // number of times proc has crashed with service running
int totalRestartCount; // number of times we have had to restart.
int restartCount; // number of restarts performed in a row.
@@ -226,22 +228,25 @@
TimeUtils.formatDuration(createTime, nowReal, pw);
pw.print(" lastActivity=");
TimeUtils.formatDuration(lastActivity, now, pw);
- pw.println("");
- pw.print(prefix); pw.print("executingStart=");
- TimeUtils.formatDuration(executingStart, now, pw);
- pw.print(" restartTime=");
+ pw.println();
+ pw.print(prefix); pw.print("restartTime=");
TimeUtils.formatDuration(restartTime, now, pw);
- pw.println("");
+ pw.print(" createdFromFg="); pw.println(createdFromFg);
if (startRequested || lastStartId != 0) {
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
pw.print(" stopIfKilled="); pw.print(stopIfKilled);
pw.print(" callStart="); pw.print(callStart);
pw.print(" lastStartId="); pw.println(lastStartId);
}
- if (executeNesting != 0 || crashCount != 0 || restartCount != 0
- || restartDelay != 0 || nextRestartTime != 0) {
+ if (executeNesting != 0) {
pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
- pw.print(" restartCount="); pw.print(restartCount);
+ pw.print(" executeFg="); pw.print(executeFg);
+ pw.print(" executingStart=");
+ TimeUtils.formatDuration(executingStart, now, pw);
+ }
+ if (crashCount != 0 || restartCount != 0
+ || restartDelay != 0 || nextRestartTime != 0) {
+ pw.print(prefix); pw.print("restartCount="); pw.print(restartCount);
pw.print(" restartDelay=");
TimeUtils.formatDuration(restartDelay, now, pw);
pw.print(" nextRestartTime=");
@@ -282,7 +287,8 @@
ServiceRecord(ActivityManagerService ams,
BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
- Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
+ Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
+ Runnable restarter) {
this.ams = ams;
this.stats = servStats;
this.name = name;
@@ -301,6 +307,7 @@
createTime = SystemClock.elapsedRealtime();
lastActivity = SystemClock.uptimeMillis();
userId = UserHandle.getUserId(appInfo.uid);
+ createdFromFg = callerIsFg;
}
public ProcessTracker.ServiceState getTracker() {
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index d1c682b..ce1dde4 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -304,8 +304,9 @@
}
/**
- * If two SyncOperation intervals are disjoint, the smaller is the interval that occurs before.
- * If the intervals overlap, the two are considered equal.
+ * SyncOperations are sorted based on their earliest effective run time.
+ * This comparator is used to sort the SyncOps at a given time when
+ * deciding which to run, so earliest run time is the best criteria.
*/
@Override
public int compareTo(Object o) {
@@ -313,17 +314,15 @@
if (expedited != other.expedited) {
return expedited ? -1 : 1;
}
- long x1 = effectiveRunTime - flexTime;
- long y1 = effectiveRunTime;
- long x2 = other.effectiveRunTime - other.flexTime;
- long y2 = other.effectiveRunTime;
- // Overlapping intervals.
- if ((x1 <= y2 && x1 >= x2) || (x2 <= y1 && x2 >= x1)) {
+ long thisIntervalStart = Math.max(effectiveRunTime - flexTime, 0);
+ long otherIntervalStart = Math.max(
+ other.effectiveRunTime - other.flexTime, 0);
+ if (thisIntervalStart < otherIntervalStart) {
+ return -1;
+ } else if (otherIntervalStart < thisIntervalStart) {
+ return 1;
+ } else {
return 0;
}
- if (x1 < x2 && y1 < x2) {
- return -1;
- }
- return 1;
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7a01219..cd2dc21 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5383,7 +5383,7 @@
== PackageManager.SIGNATURE_MATCH);
if (!allowed && (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
- if (isPrivilegedApp(pkg)) {
+ if (isSystemApp(pkg)) {
// For updated system applications, a system permission
// is granted only if it had been defined by the original application.
if (isUpdatedSystemApp(pkg)) {
@@ -5391,7 +5391,11 @@
.getDisabledSystemPkgLPr(pkg.packageName);
final GrantedPermissions origGp = sysPs.sharedUser != null
? sysPs.sharedUser : sysPs;
+
if (origGp.grantedPermissions.contains(perm)) {
+ // If the original was granted this permission, we take
+ // that grant decision as read and propagate it to the
+ // update.
allowed = true;
} else {
// The system apk may have been updated with an older
@@ -5413,7 +5417,7 @@
}
}
} else {
- allowed = true;
+ allowed = isPrivilegedApp(pkg);
}
}
}
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index 203bc86..7acf6ab 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -28,6 +29,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.IBinder.DeathRecipient;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
import android.print.PrintManager;
@@ -46,11 +48,11 @@
* and unbinding from the remote implementation. Clients can call methods of
* this class without worrying about when and how to bind/unbind.
*/
-final class RemotePrintService {
+final class RemotePrintService implements DeathRecipient {
private static final String LOG_TAG = "RemotePrintService";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
private final Context mContext;
@@ -98,7 +100,16 @@
}
public void onAllPrintJobsHandled() {
- mHandler.sendEmptyMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED);
+ mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED);
+ }
+
+ @Override
+ public void binderDied() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED);
+ }
+
+ private void handleBinderDied() {
+ ensureUnbound();
}
private void handleOnAllPrintJobsHandled() {
@@ -113,7 +124,7 @@
}
public void onRequestCancelPrintJob(PrintJobInfo printJob) {
- mHandler.obtainMessage(MyHandler.MSG_REQUEST_CANCEL_PRINT_JOB,
+ mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINT_JOB,
printJob).sendToTarget();
}
@@ -126,7 +137,7 @@
Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnRequestCancelPrintJob()");
}
try {
- mPrintService.requestCancelPrintJob(printJob);
+ mPrintService.onRequestCancelPrintJob(printJob);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error canceling pring job.", re);
}
@@ -134,7 +145,7 @@
}
public void onPrintJobQueued(PrintJobInfo printJob) {
- mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED,
+ mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED,
printJob).sendToTarget();
}
@@ -161,7 +172,7 @@
}
public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
- mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, observer).sendToTarget();
+ mHandler.obtainMessage(MyHandler.MSG_ON_START_PRINTER_DISCOVERY, observer).sendToTarget();
}
private void handleOnStartPrinterDiscovery(final IPrinterDiscoveryObserver observer) {
@@ -179,7 +190,7 @@
Slog.i(LOG_TAG, "[user: " + mUserId + "] onStartPrinterDiscovery()");
}
try {
- mPrintService.startPrinterDiscovery(observer);
+ mPrintService.onStartPrinterDiscovery(observer);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re);
}
@@ -187,7 +198,7 @@
}
public void onStopPrinterDiscovery() {
- mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY);
+ mHandler.sendEmptyMessage(MyHandler.MSG_ON_STOP_PRINTER_DISCOVERY);
}
private void handleStopPrinterDiscovery() {
@@ -205,13 +216,40 @@
Slog.i(LOG_TAG, "[user: " + mUserId + "] onStopPrinterDiscovery()");
}
try {
- mPrintService.stopPrinterDiscovery();
+ mPrintService.onStopPrinterDiscovery();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error announcing stop printer dicovery.", re);
}
}
}
+ public void onRequestUpdatePrinters(List<PrinterId> printerIds) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_UPDATE_PRINTERS,
+ printerIds).sendToTarget();
+ }
+
+ private void handleReqeustUpdatePritners(final List<PrinterId> printerIds) {
+ throwIfDestroyed();
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleReqeustUpdatePritners(printerIds);
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] handleReqeustUpdatePritners()");
+ }
+ try {
+ mPrintService.onRequestUpdatePrinters(printerIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error requesting to update printers.", re);
+ }
+ }
+ }
+
private boolean isBound() {
return mPrintService != null;
}
@@ -243,6 +281,7 @@
} catch (RemoteException re) {
/* ignore */
}
+ mPrintService.asBinder().unlinkToDeath(this, 0);
mPrintService = null;
mContext.unbindService(mServiceConnection);
}
@@ -263,10 +302,16 @@
mBinding = false;
mPrintService = IPrintService.Stub.asInterface(service);
try {
+ service.linkToDeath(RemotePrintService.this, 0);
+ } catch (RemoteException re) {
+ handleBinderDied();
+ return;
+ }
+ try {
mPrintService.setClient(mPrintServiceClient);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error setting client for: " + service, re);
- handleDestroy();
+ handleBinderDied();
return;
}
final int pendingCommandCount = mPendingCommands.size();
@@ -283,47 +328,59 @@
}
private final class MyHandler extends Handler {
- public static final int MSG_ALL_PRINT_JOBS_HANDLED = 1;
- public static final int MSG_REQUEST_CANCEL_PRINT_JOB = 2;
- public static final int MSG_PRINT_JOB_QUEUED = 3;
- public static final int MSG_START_PRINTER_DISCOVERY = 4;
- public static final int MSG_STOP_PRINTER_DISCOVERY = 5;
- public static final int MSG_DESTROY = 6;
+ public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 1;
+ public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 2;
+ public static final int MSG_ON_PRINT_JOB_QUEUED = 3;
+ public static final int MSG_ON_START_PRINTER_DISCOVERY = 4;
+ public static final int MSG_ON_STOP_PRINTER_DISCOVERY = 5;
+ public static final int MSG_ON_REQUEST_UPDATE_PRINTERS = 6;
+ public static final int MSG_DESTROY = 7;
+ public static final int MSG_BINDER_DIED = 8;
public MyHandler(Looper looper) {
super(looper, null, false);
}
@Override
+ @SuppressWarnings("unchecked")
public void handleMessage(Message message) {
switch (message.what) {
- case MSG_ALL_PRINT_JOBS_HANDLED: {
+ case MSG_ON_ALL_PRINT_JOBS_HANDLED: {
handleOnAllPrintJobsHandled();
} break;
- case MSG_REQUEST_CANCEL_PRINT_JOB: {
+ case MSG_ON_REQUEST_CANCEL_PRINT_JOB: {
PrintJobInfo printJob = (PrintJobInfo) message.obj;
handleOnRequestCancelPrintJob(printJob);
} break;
- case MSG_PRINT_JOB_QUEUED: {
+ case MSG_ON_PRINT_JOB_QUEUED: {
PrintJobInfo printJob = (PrintJobInfo) message.obj;
handleOnPrintJobQueued(printJob);
} break;
- case MSG_START_PRINTER_DISCOVERY: {
+ case MSG_ON_START_PRINTER_DISCOVERY: {
IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) message.obj;
handleOnStartPrinterDiscovery(new SecurePrinterDiscoveryObserver(
mComponentName, observer));
} break;
- case MSG_STOP_PRINTER_DISCOVERY: {
+ case MSG_ON_REQUEST_UPDATE_PRINTERS: {
+ List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+ handleReqeustUpdatePritners(printerIds);
+ } break;
+
+ case MSG_ON_STOP_PRINTER_DISCOVERY: {
handleStopPrinterDiscovery();
} break;
case MSG_DESTROY: {
handleDestroy();
} break;
+
+ case MSG_BINDER_DIED: {
+ handleBinderDied();
+ } break;
}
}
}
@@ -420,22 +477,32 @@
}
@Override
- public void addDiscoveredPrinters(List<PrinterInfo> printers) {
+ public void onPrintersAdded(List<PrinterInfo> printers) {
throwIfPrinterIdsForPrinterInfoTampered(printers);
try {
- mDecoratedObsever.addDiscoveredPrinters(printers);
+ mDecoratedObsever.onPrintersAdded(printers);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error delegating to addDiscoveredPrinters", re);
+ Slog.e(LOG_TAG, "Error delegating to onPrintersAdded", re);
}
}
@Override
- public void removeDiscoveredPrinters(List<PrinterId> printerIds) {
+ public void onPrintersUpdated(List<PrinterInfo> printers) {
+ throwIfPrinterIdsForPrinterInfoTampered(printers);
+ try {
+ mDecoratedObsever.onPrintersUpdated(printers);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error delegating to onPrintersUpdated.", re);
+ }
+ }
+
+ @Override
+ public void onPrintersRemoved(List<PrinterId> printerIds) {
throwIfPrinterIdsTampered(printerIds);
try {
- mDecoratedObsever.removeDiscoveredPrinters(printerIds);
+ mDecoratedObsever.onPrintersRemoved(printerIds);
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error delegating to removeDiscoveredPrinters", re);
+ Slog.e(LOG_TAG, "Error delegating to onPrintersRemoved", re);
}
}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 6445c2e..fe5b067 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -34,6 +35,7 @@
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
import android.util.Slog;
import android.util.TimedRemoteCaller;
@@ -54,7 +56,7 @@
private static final String LOG_TAG = "RemotePrintSpooler";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
@@ -88,11 +90,14 @@
private boolean mDestroyed;
+ private boolean mCanUnbind;
+
public static interface PrintSpoolerCallbacks {
public void onPrintJobQueued(PrintJobInfo printJob);
public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer);
public void onStopPrinterDiscovery();
public void onAllPrintJobsForServiceHandled(ComponentName printService);
+ public void onRequestUpdatePrinters(List<PrinterId> printerIds);
}
public RemotePrintSpooler(Context context, int userId,
@@ -111,6 +116,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()");
@@ -122,6 +128,11 @@
Slog.e(LOG_TAG, "Error getting print jobs.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error getting print jobs.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return null;
}
@@ -131,6 +142,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()");
@@ -142,6 +154,11 @@
Slog.e(LOG_TAG, "Error creating print job.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error creating print job.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return null;
}
@@ -150,6 +167,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] cancelPrintJob()");
@@ -161,6 +179,11 @@
Slog.e(LOG_TAG, "Error canceling print job.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error canceling print job.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return false;
}
@@ -169,6 +192,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()");
@@ -183,6 +207,10 @@
// We passed the file descriptor across and now the other
// side is responsible to close it, so close the local copy.
IoUtils.closeQuietly(fd);
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
}
@@ -190,6 +218,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()");
@@ -201,6 +230,11 @@
Slog.e(LOG_TAG, "Error getting print job info.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error getting print job info.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return null;
}
@@ -209,6 +243,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()");
@@ -220,6 +255,11 @@
Slog.e(LOG_TAG, "Error setting print job state.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error setting print job state.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return false;
}
@@ -228,6 +268,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()");
@@ -239,6 +280,11 @@
Slog.e(LOG_TAG, "Error setting print job tag.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error setting print job tag.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
return false;
}
@@ -247,6 +293,7 @@
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
+ mCanUnbind = false;
}
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
@@ -258,6 +305,11 @@
Slog.e(LOG_TAG, "Error asking for active print job notification.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error asking for active print job notification.", te);
+ } finally {
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
}
}
@@ -270,6 +322,7 @@
throwIfDestroyedLocked();
unbindLocked();
mDestroyed = true;
+ mCanUnbind = false;
}
}
@@ -314,15 +367,29 @@
/* ignore */
}
}
+
+ mCanUnbind = true;
+ mLock.notifyAll();
}
private void unbindLocked() {
- if (DEBUG) {
- Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
+ while (true) {
+ if (mCanUnbind) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
+ }
+ clearClientLocked();
+ mRemoteInstance = null;
+ mContext.unbindService(mServiceConnection);
+ return;
+ }
+ try {
+ mLock.wait();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
}
- clearClientLocked();
- mRemoteInstance = null;
- mContext.unbindService(mServiceConnection);
+
}
private void setClientLocked() {
@@ -597,7 +664,7 @@
}
@Override
- public void onStopPrinterDiscovery() throws RemoteException {
+ public void onStopPrinterDiscovery() {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
@@ -608,5 +675,18 @@
}
}
}
+
+ @Override
+ public void onRequestUpdatePrinters(List<PrinterId> printerIds) {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.mCallbacks.onRequestUpdatePrinters(printerIds);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
}
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 5cef4d3..c41f9b0 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -23,6 +23,7 @@
import android.content.pm.ResolveInfo;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
@@ -138,6 +139,21 @@
}
}
+ @Override
+ public void onRequestUpdatePrinters(List<PrinterId> printerIds) {
+ final RemotePrintService service;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mActiveServices.isEmpty()) {
+ return;
+ }
+ service = mActiveServices.get(printerIds.get(0).getService());
+ }
+ if (service != null) {
+ service.onRequestUpdatePrinters(printerIds);
+ }
+ }
+
public void updateIfNeededLocked() {
throwIfDestroyedLocked();
if (readConfigurationLocked()) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 9a5026d..304fbb1 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -7637,7 +7637,7 @@
private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.DISPLAY_SIZE_FORCED);
- if (sizeStr == null) {
+ if (sizeStr == null || sizeStr.length() == 0) {
sizeStr = SystemProperties.get(SIZE_OVERRIDE, null);
}
if (sizeStr != null && sizeStr.length() > 0) {
@@ -7661,7 +7661,7 @@
}
String densityStr = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.DISPLAY_DENSITY_FORCED);
- if (densityStr == null) {
+ if (densityStr == null || densityStr.length() == 0) {
densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
}
if (densityStr != null && densityStr.length() > 0) {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 957c448..3946f15 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,7 +4,6 @@
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_AssetAtlasService.cpp \
- com_android_server_BatteryService.cpp \
com_android_server_input_InputApplicationHandle.cpp \
com_android_server_input_InputManagerService.cpp \
com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
deleted file mode 100644
index 0c8b4a5..0000000
--- a/services/jni/com_android_server_BatteryService.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BatteryService"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <linux/ioctl.h>
-#include <utils/Vector.h>
-#include <utils/String8.h>
-
-namespace android {
-
-#define POWER_SUPPLY_PATH "/sys/class/power_supply"
-
-struct FieldIds {
- // members
- jfieldID mAcOnline;
- jfieldID mUsbOnline;
- jfieldID mWirelessOnline;
- jfieldID mBatteryStatus;
- jfieldID mBatteryHealth;
- jfieldID mBatteryPresent;
- jfieldID mBatteryLevel;
- jfieldID mBatteryVoltage;
- jfieldID mBatteryTemperature;
- jfieldID mBatteryTechnology;
-};
-static FieldIds gFieldIds;
-
-struct BatteryManagerConstants {
- jint statusUnknown;
- jint statusCharging;
- jint statusDischarging;
- jint statusNotCharging;
- jint statusFull;
- jint healthUnknown;
- jint healthGood;
- jint healthOverheat;
- jint healthDead;
- jint healthOverVoltage;
- jint healthUnspecifiedFailure;
- jint healthCold;
-};
-static BatteryManagerConstants gConstants;
-
-struct PowerSupplyPaths {
- String8 batteryStatusPath;
- String8 batteryHealthPath;
- String8 batteryPresentPath;
- String8 batteryCapacityPath;
- String8 batteryVoltagePath;
- String8 batteryTemperaturePath;
- String8 batteryTechnologyPath;
-};
-static PowerSupplyPaths gPaths;
-
-static Vector<String8> gChargerNames;
-
-static int gVoltageDivisor = 1;
-
-enum PowerSupplyType {
- ANDROID_POWER_SUPPLY_TYPE_UNKNOWN = 0,
- ANDROID_POWER_SUPPLY_TYPE_AC,
- ANDROID_POWER_SUPPLY_TYPE_USB,
- ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
- ANDROID_POWER_SUPPLY_TYPE_BATTERY
-};
-
-static jint getBatteryStatus(const char* status)
-{
- switch (status[0]) {
- case 'C': return gConstants.statusCharging; // Charging
- case 'D': return gConstants.statusDischarging; // Discharging
- case 'F': return gConstants.statusFull; // Full
- case 'N': return gConstants.statusNotCharging; // Not charging
- case 'U': return gConstants.statusUnknown; // Unknown
-
- default: {
- ALOGW("Unknown battery status '%s'", status);
- return gConstants.statusUnknown;
- }
- }
-}
-
-static jint getBatteryHealth(const char* status)
-{
- switch (status[0]) {
- case 'C': return gConstants.healthCold; // Cold
- case 'D': return gConstants.healthDead; // Dead
- case 'G': return gConstants.healthGood; // Good
- case 'O': {
- if (strcmp(status, "Overheat") == 0) {
- return gConstants.healthOverheat;
- } else if (strcmp(status, "Over voltage") == 0) {
- return gConstants.healthOverVoltage;
- }
- ALOGW("Unknown battery health[1] '%s'", status);
- return gConstants.healthUnknown;
- }
-
- case 'U': {
- if (strcmp(status, "Unspecified failure") == 0) {
- return gConstants.healthUnspecifiedFailure;
- } else if (strcmp(status, "Unknown") == 0) {
- return gConstants.healthUnknown;
- }
- // fall through
- }
-
- default: {
- ALOGW("Unknown battery health[2] '%s'", status);
- return gConstants.healthUnknown;
- }
- }
-}
-
-static int readFromFile(const String8& path, char* buf, size_t size)
-{
- if (path.isEmpty())
- return -1;
- int fd = open(path.string(), O_RDONLY, 0);
- if (fd == -1) {
- ALOGE("Could not open '%s'", path.string());
- return -1;
- }
-
- ssize_t count = read(fd, buf, size);
- if (count > 0) {
- while (count > 0 && buf[count-1] == '\n')
- count--;
- buf[count] = '\0';
- } else {
- buf[0] = '\0';
- }
-
- close(fd);
- return count;
-}
-
-static void setBooleanField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
- const int SIZE = 16;
- char buf[SIZE];
-
- jboolean value = false;
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
- value = true;
- }
- }
- env->SetBooleanField(obj, fieldID, value);
-}
-
-static void setIntField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
- const int SIZE = 128;
- char buf[SIZE];
-
- jint value = 0;
- if (readFromFile(path, buf, SIZE) > 0) {
- value = atoi(buf);
- }
- env->SetIntField(obj, fieldID, value);
-}
-
-static void setVoltageField(JNIEnv* env, jobject obj, const String8& path, jfieldID fieldID)
-{
- const int SIZE = 128;
- char buf[SIZE];
-
- jint value = 0;
- if (readFromFile(path, buf, SIZE) > 0) {
- value = atoi(buf);
- value /= gVoltageDivisor;
- }
- env->SetIntField(obj, fieldID, value);
-}
-
-static PowerSupplyType readPowerSupplyType(const String8& path) {
- const int SIZE = 128;
- char buf[SIZE];
- int length = readFromFile(path, buf, SIZE);
-
- if (length <= 0)
- return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- if (buf[length - 1] == '\n')
- buf[length - 1] = 0;
- if (strcmp(buf, "Battery") == 0)
- return ANDROID_POWER_SUPPLY_TYPE_BATTERY;
- else if (strcmp(buf, "Mains") == 0 || strcmp(buf, "USB_DCP") == 0 ||
- strcmp(buf, "USB_CDP") == 0 || strcmp(buf, "USB_ACA") == 0)
- return ANDROID_POWER_SUPPLY_TYPE_AC;
- else if (strcmp(buf, "USB") == 0)
- return ANDROID_POWER_SUPPLY_TYPE_USB;
- else if (strcmp(buf, "Wireless") == 0)
- return ANDROID_POWER_SUPPLY_TYPE_WIRELESS;
- else
- return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
-}
-
-static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
-{
- setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
-
- setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
- setVoltageField(env, obj, gPaths.batteryVoltagePath, gFieldIds.mBatteryVoltage);
- setIntField(env, obj, gPaths.batteryTemperaturePath, gFieldIds.mBatteryTemperature);
-
- const int SIZE = 128;
- char buf[SIZE];
-
- if (readFromFile(gPaths.batteryStatusPath, buf, SIZE) > 0)
- env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
- else
- env->SetIntField(obj, gFieldIds.mBatteryStatus,
- gConstants.statusUnknown);
-
- if (readFromFile(gPaths.batteryHealthPath, buf, SIZE) > 0)
- env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
-
- if (readFromFile(gPaths.batteryTechnologyPath, buf, SIZE) > 0)
- env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
-
- unsigned int i;
- String8 path;
- jboolean acOnline = false;
- jboolean usbOnline = false;
- jboolean wirelessOnline = false;
-
- for (i = 0; i < gChargerNames.size(); i++) {
- path.clear();
- path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH,
- gChargerNames[i].string());
-
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
- path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH,
- gChargerNames[i].string());
- switch(readPowerSupplyType(path)) {
- case ANDROID_POWER_SUPPLY_TYPE_AC:
- acOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_USB:
- usbOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- wirelessOnline = true;
- break;
- default:
- ALOGW("%s: Unknown power supply type",
- gChargerNames[i].string());
- }
- }
- }
- }
-
- env->SetBooleanField(obj, gFieldIds.mAcOnline, acOnline);
- env->SetBooleanField(obj, gFieldIds.mUsbOnline, usbOnline);
- env->SetBooleanField(obj, gFieldIds.mWirelessOnline, wirelessOnline);
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- {"native_update", "()V", (void*)android_server_BatteryService_update},
-};
-
-int register_android_server_BatteryService(JNIEnv* env)
-{
- String8 path;
- struct dirent* entry;
-
- DIR* dir = opendir(POWER_SUPPLY_PATH);
- if (dir == NULL) {
- ALOGE("Could not open %s\n", POWER_SUPPLY_PATH);
- } else {
- while ((entry = readdir(dir))) {
- const char* name = entry->d_name;
-
- // ignore "." and ".."
- if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
- continue;
- }
-
- char buf[20];
- // Look for "type" file in each subdirectory
- path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_PATH, name);
- switch(readPowerSupplyType(path)) {
- case ANDROID_POWER_SUPPLY_TYPE_AC:
- case ANDROID_POWER_SUPPLY_TYPE_USB:
- case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- path.clear();
- path.appendFormat("%s/%s/online", POWER_SUPPLY_PATH, name);
- if (access(path.string(), R_OK) == 0)
- gChargerNames.add(String8(name));
- break;
-
- case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
- path.clear();
- path.appendFormat("%s/%s/status", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryStatusPath = path;
- path.clear();
- path.appendFormat("%s/%s/health", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryHealthPath = path;
- path.clear();
- path.appendFormat("%s/%s/present", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryPresentPath = path;
- path.clear();
- path.appendFormat("%s/%s/capacity", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryCapacityPath = path;
-
- path.clear();
- path.appendFormat("%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryVoltagePath = path;
- // voltage_now is in microvolts, not millivolts
- gVoltageDivisor = 1000;
- } else {
- path.clear();
- path.appendFormat("%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryVoltagePath = path;
- }
-
- path.clear();
- path.appendFormat("%s/%s/temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0) {
- gPaths.batteryTemperaturePath = path;
- } else {
- path.clear();
- path.appendFormat("%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryTemperaturePath = path;
- }
-
- path.clear();
- path.appendFormat("%s/%s/technology", POWER_SUPPLY_PATH, name);
- if (access(path, R_OK) == 0)
- gPaths.batteryTechnologyPath = path;
- break;
-
- case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
- break;
- }
- }
- closedir(dir);
- }
-
- if (!gChargerNames.size())
- ALOGE("No charger supplies found");
- if (gPaths.batteryStatusPath.isEmpty())
- ALOGE("batteryStatusPath not found");
- if (gPaths.batteryHealthPath.isEmpty())
- ALOGE("batteryHealthPath not found");
- if (gPaths.batteryPresentPath.isEmpty())
- ALOGE("batteryPresentPath not found");
- if (gPaths.batteryCapacityPath.isEmpty())
- ALOGE("batteryCapacityPath not found");
- if (gPaths.batteryVoltagePath.isEmpty())
- ALOGE("batteryVoltagePath not found");
- if (gPaths.batteryTemperaturePath.isEmpty())
- ALOGE("batteryTemperaturePath not found");
- if (gPaths.batteryTechnologyPath.isEmpty())
- ALOGE("batteryTechnologyPath not found");
-
- jclass clazz = env->FindClass("com/android/server/BatteryService");
-
- if (clazz == NULL) {
- ALOGE("Can't find com/android/server/BatteryService");
- return -1;
- }
-
- gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
- gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
- gFieldIds.mWirelessOnline = env->GetFieldID(clazz, "mWirelessOnline", "Z");
- gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
- gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
- gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
- gFieldIds.mBatteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
- gFieldIds.mBatteryTechnology = env->GetFieldID(clazz, "mBatteryTechnology", "Ljava/lang/String;");
- gFieldIds.mBatteryVoltage = env->GetFieldID(clazz, "mBatteryVoltage", "I");
- gFieldIds.mBatteryTemperature = env->GetFieldID(clazz, "mBatteryTemperature", "I");
-
- LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
- LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
- LOG_FATAL_IF(gFieldIds.mWirelessOnline == NULL, "Unable to find BatteryService.WIRELESS_ONLINE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryLevel == NULL, "Unable to find BatteryService.BATTERY_CAPACITY_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryVoltage == NULL, "Unable to find BatteryService.BATTERY_VOLTAGE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryTemperature == NULL, "Unable to find BatteryService.BATTERY_TEMPERATURE_PATH");
- LOG_FATAL_IF(gFieldIds.mBatteryTechnology == NULL, "Unable to find BatteryService.BATTERY_TECHNOLOGY_PATH");
-
- clazz = env->FindClass("android/os/BatteryManager");
-
- if (clazz == NULL) {
- ALOGE("Can't find android/os/BatteryManager");
- return -1;
- }
-
- gConstants.statusUnknown = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_UNKNOWN", "I"));
-
- gConstants.statusCharging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_CHARGING", "I"));
-
- gConstants.statusDischarging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_DISCHARGING", "I"));
-
- gConstants.statusNotCharging = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_NOT_CHARGING", "I"));
-
- gConstants.statusFull = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_STATUS_FULL", "I"));
-
- gConstants.healthUnknown = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNKNOWN", "I"));
-
- gConstants.healthGood = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_GOOD", "I"));
-
- gConstants.healthOverheat = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVERHEAT", "I"));
-
- gConstants.healthDead = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_DEAD", "I"));
-
- gConstants.healthOverVoltage = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_OVER_VOLTAGE", "I"));
-
- gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
-
- gConstants.healthCold = env->GetStaticIntField(clazz,
- env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I"));
-
- return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
-}
-
-} /* namespace android */
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index bb679aa..736ef24f 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -21,7 +21,6 @@
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
-int register_android_server_BatteryService(JNIEnv* env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
@@ -57,7 +56,6 @@
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
- register_android_server_BatteryService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbHostManager(env);
register_android_server_VibratorService(env);
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 4d8342c..4f1ae11 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -106,7 +106,8 @@
public static final int APN_IMS_ID = 5;
public static final int APN_FOTA_ID = 6;
public static final int APN_CBS_ID = 7;
- public static final int APN_NUM_TYPES = 8;
+ public static final int APN_IA_ID = 8;
+ public static final int APN_NUM_TYPES = 9;
public static final int DISABLED = 0;
public static final int ENABLED = 1;
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 16ea625..4a4a62b 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -119,5 +119,7 @@
public static final String APN_TYPE_IMS = "ims";
/** APN type for CBS */
public static final String APN_TYPE_CBS = "cbs";
+ /** APN type for IA Initial Attach APN */
+ public static final String APN_TYPE_IA = "ia";
}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java b/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java
index 28e86bf..4ad6dc7 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ArrayMapTests.java
@@ -146,6 +146,65 @@
}
}
+ if (map.entrySet().hashCode() != array.entrySet().hashCode()) {
+ Log.e("test", "Entry set hash codes differ: map=0x"
+ + Integer.toHexString(map.entrySet().hashCode()) + " array=0x"
+ + Integer.toHexString(array.entrySet().hashCode()));
+ return false;
+ }
+
+ if (!map.entrySet().equals(array.entrySet())) {
+ Log.e("test", "Failed calling equals on map entry set against array set");
+ return false;
+ }
+
+ if (!array.entrySet().equals(map.entrySet())) {
+ Log.e("test", "Failed calling equals on array entry set against map set");
+ return false;
+ }
+
+ if (map.keySet().hashCode() != array.keySet().hashCode()) {
+ Log.e("test", "Key set hash codes differ: map=0x"
+ + Integer.toHexString(map.keySet().hashCode()) + " array=0x"
+ + Integer.toHexString(array.keySet().hashCode()));
+ return false;
+ }
+
+ if (!map.keySet().equals(array.keySet())) {
+ Log.e("test", "Failed calling equals on map key set against array set");
+ return false;
+ }
+
+ if (!array.keySet().equals(map.keySet())) {
+ Log.e("test", "Failed calling equals on array key set against map set");
+ return false;
+ }
+
+ if (!map.keySet().containsAll(array.keySet())) {
+ Log.e("test", "Failed map key set contains all of array key set");
+ return false;
+ }
+
+ if (!array.keySet().containsAll(map.keySet())) {
+ Log.e("test", "Failed array key set contains all of map key set");
+ return false;
+ }
+
+ if (!array.containsAll(map.keySet())) {
+ Log.e("test", "Failed array contains all of map key set");
+ return false;
+ }
+
+ if (!map.entrySet().containsAll(array.entrySet())) {
+ Log.e("test", "Failed map entry set contains all of array entry set");
+ return false;
+ }
+
+ if (!array.entrySet().containsAll(map.entrySet())) {
+ Log.e("test", "Failed array entry set contains all of map entry set");
+ return false;
+ }
+
return true;
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index bdd8aa6..1bb0db0 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -41,6 +41,16 @@
</activity>
<activity
+ android:name="PathOpsActivity"
+ android:label="Path/Ops"
+ android:theme="@android:style/Theme.Holo.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="AssetsAtlasActivity"
android:label="Atlas/Framework"
android:theme="@android:style/Theme.Holo.Light">
@@ -735,7 +745,7 @@
android:name="PathsCacheActivity"
android:label="Path/Cache">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
+ <action android:name="android.intent.action.MAIN" />`
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
new file mode 100644
index 0000000..b9927ac
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathOpsActivity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class PathOpsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final PathsView view = new PathsView(this);
+ setContentView(view);
+ }
+
+ public static class PathsView extends View {
+ private final Paint mPaint;
+ private Path[] mPaths;
+ private float mSize;
+
+
+ public PathsView(Context c) {
+ super(c);
+
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(Color.RED);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ Path.Op[] ops = Path.Op.values();
+ mPaths = new Path[ops.length];
+
+ mSize = w / (ops.length * 2.0f);
+
+ Path p1 = new Path();
+ p1.addRect(0.0f, 0.0f, mSize, mSize, Path.Direction.CW);
+
+ Path p2 = new Path();
+ p2.addCircle(mSize, mSize, mSize / 2.0f, Path.Direction.CW);
+
+ for (int i = 0; i < ops.length; i++) {
+ mPaths[i] = new Path();
+ if (!mPaths[i].op(p1, p2, ops[i])) {
+ Log.d("PathOps", ops[i].name() + " failed!");
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.translate(mSize * 0.2f, getHeight() / 2.0f);
+ for (Path path : mPaths) {
+ canvas.drawPath(path, mPaint);
+ canvas.translate(mSize * 1.8f, 0.0f);
+ }
+ }
+ }
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 2149190..3797b49 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -934,6 +934,9 @@
if (out) {
out->mnc = atoi(val);
+ if (out->mnc == 0) {
+ out->mnc = ACONFIGURATION_MNC_ZERO;
+ }
}
return true;