Merge "Fix missing lock in power manager."
diff --git a/Android.mk b/Android.mk
index db6a704..d81e581 100644
--- a/Android.mk
+++ b/Android.mk
@@ -159,13 +159,15 @@
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
+ core/java/android/print/ILayoutResultCallback.aidl \
+ core/java/android/print/IPrintDocumentAdapter.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
- core/java/android/print/IPrintAdapter.aidl \
core/java/android/print/IPrintClient.aidl \
- core/java/android/print/IPrintResultCallback.aidl \
core/java/android/print/IPrintManager.aidl \
- core/java/android/print/IPrintSpoolerService.aidl \
- core/java/android/print/IPrintSpoolerServiceCallbacks.aidl \
+ core/java/android/print/IPrintSpooler.aidl \
+ core/java/android/print/IPrintSpoolerCallbacks.aidl \
+ core/java/android/print/IPrintSpoolerClient.aidl \
+ core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 893daf1..58de3f3 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -163,6 +163,7 @@
$(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_intermediates)
$(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)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index 201dc58..e0025ea 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18448,36 +18448,6 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public abstract class PrintAdapter {
- ctor public PrintAdapter();
- method public abstract android.print.PrintAdapterInfo getInfo();
- method public void onFinish();
- method public abstract void onPrint(java.util.List<android.print.PageRange>, java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintAdapter.PrintResultCallback);
- method public boolean onPrintAttributesChanged(android.print.PrintAttributes);
- method public void onStart();
- }
-
- public static abstract class PrintAdapter.PrintResultCallback {
- method public void onPrintFailed(java.lang.CharSequence);
- method public void onPrintFinished(java.util.List<android.print.PageRange>);
- }
-
- public final class PrintAdapterInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getFlags();
- method public int getPageCount();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff
- }
-
- public static final class PrintAdapterInfo.Builder {
- ctor public PrintAdapterInfo.Builder();
- method public android.print.PrintAdapterInfo create();
- method public android.print.PrintAdapterInfo.Builder setFlags(int);
- method public android.print.PrintAdapterInfo.Builder setPageCount(int);
- }
-
public final class PrintAttributes implements android.os.Parcelable {
method public void clear();
method public int describeContents();
@@ -18528,54 +18498,55 @@
}
public static final class PrintAttributes.MediaSize {
- ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.String, int, int, int);
+ ctor public PrintAttributes.MediaSize(java.lang.String, java.lang.CharSequence, int, int);
+ method public static android.print.PrintAttributes.MediaSize createMediaSize(android.content.pm.PackageManager, int);
method public int getHeightMils();
method public java.lang.String getId();
- method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
+ method public java.lang.CharSequence getLabel();
method public int getWidthMils();
- field public static final android.print.PrintAttributes.MediaSize ISO_A0;
- field public static final android.print.PrintAttributes.MediaSize ISO_A1;
- field public static final android.print.PrintAttributes.MediaSize ISO_A10;
- field public static final android.print.PrintAttributes.MediaSize ISO_A2;
- field public static final android.print.PrintAttributes.MediaSize ISO_A3;
- field public static final android.print.PrintAttributes.MediaSize ISO_A4;
- field public static final android.print.PrintAttributes.MediaSize ISO_A5;
- field public static final android.print.PrintAttributes.MediaSize ISO_A6;
- field public static final android.print.PrintAttributes.MediaSize ISO_A7;
- field public static final android.print.PrintAttributes.MediaSize ISO_A8;
- field public static final android.print.PrintAttributes.MediaSize ISO_A9;
- field public static final android.print.PrintAttributes.MediaSize ISO_B0;
- field public static final android.print.PrintAttributes.MediaSize ISO_B1;
- field public static final android.print.PrintAttributes.MediaSize ISO_B10;
- field public static final android.print.PrintAttributes.MediaSize ISO_B2;
- field public static final android.print.PrintAttributes.MediaSize ISO_B3;
- field public static final android.print.PrintAttributes.MediaSize ISO_B4;
- field public static final android.print.PrintAttributes.MediaSize ISO_B5;
- field public static final android.print.PrintAttributes.MediaSize ISO_B6;
- field public static final android.print.PrintAttributes.MediaSize ISO_B7;
- field public static final android.print.PrintAttributes.MediaSize ISO_B8;
- field public static final android.print.PrintAttributes.MediaSize ISO_B9;
- field public static final android.print.PrintAttributes.MediaSize ISO_C0;
- field public static final android.print.PrintAttributes.MediaSize ISO_C1;
- field public static final android.print.PrintAttributes.MediaSize ISO_C10;
- field public static final android.print.PrintAttributes.MediaSize ISO_C2;
- field public static final android.print.PrintAttributes.MediaSize ISO_C3;
- field public static final android.print.PrintAttributes.MediaSize ISO_C4;
- field public static final android.print.PrintAttributes.MediaSize ISO_C5;
- field public static final android.print.PrintAttributes.MediaSize ISO_C6;
- field public static final android.print.PrintAttributes.MediaSize ISO_C7;
- field public static final android.print.PrintAttributes.MediaSize ISO_C8;
- field public static final android.print.PrintAttributes.MediaSize ISO_C9;
- field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
- field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
- field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
- field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
- field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
- field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+ field public static final int ISO_A0 = 1; // 0x1
+ field public static final int ISO_A1 = 2; // 0x2
+ field public static final int ISO_A10 = 11; // 0xb
+ field public static final int ISO_A2 = 3; // 0x3
+ field public static final int ISO_A3 = 4; // 0x4
+ field public static final int ISO_A4 = 5; // 0x5
+ field public static final int ISO_A5 = 6; // 0x6
+ field public static final int ISO_A6 = 7; // 0x7
+ field public static final int ISO_A7 = 8; // 0x8
+ field public static final int ISO_A8 = 9; // 0x9
+ field public static final int ISO_A9 = 10; // 0xa
+ field public static final int ISO_B0 = 100; // 0x64
+ field public static final int ISO_B1 = 101; // 0x65
+ field public static final int ISO_B10 = 110; // 0x6e
+ field public static final int ISO_B2 = 102; // 0x66
+ field public static final int ISO_B3 = 103; // 0x67
+ field public static final int ISO_B4 = 104; // 0x68
+ field public static final int ISO_B5 = 105; // 0x69
+ field public static final int ISO_B6 = 106; // 0x6a
+ field public static final int ISO_B7 = 107; // 0x6b
+ field public static final int ISO_B8 = 108; // 0x6c
+ field public static final int ISO_B9 = 109; // 0x6d
+ field public static final int ISO_C0 = 200; // 0xc8
+ field public static final int ISO_C1 = 201; // 0xc9
+ field public static final int ISO_C10 = 210; // 0xd2
+ field public static final int ISO_C2 = 202; // 0xca
+ field public static final int ISO_C3 = 203; // 0xcb
+ field public static final int ISO_C4 = 204; // 0xcc
+ field public static final int ISO_C5 = 205; // 0xcd
+ field public static final int ISO_C6 = 206; // 0xce
+ field public static final int ISO_C7 = 207; // 0xcf
+ field public static final int ISO_C8 = 208; // 0xd0
+ field public static final int ISO_C9 = 209; // 0xd1
+ field public static final int NA_GOVT_LETTER = 301; // 0x12d
+ field public static final int NA_JUNIOR_LEGAL = 303; // 0x12f
+ field public static final int NA_LEDGER = 304; // 0x130
+ field public static final int NA_LEGAL = 302; // 0x12e
+ field public static final int NA_LETTER = 300; // 0x12c
+ field public static final int NA_TBLOID = 305; // 0x131
}
public static final class PrintAttributes.Resolution {
- ctor public PrintAttributes.Resolution(java.lang.String, java.lang.String, int, int, int);
+ ctor public PrintAttributes.Resolution(java.lang.String, java.lang.CharSequence, int, int);
method public int getHorizontalDpi();
method public java.lang.String getId();
method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
@@ -18583,11 +18554,48 @@
}
public static final class PrintAttributes.Tray {
- ctor public PrintAttributes.Tray(java.lang.String, java.lang.String, int);
+ ctor public PrintAttributes.Tray(java.lang.String, java.lang.CharSequence);
method public java.lang.String getId();
method public java.lang.CharSequence getLabel(android.content.pm.PackageManager);
}
+ public abstract class PrintDocumentAdapter {
+ ctor public PrintDocumentAdapter();
+ method public void onFinish();
+ method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback);
+ 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);
+ }
+
+ public static abstract class PrintDocumentAdapter.LayoutResultCallback {
+ method public void onLayoutFailed(java.lang.CharSequence);
+ method public void onLayoutFinished(android.print.PrintDocumentInfo, boolean);
+ }
+
+ public static abstract class PrintDocumentAdapter.WriteResultCallback {
+ method public void onWriteFailed(java.lang.CharSequence);
+ method public void onWriteFinished(java.util.List<android.print.PageRange>);
+ }
+
+ public final class PrintDocumentInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getContentType();
+ method public int getPageCount();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0
+ field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1
+ field public static final int CONTENT_TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public static final class PrintDocumentInfo.Builder {
+ ctor public PrintDocumentInfo.Builder();
+ method public android.print.PrintDocumentInfo create();
+ method public android.print.PrintDocumentInfo.Builder setContentType(int);
+ method public android.print.PrintDocumentInfo.Builder setPageCount(int);
+ }
+
public final class PrintJob {
method public void cancel();
method public int getId();
@@ -18617,7 +18625,7 @@
public final class PrintManager {
method public java.util.List<android.print.PrintJob> getPrintJobs();
method public android.print.PrintJob print(java.lang.String, java.io.File, android.print.PrintAttributes);
- method public android.print.PrintJob print(java.lang.String, android.print.PrintAdapter, android.print.PrintAttributes);
+ method public android.print.PrintJob print(java.lang.String, android.print.PrintDocumentAdapter, android.print.PrintAttributes);
}
public final class PrinterId implements android.os.Parcelable {
@@ -18699,11 +18707,16 @@
package android.printservice {
+ public final class PrintDocument {
+ method public java.io.FileDescriptor getData();
+ method public android.print.PrintDocumentInfo getInfo();
+ }
+
public final class PrintJob {
method public boolean cancel();
method public boolean complete();
method public boolean fail(java.lang.CharSequence);
- method public final java.io.FileDescriptor getData();
+ method public android.printservice.PrintDocument getDocument();
method public int getId();
method public android.print.PrintJobInfo getInfo();
method public boolean isQueued();
@@ -27034,6 +27047,7 @@
field protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET;
field protected static final int[] PRESSED_SELECTED_STATE_SET;
field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET;
+ field protected static final int[] PRESSED_STATE_SET;
field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET;
field public static final android.util.Property ROTATION;
field public static final android.util.Property ROTATION_X;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c79768e..4e6c3dc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -234,32 +234,49 @@
/** @hide Process is a persistent system process and is doing UI. */
public static final int PROCESS_STATE_PERSISTENT_UI = 1;
- /** @hide Process is hosting the current top activity. */
+ /** @hide Process is hosting the current top activities. Note that this covers
+ * all activities that are visible to the user. */
public static final int PROCESS_STATE_TOP = 2;
/** @hide Process is important to the user, and something they are aware of. */
- public static final int PROCESS_STATE_IMPORTANT_PERCEPTIBLE = 3;
+ public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
- /** @hide Process is in the background running a receiver. */
- public static final int PROCESS_STATE_RECEIVER = 5;
-
/** @hide Process is in the background running a backup/restore operation. */
- public static final int PROCESS_STATE_BACKUP = 6;
+ public static final int PROCESS_STATE_BACKUP = 5;
- /** @hide Process is in the background running a service. */
+ /** @hide Process is in the background, but it can't restore its state so we want
+ * to try to avoid killing it. */
+ public static final int PROCESS_STATE_HEAVY_WEIGHT = 6;
+
+ /** @hide Process is in the background running a service. Unlike oom_adj, this level
+ * is used for both the normal running in background state and the executing
+ * operations state. */
public static final int PROCESS_STATE_SERVICE = 7;
+ /** @hide Process is in the background running a receiver. Note that from the
+ * perspective of oom_adj receivers run at a higher foreground level, but for our
+ * prioritization here that is not necessary and putting them below services means
+ * many fewer changes in some process states as they receive broadcasts. */
+ public static final int PROCESS_STATE_RECEIVER = 8;
+
/** @hide Process is in the background but hosts the home activity. */
- public static final int PROCESS_STATE_HOME = 8;
+ public static final int PROCESS_STATE_HOME = 9;
/** @hide Process is in the background but hosts the last shown activity. */
- public static final int PROCESS_STATE_LAST_ACTIVITY = 9;
+ public static final int PROCESS_STATE_LAST_ACTIVITY = 10;
- /** @hide Process is being cached for later use. */
- public static final int PROCESS_STATE_CACHED = 10;
+ /** @hide Process is being cached for later use and contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY = 11;
+
+ /** @hide Process is being cached for later use and is a client of another cached
+ * process that contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12;
+
+ /** @hide Process is being cached for later use and is empty. */
+ public static final int PROCESS_STATE_CACHED_EMPTY = 13;
/*package*/ ActivityManager(Context context, Handler handler) {
mContext = context;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c3d1971..aa326ad 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -230,7 +230,15 @@
* tries to balance such requests from one app vs. the importantance of
* keeping other apps around.
*/
- public static final int BIND_VISIBLE = 0x0100;
+ public static final int BIND_VISIBLE = 0x10000000;
+
+ /**
+ * @hide
+ * Flag for {@link #bindService}: Consider this binding to be causing the target
+ * process to be showing UI, so it will be do a UI_HIDDEN memory trim when it goes
+ * away.
+ */
+ public static final int BIND_SHOWING_UI = 0x20000000;
/**
* Flag for {@link #bindService}: Don't consider the bound service to be
diff --git a/core/java/android/hardware/photography/CameraPropertiesKeys.java b/core/java/android/hardware/photography/CameraPropertiesKeys.java
index 7e6380e..f511ae7 100644
--- a/core/java/android/hardware/photography/CameraPropertiesKeys.java
+++ b/core/java/android/hardware/photography/CameraPropertiesKeys.java
@@ -39,11 +39,8 @@
**/
public final class CameraPropertiesKeys {
public static final class Control {
-
public static final Key<byte[]> AE_AVAILABLE_ANTIBANDING_MODES =
new Key<byte[]>("android.control.aeAvailableAntibandingModes", byte[].class);
- public static final Key<byte[]> AE_AVAILABLE_MODES =
- new Key<byte[]>("android.control.aeAvailableModes", byte[].class);
public static final Key<int[]> AE_AVAILABLE_TARGET_FPS_RANGES =
new Key<int[]>("android.control.aeAvailableTargetFpsRanges", int[].class);
public static final Key<int[]> AE_COMPENSATION_RANGE =
@@ -62,40 +59,23 @@
new Key<byte[]>("android.control.awbAvailableModes", byte[].class);
public static final Key<Integer> MAX_REGIONS =
new Key<Integer>("android.control.maxRegions", int.class);
- public static final Key<byte[]> SCENE_MODE_OVERRIDES =
- new Key<byte[]>("android.control.sceneModeOverrides", byte[].class);
}
+
public static final class Flash {
public static final class Info {
public static final Key<Byte> AVAILABLE =
new Key<Byte>("android.flash.info.available", byte.class);
- public static final Key<Long> CHARGE_DURATION =
- new Key<Long>("android.flash.info.chargeDuration", long.class);
}
- public static final Key<Byte> COLOR_TEMPERATURE =
- new Key<Byte>("android.flash.colorTemperature", byte.class);
- public static final Key<Byte> MAX_ENERGY =
- new Key<Byte>("android.flash.maxEnergy", byte.class);
-
}
- public static final class HotPixel {
- public static final class Info {
- public static final Key<int[]> MAP =
- new Key<int[]>("android.hotPixel.info.map", int[].class);
- }
-
- }
public static final class Jpeg {
-
public static final Key<int[]> AVAILABLE_THUMBNAIL_SIZES =
new Key<int[]>("android.jpeg.availableThumbnailSizes", int[].class);
- public static final Key<Integer> MAX_SIZE =
- new Key<Integer>("android.jpeg.maxSize", int.class);
}
+
public static final class Lens {
public static final class Info {
public static final Key<float[]> AVAILABLE_APERTURES =
@@ -106,21 +86,14 @@
new Key<float[]>("android.lens.info.availableFocalLengths", float[].class);
public static final Key<byte[]> AVAILABLE_OPTICAL_STABILIZATION =
new Key<byte[]>("android.lens.info.availableOpticalStabilization", byte[].class);
- public static final Key<float[]> GEOMETRIC_CORRECTION_MAP =
- new Key<float[]>("android.lens.info.geometricCorrectionMap", float[].class);
- public static final Key<int[]> GEOMETRIC_CORRECTION_MAP_SIZE =
- new Key<int[]>("android.lens.info.geometricCorrectionMapSize", int[].class);
public static final Key<Float> HYPERFOCAL_DISTANCE =
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<float[]> SHADING_MAP =
- new Key<float[]>("android.lens.info.shadingMap", float[].class);
public static final Key<int[]> SHADING_MAP_SIZE =
new Key<int[]>("android.lens.info.shadingMapSize", int[].class);
}
-
public static final class FacingKey extends Key<Lens.FacingKey.Enum> {
public enum Enum {
FRONT,
@@ -139,32 +112,16 @@
public static final Key<Lens.FacingKey.Enum> FACING =
new FacingKey("android.lens.facing");
- public static final Key<float[]> OPTICAL_AXIS_ANGLE =
- new Key<float[]>("android.lens.opticalAxisAngle", float[].class);
- public static final Key<float[]> POSITION =
- new Key<float[]>("android.lens.position", float[].class);
}
- public static final class Quirks {
- public static final Key<Byte> METERING_CROP_REGION =
- new Key<Byte>("android.quirks.meteringCropRegion", byte.class);
- public static final Key<Byte> TRIGGER_AF_WITH_AUTO =
- new Key<Byte>("android.quirks.triggerAfWithAuto", byte.class);
- public static final Key<Byte> USE_ZSL_FORMAT =
- new Key<Byte>("android.quirks.useZslFormat", byte.class);
-
- }
public static final class Request {
-
public static final Key<int[]> MAX_NUM_OUTPUT_STREAMS =
new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
- public static final Key<int[]> MAX_NUM_REPROCESS_STREAMS =
- new Key<int[]>("android.request.maxNumReprocessStreams", int[].class);
}
- public static final class Scaler {
+ public static final class Scaler {
public static final class AvailableFormatsKey extends Key<Scaler.AvailableFormatsKey.Enum[]> {
public enum Enum {
@@ -212,184 +169,55 @@
new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
public static final Key<int[]> AVAILABLE_PROCESSED_SIZES =
new Key<int[]>("android.scaler.availableProcessedSizes", int[].class);
- public static final Key<long[]> AVAILABLE_RAW_MIN_DURATIONS =
- new Key<long[]>("android.scaler.availableRawMinDurations", long[].class);
- public static final Key<int[]> AVAILABLE_RAW_SIZES =
- new Key<int[]>("android.scaler.availableRawSizes", int[].class);
}
+
public static final class Sensor {
public static final class Info {
public static final Key<int[]> ACTIVE_ARRAY_SIZE =
new Key<int[]>("android.sensor.info.activeArraySize", int[].class);
public static final Key<int[]> AVAILABLE_SENSITIVITIES =
new Key<int[]>("android.sensor.info.availableSensitivities", int[].class);
-
- public static final class ColorFilterArrangementKey extends Key<Sensor.Info.ColorFilterArrangementKey.Enum> {
- public enum Enum {
- RGGB,
- GRBG,
- GBRG,
- BGGR,
- RGB;
- }
-
- public static final Enum RGGB = Enum.RGGB;
- public static final Enum GRBG = Enum.GRBG;
- public static final Enum GBRG = Enum.GBRG;
- public static final Enum BGGR = Enum.BGGR;
- public static final Enum RGB = Enum.RGB;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ColorFilterArrangementKey(String name) {
- super(name, Sensor.Info.ColorFilterArrangementKey.Enum.class);
- }
-
- }
-
- public static final Key<Sensor.Info.ColorFilterArrangementKey.Enum> COLOR_FILTER_ARRANGEMENT =
- new ColorFilterArrangementKey("android.sensor.info.colorFilterArrangement");
public static final Key<long[]> EXPOSURE_TIME_RANGE =
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<float[]> PHYSICAL_SIZE =
new Key<float[]>("android.sensor.info.physicalSize", float[].class);
- public static final Key<int[]> PIXEL_ARRAY_SIZE =
- new Key<int[]>("android.sensor.info.pixelArraySize", int[].class);
- public static final Key<Integer> WHITE_LEVEL =
- new Key<Integer>("android.sensor.info.whiteLevel", int.class);
}
-
public static final Key<Rational> BASE_GAIN_FACTOR =
new Key<Rational>("android.sensor.baseGainFactor", Rational.class);
- public static final Key<int[]> BLACK_LEVEL_PATTERN =
- new Key<int[]>("android.sensor.blackLevelPattern", int[].class);
- public static final Key<Rational[]> CALIBRATION_TRANSFORM1 =
- new Key<Rational[]>("android.sensor.calibrationTransform1", Rational[].class);
- public static final Key<Rational[]> CALIBRATION_TRANSFORM2 =
- new Key<Rational[]>("android.sensor.calibrationTransform2", Rational[].class);
- public static final Key<Rational[]> COLOR_TRANSFORM1 =
- new Key<Rational[]>("android.sensor.colorTransform1", Rational[].class);
- public static final Key<Rational[]> COLOR_TRANSFORM2 =
- new Key<Rational[]>("android.sensor.colorTransform2", Rational[].class);
- public static final Key<Rational[]> FORWARD_MATRIX1 =
- new Key<Rational[]>("android.sensor.forwardMatrix1", Rational[].class);
- public static final Key<Rational[]> FORWARD_MATRIX2 =
- new Key<Rational[]>("android.sensor.forwardMatrix2", Rational[].class);
public static final Key<Integer> MAX_ANALOG_SENSITIVITY =
new Key<Integer>("android.sensor.maxAnalogSensitivity", int.class);
- public static final Key<float[]> NOISE_MODEL_COEFFICIENTS =
- new Key<float[]>("android.sensor.noiseModelCoefficients", float[].class);
public static final Key<Integer> ORIENTATION =
new Key<Integer>("android.sensor.orientation", int.class);
- public static final class ReferenceIlluminant1Key extends Key<Sensor.ReferenceIlluminant1Key.Enum> {
- public enum Enum {
- DAYLIGHT,
- FLUORESCENT,
- TUNGSTEN,
- FLASH,
- FINE_WEATHER,
- CLOUDY_WEATHER,
- SHADE,
- DAYLIGHT_FLUORESCENT,
- DAY_WHITE_FLUORESCENT,
- COOL_WHITE_FLUORESCENT,
- WHITE_FLUORESCENT,
- STANDARD_A,
- STANDARD_B,
- STANDARD_C,
- D55,
- D65,
- D75,
- D50,
- ISO_STUDIO_TUNGSTEN;
- }
-
- public static final Enum DAYLIGHT = Enum.DAYLIGHT;
- public static final Enum FLUORESCENT = Enum.FLUORESCENT;
- public static final Enum TUNGSTEN = Enum.TUNGSTEN;
- public static final Enum FLASH = Enum.FLASH;
- public static final Enum FINE_WEATHER = Enum.FINE_WEATHER;
- public static final Enum CLOUDY_WEATHER = Enum.CLOUDY_WEATHER;
- public static final Enum SHADE = Enum.SHADE;
- public static final Enum DAYLIGHT_FLUORESCENT = Enum.DAYLIGHT_FLUORESCENT;
- public static final Enum DAY_WHITE_FLUORESCENT = Enum.DAY_WHITE_FLUORESCENT;
- public static final Enum COOL_WHITE_FLUORESCENT = Enum.COOL_WHITE_FLUORESCENT;
- public static final Enum WHITE_FLUORESCENT = Enum.WHITE_FLUORESCENT;
- public static final Enum STANDARD_A = Enum.STANDARD_A;
- public static final Enum STANDARD_B = Enum.STANDARD_B;
- public static final Enum STANDARD_C = Enum.STANDARD_C;
- public static final Enum D55 = Enum.D55;
- public static final Enum D65 = Enum.D65;
- public static final Enum D75 = Enum.D75;
- public static final Enum D50 = Enum.D50;
- public static final Enum ISO_STUDIO_TUNGSTEN = Enum.ISO_STUDIO_TUNGSTEN;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ReferenceIlluminant1Key(String name) {
- super(name, Sensor.ReferenceIlluminant1Key.Enum.class);
- }
-
- static {
- CameraMetadata.registerEnumValues(Sensor.ReferenceIlluminant1Key.Enum.class, new int[] {
- 1, // DAYLIGHT
- 2, // FLUORESCENT
- 3, // TUNGSTEN
- 4, // FLASH
- 9, // FINE_WEATHER
- 10, // CLOUDY_WEATHER
- 11, // SHADE
- 12, // DAYLIGHT_FLUORESCENT
- 13, // DAY_WHITE_FLUORESCENT
- 14, // COOL_WHITE_FLUORESCENT
- 15, // WHITE_FLUORESCENT
- 17, // STANDARD_A
- 18, // STANDARD_B
- 19, // STANDARD_C
- 20, // D55
- 21, // D65
- 22, // D75
- 23, // D50
- 24 // ISO_STUDIO_TUNGSTEN
- });
- }
- }
-
- public static final Key<Sensor.ReferenceIlluminant1Key.Enum> REFERENCE_ILLUMINANT1 =
- new ReferenceIlluminant1Key("android.sensor.referenceIlluminant1");
- public static final Key<Byte> REFERENCE_ILLUMINANT2 =
- new Key<Byte>("android.sensor.referenceIlluminant2", byte.class);
-
}
+
public static final class Statistics {
public static final class Info {
public static final Key<byte[]> AVAILABLE_FACE_DETECT_MODES =
new Key<byte[]>("android.statistics.info.availableFaceDetectModes", byte[].class);
- public static final Key<Integer> HISTOGRAM_BUCKET_COUNT =
- new Key<Integer>("android.statistics.info.histogramBucketCount", int.class);
public static final Key<Integer> MAX_FACE_COUNT =
new Key<Integer>("android.statistics.info.maxFaceCount", int.class);
- public static final Key<Integer> MAX_HISTOGRAM_COUNT =
- new Key<Integer>("android.statistics.info.maxHistogramCount", int.class);
- public static final Key<Integer> MAX_SHARPNESS_MAP_VALUE =
- new Key<Integer>("android.statistics.info.maxSharpnessMapValue", int.class);
- public static final Key<int[]> SHARPNESS_MAP_SIZE =
- new Key<int[]>("android.statistics.info.sharpnessMapSize", int[].class);
}
-
}
- public static final class Tonemap {
+ public static final class Tonemap {
public static final Key<Integer> MAX_CURVE_POINTS =
new Key<Integer>("android.tonemap.maxCurvePoints", int.class);
}
+
+ /**
+ * @hide
+ */
public static final class Led {
-
+ /**
+ * @hide
+ */
public static final class AvailableLedsKey extends Key<Led.AvailableLedsKey.Enum[]> {
public enum Enum {
TRANSMIT;
@@ -404,12 +232,15 @@
}
+ /**
+ * @hide
+ */
public static final Key<Led.AvailableLedsKey.Enum[]> AVAILABLE_LEDS =
new AvailableLedsKey("android.led.availableLeds");
}
- public static final class Info {
+ public static final class Info {
public static final class SupportedHardwareLevelKey extends Key<Info.SupportedHardwareLevelKey.Enum> {
public enum Enum {
@@ -431,6 +262,7 @@
new SupportedHardwareLevelKey("android.info.supportedHardwareLevel");
}
+
}
diff --git a/core/java/android/hardware/photography/CaptureRequestKeys.java b/core/java/android/hardware/photography/CaptureRequestKeys.java
index b8abe2b..b23e71d 100644
--- a/core/java/android/hardware/photography/CaptureRequestKeys.java
+++ b/core/java/android/hardware/photography/CaptureRequestKeys.java
@@ -40,7 +40,6 @@
public final class CaptureRequestKeys {
public static final class ColorCorrection {
-
public static final class ModeKey extends Key<ColorCorrection.ModeKey.Enum> {
public enum Enum {
TRANSFORM_MATRIX,
@@ -65,8 +64,8 @@
new Key<float[]>("android.colorCorrection.transform", float[].class);
}
- public static final class Control {
+ public static final class Control {
public static final class AeAntibandingModeKey extends Key<Control.AeAntibandingModeKey.Enum> {
public enum Enum {
@@ -435,32 +434,9 @@
new VideoStabilizationModeKey("android.control.videoStabilizationMode");
}
- public static final class Demosaic {
-
- public static final class ModeKey extends Key<Demosaic.ModeKey.Enum> {
- public enum Enum {
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, Demosaic.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Demosaic.ModeKey.Enum> MODE =
- new ModeKey("android.demosaic.mode");
-
- }
public static final class Edge {
-
public static final class ModeKey extends Key<Edge.ModeKey.Enum> {
public enum Enum {
OFF,
@@ -481,16 +457,10 @@
public static final Key<Edge.ModeKey.Enum> MODE =
new ModeKey("android.edge.mode");
- public static final Key<Byte> STRENGTH =
- new Key<Byte>("android.edge.strength", byte.class);
}
- public static final class Flash {
- public static final Key<Byte> FIRING_POWER =
- new Key<Byte>("android.flash.firingPower", byte.class);
- public static final Key<Long> FIRING_TIME =
- new Key<Long>("android.flash.firingTime", long.class);
+ public static final class Flash {
public static final class ModeKey extends Key<Flash.ModeKey.Enum> {
public enum Enum {
@@ -514,60 +484,8 @@
new ModeKey("android.flash.mode");
}
- public static final class Geometric {
-
- public static final class ModeKey extends Key<Geometric.ModeKey.Enum> {
- public enum Enum {
- OFF,
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, Geometric.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Geometric.ModeKey.Enum> MODE =
- new ModeKey("android.geometric.mode");
- public static final Key<Byte> STRENGTH =
- new Key<Byte>("android.geometric.strength", byte.class);
-
- }
- public static final class HotPixel {
-
-
- public static final class ModeKey extends Key<HotPixel.ModeKey.Enum> {
- public enum Enum {
- OFF,
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, HotPixel.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<HotPixel.ModeKey.Enum> MODE =
- new ModeKey("android.hotPixel.mode");
-
- }
public static final class Jpeg {
-
public static final Key<double[]> GPS_COORDINATES =
new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
public static final Key<Byte> GPS_PROCESSING_METHOD =
@@ -584,8 +502,8 @@
new Key<int[]>("android.jpeg.thumbnailSize", int[].class);
}
- public static final class Lens {
+ public static final class Lens {
public static final Key<Float> APERTURE =
new Key<Float>("android.lens.aperture", float.class);
public static final Key<Float> FILTER_DENSITY =
@@ -615,8 +533,8 @@
new OpticalStabilizationModeKey("android.lens.opticalStabilizationMode");
}
- public static final class NoiseReduction {
+ public static final class NoiseReduction {
public static final class ModeKey extends Key<NoiseReduction.ModeKey.Enum> {
public enum Enum {
@@ -638,68 +556,28 @@
public static final Key<NoiseReduction.ModeKey.Enum> MODE =
new ModeKey("android.noiseReduction.mode");
- public static final Key<Byte> STRENGTH =
- new Key<Byte>("android.noiseReduction.strength", byte.class);
}
- public static final class Request {
- public static final Key<Integer> FRAME_COUNT =
- new Key<Integer>("android.request.frameCount", int.class);
+ /**
+ * @hide
+ */
+ public static final class Request {
+ /**
+ * @hide
+ */
public static final Key<Integer> ID =
new Key<Integer>("android.request.id", int.class);
- public static final Key<Byte> INPUT_STREAMS =
- new Key<Byte>("android.request.inputStreams", byte.class);
-
- public static final class MetadataModeKey extends Key<Request.MetadataModeKey.Enum> {
- public enum Enum {
- NONE,
- FULL;
- }
-
- public static final Enum NONE = Enum.NONE;
- public static final Enum FULL = Enum.FULL;
-
- // TODO: remove requirement for constructor by making Key an interface
- private MetadataModeKey(String name) {
- super(name, Request.MetadataModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Request.MetadataModeKey.Enum> METADATA_MODE =
- new MetadataModeKey("android.request.metadataMode");
- public static final Key<Byte> OUTPUT_STREAMS =
- new Key<Byte>("android.request.outputStreams", byte.class);
-
- public static final class TypeKey extends Key<Request.TypeKey.Enum> {
- public enum Enum {
- CAPTURE,
- REPROCESS;
- }
-
- public static final Enum CAPTURE = Enum.CAPTURE;
- public static final Enum REPROCESS = Enum.REPROCESS;
-
- // TODO: remove requirement for constructor by making Key an interface
- private TypeKey(String name) {
- super(name, Request.TypeKey.Enum.class);
- }
-
- }
-
- public static final Key<Request.TypeKey.Enum> TYPE =
- new TypeKey("android.request.type");
}
- public static final class Scaler {
+ public static final class Scaler {
public static final Key<int[]> CROP_REGION =
new Key<int[]>("android.scaler.cropRegion", int[].class);
}
- public static final class Sensor {
+ public static final class Sensor {
public static final Key<Long> EXPOSURE_TIME =
new Key<Long>("android.sensor.exposureTime", long.class);
public static final Key<Long> FRAME_DURATION =
@@ -708,36 +586,9 @@
new Key<Integer>("android.sensor.sensitivity", int.class);
}
- public static final class Shading {
-
- public static final class ModeKey extends Key<Shading.ModeKey.Enum> {
- public enum Enum {
- OFF,
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, Shading.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Shading.ModeKey.Enum> MODE =
- new ModeKey("android.shading.mode");
- public static final Key<Byte> STRENGTH =
- new Key<Byte>("android.shading.strength", byte.class);
-
- }
public static final class Statistics {
-
public static final class FaceDetectModeKey extends Key<Statistics.FaceDetectModeKey.Enum> {
public enum Enum {
OFF,
@@ -759,47 +610,9 @@
public static final Key<Statistics.FaceDetectModeKey.Enum> FACE_DETECT_MODE =
new FaceDetectModeKey("android.statistics.faceDetectMode");
- public static final class HistogramModeKey extends Key<Statistics.HistogramModeKey.Enum> {
- public enum Enum {
- OFF,
- ON;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum ON = Enum.ON;
-
- // TODO: remove requirement for constructor by making Key an interface
- private HistogramModeKey(String name) {
- super(name, Statistics.HistogramModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Statistics.HistogramModeKey.Enum> HISTOGRAM_MODE =
- new HistogramModeKey("android.statistics.histogramMode");
-
- public static final class SharpnessMapModeKey extends Key<Statistics.SharpnessMapModeKey.Enum> {
- public enum Enum {
- OFF,
- ON;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum ON = Enum.ON;
-
- // TODO: remove requirement for constructor by making Key an interface
- private SharpnessMapModeKey(String name) {
- super(name, Statistics.SharpnessMapModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Statistics.SharpnessMapModeKey.Enum> SHARPNESS_MAP_MODE =
- new SharpnessMapModeKey("android.statistics.sharpnessMapMode");
-
}
- public static final class Tonemap {
+ public static final class Tonemap {
public static final Key<Float> CURVE_BLUE =
new Key<Float>("android.tonemap.curveBlue", float.class);
public static final Key<Float> CURVE_GREEN =
@@ -829,9 +642,15 @@
new ModeKey("android.tonemap.mode");
}
+
+ /**
+ * @hide
+ */
public static final class Led {
-
+ /**
+ * @hide
+ */
public static final class TransmitKey extends Key<Led.TransmitKey.Enum> {
public enum Enum {
OFF,
@@ -848,10 +667,14 @@
}
+ /**
+ * @hide
+ */
public static final Key<Led.TransmitKey.Enum> TRANSMIT =
new TransmitKey("android.led.transmit");
}
+
}
diff --git a/core/java/android/hardware/photography/CaptureResultKeys.java b/core/java/android/hardware/photography/CaptureResultKeys.java
index 5a638ed..e44fc91 100644
--- a/core/java/android/hardware/photography/CaptureResultKeys.java
+++ b/core/java/android/hardware/photography/CaptureResultKeys.java
@@ -40,7 +40,6 @@
public final class CaptureResultKeys {
public static final class ColorCorrection {
-
public static final class ModeKey extends Key<ColorCorrection.ModeKey.Enum> {
public enum Enum {
TRANSFORM_MATRIX,
@@ -63,8 +62,11 @@
new ModeKey("android.colorCorrection.mode");
}
- public static final class Control {
+ public static final class Control {
+ /**
+ * @hide
+ */
public static final Key<Integer> AE_PRECAPTURE_ID =
new Key<Integer>("android.control.aePrecaptureId", int.class);
public static final Key<int[]> AE_REGIONS =
@@ -152,6 +154,9 @@
public static final Key<Control.AfStateKey.Enum> AF_STATE =
new AfStateKey("android.control.afState");
+ /**
+ * @hide
+ */
public static final Key<Integer> AF_TRIGGER_ID =
new Key<Integer>("android.control.afTriggerId", int.class);
@@ -235,8 +240,8 @@
new ModeKey("android.control.mode");
}
- public static final class Edge {
+ public static final class Edge {
public static final class ModeKey extends Key<Edge.ModeKey.Enum> {
public enum Enum {
@@ -260,12 +265,8 @@
new ModeKey("android.edge.mode");
}
- public static final class Flash {
- public static final Key<Byte> FIRING_POWER =
- new Key<Byte>("android.flash.firingPower", byte.class);
- public static final Key<Long> FIRING_TIME =
- new Key<Long>("android.flash.firingTime", long.class);
+ public static final class Flash {
public static final class ModeKey extends Key<Flash.ModeKey.Enum> {
public enum Enum {
@@ -312,33 +313,8 @@
new StateKey("android.flash.state");
}
- public static final class HotPixel {
-
- public static final class ModeKey extends Key<HotPixel.ModeKey.Enum> {
- public enum Enum {
- OFF,
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, HotPixel.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<HotPixel.ModeKey.Enum> MODE =
- new ModeKey("android.hotPixel.mode");
-
- }
public static final class Jpeg {
-
public static final Key<double[]> GPS_COORDINATES =
new Key<double[]>("android.jpeg.gpsCoordinates", double[].class);
public static final Key<Byte> GPS_PROCESSING_METHOD =
@@ -349,16 +325,14 @@
new Key<Integer>("android.jpeg.orientation", int.class);
public static final Key<Byte> QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
- public static final Key<Integer> SIZE =
- new Key<Integer>("android.jpeg.size", int.class);
public static final Key<Byte> THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
public static final Key<int[]> THUMBNAIL_SIZE =
new Key<int[]>("android.jpeg.thumbnailSize", int[].class);
}
- public static final class Lens {
+ public static final class Lens {
public static final Key<Float> APERTURE =
new Key<Float>("android.lens.aperture", float.class);
public static final Key<Float> FILTER_DENSITY =
@@ -407,8 +381,8 @@
new StateKey("android.lens.state");
}
- public static final class NoiseReduction {
+ public static final class NoiseReduction {
public static final class ModeKey extends Key<NoiseReduction.ModeKey.Enum> {
public enum Enum {
@@ -432,43 +406,25 @@
new ModeKey("android.noiseReduction.mode");
}
- public static final class Request {
+ public static final class Request {
public static final Key<Integer> FRAME_COUNT =
new Key<Integer>("android.request.frameCount", int.class);
+ /**
+ * @hide
+ */
public static final Key<Integer> ID =
new Key<Integer>("android.request.id", int.class);
- public static final class MetadataModeKey extends Key<Request.MetadataModeKey.Enum> {
- public enum Enum {
- NONE,
- FULL;
- }
-
- public static final Enum NONE = Enum.NONE;
- public static final Enum FULL = Enum.FULL;
-
- // TODO: remove requirement for constructor by making Key an interface
- private MetadataModeKey(String name) {
- super(name, Request.MetadataModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Request.MetadataModeKey.Enum> METADATA_MODE =
- new MetadataModeKey("android.request.metadataMode");
- public static final Key<Byte> OUTPUT_STREAMS =
- new Key<Byte>("android.request.outputStreams", byte.class);
-
}
- public static final class Scaler {
+ public static final class Scaler {
public static final Key<int[]> CROP_REGION =
new Key<int[]>("android.scaler.cropRegion", int[].class);
}
- public static final class Sensor {
+ public static final class Sensor {
public static final Key<Long> EXPOSURE_TIME =
new Key<Long>("android.sensor.exposureTime", long.class);
public static final Key<Long> FRAME_DURATION =
@@ -479,34 +435,9 @@
new Key<Long>("android.sensor.timestamp", long.class);
}
- public static final class Shading {
-
- public static final class ModeKey extends Key<Shading.ModeKey.Enum> {
- public enum Enum {
- OFF,
- FAST,
- HIGH_QUALITY;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum FAST = Enum.FAST;
- public static final Enum HIGH_QUALITY = Enum.HIGH_QUALITY;
-
- // TODO: remove requirement for constructor by making Key an interface
- private ModeKey(String name) {
- super(name, Shading.ModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Shading.ModeKey.Enum> MODE =
- new ModeKey("android.shading.mode");
-
- }
public static final class Statistics {
-
public static final class FaceDetectModeKey extends Key<Statistics.FaceDetectModeKey.Enum> {
public enum Enum {
OFF,
@@ -535,52 +466,10 @@
new Key<int[]>("android.statistics.faceRectangles", int[].class);
public static final Key<byte[]> FACE_SCORES =
new Key<byte[]>("android.statistics.faceScores", byte[].class);
- public static final Key<int[]> HISTOGRAM =
- new Key<int[]>("android.statistics.histogram", int[].class);
-
- public static final class HistogramModeKey extends Key<Statistics.HistogramModeKey.Enum> {
- public enum Enum {
- OFF,
- ON;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum ON = Enum.ON;
-
- // TODO: remove requirement for constructor by making Key an interface
- private HistogramModeKey(String name) {
- super(name, Statistics.HistogramModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Statistics.HistogramModeKey.Enum> HISTOGRAM_MODE =
- new HistogramModeKey("android.statistics.histogramMode");
- public static final Key<int[]> SHARPNESS_MAP =
- new Key<int[]>("android.statistics.sharpnessMap", int[].class);
-
- public static final class SharpnessMapModeKey extends Key<Statistics.SharpnessMapModeKey.Enum> {
- public enum Enum {
- OFF,
- ON;
- }
-
- public static final Enum OFF = Enum.OFF;
- public static final Enum ON = Enum.ON;
-
- // TODO: remove requirement for constructor by making Key an interface
- private SharpnessMapModeKey(String name) {
- super(name, Statistics.SharpnessMapModeKey.Enum.class);
- }
-
- }
-
- public static final Key<Statistics.SharpnessMapModeKey.Enum> SHARPNESS_MAP_MODE =
- new SharpnessMapModeKey("android.statistics.sharpnessMapMode");
}
- public static final class Tonemap {
+ public static final class Tonemap {
public static final Key<Float> CURVE_BLUE =
new Key<Float>("android.tonemap.curveBlue", float.class);
public static final Key<Float> CURVE_GREEN =
@@ -610,9 +499,15 @@
new ModeKey("android.tonemap.mode");
}
+
+ /**
+ * @hide
+ */
public static final class Led {
-
+ /**
+ * @hide
+ */
public static final class TransmitKey extends Key<Led.TransmitKey.Enum> {
public enum Enum {
OFF,
@@ -629,10 +524,14 @@
}
+ /**
+ * @hide
+ */
public static final Key<Led.TransmitKey.Enum> TRANSMIT =
new TransmitKey("android.led.transmit");
}
+
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index c5f473e..0a6db25 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -192,6 +192,14 @@
return dalvikPss + nativePss + otherPss;
}
+ /**
+ * @hide Return total PSS memory usage in kB.
+ */
+ public int getTotalUss() {
+ return dalvikPrivateClean + dalvikPrivateDirty
+ + nativePrivateClean + nativePrivateDirty
+ + otherPrivateClean + otherPrivateDirty;
+ }
/**
* Return total PSS memory usage in kB.
@@ -1001,9 +1009,10 @@
/**
* Retrieves the PSS memory used by the process as given by the
- * smaps. @hide
+ * smaps. Optionally supply a long array of 1 entry to also
+ * receive the uss of the process. @hide
*/
- public static native long getPss(int pid);
+ public static native long getPss(int pid, long[] outUss);
/**
* Establish an object allocation limit in the current thread.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 159d3eb..1d482dc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -894,6 +894,19 @@
public static final native boolean setOomAdj(int pid, int amt);
/**
+ * Adjust the swappiness level for a process.
+ *
+ * @param pid The process identifier to set.
+ * @param is_increased Whether swappiness should be increased or default.
+ *
+ * @return Returns true if the underlying system supports this
+ * feature, else false.
+ *
+ * {@hide}
+ */
+ public static final native boolean setSwappiness(int pid, boolean is_increased);
+
+ /**
* Change this process's argv[0] parameter. This can be useful to show
* more descriptive information in things like the 'ps' command.
*
diff --git a/core/java/android/print/FileDocumentAdapter.java b/core/java/android/print/FileDocumentAdapter.java
new file mode 100644
index 0000000..2871d45
--- /dev/null
+++ b/core/java/android/print/FileDocumentAdapter.java
@@ -0,0 +1,140 @@
+/*
+ * 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.content.Context;
+import android.os.AsyncTask;
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Adapter for printing files.
+ */
+final class FileDocumentAdapter extends PrintDocumentAdapter {
+
+ private static final String LOG_TAG = "FileDocumentAdapter";
+
+ private final Context mContext;
+
+ private final File mFile;
+
+ private WriteFileAsyncTask mWriteFileAsyncTask;
+
+ public FileDocumentAdapter(Context context, File file) {
+ if (file == null) {
+ throw new IllegalArgumentException("File cannot be null!");
+ }
+ mContext = context;
+ mFile = file;
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback) {
+ // TODO: When we have a PDF rendering library we should query the page count.
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder()
+ .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).create();
+ callback.onLayoutFinished(info, false);
+ }
+
+ @Override
+ public void onWrite(List<PageRange> pages, FileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
+ mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+ (Void[]) null);
+ }
+
+ private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
+
+ private final FileDescriptor mDestination;
+
+ private final WriteResultCallback mResultCallback;
+
+ private final CancellationSignal mCancellationSignal;
+
+ public WriteFileAsyncTask(FileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ mDestination = destination;
+ mResultCallback = callback;
+ mCancellationSignal = cancellationSignal;
+ mCancellationSignal.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel() {
+ cancel(true);
+ }
+ });
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ InputStream in = null;
+ OutputStream out = new FileOutputStream(mDestination);
+ final byte[] buffer = new byte[8192];
+ try {
+ in = new FileInputStream(mFile);
+ while (true) {
+ if (isCancelled()) {
+ break;
+ }
+ final int readByteCount = in.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ out.write(buffer, 0, readByteCount);
+ }
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error writing data!", ioe);
+ mResultCallback.onWriteFailed(mContext.getString(
+ R.string.write_fail_reason_cannot_write));
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ List<PageRange> pages = new ArrayList<PageRange>();
+ pages.add(PageRange.ALL_PAGES);
+ mResultCallback.onWriteFinished(pages);
+ }
+
+ @Override
+ protected void onCancelled(Void result) {
+ mResultCallback.onWriteFailed(mContext.getString(
+ R.string.write_fail_reason_cancelled));
+ }
+ }
+}
+
diff --git a/core/java/android/print/IPrintResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl
similarity index 64%
copy from core/java/android/print/IPrintResultCallback.aidl
copy to core/java/android/print/ILayoutResultCallback.aidl
index 838377e..e4d79f3 100644
--- a/core/java/android/print/IPrintResultCallback.aidl
+++ b/core/java/android/print/ILayoutResultCallback.aidl
@@ -17,17 +17,15 @@
package android.print;
import android.os.ICancellationSignal;
-import android.print.PageRange;
-import android.print.PrintAdapterInfo;
+import android.print.PrintDocumentInfo;
/**
- * Callbacks for observing the print progress (writing of printed content)
- * of a PrintAdapter.
+ * Callback for observing the result of android.print.PrintAdapter#onLayout.
*
* @hide
*/
-oneway interface IPrintResultCallback {
- void onPrintStarted(in PrintAdapterInfo info, ICancellationSignal cancellationSignal);
- void onPrintFinished(in List<PageRange> pages);
- void onPrintFailed(CharSequence error);
+oneway interface ILayoutResultCallback {
+ void onLayoutStarted(ICancellationSignal cancellationSignal);
+ void onLayoutFinished(in PrintDocumentInfo info, boolean changed);
+ void onLayoutFailed(CharSequence error);
}
diff --git a/core/java/android/print/IPrintAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
similarity index 70%
rename from core/java/android/print/IPrintAdapter.aidl
rename to core/java/android/print/IPrintDocumentAdapter.aidl
index f3ff8c4..36938e3 100644
--- a/core/java/android/print/IPrintAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -17,7 +17,8 @@
package android.print;
import android.os.ParcelFileDescriptor;
-import android.print.IPrintResultCallback;
+import android.print.ILayoutResultCallback;
+import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -26,10 +27,11 @@
*
* @hide
*/
-oneway interface IPrintAdapter {
+oneway interface IPrintDocumentAdapter {
void start();
- void printAttributesChanged(in PrintAttributes attributes);
- void print(in List<PageRange> pages, in ParcelFileDescriptor fd,
- IPrintResultCallback callback);
+ void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes,
+ ILayoutResultCallback callback);
+ void write(in List<PageRange> pages, in ParcelFileDescriptor fd,
+ IWriteResultCallback callback);
void finish();
}
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index ff9877e..a466e74 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,11 +16,8 @@
package android.print;
-import android.os.ICancellationSignal;
-import android.print.IPrintAdapter;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -30,12 +27,11 @@
* @hide
*/
interface IPrintManager {
- List<PrintJobInfo> getPrintJobs(int appId, int userId);
- PrintJobInfo getPrintJob(int printJobId, int appId, int userId);
- PrintJobInfo print(String printJobName, in IPrintClient client, in IPrintAdapter printAdapter,
- in PrintAttributes attributes, int appId, int userId);
+ List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
+ PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId);
+ PrintJobInfo print(String printJobName, in IPrintClient client,
+ in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
+ int appId, int userId);
void cancelPrintJob(int printJobId, int appId, int userId);
- void onPrintJobQueued(in PrinterId printerId, in PrintJobInfo printJob);
- void startDiscoverPrinters(IPrinterDiscoveryObserver observer);
- void stopDiscoverPrinters();
+
}
diff --git a/core/java/android/print/IPrintSpoolerService.aidl b/core/java/android/print/IPrintSpooler.aidl
similarity index 64%
rename from core/java/android/print/IPrintSpoolerService.aidl
rename to core/java/android/print/IPrintSpooler.aidl
index e84d592..c55205d 100644
--- a/core/java/android/print/IPrintSpoolerService.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -18,32 +18,35 @@
import android.content.ComponentName;
import android.os.ParcelFileDescriptor;
-import android.print.IPrintAdapter;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
-import android.print.IPrintSpoolerServiceCallbacks;
+import android.print.IPrintSpoolerClient;
+import android.print.IPrintSpoolerCallbacks;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
/**
* Interface for communication with the print spooler service.
*
- * @see android.print.IPrintSpoolerServiceCallbacks
+ * @see android.print.IPrintSpoolerCallbacks
*
* @hide
*/
-oneway interface IPrintSpoolerService {
- void getPrintJobs(IPrintSpoolerServiceCallbacks callback, in ComponentName componentName,
+oneway interface IPrintSpooler {
+ void getPrintJobInfos(IPrintSpoolerCallbacks callback, in ComponentName componentName,
int state, int appId, int sequence);
- void getPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback,
+ void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
- void createPrintJob(String printJobName, in IPrintClient client, in IPrintAdapter printAdapter,
- in PrintAttributes attributes, IPrintSpoolerServiceCallbacks callback, int appId,
- int sequence);
- void cancelPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback,
+ void createPrintJob(String printJobName, in IPrintClient client,
+ in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
+ IPrintSpoolerCallbacks callback, int appId, int sequence);
+ void cancelPrintJob(int printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
- void setPrintJobState(int printJobId, int status, IPrintSpoolerServiceCallbacks callback,
+ void setPrintJobState(int printJobId, int status, IPrintSpoolerCallbacks callback,
int sequence);
- void setPrintJobTag(int printJobId, String tag, IPrintSpoolerServiceCallbacks callback,
+ void setPrintJobTag(int printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
-}
\ No newline at end of file
+ void setClient(IPrintSpoolerClient client);
+ void notifyClientForActivteJobs();
+}
diff --git a/core/java/android/print/IPrintSpoolerServiceCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
similarity index 90%
rename from core/java/android/print/IPrintSpoolerServiceCallbacks.aidl
rename to core/java/android/print/IPrintSpoolerCallbacks.aidl
index 0c51913..7912964 100644
--- a/core/java/android/print/IPrintSpoolerServiceCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -26,8 +26,8 @@
*
* @hide
*/
-oneway interface IPrintSpoolerServiceCallbacks {
- void onGetPrintJobsResult(in List<PrintJobInfo> printJob, int sequence);
+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);
diff --git a/core/java/android/print/IPrintSpoolerClient.aidl b/core/java/android/print/IPrintSpoolerClient.aidl
new file mode 100644
index 0000000..47975e1
--- /dev/null
+++ b/core/java/android/print/IPrintSpoolerClient.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.content.ComponentName;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintJobInfo;
+
+
+/**
+ * Interface for receiving interesting state updates from the print spooler.
+ *
+ * @hide
+ */
+oneway interface IPrintSpoolerClient {
+ void onPrintJobQueued(in PrintJobInfo printJob);
+ void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer);
+ void onStopPrinterDiscovery();
+ void onAllPrintJobsForServiceHandled(in ComponentName printService);
+ void onAllPrintJobsHandled();
+}
diff --git a/core/java/android/print/IPrintResultCallback.aidl b/core/java/android/print/IPrintSpoolerObserver.aidl
similarity index 60%
copy from core/java/android/print/IPrintResultCallback.aidl
copy to core/java/android/print/IPrintSpoolerObserver.aidl
index 838377e..7b8f40e 100644
--- a/core/java/android/print/IPrintResultCallback.aidl
+++ b/core/java/android/print/IPrintSpoolerObserver.aidl
@@ -16,18 +16,16 @@
package android.print;
-import android.os.ICancellationSignal;
-import android.print.PageRange;
-import android.print.PrintAdapterInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
/**
- * Callbacks for observing the print progress (writing of printed content)
- * of a PrintAdapter.
+ * Interface for observing the state of the print spooler.
*
* @hide
*/
-oneway interface IPrintResultCallback {
- void onPrintStarted(in PrintAdapterInfo info, ICancellationSignal cancellationSignal);
- void onPrintFinished(in List<PageRange> pages);
- void onPrintFailed(CharSequence error);
+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/IPrintResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl
similarity index 67%
rename from core/java/android/print/IPrintResultCallback.aidl
rename to core/java/android/print/IWriteResultCallback.aidl
index 838377e..d5428b1 100644
--- a/core/java/android/print/IPrintResultCallback.aidl
+++ b/core/java/android/print/IWriteResultCallback.aidl
@@ -18,16 +18,14 @@
import android.os.ICancellationSignal;
import android.print.PageRange;
-import android.print.PrintAdapterInfo;
/**
- * Callbacks for observing the print progress (writing of printed content)
- * of a PrintAdapter.
+ * Callback for observing the result of android.print.DocuemntAdapter#onWrite.
*
* @hide
*/
-oneway interface IPrintResultCallback {
- void onPrintStarted(in PrintAdapterInfo info, ICancellationSignal cancellationSignal);
- void onPrintFinished(in List<PageRange> pages);
- void onPrintFailed(CharSequence error);
+oneway interface IWriteResultCallback {
+ void onWriteStarted(ICancellationSignal cancellationSignal);
+ void onWriteFinished(in List<PageRange> pages);
+ void onWriteFailed(CharSequence error);
}
diff --git a/core/java/android/print/PrintAdapter.java b/core/java/android/print/PrintAdapter.java
deleted file mode 100644
index 6547c55..0000000
--- a/core/java/android/print/PrintAdapter.java
+++ /dev/null
@@ -1,164 +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.os.CancellationSignal;
-
-import java.io.FileDescriptor;
-import java.util.List;
-
-/**
- * Base class that provides data to be printed.
- *
- * <h3>Lifecycle</h3>
- * <p>
- * <ul>
- * <li>
- * You will receive a call on {@link #onStart()} when printing starts.
- * This callback can be used to allocate resources.
- * </li>
- * <li>
- * Next you will get one or more calls to {@link #onPrintAttributesChanged(
- * PrintAttributes) to informs you that the print attributes (page size, density,
- * etc) changed giving you an opportunity to re-layout the content.
- * </li>
- * <li>
- * After every {@link #onPrintAttributesChanged(PrintAttributes) you will receive
- * one or more calls to {@link #onPrint(List, FileDescriptor, CancellationSignal,
- * PrintResultCallback)} asking you to write a PDF file with the content for
- * specific pages.
- * </li>
- * <li>
- * Finally, you will receive a call on {@link #onFinish()} right after printing.
- * You can use this callback to release resources.
- * </li>
- * <li>
- * You can receive calls to {@link #getInfo()} at any point after a call to
- * {@link #onPrintAttributesChanged(PrintAttributes)} which should return
- * a {@link PrintAdapterInfo} describing your {@link PrintAdapter}.
- * </li>
- * </ul>
- * </p>
- * <p>
- */
-public abstract class PrintAdapter {
-
- /**
- * Called when printing started. You can use this callback to
- * allocate resources.
- * <p>
- * <strong>Note:</strong> Invoked on the main thread.
- * </p>
- */
- public void onStart() {
- /* do nothing - stub */
- }
-
- /**
- * Called when the print job attributes (page size, density, etc)
- * changed giving you a chance to re-layout the content such that
- * it matches the new constraints.
- * <p>
- * <strong>Note:</strong> Invoked on the main thread.
- * </p>
- *
- * @param attributes The print job attributes.
- * @return Whether the content changed based on the provided attributes.
- */
- public boolean onPrintAttributesChanged(PrintAttributes attributes) {
- return false;
- }
-
- /**
- * Called when specific pages of the content have to be printed in the from of
- * a PDF file to the given file descriptor. You should <strong>not</strong>
- * close the file descriptor instead you have to invoke {@link PrintResultCallback
- * #onPrintFinished()} or {@link PrintResultCallback#onPrintFailed(CharSequence)}.
- * <p>
- * <strong>Note:</strong> If the printed content is large, it is a good
- * practice to schedule writing it on a dedicated thread and register a
- * callback in the provided {@link CancellationSignal} upon invocation of
- * which you should stop writing data. The cancellation callback will not
- * be made on the main thread.
- * </p>
- * <p>
- * <strong>Note:</strong> Invoked on the main thread.
- * </p>
- *
- * @param pages The pages whose content to print.
- * @param destination The destination file descriptor to which to start writing.
- * @param cancellationSignal Signal for observing cancel print requests.
- * @param progressListener Callback to inform the system with the write progress.
- *
- * @see CancellationSignal
- */
- public abstract void onPrint(List<PageRange> pages, FileDescriptor destination,
- CancellationSignal cancellationSignal, PrintResultCallback progressListener);
-
- /**
- * Called when printing finished. You can use this callback to release
- * resources.
- * <p>
- * <strong>Note:</strong> Invoked on the main thread.
- * </p>
- */
- public void onFinish() {
- /* do nothing - stub */
- }
-
- /**
- * Gets a {@link PrinterInfo} object that contains metadata about the
- * printed content.
- * <p>
- * <strong>Note:</strong> Invoked on the main thread.
- * </p>
- *
- * @return The info object for this {@link PrintAdapter}.
- *
- * @see PrintAdapterInfo
- */
- public abstract PrintAdapterInfo getInfo();
-
- /**
- * Base class for implementing a listener for the print result
- * of a {@link PrintAdapter}.
- */
- public static abstract class PrintResultCallback {
-
- PrintResultCallback() {
- /* do nothing - hide constructor */
- }
-
- /**
- * Notifies that all the data was printed.
- *
- * @param pages The pages that were printed.
- */
- public void onPrintFinished(List<PageRange> pages) {
- /* do nothing - stub */
- }
-
- /**
- * Notifies that an error occurred while printing the data.
- *
- * @param error Error message. May be null if error is unknown.
- */
- public void onPrintFailed(CharSequence error) {
- /* do nothing - stub */
- }
- }
-}
diff --git a/core/java/android/print/PrintAdapterInfo.java b/core/java/android/print/PrintAdapterInfo.java
deleted file mode 100644
index 06e6b10..0000000
--- a/core/java/android/print/PrintAdapterInfo.java
+++ /dev/null
@@ -1,136 +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.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * This class encapsulates information about a {@link PrintAdapter} object.
- */
-public final class PrintAdapterInfo implements Parcelable {
-
- /**
- * Constant for unknown page count.
- */
- public static final int PAGE_COUNT_UNKNOWN = -1;
-
- private int mPageCount;
- private int mFlags;
-
- /**
- * Creates a new instance.
- */
- private PrintAdapterInfo() {
- /* do nothing */
- }
-
- /**
- * Creates a new instance.
- *
- * @param parcel Data from which to initialize.
- */
- private PrintAdapterInfo(Parcel parcel) {
- mPageCount = parcel.readInt();
- mFlags = parcel.readInt();
- }
-
- /**
- * Gets the total number of pages.
- *
- * @return The number of pages.
- */
- public int getPageCount() {
- return mPageCount;
- }
-
- /**
- * @return The flags of this printable info.
- *
- * @see #FLAG_NOTIFY_FOR_ATTRIBUTES_CHANGE
- */
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(mPageCount);
- parcel.writeInt(mFlags);
- }
-
- /**
- * Builder for creating an {@link PrintAdapterInfo}.
- */
- public static final class Builder {
- private final PrintAdapterInfo mPrintableInfo = new PrintAdapterInfo();
-
- /**
- * Sets the total number of pages.
- *
- * @param pageCount The number of pages. Must be
- * greater than zero.
- */
- public Builder setPageCount(int pageCount) {
- if (pageCount < 0) {
- throw new IllegalArgumentException("pageCount"
- + " must be greater than or euqal to zero!");
- }
- mPrintableInfo.mPageCount = pageCount;
- return this;
- }
-
- /**
- * Sets the flags of this printable info.
- *
- * @param flags The flags.
- *
- * @see #FLAG_NOTIFY_FOR_ATTRIBUTES_CHANGE
- */
- public Builder setFlags(int flags) {
- mPrintableInfo.mFlags = flags;
- return this;
- }
-
- /**
- * Creates a new {@link PrintAdapterInfo} instance.
- *
- * @return The new instance.
- */
- public PrintAdapterInfo create() {
- return mPrintableInfo;
- }
- }
-
- public static final Parcelable.Creator<PrintAdapterInfo> CREATOR =
- new Creator<PrintAdapterInfo>() {
- @Override
- public PrintAdapterInfo createFromParcel(Parcel parcel) {
- return new PrintAdapterInfo(parcel);
- }
-
- @Override
- public PrintAdapterInfo[] newArray(int size) {
- return new PrintAdapterInfo[size];
- }
- };
-}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 8511d0b..2a27a32 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -18,11 +18,10 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.util.Log;
import com.android.internal.R;
@@ -388,145 +387,506 @@
* This class specifies a supported media size.
*/
public static final class MediaSize {
- private static final String LOG_TAG = "MediaSize";
// TODO: Verify media sizes and add more standard ones.
// ISO sizes
- /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
- public static final MediaSize ISO_A0 =
- new MediaSize("ISO_A0", "android", R.string.mediaSize_iso_a0, 33110, 46810);
- /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
- public static final MediaSize ISO_A1 =
- new MediaSize("ISO_A1", "android", R.string.mediaSize_iso_a1, 23390, 33110);
- /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
- public static final MediaSize ISO_A2 =
- new MediaSize("ISO_A2", "android", R.string.mediaSize_iso_a2, 16540, 23390);
- /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
- public static final MediaSize ISO_A3 =
- new MediaSize("ISO_A3", "android", R.string.mediaSize_iso_a3, 11690, 16540);
- /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
- public static final MediaSize ISO_A4 =
- new MediaSize("ISO_A4", "android", R.string.mediaSize_iso_a4, 8270, 11690);
- /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
- public static final MediaSize ISO_A5 =
- new MediaSize("ISO_A5", "android", R.string.mediaSize_iso_a5, 5830, 8270);
- /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
- public static final MediaSize ISO_A6 =
- new MediaSize("ISO_A6", "android", R.string.mediaSize_iso_a6, 4130, 5830);
- /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
- public static final MediaSize ISO_A7 =
- new MediaSize("ISO_A7", "android", R.string.mediaSize_iso_a7, 2910, 4130);
- /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
- public static final MediaSize ISO_A8 =
- new MediaSize("ISO_A8", "android", R.string.mediaSize_iso_a8, 2050, 2910);
- /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
- public static final MediaSize ISO_A9 =
- new MediaSize("ISO_A9", "android", R.string.mediaSize_iso_a9, 1460, 2050);
- /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
- public static final MediaSize ISO_A10 =
- new MediaSize("ISO_A10", "android", R.string.mediaSize_iso_a10, 1020, 1460);
+ /**
+ * ISO A0 media size: 841mm x 1189mm (33.11" x 46.81")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A0 = 1;
- /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
- public static final MediaSize ISO_B0 =
- new MediaSize("ISO_B0", "android", R.string.mediaSize_iso_b0, 39370, 55670);
- /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
- public static final MediaSize ISO_B1 =
- new MediaSize("ISO_B1", "android", R.string.mediaSize_iso_b1, 27830, 39370);
- /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
- public static final MediaSize ISO_B2 =
- new MediaSize("ISO_B2", "android", R.string.mediaSize_iso_b2, 19690, 27830);
- /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
- public static final MediaSize ISO_B3 =
- new MediaSize("ISO_B3", "android", R.string.mediaSize_iso_b3, 13900, 19690);
- /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
- public static final MediaSize ISO_B4 =
- new MediaSize("ISO_B4", "android", R.string.mediaSize_iso_b4, 9840, 13900);
- /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
- public static final MediaSize ISO_B5 =
- new MediaSize("ISO_B5", "android", R.string.mediaSize_iso_b5, 6930, 9840);
- /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
- public static final MediaSize ISO_B6 =
- new MediaSize("ISO_B6", "android", R.string.mediaSize_iso_b6, 4920, 6930);
- /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
- public static final MediaSize ISO_B7 =
- new MediaSize("ISO_B7", "android", R.string.mediaSize_iso_b7, 3460, 4920);
- /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
- public static final MediaSize ISO_B8 =
- new MediaSize("ISO_B8", "android", R.string.mediaSize_iso_b8, 2440, 3460);
- /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
- public static final MediaSize ISO_B9 =
- new MediaSize("ISO_B9", "android", R.string.mediaSize_iso_b9, 1730, 2440);
- /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
- public static final MediaSize ISO_B10 =
- new MediaSize("ISO_B10", "android", R.string.mediaSize_iso_b10, 1220, 1730);
+ /**
+ * ISO A1 media size: 594mm x 841mm (23.39" x 33.11")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A1 = 2;
- /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
- public static final MediaSize ISO_C0 =
- new MediaSize("ISO_C0", "android", R.string.mediaSize_iso_c0, 36100, 51060);
- /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
- public static final MediaSize ISO_C1 =
- new MediaSize("ISO_C1", "android", R.string.mediaSize_iso_c1, 25510, 36100);
- /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
- public static final MediaSize ISO_C2 =
- new MediaSize("ISO_C2", "android", R.string.mediaSize_iso_c2, 18030, 25510);
- /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
- public static final MediaSize ISO_C3 =
- new MediaSize("ISO_C3", "android", R.string.mediaSize_iso_c3, 12760, 18030);
- /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
- public static final MediaSize ISO_C4 =
- new MediaSize("ISO_C4", "android", R.string.mediaSize_iso_c4, 9020, 12760);
- /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
- public static final MediaSize ISO_C5 =
- new MediaSize("ISO_C5", "android", R.string.mediaSize_iso_c5, 6380, 9020);
- /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
- public static final MediaSize ISO_C6 =
- new MediaSize("ISO_C6", "android", R.string.mediaSize_iso_c6, 4490, 6380);
- /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
- public static final MediaSize ISO_C7 =
- new MediaSize("ISO_C7", "android", R.string.mediaSize_iso_c7, 3190, 4490);
- /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
- public static final MediaSize ISO_C8 =
- new MediaSize("ISO_C8", "android", R.string.mediaSize_iso_c8, 2240, 3190);
- /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
- public static final MediaSize ISO_C9 =
- new MediaSize("ISO_C9", "android", R.string.mediaSize_iso_c9, 1570, 2240);
- /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
- public static final MediaSize ISO_C10 =
- new MediaSize("ISO_C10", "android", R.string.mediaSize_iso_c10, 1100, 1570);
+ /**
+ *
+ *ISO A2 media size: 420mm x 594mm (16.54" x 23.39")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A2 = 3;
+
+ /**
+ * ISO A3 media size: 297mm x 420mm (11.69" x 16.54")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A3 = 4;
+
+ /**
+ * ISO A4 media size: 210mm x 297mm (8.27" x 11.69")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A4 = 5;
+
+ /**
+ * ISO A5 media size: 148mm x 210mm (5.83" x 8.27")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A5 = 6;
+
+ /**
+ * ISO A6 media size: 105mm x 148mm (4.13" x 5.83")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A6 = 7;
+
+ /**
+ * ISO A7 media size: 74mm x 105mm (2.91" x 4.13")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A7 = 8;
+
+ /**
+ * ISO A8 media size: 52mm x 74mm (2.05" x 2.91")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A8 = 9;
+
+ /**
+ * ISO A9 media size: 37mm x 52mm (1.46" x 2.05")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A9 = 10;
+
+ /**
+ * ISO A10 media size: 26mm x 37mm (1.02" x 1.46")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_A10 = 11;
+
+
+ /**
+ * ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B0 = 100;
+
+ /**
+ * ISO B1 media size: 707mm x 1000mm (27.83" x 39.37")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B1 = 101;
+
+ /**
+ * ISO B2 media size: 500mm x 707mm (19.69" x 27.83")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B2 = 102;
+
+ /**
+ * ISO B3 media size: 353mm x 500mm (13.90" x 19.69")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B3 = 103;
+
+ /**
+ * ISO B4 media size: 250mm x 353mm (9.84" x 13.90")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B4 = 104;
+
+ /**
+ * ISO B5 media size: 176mm x 250mm (6.93" x 9.84")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B5 = 105;
+
+ /**
+ * ISO B6 media size: 125mm x 176mm (4.92" x 6.93")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B6 = 106;
+
+ /**
+ * ISO B7 media size: 88mm x 125mm (3.46" x 4.92")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B7 = 107;
+
+ /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B8 = 108;
+
+ /**
+ * ISO B9 media size: 44mm x 62mm (1.73" x 2.44")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B9 = 109;
+
+ /**
+ * ISO B10 media size: 31mm x 44mm (1.22" x 1.73")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_B10 = 110;
+
+
+ /**
+ * ISO C0 media size: 917mm x 1297mm (36.10" x 51.06")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C0 = 200;
+
+ /**
+ * ISO C1 media size: 648mm x 917mm (25.51" x 36.10")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+
+ public static final int ISO_C1 = 201;
+ /**
+ * ISO C2 media size: 458mm x 648mm (18.03" x 25.51")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C2 = 202;
+
+ /**
+ * ISO C3 media size: 324mm x 458mm (12.76" x 18.03")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C3 = 203;
+
+ /**
+ * ISO C4 media size: 229mm x 324mm (9.02" x 12.76")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C4 = 204;
+
+ /**
+ * ISO C5 media size: 162mm x 229mm (6.38" x 9.02")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C5 = 205;
+
+ /**
+ * ISO C6 media size: 114mm x 162mm (4.49" x 6.38")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C6 = 206;
+
+ /**
+ * ISO C7 media size: 81mm x 114mm (3.19" x 4.49")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C7 = 207;
+
+ /**
+ * ISO C8 media size: 57mm x 81mm (2.24" x 3.19")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C8 = 208;
+
+ /**
+ * ISO C9 media size: 40mm x 57mm (1.57" x 2.24")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C9 = 209;
+
+ /**
+ * ISO C10 media size: 28mm x 40mm (1.10" x 1.57")
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int ISO_C10 = 210;
+
// North America
- /** North America Letter media size: 8.5" x 11" */
- public static final MediaSize NA_LETTER =
- new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
- /** North America Government-Letter media size: 8.0" x 10.5" */
- public static final MediaSize NA_GOVT_LETTER =
- new MediaSize("NA_GOVT_LETTER", "android",
- R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
- /** North America Legal media size: 8.5" x 14" */
- public static final MediaSize NA_LEGAL =
- new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
- /** North America Junior Legal media size: 8.0" x 5.0" */
- public static final MediaSize NA_JUNIOR_LEGAL =
- new MediaSize("NA_JUNIOR_LEGAL", "android",
- R.string.mediaSize_na_junior_legal, 8000, 5000);
- /** North America Ledger media size: 17" x 11" */
- public static final MediaSize NA_LEDGER =
- new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
- /** North America Tabloid media size: 11" x 17" */
- public static final MediaSize NA_TBLOID =
- new MediaSize("NA_TABLOID", "android",
- R.string.mediaSize_na_tabloid, 11000, 17000);
+ /**
+ * North America Letter media size: 8.5" x 11"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_LETTER = 300;
+
+ /**
+ * North America Government-Letter media size: 8.0" x 10.5"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_GOVT_LETTER = 301;
+
+ /**
+ * North America Legal media size: 8.5" x 14"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_LEGAL = 302;
+
+ /**
+ * North America Junior Legal media size: 8.0" x 5.0"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_JUNIOR_LEGAL = 303;
+
+ /**
+ * North America Ledger media size: 17" x 11"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_LEDGER = 304;
+
+ /**
+ * North America Tabloid media size: 11" x 17"
+ *
+ * @see #createMediaSize(PackageManager, int)
+ */
+ public static final int NA_TBLOID = 305;
+
+ /**
+ * Creates a standard media size with a localized label.
+ *
+ * @param pm Package manager used to load the label.
+ * @param mediaSize Media size constant.
+ * @return A {@link MediaSize} instance with a localized label.
+ */
+ public static MediaSize createMediaSize(PackageManager pm, int mediaSize) {
+ final Resources resources;
+ try {
+ resources = pm.getResourcesForApplication("android");
+ } catch (NameNotFoundException nnfe) {
+ return null;
+ }
+ switch (mediaSize) {
+ case ISO_A0: {
+ return new MediaSize("ISO_A0", resources
+ .getString(R.string.mediaSize_iso_a0), 33110, 46810);
+ }
+ case ISO_A1: {
+ return new MediaSize("ISO_A1", resources
+ .getString(R.string.mediaSize_iso_a1), 23390, 33110);
+ }
+ case ISO_A2: {
+ return new MediaSize("ISO_A2", resources
+ .getString(R.string.mediaSize_iso_a2), 16540, 23390);
+ }
+ case ISO_A3: {
+ return new MediaSize("ISO_A3", resources
+ .getString(R.string.mediaSize_iso_a3), 11690, 16540);
+ }
+ case ISO_A4: {
+ return new MediaSize("ISO_A4", resources
+ .getString(R.string.mediaSize_iso_a4), 8270, 11690);
+ }
+ case ISO_A5: {
+ return new MediaSize("ISO_A5", resources
+ .getString(R.string.mediaSize_iso_a5), 5830, 8270);
+ }
+ case ISO_A6: {
+ return new MediaSize("ISO_A6", resources
+ .getString(R.string.mediaSize_iso_a6), 4130, 5830);
+ }
+ case ISO_A7: {
+ return new MediaSize("ISO_A7", resources
+ .getString(R.string.mediaSize_iso_a7), 2910, 4130);
+ }
+ case ISO_A8: {
+ return new MediaSize("ISO_A8", resources
+ .getString(R.string.mediaSize_iso_a8), 2050, 2910);
+ }
+ case ISO_A9: {
+ return new MediaSize("ISO_A9", resources
+ .getString(R.string.mediaSize_iso_a9), 1460, 2050);
+ }
+ case ISO_A10: {
+ return new MediaSize("ISO_A10", resources
+ .getString(R.string.mediaSize_iso_a10), 1020, 1460);
+ }
+ case ISO_B0: {
+ return new MediaSize("ISO_B0", resources
+ .getString(R.string.mediaSize_iso_b0), 39370, 55670);
+ }
+ case ISO_B1: {
+ return new MediaSize("ISO_B1", resources
+ .getString(R.string.mediaSize_iso_b1), 27830, 39370);
+ }
+ case ISO_B2: {
+ return new MediaSize("ISO_B2", resources
+ .getString(R.string.mediaSize_iso_b2), 19690, 27830);
+ }
+ case ISO_B3: {
+ return new MediaSize("ISO_B3", resources
+ .getString(R.string.mediaSize_iso_b3), 13900, 19690);
+ }
+ case ISO_B4: {
+ return new MediaSize("ISO_B4", resources
+ .getString(R.string.mediaSize_iso_b4), 9840, 13900);
+ }
+ case ISO_B5: {
+ return new MediaSize("ISO_B5", resources
+ .getString(R.string.mediaSize_iso_b5), 6930, 9840);
+ }
+ case ISO_B6: {
+ return new MediaSize("ISO_B6", resources
+ .getString(R.string.mediaSize_iso_b6), 4920, 6930);
+ }
+ case ISO_B7: {
+ return new MediaSize("ISO_B7", resources
+ .getString(R.string.mediaSize_iso_b7), 3460, 4920);
+ }
+ case ISO_B8: {
+ return new MediaSize("ISO_B8", resources
+ .getString(R.string.mediaSize_iso_b8), 2440, 3460);
+ }
+ case ISO_B9: {
+ return new MediaSize("ISO_B9", resources
+ .getString(R.string.mediaSize_iso_b9), 1730, 2440);
+ }
+ case ISO_B10: {
+ return new MediaSize("ISO_B10", resources
+ .getString(R.string.mediaSize_iso_b10), 1220, 1730);
+ }
+ case ISO_C0: {
+ return new MediaSize("ISO_C0", resources
+ .getString(R.string.mediaSize_iso_c0), 36100, 51060);
+ }
+ case ISO_C1: {
+ return new MediaSize("ISO_C1", resources
+ .getString(R.string.mediaSize_iso_c1), 25510, 36100);
+ }
+ case ISO_C2: {
+ return new MediaSize("ISO_C2", resources
+ .getString(R.string.mediaSize_iso_c2), 18030, 25510);
+ }
+ case ISO_C3: {
+ return new MediaSize("ISO_C3", resources
+ .getString(R.string.mediaSize_iso_c3), 12760, 18030);
+ }
+ case ISO_C4: {
+ return new MediaSize("ISO_C4", resources
+ .getString(R.string.mediaSize_iso_c4), 9020, 12760);
+ }
+ case ISO_C5: {
+ return new MediaSize("ISO_C5", resources
+ .getString(R.string.mediaSize_iso_c5), 6380, 9020);
+ }
+ case ISO_C6: {
+ return new MediaSize("ISO_C6", resources
+ .getString(R.string.mediaSize_iso_c6), 4490, 6380);
+ }
+ case ISO_C7: {
+ return new MediaSize("ISO_C7", resources
+ .getString(R.string.mediaSize_iso_c7), 3190, 4490);
+ }
+ case ISO_C8: {
+ return new MediaSize("ISO_C8", resources
+ .getString(R.string.mediaSize_iso_c8), 2240, 3190);
+ }
+ case ISO_C9: {
+ return new MediaSize("ISO_C9", resources
+ .getString(R.string.mediaSize_iso_c9), 1570, 2240);
+ }
+ case ISO_C10: {
+ return new MediaSize("ISO_C10", resources
+ .getString(R.string.mediaSize_iso_c10), 1100, 1570);
+ }
+ case NA_LETTER: {
+ return new MediaSize("NA_LETTER", resources
+ .getString(R.string.mediaSize_na_letter), 8500, 11000);
+ }
+ case NA_GOVT_LETTER: {
+ return new MediaSize("NA_GOVT_LETTER", resources
+ .getString(R.string.mediaSize_na_gvrnmt_letter), 8000, 10500);
+ }
+ case NA_LEGAL: {
+ return new MediaSize("NA_LEGAL", resources
+ .getString(R.string.mediaSize_na_legal), 8500, 14000);
+ }
+ case NA_JUNIOR_LEGAL: {
+ return new MediaSize("NA_JUNIOR_LEGAL", resources
+ .getString(R.string.mediaSize_na_junior_legal), 8000, 5000);
+ }
+ case NA_LEDGER: {
+ return new MediaSize("NA_LEDGER", resources
+ .getString(R.string.mediaSize_na_ledger), 17000, 11000);
+ }
+ case NA_TBLOID: {
+ return new MediaSize("NA_TABLOID", resources
+ .getString(R.string.mediaSize_na_tabloid), 11000, 17000);
+ }
+ default: {
+ throw new IllegalArgumentException("Unknown media size.");
+ }
+ }
+ }
private final String mId;
- private final String mPackageName;
- private final int mLabelResId;
+ private final CharSequence mLabel;
private final int mWidthMils;
private final int mHeightMils;
/**
+ * Creates a new instance.
+ *
+ * @param id The unique media size id.
+ * @param label The <strong>internationalized</strong> human readable label.
+ * @param widthMils The width in mils (thousands of an inch).
+ * @param heightMils The height in mils (thousands of an inch).
+ *
+ * @throws IllegalArgumentException If the id is empty.
+ * @throws IllegalArgumentException If the label is empty.
+ * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
+ * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
+ */
+ public MediaSize(String id, CharSequence label, int widthMils, int heightMils) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id cannot be empty.");
+ }
+ if (TextUtils.isEmpty(label)) {
+ throw new IllegalArgumentException("label cannot be empty.");
+ }
+ if (widthMils <= 0) {
+ throw new IllegalArgumentException("widthMils "
+ + "cannot be less than or equal to zero.");
+ }
+ if (heightMils <= 0) {
+ throw new IllegalArgumentException("heightMils "
+ + "cannot be less than or euqual to zero.");
+ }
+ mId = id;
+ mLabel = label;
+ mWidthMils = widthMils;
+ mHeightMils = heightMils;
+ }
+
+ /**
* Gets the unique media size id.
*
* @return The unique media size id.
@@ -540,18 +900,8 @@
*
* @return The human readable label.
*/
- public CharSequence getLabel(PackageManager packageManager) {
- try {
- return packageManager.getResourcesForApplication(
- mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- }
- return null;
+ public CharSequence getLabel() {
+ return mLabel;
}
/**
@@ -572,50 +922,9 @@
return mHeightMils;
}
- /**
- * Creates a new instance.
- *
- * @param id The unique media size id.
- * @param packageName The name of the creating package.
- * @param labelResId The resource if of a human readable label.
- * @param widthMils The width in mils (thousands of an inch).
- * @param heightMils The height in mils (thousands of an inch).
- *
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
- * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
- */
- public MediaSize(String id, String packageName, int labelResId,
- int widthMils, int heightMils) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("labelResId must be greater than zero.");
- }
- if (widthMils <= 0) {
- throw new IllegalArgumentException("widthMils "
- + "cannot be less than or equal to zero.");
- }
- if (heightMils <= 0) {
- throw new IllegalArgumentException("heightMils "
- + "cannot be less than or euqual to zero.");
- }
- mPackageName = packageName;
- mId = id;
- mLabelResId = labelResId;
- mWidthMils = widthMils;
- mHeightMils = heightMils;
- }
-
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
- parcel.writeString(mPackageName);
- parcel.writeInt(mLabelResId);
+ parcel.writeCharSequence(mLabel);
parcel.writeInt(mWidthMils);
parcel.writeInt(mHeightMils);
}
@@ -623,8 +932,7 @@
static MediaSize createFromParcel(Parcel parcel) {
return new MediaSize(
parcel.readString(),
- parcel.readString(),
- parcel.readInt(),
+ parcel.readCharSequence(),
parcel.readInt(),
parcel.readInt());
}
@@ -634,8 +942,7 @@
StringBuilder builder = new StringBuilder();
builder.append("MediaSize{");
builder.append("id: ").append(mId);
- builder.append(", packageName: ").append(mPackageName);
- builder.append(", labelResId: ").append(mLabelResId);
+ builder.append(", label: ").append(mLabel);
builder.append(", heightMils: ").append(mHeightMils);
builder.append(", widthMils: ").append(mWidthMils);
builder.append("}");
@@ -647,15 +954,46 @@
* This class specifies a supported resolution in dpi (dots per inch).
*/
public static final class Resolution {
- private static final String LOG_TAG = "Resolution";
-
private final String mId;
- private final String mPackageName;
- private final int mLabelResId;
+ private final CharSequence mLabel;
private final int mHorizontalDpi;
private final int mVerticalDpi;
/**
+ * Creates a new instance.
+ *
+ * @param id The unique resolution id.
+ * @param label The <strong>internationalized</strong> human readable label.
+ * @param horizontalDpi The horizontal resolution in dpi.
+ * @param verticalDpi The vertical resolution in dpi.
+ *
+ * @throws IllegalArgumentException If the id is empty.
+ * @throws IllegalArgumentException If the label is empty.
+ * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
+ * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
+ */
+ public Resolution(String id, CharSequence label, int horizontalDpi, int verticalDpi) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id cannot be empty.");
+ }
+ if (TextUtils.isEmpty(label)) {
+ throw new IllegalArgumentException("label cannot be empty.");
+ }
+ if (horizontalDpi <= 0) {
+ throw new IllegalArgumentException("horizontalDpi "
+ + "cannot be less than or equal to zero.");
+ }
+ if (verticalDpi <= 0) {
+ throw new IllegalArgumentException("verticalDpi"
+ + " cannot be less than or equal to zero.");
+ }
+ mId = id;
+ mLabel = label;
+ mHorizontalDpi = horizontalDpi;
+ mVerticalDpi = verticalDpi;
+ }
+
+ /**
* Gets the unique resolution id.
*
* @return The unique resolution id.
@@ -670,17 +1008,7 @@
* @return The human readable label.
*/
public CharSequence getLabel(PackageManager packageManager) {
- try {
- return packageManager.getResourcesForApplication(
- mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- }
- return null;
+ return mLabel;
}
/**
@@ -701,50 +1029,9 @@
return mVerticalDpi;
}
- /**
- * Creates a new instance.
- *
- * @param id The unique resolution id.
- * @param packageName The name of the creating package.
- * @param labelResId The resource id of a human readable label.
- * @param horizontalDpi The horizontal resolution in dpi.
- * @param verticalDpi The vertical resolution in dpi.
- *
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
- * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
- */
- public Resolution(String id, String packageName, int labelResId,
- int horizontalDpi, int verticalDpi) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("labelResId must be greater than zero.");
- }
- if (horizontalDpi <= 0) {
- throw new IllegalArgumentException("horizontalDpi "
- + "cannot be less than or equal to zero.");
- }
- if (verticalDpi <= 0) {
- throw new IllegalArgumentException("verticalDpi"
- + " cannot be less than or equal to zero.");
- }
- mId = id;
- mPackageName = packageName;
- mLabelResId = labelResId;
- mHorizontalDpi = horizontalDpi;
- mVerticalDpi = verticalDpi;
- }
-
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
- parcel.writeString(mPackageName);
- parcel.writeInt(mLabelResId);
+ parcel.writeCharSequence(mLabel);
parcel.writeInt(mHorizontalDpi);
parcel.writeInt(mVerticalDpi);
}
@@ -752,8 +1039,7 @@
static Resolution createFromParcel(Parcel parcel) {
return new Resolution(
parcel.readString(),
- parcel.readString(),
- parcel.readInt(),
+ parcel.readCharSequence(),
parcel.readInt(),
parcel.readInt());
}
@@ -763,8 +1049,7 @@
StringBuilder builder = new StringBuilder();
builder.append("Resolution{");
builder.append("id: ").append(mId);
- builder.append(", packageName: ").append(mPackageName);
- builder.append(", labelResId: ").append(mLabelResId);
+ builder.append(", label: ").append(mLabel);
builder.append(", horizontalDpi: ").append(mHorizontalDpi);
builder.append(", verticalDpi: ").append(mVerticalDpi);
builder.append("}");
@@ -782,6 +1067,38 @@
private final int mBottomMils;
/**
+ * Creates a new instance.
+ *
+ * @param leftMils The left margin in mils (thousands of an inch).
+ * @param topMils The top margin in mils (thousands of an inch).
+ * @param rightMils The right margin in mils (thousands of an inch).
+ * @param bottomMils The bottom margin in mils (thousands of an inch).
+ *
+ * @throws IllegalArgumentException If the leftMils is less than zero.
+ * @throws IllegalArgumentException If the topMils is less than zero.
+ * @throws IllegalArgumentException If the rightMils is less than zero.
+ * @throws IllegalArgumentException If the bottomMils is less than zero.
+ */
+ public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
+ if (leftMils < 0) {
+ throw new IllegalArgumentException("leftMils cannot be less than zero.");
+ }
+ if (topMils < 0) {
+ throw new IllegalArgumentException("topMils cannot be less than zero.");
+ }
+ if (rightMils < 0) {
+ throw new IllegalArgumentException("rightMils cannot be less than zero.");
+ }
+ if (bottomMils < 0) {
+ throw new IllegalArgumentException("bottomMils cannot be less than zero.");
+ }
+ mTopMils = topMils;
+ mLeftMils = leftMils;
+ mRightMils = rightMils;
+ mBottomMils = bottomMils;
+ }
+
+ /**
* Gets the left margin in mils (thousands of an inch).
*
* @return The left margin.
@@ -817,38 +1134,6 @@
return mBottomMils;
}
- /**
- * Creates a new instance.
- *
- * @param leftMils The left margin in mils (thousands of an inch).
- * @param topMils The top margin in mils (thousands of an inch).
- * @param rightMils The right margin in mils (thousands of an inch).
- * @param bottomMils The bottom margin in mils (thousands of an inch).
- *
- * @throws IllegalArgumentException If the leftMils is less than zero.
- * @throws IllegalArgumentException If the topMils is less than zero.
- * @throws IllegalArgumentException If the rightMils is less than zero.
- * @throws IllegalArgumentException If the bottomMils is less than zero.
- */
- public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
- if (leftMils < 0) {
- throw new IllegalArgumentException("leftMils cannot be less than zero.");
- }
- if (topMils < 0) {
- throw new IllegalArgumentException("topMils cannot be less than zero.");
- }
- if (rightMils < 0) {
- throw new IllegalArgumentException("rightMils cannot be less than zero.");
- }
- if (bottomMils < 0) {
- throw new IllegalArgumentException("bottomMils cannot be less than zero.");
- }
- mTopMils = topMils;
- mLeftMils = leftMils;
- mRightMils = rightMils;
- mBottomMils = bottomMils;
- }
-
void writeToParcel(Parcel parcel) {
parcel.writeInt(mLeftMils);
parcel.writeInt(mTopMils);
@@ -881,11 +1166,28 @@
* Represents a printer tray.
*/
public static final class Tray {
- private static final String LOG_TAG = "Tray";
-
private final String mId;
- private final String mPackageName;
- private final int mLabelResId;
+ private final CharSequence mLabel;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param id The unique tray id.
+ * @param label The <strong>internationalized</strong> human readable label.
+ *
+ * @throws IllegalArgumentException If the id is empty.
+ * @throws IllegalArgumentException If the label is empty.
+ */
+ public Tray(String id, CharSequence label) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id cannot be empty.");
+ }
+ if (TextUtils.isEmpty(label)) {
+ throw new IllegalArgumentException("label cannot be empty.");
+ }
+ mId = id;
+ mLabel = label;
+ }
/**
* Gets the unique tray id.
@@ -902,55 +1204,18 @@
* @return The human readable label.
*/
public CharSequence getLabel(PackageManager packageManager) {
- try {
- return packageManager.getResourcesForApplication(
- mPackageName).getString(mLabelResId);
- } catch (NotFoundException nfe) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- } catch (NameNotFoundException nnfee) {
- Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
- + " from package " + mPackageName);
- }
- return null;
- }
-
- /**
- * Creates a new instance.
- *
- * @param id The unique tray id.
- * @param packageName The name of the creating package.
- * @param labelResId The resource id of a human readable label.
- *
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- */
- public Tray(String id, String packageName, int labelResId) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(packageName)) {
- throw new IllegalArgumentException("packageName cannot be empty.");
- }
- if (labelResId <= 0) {
- throw new IllegalArgumentException("label must be greater than zero.");
- }
- mId = id;
- mPackageName = packageName;
- mLabelResId = labelResId;
+ return mLabel;
}
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
- parcel.writeString(mPackageName);
- parcel.writeInt(mLabelResId);
+ parcel.writeCharSequence(mLabel);
}
static Tray createFromParcel(Parcel parcel) {
return new Tray(
parcel.readString(),
- parcel.readString(),
- parcel.readInt());
+ parcel.readCharSequence());
}
@Override
@@ -959,8 +1224,7 @@
builder.append("Tray{");
builder.append("id: ").append(mId);
builder.append("id: ").append(mId);
- builder.append(", packageName: ").append(mPackageName);
- builder.append(", labelResId: ").append(mLabelResId);
+ builder.append(", label: ").append(mLabel);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
new file mode 100644
index 0000000..ef69400
--- /dev/null
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -0,0 +1,200 @@
+/*
+ * 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.os.CancellationSignal;
+
+import java.io.FileDescriptor;
+import java.util.List;
+
+/**
+ * Base class that provides the content of a document to be printed.
+ *
+ * <h3>Lifecycle</h3>
+ * <p>
+ * <ul>
+ * <li>
+ * Initially, you will receive a call to {@link #onStart()}. This callback
+ * can be used to allocate resources.
+ * </li>
+ * <li>
+ * Next, you will get one or more calls to {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback)} to inform you
+ * that the print attributes (page size, density, etc) changed giving you an
+ * opportunity to layout the content to match the new constraints.
+ * </li>
+ * <li>
+ * After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
+ * CancellationSignal, LayoutResultCallback)}, you may get a call to {@link
+ * #onWrite(List, FileDescriptor, CancellationSignal, WriteResultCallback)}
+ * asking you to write a PDF file with the content for specific pages.
+ * </li>
+ * <li>
+ * Finally, you will receive a call to {@link #onFinish()}. You can use this
+ * callback to release resources allocated in {@link #onStart()}.
+ * </li>
+ * </ul>
+ * </p>
+ */
+public abstract class PrintDocumentAdapter {
+
+ /**
+ * Called when printing starts. You can use this callback to allocate
+ * resources. This method is invoked on the main thread.
+ */
+ public void onStart() {
+ /* do nothing - stub */
+ }
+
+ /**
+ * Called when the print attributes (page size, density, etc) changed
+ * giving you a chance to layout the content such that it matches the
+ * new constraints. This method is invoked on the main thread.
+ * <p>
+ * After you are done laying out, you must invoke: {@link LayoutResultCallback
+ * #onLayoutFinished(PrintDocumentInfo, boolean)} with the last argument <code>true
+ * </code> or <code>false</code> depending on whether the layout changed the
+ * content or not, respectively; and {@link LayoutResultCallback#onLayoutFailed(
+ * CharSequence), if an error occurred.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> If the content is large and a layout will be
+ * performed, it is a good practice to schedule the work on a dedicated
+ * thread and register an observer in the provided {@link
+ * CancellationSignal} upon invocation of which you should stop the
+ * layout. The cancellation callback will not be made on the main
+ * thread.
+ * </p>
+ *
+ * @param oldAttributes The old print attributes.
+ * @param newAttributes The new print attributes.
+ * @param cancellationSignal Signal for observing cancel layout requests.
+ * @param callback Callback to inform the system for the layout result.
+ *
+ * @see LayoutResultCallback
+ * @see CancellationSignal
+ */
+ public abstract void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback);
+
+ /**
+ * Called when specific pages of the content should be written in the
+ * from of a PDF file to the given file descriptor. This method is invoked
+ * on the main thread.
+ *<p>
+ * After you are done writing, you should <strong>not</strong> close the
+ * file descriptor, rather you must invoke: {@link WriteResultCallback
+ * #onWriteFinished()}, if writing completed successfully; or {@link
+ * WriteResultCallback#onWriteFailed(CharSequence)}, if an error occurred.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> If the printed content is large, it is a good
+ * practice to schedule writing it on a dedicated thread and register an
+ * observer in the provided {@link CancellationSignal} upon invocation of
+ * which you should stop writing. The cancellation callback will not be
+ * made on the main thread.
+ * </p>
+ *
+ * @param pages The pages whose content to print.
+ * @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.
+ *
+ * @see WriteResultCallback
+ * @see CancellationSignal
+ */
+ public abstract void onWrite(List<PageRange> pages, FileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback);
+
+ /**
+ * Called when printing finishes. You can use this callback to release
+ * resources acquired in {@link #onStart()}. This method is invoked on
+ * the main thread.
+ */
+ public void onFinish() {
+ /* do nothing - stub */
+ }
+
+ /**
+ * Base class for implementing a callback for the result of {@link
+ * PrintDocumentAdapter#onWrite(List, FileDescriptor, CancellationSignal,
+ * WriteResultCallback)}.
+ */
+ public static abstract class WriteResultCallback {
+
+ /**
+ * @hide
+ */
+ public WriteResultCallback() {
+ /* do nothing - hide constructor */
+ }
+
+ /**
+ * Notifies that all the data was written.
+ *
+ * @param pages The pages that were written.
+ */
+ public void onWriteFinished(List<PageRange> pages) {
+ /* do nothing - stub */
+ }
+
+ /**
+ * Notifies that an error occurred while writing the data.
+ *
+ * @param error Error message. May be null if error is unknown.
+ */
+ public void onWriteFailed(CharSequence error) {
+ /* do nothing - stub */
+ }
+ }
+
+ /**
+ * Base class for implementing a callback for the result of {@link
+ * PrintDocumentAdapter#onLayout(PrintAttributes, PrintAttributes,
+ * CancellationSignal, LayoutResultCallback)}.
+ */
+ public static abstract class LayoutResultCallback {
+
+ /**
+ * @hide
+ */
+ public LayoutResultCallback() {
+ /* do nothing - hide constructor */
+ }
+
+ /**
+ * Notifies that the layout finished and whether the content changed.
+ *
+ * @param info An info object describing the document.
+ * @param changed Whether the layout changed.
+ *
+ * @see PrintDocumentInfo
+ */
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ /* do nothing - stub */
+ }
+
+ /**
+ * Notifies that an error occurred while laying out the document.
+ *
+ * @param error Error message. May be null if error is unknown.
+ */
+ public void onLayoutFailed(CharSequence error) {
+ /* do nothing - stub */
+ }
+ }
+}
diff --git a/core/java/android/print/PrintAdapterInfo.aidl b/core/java/android/print/PrintDocumentInfo.aidl
similarity index 95%
rename from core/java/android/print/PrintAdapterInfo.aidl
rename to core/java/android/print/PrintDocumentInfo.aidl
index 27bf717..831dcb7 100644
--- a/core/java/android/print/PrintAdapterInfo.aidl
+++ b/core/java/android/print/PrintDocumentInfo.aidl
@@ -16,4 +16,4 @@
package android.print;
-parcelable PrintAdapterInfo;
+parcelable PrintDocumentInfo;
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
new file mode 100644
index 0000000..7731deb
--- /dev/null
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -0,0 +1,171 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class encapsulates information about a printed document.
+ */
+public final class PrintDocumentInfo implements Parcelable {
+
+ /**
+ * Constant for unknown page count (default).
+ */
+ public static final int PAGE_COUNT_UNKNOWN = -1;
+
+ /**
+ * Content type: unknown (default).
+ */
+ public static final int CONTENT_TYPE_UNKNOWN = -1;
+
+ /**
+ * Content type: document.
+ */
+ public static final int CONTENT_TYPE_DOCUMENT = 0;
+
+ /**
+ * Content type: photo.
+ */
+ public static final int CONTENT_TYPE_PHOTO = 1;
+
+ private int mPageCount;
+ private int mContentType;
+
+ /**
+ * Creates a new instance.
+ */
+ private PrintDocumentInfo() {
+ mPageCount = PAGE_COUNT_UNKNOWN;
+ mContentType = CONTENT_TYPE_UNKNOWN;
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param Prototype from which to clone.
+ */
+ private PrintDocumentInfo(PrintDocumentInfo prototype) {
+ mPageCount = prototype.mPageCount;
+ mContentType = prototype.mContentType;
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param parcel Data from which to initialize.
+ */
+ private PrintDocumentInfo(Parcel parcel) {
+ mPageCount = parcel.readInt();
+ mContentType = parcel.readInt();
+ }
+
+ /**
+ * Gets the total number of pages.
+ *
+ * @return The number of pages.
+ *
+ * @see #PAGE_COUNT_UNKNOWN
+ */
+ public int getPageCount() {
+ return mPageCount;
+ }
+
+ /**
+ * Gets the content type.
+ *
+ * @return The content type.
+ *
+ * @see #CONTENT_TYPE_UNKNOWN
+ * @see #CONTENT_TYPE_DOCUMENT
+ * @see #CONTENT_TYPE_PHOTO
+ */
+ public int getContentType() {
+ return mContentType;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mPageCount);
+ parcel.writeInt(mContentType);
+ }
+
+ /**
+ * Builder for creating an {@link PrintDocumentInfo}.
+ */
+ public static final class Builder {
+ private final PrintDocumentInfo mPrototype = new PrintDocumentInfo();
+
+ /**
+ * Sets the total number of pages.
+ *
+ * @param pageCount The number of pages. Must be greater than
+ * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+ */
+ public Builder setPageCount(int pageCount) {
+ if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
+ throw new IllegalArgumentException("pageCount"
+ + " must be greater than or euqal to zero or"
+ + " DocumentInfo#PAGE_COUNT_UNKNOWN");
+ }
+ mPrototype.mPageCount = pageCount;
+ return this;
+ }
+
+ /**
+ * Sets the content type.
+ *
+ * @param type The content type.
+ *
+ * @see #CONTENT_TYPE_UNKNOWN
+ * @see #CONTENT_TYPE_DOCUMENT
+ * @see #CONTENT_TYPE_PHOTO
+ */
+ public Builder setContentType(int type) {
+ mPrototype.mContentType = type;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link PrintDocumentInfo} instance.
+ *
+ * @return The new instance.
+ */
+ public PrintDocumentInfo create() {
+ return new PrintDocumentInfo(mPrototype);
+ }
+ }
+
+ public static final Parcelable.Creator<PrintDocumentInfo> CREATOR =
+ new Creator<PrintDocumentInfo>() {
+ @Override
+ public PrintDocumentInfo createFromParcel(Parcel parcel) {
+ return new PrintDocumentInfo(parcel);
+ }
+
+ @Override
+ public PrintDocumentInfo[] newArray(int size) {
+ return new PrintDocumentInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/print/PrintFileAdapter.java b/core/java/android/print/PrintFileAdapter.java
deleted file mode 100644
index dab9648..0000000
--- a/core/java/android/print/PrintFileAdapter.java
+++ /dev/null
@@ -1,125 +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.os.AsyncTask;
-import android.os.CancellationSignal;
-import android.os.CancellationSignal.OnCancelListener;
-import android.util.Log;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Adapter for printing files.
- */
-class PrintFileAdapter extends PrintAdapter {
-
- private static final String LOG_TAG = "PrintFileAdapter";
-
- private final File mFile;
-
- private WriteFileAsyncTask mWriteFileAsyncTask;
-
- public PrintFileAdapter(File file) {
- if (file == null) {
- throw new IllegalArgumentException("File cannot be null!");
- }
- mFile = file;
- }
-
- @Override
- public void onPrint(List<PageRange> pages, FileDescriptor destination,
- CancellationSignal cancellationSignal, PrintResultCallback callback) {
- mWriteFileAsyncTask = new WriteFileAsyncTask(mFile, destination, cancellationSignal,
- callback);
- mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
- (Void[]) null);
-
- }
-
- @Override
- public PrintAdapterInfo getInfo() {
- // TODO: When we have PDF render library we should query the page count.
- return new PrintAdapterInfo.Builder().create();
- }
-
- private static final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
-
- private final File mSource;
-
- private final FileDescriptor mDestination;
-
- private final PrintResultCallback mResultCallback;
-
- private final CancellationSignal mCancellationSignal;
-
- public WriteFileAsyncTask(File source, FileDescriptor destination,
- CancellationSignal cancellationSignal, PrintResultCallback callback) {
- mSource = source;
- mDestination = destination;
- mResultCallback = callback;
- mCancellationSignal = cancellationSignal;
- mCancellationSignal.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel() {
- cancel(true);
- }
- });
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- InputStream in = null;
- OutputStream out = new FileOutputStream(mDestination);
- final byte[] buffer = new byte[8192];
- try {
- in = new FileInputStream(mSource);
- while (true) {
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
- }
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error writing data!", ioe);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- if (!isCancelled()) {
- List<PageRange> pages = new ArrayList<PageRange>();
- pages.add(PageRange.ALL_PAGES);
- mResultCallback.onPrintFinished(pages);
- } else {
- mResultCallback.onPrintFailed("Cancelled");
- }
- }
- return null;
- }
- }
-}
-
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index f7cca87..a5e0b79 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -55,7 +55,7 @@
* @return The print job info.
*/
public PrintJobInfo getInfo() {
- PrintJobInfo info = mPrintManager.getPrintJob(mId);
+ PrintJobInfo info = mPrintManager.getPrintJobInfo(mId);
if (info != null) {
mCachedInfo = info;
}
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 72d6057..6e613bc 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -116,6 +116,44 @@
/** The print job attributes size. */
private PrintAttributes mAttributes;
+ /** Information about the printed document. */
+ private PrintDocumentInfo mDocumentInfo;
+
+ /** @hide*/
+ public PrintJobInfo() {
+ /* do nothing */
+ }
+
+ /** @hide */
+ public PrintJobInfo(PrintJobInfo other) {
+ mId = other.mId;
+ mLabel = other.mLabel;
+ mPrinterId = other.mPrinterId;
+ mState = other.mState;
+ mAppId = other.mAppId;
+ mUserId = other.mUserId;
+ mAttributes = other.mAttributes;
+ mDocumentInfo = other.mDocumentInfo;
+ }
+
+ private PrintJobInfo(Parcel parcel) {
+ mId = parcel.readInt();
+ mLabel = parcel.readCharSequence();
+ mPrinterId = parcel.readParcelable(null);
+ mState = parcel.readInt();
+ mAppId = parcel.readInt();
+ mUserId = parcel.readInt();
+ if (parcel.readInt() == 1) {
+ mPageRanges = (PageRange[]) parcel.readParcelableArray(null);
+ }
+ if (parcel.readInt() == 1) {
+ mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel);
+ }
+ if (parcel.readInt() == 1) {
+ mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel);
+ }
+ }
+
/**
* Gets the unique print job id.
*
@@ -300,35 +338,26 @@
mAttributes = attributes;
}
- /** @hide*/
- public PrintJobInfo() {
- /* do nothing */
+ /**
+ * Gets the info describing the printed document.
+ *
+ * @return The document info.
+ *
+ * @hide
+ */
+ public PrintDocumentInfo getDocumentInfo() {
+ return mDocumentInfo;
}
- /** @hide */
- public PrintJobInfo(PrintJobInfo other) {
- mId = other.mId;
- mLabel = other.mLabel;
- mPrinterId = other.mPrinterId;
- mState = other.mState;
- mAppId = other.mAppId;
- mUserId = other.mUserId;
- mAttributes = other.mAttributes;
- }
-
- private PrintJobInfo(Parcel parcel) {
- mId = parcel.readInt();
- mLabel = parcel.readCharSequence();
- mPrinterId = parcel.readParcelable(null);
- mState = parcel.readInt();
- mAppId = parcel.readInt();
- mUserId = parcel.readInt();
- if (parcel.readInt() == 1) {
- mPageRanges = (PageRange[]) parcel.readParcelableArray(null);
- }
- if (parcel.readInt() == 1) {
- mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel);
- }
+ /**
+ * Sets the info describing the printed document.
+ *
+ * @param info The document info.
+ *
+ * @hide
+ */
+ public void setDocumentInfo(PrintDocumentInfo info) {
+ mDocumentInfo = info;
}
@Override
@@ -356,6 +385,12 @@
} else {
parcel.writeInt(0);
}
+ if (mDocumentInfo != null) {
+ parcel.writeInt(1);
+ mDocumentInfo.writeToParcel(parcel, flags);
+ } else {
+ parcel.writeInt(0);
+ }
}
@Override
@@ -366,7 +401,10 @@
builder.append(", id: ").append(mId);
builder.append(", status: ").append(stateToString(mState));
builder.append(", printer: " + mPrinterId);
- builder.append(", attributes: " + (mAttributes != null ? mAttributes.toString() : null));
+ builder.append(", attributes: " + (mAttributes != null
+ ? mAttributes.toString() : null));
+ builder.append(", documentInfo: " + (mDocumentInfo != null
+ ? mDocumentInfo.toString() : null));
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index be9b596..5ca19d4 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -26,7 +26,8 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.print.PrintAdapter.PrintResultCallback;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.util.Log;
import com.android.internal.os.SomeArgs;
@@ -103,7 +104,7 @@
* Creates an instance that can access all print jobs.
*
* @param userId The user id for which to get all print jobs.
- * @return An instance of the caller has the permission to access
+ * @return An instance if the caller has the permission to access
* all print jobs, null otherwise.
*
* @hide
@@ -112,11 +113,11 @@
return new PrintManager(mContext, mService, userId, APP_ID_ANY);
}
- PrintJobInfo getPrintJob(int printJobId) {
+ PrintJobInfo getPrintJobInfo(int printJobId) {
try {
- return mService.getPrintJob(printJobId, mAppId, mUserId);
+ return mService.getPrintJobInfo(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting print job:" + printJobId, re);
+ Log.e(LOG_TAG, "Error getting a print job info:" + printJobId, re);
}
return null;
}
@@ -130,7 +131,7 @@
*/
public List<PrintJob> getPrintJobs() {
try {
- List<PrintJobInfo> printJobInfos = mService.getPrintJobs(mAppId, mUserId);
+ List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
if (printJobInfos == null) {
return Collections.emptyList();
}
@@ -141,18 +142,17 @@
}
return printJobs;
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error getting print jobs!", re);
+ Log.e(LOG_TAG, "Error getting print jobs", re);
}
return Collections.emptyList();
}
- ICancellationSignal cancelPrintJob(int printJobId) {
+ void cancelPrintJob(int printJobId) {
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error cancleing a print job:" + printJobId, re);
+ Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re);
}
- return null;
}
/**
@@ -166,24 +166,24 @@
* @see PrintJob
*/
public PrintJob print(String printJobName, File pdfFile, PrintAttributes attributes) {
- PrintFileAdapter printable = new PrintFileAdapter(pdfFile);
- return print(printJobName, printable, attributes);
+ FileDocumentAdapter documentAdapter = new FileDocumentAdapter(mContext, pdfFile);
+ return print(printJobName, documentAdapter, attributes);
}
/**
- * Creates a print job for printing a {@link PrintAdapter} with default print
+ * Creates a print job for printing a {@link PrintDocumentAdapter} with default print
* attributes.
*
* @param printJobName A name for the new print job.
- * @param printAdapter The printable adapter to print.
+ * @param documentAdapter An adapter that emits the document to print.
* @param attributes The default print job attributes.
* @return The created print job.
*
* @see PrintJob
*/
- public PrintJob print(String printJobName, PrintAdapter printAdapter,
+ public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
PrintAttributes attributes) {
- PrintAdapterDelegate delegate = new PrintAdapterDelegate(printAdapter,
+ PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
mContext.getMainLooper());
try {
PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate,
@@ -217,145 +217,118 @@
}
}
- private static final class PrintAdapterDelegate extends IPrintAdapter.Stub {
- private final Object mLock = new Object();
+ private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
+ private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish()
- private PrintAdapter mPrintAdapter;
+ private Handler mHandler; // Strong reference OK - cleared in finish()
- private Handler mHandler;
-
- public PrintAdapterDelegate(PrintAdapter printAdapter, Looper looper) {
- mPrintAdapter = printAdapter;
+ public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
+ mDocumentAdapter = documentAdapter;
mHandler = new MyHandler(looper);
}
@Override
public void start() {
- synchronized (mLock) {
- if (isFinishedLocked()) {
- return;
- }
- mHandler.obtainMessage(MyHandler.MESSAGE_START,
- mPrintAdapter).sendToTarget();
- }
+ mHandler.sendEmptyMessage(MyHandler.MSG_START);
}
@Override
- public void printAttributesChanged(PrintAttributes attributes) {
- synchronized (mLock) {
- if (isFinishedLocked()) {
- return;
- }
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = mPrintAdapter;
- args.arg2 = attributes;
- mHandler.obtainMessage(MyHandler.MESSAGE_PRINT_ATTRIBUTES_CHANGED,
- args).sendToTarget();
- }
+ public void layout(PrintAttributes oldAttributes,
+ PrintAttributes newAttributes, ILayoutResultCallback callback) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = oldAttributes;
+ args.arg2 = newAttributes;
+ args.arg3 = callback;
+ mHandler.obtainMessage(MyHandler.MSG_LAYOUT, args).sendToTarget();
}
@Override
- public void print(List<PageRange> pages, ParcelFileDescriptor fd,
- IPrintResultCallback callback) {
- synchronized (mLock) {
- if (isFinishedLocked()) {
- return;
- }
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = mPrintAdapter;
- args.arg2 = pages;
- args.arg3 = fd.getFileDescriptor();
- args.arg4 = callback;
- mHandler.obtainMessage(MyHandler.MESSAGE_PRINT, args).sendToTarget();
- }
+ public void write(List<PageRange> pages, ParcelFileDescriptor fd,
+ IWriteResultCallback callback) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = pages;
+ args.arg2 = fd.getFileDescriptor();
+ args.arg3 = callback;
+ mHandler.obtainMessage(MyHandler.MSG_WRITE, args).sendToTarget();
}
@Override
public void finish() {
- synchronized (mLock) {
- if (isFinishedLocked()) {
- return;
- }
- mHandler.obtainMessage(MyHandler.MESSAGE_FINIS,
- mPrintAdapter).sendToTarget();
- }
+ mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
}
- private boolean isFinishedLocked() {
- return mPrintAdapter == null;
+ private boolean isFinished() {
+ return mDocumentAdapter == null;
}
- private void finishLocked() {
- mPrintAdapter = null;
+ private void doFinish() {
+ mDocumentAdapter = null;
mHandler = null;
}
private final class MyHandler extends Handler {
- public static final int MESSAGE_START = 1;
- public static final int MESSAGE_PRINT_ATTRIBUTES_CHANGED = 2;
- public static final int MESSAGE_PRINT = 3;
- public static final int MESSAGE_FINIS = 4;
+ public static final int MSG_START = 1;
+ public static final int MSG_LAYOUT = 2;
+ public static final int MSG_WRITE = 3;
+ public static final int MSG_FINISH = 4;
public MyHandler(Looper looper) {
super(looper, null, true);
}
@Override
+ @SuppressWarnings("unchecked")
public void handleMessage(Message message) {
+ if (isFinished()) {
+ return;
+ }
switch (message.what) {
- case MESSAGE_START: {
- PrintAdapter adapter = (PrintAdapter) message.obj;
- adapter.onStart();
+ case MSG_START: {
+ mDocumentAdapter.onStart();
} break;
- case MESSAGE_PRINT_ATTRIBUTES_CHANGED: {
+ case MSG_LAYOUT: {
SomeArgs args = (SomeArgs) message.obj;
- PrintAdapter adapter = (PrintAdapter) args.arg1;
- PrintAttributes attributes = (PrintAttributes) args.arg2;
+ PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
+ PrintAttributes newAttributes = (PrintAttributes) args.arg2;
+ ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
args.recycle();
- adapter.onPrintAttributesChanged(attributes);
- } break;
- case MESSAGE_PRINT: {
- SomeArgs args = (SomeArgs) message.obj;
- PrintAdapter adapter = (PrintAdapter) args.arg1;
- @SuppressWarnings("unchecked")
- List<PageRange> pages = (List<PageRange>) args.arg2;
- final FileDescriptor fd = (FileDescriptor) args.arg3;
- IPrintResultCallback callback = (IPrintResultCallback) args.arg4;
- args.recycle();
try {
ICancellationSignal remoteSignal = CancellationSignal.createTransport();
- callback.onPrintStarted(adapter.getInfo(), remoteSignal);
+ callback.onLayoutStarted(remoteSignal);
- CancellationSignal localSignal = CancellationSignal.fromTransport(
- remoteSignal);
- adapter.onPrint(pages, fd, localSignal,
- new PrintResultCallbackWrapper(callback) {
- @Override
- public void onPrintFinished(List<PageRange> pages) {
- IoUtils.closeQuietly(fd);
- super.onPrintFinished(pages);
- }
+ mDocumentAdapter.onLayout(oldAttributes, newAttributes,
+ CancellationSignal.fromTransport(remoteSignal),
+ new LayoutResultCallbackWrapper(callback));
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error printing", re);
+ }
+ } break;
- @Override
- public void onPrintFailed(CharSequence error) {
- IoUtils.closeQuietly(fd);
- super.onPrintFailed(error);
- }
- });
+ 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;
+ 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);
}
} break;
- case MESSAGE_FINIS: {
- PrintAdapter adapter = (PrintAdapter) message.obj;
- adapter.onFinish();
- synchronized (mLock) {
- finishLocked();
- }
+ case MSG_FINISH: {
+ mDocumentAdapter.onFinish();
+ doFinish();
} break;
default: {
@@ -367,29 +340,65 @@
}
}
- private static abstract class PrintResultCallbackWrapper extends PrintResultCallback {
+ private static final class WriteResultCallbackWrapper extends WriteResultCallback {
- private final IPrintResultCallback mWrappedCallback;
+ private final IWriteResultCallback mWrappedCallback;
+ private final FileDescriptor mFd;
- public PrintResultCallbackWrapper(IPrintResultCallback callback) {
+ public WriteResultCallbackWrapper(IWriteResultCallback callback,
+ FileDescriptor fd) {
mWrappedCallback = callback;
+ mFd = fd;
}
@Override
- public void onPrintFinished(List<PageRange> pages) {
+ public void onWriteFinished(List<PageRange> pages) {
try {
- mWrappedCallback.onPrintFinished(pages);
+ // 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 onPrintFinished", re);
+ Log.e(LOG_TAG, "Error calling onWriteFinished", re);
}
}
@Override
- public void onPrintFailed(CharSequence error) {
+ public void onWriteFailed(CharSequence error) {
try {
- mWrappedCallback.onPrintFailed(error);
+ // 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 onPrintFailed", 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 b853eb0..8a3148c 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -54,7 +54,7 @@
*
* @hide
*/
- public ComponentName getServiceComponentName() {
+ public ComponentName getService() {
return mServiceComponentName;
}
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 9283472..da3b6bc 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -86,6 +86,31 @@
mDefaults.put(PROPERTY_ORIENTATION, DEFAULT_UNDEFINED);
}
+ private PrinterInfo(PrinterInfo prototype) {
+ mId = prototype.mId;
+ mLabel = prototype.mLabel;
+ mStatus = prototype.mStatus;
+
+ 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;
+
+ 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));
+ }
+ mDefaultMargins = prototype.mDefaultMargins;
+ }
+
/**
* Get the globally unique printer id.
*
@@ -437,7 +462,7 @@
* </p>
*/
public static final class Builder {
- private final PrinterInfo mPrinterInfo;
+ private final PrinterInfo mPrototype;
/**
* Creates a new instance.
@@ -455,9 +480,9 @@
if (TextUtils.isEmpty(label)) {
throw new IllegalArgumentException("label cannot be empty.");
}
- mPrinterInfo = new PrinterInfo();
- mPrinterInfo.mLabel = label;
- mPrinterInfo.mId = printerId;
+ mPrototype = new PrinterInfo();
+ mPrototype.mLabel = label;
+ mPrototype.mId = printerId;
}
/**
@@ -470,7 +495,7 @@
* @return This builder.
*/
public Builder setStatus(int status) {
- mPrinterInfo.mStatus = status;
+ mPrototype.mStatus = status;
return this;
}
@@ -489,11 +514,11 @@
* @see PrintAttributes.MediaSize
*/
public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
- final int insertionIndex = mPrinterInfo.mMediaSizes.size();
- mPrinterInfo.mMediaSizes.add(mediaSize);
+ final int insertionIndex = mPrototype.mMediaSizes.size();
+ mPrototype.mMediaSizes.add(mediaSize);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_MEDIA_SIZE);
- mPrinterInfo.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex);
+ mPrototype.mDefaults.put(PROPERTY_MEDIA_SIZE, insertionIndex);
}
return this;
}
@@ -514,11 +539,11 @@
* @see PrintAttributes.Resolution
*/
public Builder addResolution(Resolution resolution, boolean isDefault) {
- final int insertionIndex = mPrinterInfo.mResolutions.size();
- mPrinterInfo.mResolutions.add(resolution);
+ final int insertionIndex = mPrototype.mResolutions.size();
+ mPrototype.mResolutions.add(resolution);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_RESOLUTION);
- mPrinterInfo.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex);
+ mPrototype.mDefaults.put(PROPERTY_RESOLUTION, insertionIndex);
}
return this;
}
@@ -543,8 +568,8 @@
throw new IllegalArgumentException("Default margins"
+ " cannot be outside of the min margins.");
}
- mPrinterInfo.mMinMargins = margins;
- mPrinterInfo.mDefaultMargins = defaultMargins;
+ mPrototype.mMinMargins = margins;
+ mPrototype.mDefaultMargins = defaultMargins;
return this;
}
@@ -564,14 +589,14 @@
* @see PrintAttributes.Tray
*/
public Builder addInputTray(Tray inputTray, boolean isDefault) {
- if (mPrinterInfo.mInputTrays == null) {
- mPrinterInfo.mInputTrays = new ArrayList<Tray>();
+ if (mPrototype.mInputTrays == null) {
+ mPrototype.mInputTrays = new ArrayList<Tray>();
}
- final int insertionIndex = mPrinterInfo.mInputTrays.size();
- mPrinterInfo.mInputTrays.add(inputTray);
+ final int insertionIndex = mPrototype.mInputTrays.size();
+ mPrototype.mInputTrays.add(inputTray);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY);
- mPrinterInfo.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex);
+ mPrototype.mDefaults.put(PROPERTY_INPUT_TRAY, insertionIndex);
}
return this;
}
@@ -592,14 +617,14 @@
* @see PrintAttributes.Tray
*/
public Builder addOutputTray(Tray outputTray, boolean isDefault) {
- if (mPrinterInfo.mOutputTrays == null) {
- mPrinterInfo.mOutputTrays = new ArrayList<Tray>();
+ if (mPrototype.mOutputTrays == null) {
+ mPrototype.mOutputTrays = new ArrayList<Tray>();
}
- final int insertionIndex = mPrinterInfo.mOutputTrays.size();
- mPrinterInfo.mOutputTrays.add(outputTray);
+ final int insertionIndex = mPrototype.mOutputTrays.size();
+ mPrototype.mOutputTrays.add(outputTray);
if (isDefault) {
throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY);
- mPrinterInfo.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex);
+ mPrototype.mDefaults.put(PROPERTY_OUTPUT_TRAY, insertionIndex);
}
return this;
}
@@ -631,8 +656,8 @@
throw new IllegalArgumentException("Default color mode not in color modes.");
}
PrintAttributes.enforceValidColorMode(colorModes);
- mPrinterInfo.mColorModes = colorModes;
- mPrinterInfo.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode);
+ mPrototype.mColorModes = colorModes;
+ mPrototype.mDefaults.put(PROPERTY_COLOR_MODE, defaultColorMode);
return this;
}
@@ -664,8 +689,8 @@
throw new IllegalArgumentException("Default duplex mode not in duplex modes.");
}
PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
- mPrinterInfo.mDuplexModes = duplexModes;
- mPrinterInfo.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode);
+ mPrototype.mDuplexModes = duplexModes;
+ mPrototype.mDefaults.put(PROPERTY_DUPLEX_MODE, defaultDuplexMode);
return this;
}
@@ -696,8 +721,8 @@
throw new IllegalArgumentException("Default fitting mode not in fiting modes.");
}
PrintAttributes.enfoceValidFittingMode(defaultFittingMode);
- mPrinterInfo.mFittingModes = fittingModes;
- mPrinterInfo.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode);
+ mPrototype.mFittingModes = fittingModes;
+ mPrototype.mDefaults.put(PROPERTY_FITTING_MODE, defaultFittingMode);
return this;
}
@@ -728,8 +753,8 @@
throw new IllegalArgumentException("Default orientation not in orientations.");
}
PrintAttributes.enforceValidOrientation(defaultOrientation);
- mPrinterInfo.mOrientations = orientations;
- mPrinterInfo.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation);
+ mPrototype.mOrientations = orientations;
+ mPrototype.mDefaults.put(PROPERTY_ORIENTATION, defaultOrientation);
return this;
}
@@ -743,41 +768,41 @@
* @throws IllegalStateException If a required attribute was not specified.
*/
public PrinterInfo create() {
- if (mPrinterInfo.mMediaSizes == null || mPrinterInfo.mMediaSizes.isEmpty()) {
+ if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
throw new IllegalStateException("No media size specified.");
}
- if (mPrinterInfo.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults.valueAt(PROPERTY_MEDIA_SIZE) == DEFAULT_UNDEFINED) {
throw new IllegalStateException("No default media size specified.");
}
- if (mPrinterInfo.mResolutions == null || mPrinterInfo.mResolutions.isEmpty()) {
+ if (mPrototype.mResolutions == null || mPrototype.mResolutions.isEmpty()) {
throw new IllegalStateException("No resolution specified.");
}
- if (mPrinterInfo.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults.valueAt(PROPERTY_RESOLUTION) == DEFAULT_UNDEFINED) {
throw new IllegalStateException("No default resolution specified.");
}
- if (mPrinterInfo.mColorModes == 0) {
+ if (mPrototype.mColorModes == 0) {
throw new IllegalStateException("No color mode specified.");
}
- if (mPrinterInfo.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults.valueAt(PROPERTY_COLOR_MODE) == DEFAULT_UNDEFINED) {
throw new IllegalStateException("No default color mode specified.");
}
- if (mPrinterInfo.mOrientations == 0) {
+ if (mPrototype.mOrientations == 0) {
throw new IllegalStateException("No oprientation specified.");
}
- if (mPrinterInfo.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults.valueAt(PROPERTY_ORIENTATION) == DEFAULT_UNDEFINED) {
throw new IllegalStateException("No default orientation specified.");
}
- if (mPrinterInfo.mMinMargins == null) {
- mPrinterInfo.mMinMargins = new Margins(0, 0, 0, 0);
+ if (mPrototype.mMinMargins == null) {
+ mPrototype.mMinMargins = new Margins(0, 0, 0, 0);
}
- if (mPrinterInfo.mDefaultMargins == null) {
- mPrinterInfo.mDefaultMargins = mPrinterInfo.mMinMargins;
+ if (mPrototype.mDefaultMargins == null) {
+ mPrototype.mDefaultMargins = mPrototype.mMinMargins;
}
- return mPrinterInfo;
+ return new PrinterInfo(mPrototype);
}
private void throwIfDefaultAlreadySpecified(int propertyIndex) {
- if (mPrinterInfo.mDefaults.get(propertyIndex) != DEFAULT_UNDEFINED) {
+ if (mPrototype.mDefaults.get(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 eabd96d..c72385a 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -17,6 +17,7 @@
package android.printservice;
import android.os.ICancellationSignal;
+import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.printservice.IPrintServiceClient;
@@ -28,8 +29,8 @@
*/
oneway interface IPrintService {
void setClient(IPrintServiceClient client);
- void requestCancelPrintJob(in PrintJobInfo printJob);
- void onPrintJobQueued(in PrintJobInfo printJob);
- void startPrinterDiscovery();
+ void requestCancelPrintJob(in PrintJobInfo printJobInfo);
+ void onPrintJobQueued(in PrintJobInfo printJobInfo);
+ void startPrinterDiscovery(IPrinterDiscoveryObserver observer);
void stopPrinterDiscovery();
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index cff8c02..cdde4d8 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -27,11 +27,9 @@
* @hide
*/
interface IPrintServiceClient {
- List<PrintJobInfo> getPrintJobs();
- PrintJobInfo getPrintJob(int printJobId);
+ List<PrintJobInfo> getPrintJobInfos();
+ PrintJobInfo getPrintJobInfo(int printJobId);
boolean setPrintJobState(int printJobId, int status);
boolean setPrintJobTag(int printJobId, String tag);
oneway void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
- oneway void addDiscoveredPrinters(in List<PrinterInfo> printers);
- oneway void removeDiscoveredPrinters(in List<PrinterId> printers);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
new file mode 100644
index 0000000..2a1581a
--- /dev/null
+++ b/core/java/android/printservice/PrintDocument.java
@@ -0,0 +1,91 @@
+/*
+ * 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.printservice;
+
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.PrintDocumentInfo;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * This class represents a printed document from the perspective of a print
+ * service. It exposes APIs to query the document and obtain its data.
+ */
+public final class PrintDocument {
+
+ private static final String LOG_TAG = "PrintDocument";
+
+ private final int mPrintJobId;
+
+ private final IPrintServiceClient mPrintServiceClient;
+
+ private final PrintDocumentInfo mInfo;
+
+ PrintDocument(int printJobId, IPrintServiceClient printServiceClient,
+ PrintDocumentInfo info) {
+ mPrintJobId = printJobId;
+ mPrintServiceClient = printServiceClient;
+ mInfo = info;
+ }
+
+ /**
+ * Gets the {@link PrintDocumentInfo} that describes this document.
+ *
+ * @return The document info.
+ */
+ public PrintDocumentInfo getInfo() {
+ return mInfo;
+ }
+
+ /**
+ * Gets the data associated with this document. It is a responsibility of the
+ * client to open a stream to the returned file descriptor and fully read the
+ * data.
+ * <p>
+ * <strong>Note:</strong> It is your responsibility to close the file descriptor.
+ * </p>
+ *
+ * @return A file descriptor for reading the data or <code>null</code>.
+ */
+ public FileDescriptor getData() {
+ ParcelFileDescriptor source = null;
+ ParcelFileDescriptor sink = null;
+ try {
+ ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+ source = fds[0];
+ sink = fds[1];
+ mPrintServiceClient.writePrintJobData(sink, mPrintJobId);
+ return source.getFileDescriptor();
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling getting print job data!", re);
+ } finally {
+ if (sink != null) {
+ try {
+ sink.close();
+ } catch (IOException ioe) {
+ /* ignore */
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index f490f91..80530a7 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -16,10 +16,6 @@
package android.printservice;
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintJobInfo;
import android.util.Log;
@@ -33,19 +29,16 @@
private static final String LOG_TAG = "PrintJob";
- private final int mId;
-
private final IPrintServiceClient mPrintServiceClient;
+ private final PrintDocument mDocument;
+
private PrintJobInfo mCachedInfo;
- PrintJob(PrintJobInfo info, IPrintServiceClient client) {
- if (client == null) {
- throw new IllegalStateException("Print serivice not connected!");
- }
- mCachedInfo = info;
- mId = info.getId();
+ PrintJob(PrintJobInfo jobInfo, IPrintServiceClient client) {
+ mCachedInfo = jobInfo;
mPrintServiceClient = client;
+ mDocument = new PrintDocument(mCachedInfo.getId(), client, jobInfo.getDocumentInfo());
}
/**
@@ -54,7 +47,7 @@
* @return The id.
*/
public int getId() {
- return mId;
+ return mCachedInfo.getId();
}
/**
@@ -70,9 +63,9 @@
public PrintJobInfo getInfo() {
PrintJobInfo info = null;
try {
- info = mPrintServiceClient.getPrintJob(mId);
+ info = mPrintServiceClient.getPrintJobInfo(mCachedInfo.getId());
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Couldn't get info for job: " + mId, re);
+ Log.e(LOG_TAG, "Couldn't get info for job: " + mCachedInfo.getId(), re);
}
if (info != null) {
mCachedInfo = info;
@@ -81,6 +74,15 @@
}
/**
+ * Gets the document of this print job.
+ *
+ * @return The document.
+ */
+ public PrintDocument getDocument() {
+ return mDocument;
+ }
+
+ /**
* Gets whether this print job is queued. Such a print job is
* ready to be printed and can be started.
*
@@ -103,7 +105,7 @@
* @see #fail(CharSequence)
*/
public boolean isStarted() {
- return getInfo().getState() == PrintJobInfo.STATE_STARTED;
+ return getInfo().getState() == PrintJobInfo.STATE_STARTED;
}
/**
@@ -181,48 +183,13 @@
*/
public boolean setTag(String tag) {
try {
- return mPrintServiceClient.setPrintJobTag(mId, tag);
+ return mPrintServiceClient.setPrintJobTag(mCachedInfo.getId(), tag);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error setting tag for job:" + mId, re);
+ Log.e(LOG_TAG, "Error setting tag for job: " + mCachedInfo.getId(), re);
}
return false;
}
- /**
- * Gets the data associated with this print job. It is a responsibility of
- * the print service to open a stream to the returned file descriptor
- * and fully read the content.
- * <p>
- * <strong>Note:</strong> It is your responsibility to close the file descriptor.
- * </p>
- *
- * @return A file descriptor for reading the data or <code>null</code>.
- */
- public final FileDescriptor getData() {
- ParcelFileDescriptor source = null;
- ParcelFileDescriptor sink = null;
- try {
- ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
- source = fds[0];
- sink = fds[1];
- mPrintServiceClient.writePrintJobData(sink, mId);
- return source.getFileDescriptor();
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling getting print job data!", re);
- } finally {
- if (sink != null) {
- try {
- sink.close();
- } catch (IOException ioe) {
- /* ignore */
- }
- }
- }
- return null;
- }
-
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -235,23 +202,25 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return (mId == other.mId);
+ return (mCachedInfo.getId() == other.mCachedInfo.getId());
}
@Override
public int hashCode() {
- return mId;
+ return mCachedInfo.getId();
}
private boolean setState(int state) {
- // Best effort - update the state of the cached info since
- // we may not be able to re-fetch it later if the job gets
- // removed from the spooler.
- mCachedInfo.setState(state);
try {
- return mPrintServiceClient.setPrintJobState(mId, state);
+ if (mPrintServiceClient.setPrintJobState(mCachedInfo.getId(), state)) {
+ // Best effort - update the state of the cached info since
+ // we may not be able to re-fetch it later if the job gets
+ // removed from the spooler as a result of the state change.
+ mCachedInfo.setState(state);
+ return true;
+ }
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error setting the state of job:" + mId, re);
+ Log.e(LOG_TAG, "Error setting the state of job: " + mCachedInfo.getId(), re);
}
return false;
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 9256966..820c2d8 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -25,6 +25,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
@@ -47,7 +48,7 @@
* {@link #onStartPrinterDiscovery()} and ends with a call to
* {@link #onStopPrinterDiscovery()}. During a printer discovery
* period the print service reports newly discovered printers by
- * calling {@link #addDiscoveredPrinters(List)} and added printers
+ * calling {@link #addDiscoveredPrinters(List)} and reports added printers
* that disappeared by calling {@link #removeDiscoveredPrinters(List)}.
* Calls to {@link #addDiscoveredPrinters(List)} and
* {@link #removeDiscoveredPrinters(List)} before a call to
@@ -67,26 +68,30 @@
* a call to {@link #onPrintJobQueued(PrintJob)} is made and the print
* service may handle it immediately or schedule that for an appropriate
* time in the future. The list of all print jobs for this service
- * are be available by calling {@link #getPrintJobs()}. A queued print
- * job is one whose {@link PrintJob#isQueued()} return true.
+ * are be available by calling {@link #getPrintJobs()}.
* </p>
* <p>
* A print service is responsible for setting the print job state as
* appropriate while processing it. Initially, a print job is in a
* {@link PrintJobInfo#STATE_QUEUED} state which means that the data to
* be printed is spooled by the system and the print service can obtain
- * that data by calling {@link PrintJob#getData()}. After the print
- * service starts printing the data it should set the print job state
- * to {@link PrintJobInfo#STATE_STARTED}. Upon successful completion, the
- * print job state has to be set to {@link PrintJobInfo#STATE_COMPLETED}.
- * In a case of a failure, the print job state should be set to
- * {@link PrintJobInfo#STATE_FAILED}. If a print job is in a
- * {@link PrintJobInfo#STATE_STARTED} state and the user requests to
- * cancel it, the print service will receive a call to
- * {@link #onRequestCancelPrintJob(PrintJob)} which requests from the
- * service to do a best effort in canceling the job. In case the job
- * is successfully canceled, its state has to be set to
- * {@link PrintJobInfo#STATE_CANCELED}.
+ * that data by calling {@link PrintJob#getDocument()}. A queued print
+ * job's {@link PrintJob#isQueued()} method returns true.
+ * </p>
+ * <p>
+ * After the print service starts printing the data it should set the
+ * print job state to {@link PrintJobInfo#STATE_STARTED} by calling
+ * {@link PrintJob#start()}. Upon successful completion, the print job
+ * state has to be set to {@link PrintJobInfo#STATE_COMPLETED} by calling
+ * {@link PrintJob#complete()}. In case of a failure, the print job
+ * state should be set to {@link PrintJobInfo#STATE_FAILED} by calling
+ * {@link PrintJob#fail(CharSequence)}. If a print job is in a
+ * {@link PrintJobInfo#STATE_STARTED} state, i.e. {@link PrintJob#isStarted()}
+ * return true, and the user requests to cancel it, the print service will
+ * receive a call to {@link #onRequestCancelPrintJob(PrintJob)} which
+ * requests from the service to do a best effort in canceling the job. In
+ * case the job is successfully canceled, its state has to be set to
+ * {@link PrintJobInfo#STATE_CANCELED}. by calling {@link PrintJob#cancel()}.
* </p>
* <h3>Lifecycle</h3>
* <p>
@@ -124,9 +129,9 @@
* <p>
* A print service can be configured by specifying an optional settings
* activity which exposes service specific options, an optional add
- * prints activity which is used for manual addition of printers, etc.
- * It is a responsibility of the system to launch the settings and add
- * printers activities when appropriate.
+ * prints activity which is used for manual addition of printers, vendor
+ * name ,etc. It is a responsibility of the system to launch the settings
+ * and add printers activities when appropriate.
* </p>
* <p>
* A print service is configured by providing a
@@ -148,7 +153,7 @@
*/
public abstract class PrintService extends Service {
- private static final String LOG_TAG = PrintService.class.getSimpleName();
+ private static final String LOG_TAG = "PrintService";
/**
* The {@link Intent} action that must be declared as handled by a service
@@ -162,6 +167,7 @@
* <code><{@link android.R.styleable#PrintService print-service}></code>
* tag. This is a a sample XML file configuring a print service:
* <pre> <print-service
+ * android:vendor="SomeVendor"
* android:settingsActivity="foo.bar.MySettingsActivity"
* andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
* . . .
@@ -175,7 +181,7 @@
private IPrintServiceClient mClient;
- private boolean mDiscoveringPrinters;
+ private IPrinterDiscoveryObserver mDiscoveryObserver;
@Override
protected void attachBaseContext(Context base) {
@@ -230,29 +236,29 @@
* 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.
+ * discovery period, it will be ignored. If you want to update an already
+ * added printer, you should removed it and then re-add it.
* </p>
*
* @param printers A list with discovered printers.
*
- * @throws IllegalStateException If this service is not connected.
- *
* @see #removeDiscoveredPrinters(List)
* @see #onStartPrinterDiscovery()
* @see #onStopPrinterDiscovery()
+ *
+ * @throws IllegalStateException If this service is not connected.
*/
public final void addDiscoveredPrinters(List<PrinterInfo> printers) {
+ final IPrinterDiscoveryObserver observer;
synchronized (mLock) {
- if (mClient == null) {
- throw new IllegalStateException("Print serivice not connected!");
- }
- if (mDiscoveringPrinters) {
- try {
- // Calling with a lock into the system is fine.
- mClient.addDiscoveredPrinters(printers);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error adding discovered printers!", re);
- }
+ throwIfNotConnectedLocked();
+ observer = mDiscoveryObserver;
+ }
+ if (observer != null) {
+ try {
+ observer.addDiscoveredPrinters(printers);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error adding discovered printers", re);
}
}
}
@@ -269,37 +275,38 @@
* 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.
+ * be ignored. If you want to update an already added printer, you should
+ * removed it and then re-add it.
* </p>
*
* @param printerIds A list with disappeared printer ids.
*
- * @throws IllegalStateException If this service is not connected.
- *
* @see #addDiscoveredPrinters(List)
* @see #onStartPrinterDiscovery()
* @see #onStopPrinterDiscovery()
+ *
+ * @throws IllegalStateException If this service is not connected.
*/
public final void removeDiscoveredPrinters(List<PrinterId> printerIds) {
+ final IPrinterDiscoveryObserver observer;
synchronized (mLock) {
- if (mClient == null) {
- throw new IllegalStateException("Print serivice not connected!");
- }
- if (mDiscoveringPrinters) {
- try {
- // Calling with a lock into the system is fine.
- mClient.removeDiscoveredPrinters(printerIds);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error removing discovered printers!", re);
- }
+ throwIfNotConnectedLocked();
+ observer = mDiscoveryObserver;
+ }
+ if (observer != null) {
+ try {
+ observer.removeDiscoveredPrinters(printerIds);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error removing discovered printers", re);
}
}
}
/**
* Called when canceling of a print job is requested. The service
- * should do best effort to fulfill the request. After the print
- * job is canceled by calling {@link PrintJob#cancel()}.
+ * should do best effort to fulfill the request. After the cancellation
+ * is performed, the print job should be set to a cancelled state by
+ * calling {@link PrintJob#cancel()}.
*
* @param printJob The print job to be canceled.
*/
@@ -310,11 +317,12 @@
* Called when there is a queued print job for one of the printers
* managed by this print service. A queued print job is ready for
* processing by a print service which can get the data to be printed
- * by calling {@link PrintJob#getData()}. This service may start
+ * by calling {@link PrintJob#getDocument()}. This service may start
* processing the passed in print job or schedule handling of queued
* print jobs at a convenient time. The service can get the print
* jobs by a call to {@link #getPrintJobs()} and examine their state
- * to find the ones with state {@link PrintJobInfo#STATE_QUEUED}.
+ * to find the ones with state {@link PrintJobInfo#STATE_QUEUED} by
+ * calling {@link PrintJob#isQueued()}.
*
* @param printJob The new queued print job.
*
@@ -330,28 +338,31 @@
* @throws IllegalStateException If this service is not connected.
*/
public final List<PrintJob> getPrintJobs() {
+ final IPrintServiceClient client;
synchronized (mLock) {
- if (mClient == null) {
- throw new IllegalStateException("Print serivice not connected!");
- }
- try {
- List<PrintJob> printJobs = null;
- List<PrintJobInfo> printJobInfos = mClient.getPrintJobs();
- if (printJobInfos != null) {
- final int printJobInfoCount = printJobInfos.size();
- printJobs = new ArrayList<PrintJob>(printJobInfoCount);
- for (int i = 0; i < printJobInfoCount; i++) {
- printJobs.add(new PrintJob(printJobInfos.get(i), mClient));
- }
- }
- if (printJobs != null) {
- return printJobs;
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
- }
+ throwIfNotConnectedLocked();
+ client = mClient;
+ }
+ if (client == null) {
return Collections.emptyList();
}
+ try {
+ List<PrintJob> printJobs = null;
+ List<PrintJobInfo> printJobInfos = client.getPrintJobInfos();
+ if (printJobInfos != null) {
+ final int printJobInfoCount = printJobInfos.size();
+ printJobs = new ArrayList<PrintJob>(printJobInfoCount);
+ for (int i = 0; i < printJobInfoCount; i++) {
+ printJobs.add(new PrintJob(printJobInfos.get(i), client));
+ }
+ }
+ if (printJobs != null) {
+ return printJobs;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling getPrintJobs()", re);
+ }
+ return Collections.emptyList();
}
/**
@@ -375,8 +386,9 @@
}
@Override
- public void startPrinterDiscovery() {
- mHandler.sendEmptyMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY);
+ public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ mHandler.obtainMessage(MyHandler.MESSAGE_START_PRINTER_DISCOVERY,
+ observer).sendToTarget();
}
@Override
@@ -385,18 +397,25 @@
}
@Override
- public void requestCancelPrintJob(PrintJobInfo printJob) {
- mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB, printJob).sendToTarget();
+ public void requestCancelPrintJob(PrintJobInfo printJobInfo) {
+ mHandler.obtainMessage(MyHandler.MESSAGE_CANCEL_PRINTJOB,
+ printJobInfo).sendToTarget();
}
@Override
- public void onPrintJobQueued(PrintJobInfo printJob) {
+ public void onPrintJobQueued(PrintJobInfo printJobInfo) {
mHandler.obtainMessage(MyHandler.MESSAGE_ON_PRINTJOB_QUEUED,
- printJob).sendToTarget();
+ printJobInfo).sendToTarget();
}
};
}
+ private void throwIfNotConnectedLocked() {
+ if (mClient == null) {
+ throw new IllegalStateException("Print serivice not connected");
+ }
+ }
+
private final class MyHandler extends Handler {
public static final int MESSAGE_START_PRINTER_DISCOVERY = 1;
public static final int MESSAGE_STOP_PRINTER_DISCOVERY = 2;
@@ -414,26 +433,26 @@
switch (action) {
case MESSAGE_START_PRINTER_DISCOVERY: {
synchronized (mLock) {
- mDiscoveringPrinters = true;
+ mDiscoveryObserver = (IPrinterDiscoveryObserver) message.obj;
}
onStartPrinterDiscovery();
} break;
case MESSAGE_STOP_PRINTER_DISCOVERY: {
synchronized (mLock) {
- mDiscoveringPrinters = false;
+ mDiscoveryObserver = null;
}
onStopPrinterDiscovery();
} break;
case MESSAGE_CANCEL_PRINTJOB: {
- PrintJobInfo printJob = (PrintJobInfo) message.obj;
- onRequestCancelPrintJob(new PrintJob(printJob, mClient));
+ PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+ onRequestCancelPrintJob(new PrintJob(printJobInfo, mClient));
} break;
case MESSAGE_ON_PRINTJOB_QUEUED: {
- PrintJobInfo printJob = (PrintJobInfo) message.obj;
- onPrintJobQueued(new PrintJob(printJob, mClient));
+ PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+ onPrintJobQueued(new PrintJob(printJobInfo, mClient));
} break;
case MESSAGE_SET_CLEINT: {
@@ -441,13 +460,12 @@
synchronized (mLock) {
mClient = client;
if (client == null) {
- mDiscoveringPrinters = false;
+ mDiscoveryObserver = null;
}
}
if (client != null) {
onConnected();
} else {
- onStopPrinterDiscovery();
onDisconnected();
}
} break;
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 0370a25..43dd1b6 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -48,8 +48,6 @@
*/
public final class PrintServiceInfo implements Parcelable {
- private static final boolean DEBUG = false;
-
private static final String LOG_TAG = PrintServiceInfo.class.getSimpleName();
private static final String TAG_PRINT_SERVICE = "print-service";
@@ -97,7 +95,6 @@
* @param context Context for accessing resources.
* @throws XmlPullParserException If a XML parsing error occurs.
* @throws IOException If a I/O error occurs.
- * @hide
*/
public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
String settingsActivityName = null;
@@ -117,7 +114,7 @@
String nodeName = parser.getName();
if (!TAG_PRINT_SERVICE.equals(nodeName)) {
throw new XmlPullParserException(
- "Meta-data does not start with" + TAG_PRINT_SERVICE + " tag");
+ "Meta-data does not start with " + TAG_PRINT_SERVICE + " tag");
}
Resources resources = packageManager.getResourcesForApplication(
@@ -213,7 +210,7 @@
@Override
public int hashCode() {
- return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
+ return 31 + ((mId == null) ? 0 : mId.hashCode());
}
@Override
@@ -244,12 +241,8 @@
builder.append("PrintServiceInfo{");
builder.append("id:").append(mId).append(", ");
builder.append("resolveInfo:").append(mResolveInfo).append(", ");
- if (DEBUG) {
- builder.append("settingsActivityName:").append(mSettingsActivityName);
- builder.append("addPrintersActivityName:").append(mAddPrintersActivityName);
- } else if (mSettingsActivityName != null || mAddPrintersActivityName != null) {
- builder.append("<has meta-data>");
- }
+ builder.append("settingsActivityName:").append(mSettingsActivityName);
+ builder.append("addPrintersActivityName:").append(mAddPrintersActivityName);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4adee14..d2d1f1b 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -621,7 +621,7 @@
@Override
public void concat(Matrix matrix) {
- nConcatMatrix(mRenderer, matrix.native_instance);
+ if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
}
private static native void nConcatMatrix(int renderer, int matrix);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7447d1b..1c0e73d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1122,7 +1122,6 @@
*
* @see android.graphics.drawable.Drawable
* @see #getDrawableState()
- * @hide
*/
protected static final int[] PRESSED_STATE_SET;
/**
diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/view/transition/Fade.java
index c2aa90b..4fd60c1 100644
--- a/core/java/android/view/transition/Fade.java
+++ b/core/java/android/view/transition/Fade.java
@@ -32,6 +32,8 @@
*/
public class Fade extends Visibility {
+ private static boolean DBG = Transition.DBG && false;
+
private static final String LOG_TAG = "Fade";
private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
@@ -121,7 +123,7 @@
View view;
View startView = (startValues != null) ? startValues.view : null;
View endView = (endValues != null) ? endValues.view : null;
- if (Transition.DBG) {
+ if (DBG) {
Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/view/transition/Transition.java
index 6d5e61a..f99ddc0 100644
--- a/core/java/android/view/transition/Transition.java
+++ b/core/java/android/view/transition/Transition.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pair;
import android.util.SparseArray;
@@ -84,11 +85,14 @@
int mNumInstances = 0;
- /**
- * The set of listeners to be sent transition lifecycle events.
- */
+
+ // The set of listeners to be sent transition lifecycle events.
ArrayList<TransitionListener> mListeners = null;
+ // The set of animators collected from calls to play(), to be run in runAnimations()
+ ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap =
+ new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>();
+
/**
* Constructs a Transition object with no target objects. A transition with
* no targets defaults to running on all target objects in the scene hierarchy
@@ -203,6 +207,9 @@
*/
protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues,
TransitionValuesMaps endValues) {
+ if (DBG) {
+ Log.d(LOG_TAG, "play() for " + this);
+ }
mPlayStartValuesList.clear();
mPlayEndValuesList.clear();
ArrayMap<View, TransitionValues> endCopy =
@@ -312,20 +319,45 @@
for (int i = 0; i < startValuesList.size(); ++i) {
TransitionValues start = startValuesList.get(i);
TransitionValues end = endValuesList.get(i);
- // TODO: what to do about targetIds and itemIds?
- Animator animator = play(sceneRoot, start, end);
- if (animator != null) {
- mAnimatorMap.put(new Pair(start, end), animator);
- // Note: we've already done the check against targetIDs in these lists
- mPlayStartValuesList.add(start);
- mPlayEndValuesList.add(end);
+ // Only bother trying to animate with values that differ between start/end
+ if (start != null || end != null) {
+ if (start == null || !start.equals(end)) {
+ if (DBG) {
+ View view = (end != null) ? end.view : start.view;
+ Log.d(LOG_TAG, " differing start/end values for view " +
+ view);
+ if (start == null || end == null) {
+ if (start == null) {
+ Log.d(LOG_TAG, " " + ((start == null) ?
+ "start null, end non-null" : "start non-null, end null"));
+ }
+ } else {
+ for (String key : start.values.keySet()) {
+ Object startValue = start.values.get(key);
+ Object endValue = end.values.get(key);
+ if (startValue != endValue && !startValue.equals(endValue)) {
+ Log.d(LOG_TAG, " " + key + ": start(" + startValue +
+ "), end(" + endValue +")");
+ }
+ }
+ }
+ }
+ // TODO: what to do about targetIds and itemIds?
+ Animator animator = play(sceneRoot, start, end);
+ if (animator != null) {
+ mAnimatorMap.put(new Pair(start, end), animator);
+ // Note: we've already done the check against targetIDs in these lists
+ mPlayStartValuesList.add(start);
+ mPlayEndValuesList.add(end);
+ }
+ } else if (DBG) {
+ View view = (end != null) ? end.view : start.view;
+ Log.d(LOG_TAG, " No change for view " + view);
+ }
}
}
}
- ArrayMap<Pair<TransitionValues, TransitionValues>, Animator> mAnimatorMap =
- new ArrayMap<Pair<TransitionValues, TransitionValues>, Animator>();
-
/**
* Internal utility method for checking whether a given view/id
* is valid for this transition, where "valid" means that either
@@ -364,14 +396,20 @@
* @hide
*/
protected void runAnimations() {
-
+ if (DBG && mPlayStartValuesList.size() > 0) {
+ Log.d(LOG_TAG, "runAnimations (" + mPlayStartValuesList.size() + ") on " + this);
+ }
startTransition();
// Now walk the list of TransitionValues, calling play for each pair
for (int i = 0; i < mPlayStartValuesList.size(); ++i) {
TransitionValues start = mPlayStartValuesList.get(i);
TransitionValues end = mPlayEndValuesList.get(i);
+ Animator anim = mAnimatorMap.get(new Pair(start, end));
+ if (DBG) {
+ Log.d(LOG_TAG, " anim: " + anim);
+ }
startTransition();
- runAnimator(mAnimatorMap.get(new Pair(start, end)));
+ runAnimator(anim);
}
mPlayStartValuesList.clear();
mPlayEndValuesList.clear();
@@ -871,27 +909,35 @@
String toString(String indent) {
String result = indent + getClass().getSimpleName() + "@" +
Integer.toHexString(hashCode()) + ": ";
- result += "dur(" + mDuration + ") ";
- result += "dly(" + mStartDelay + ") ";
- result += "interp(" + mInterpolator + ") ";
- result += "tgts(";
- if (mTargetIds != null) {
- for (int i = 0; i < mTargetIds.length; ++i) {
- if (i > 0) {
- result += ", ";
- }
- result += mTargetIds[i];
- }
+ if (mDuration != -1) {
+ result += "dur(" + mDuration + ") ";
}
- if (mTargets != null) {
- for (int i = 0; i < mTargets.length; ++i) {
- if (i > 0) {
- result += ", ";
- }
- result += mTargets[i];
- }
+ if (mStartDelay != -1) {
+ result += "dly(" + mStartDelay + ") ";
}
- result += ")";
+ if (mInterpolator != null) {
+ result += "interp(" + mInterpolator + ") ";
+ }
+ if (mTargetIds != null || mTargets != null) {
+ result += "tgts(";
+ if (mTargetIds != null) {
+ for (int i = 0; i < mTargetIds.length; ++i) {
+ if (i > 0) {
+ result += ", ";
+ }
+ result += mTargetIds[i];
+ }
+ }
+ if (mTargets != null) {
+ for (int i = 0; i < mTargets.length; ++i) {
+ if (i > 0) {
+ result += ", ";
+ }
+ result += mTargets[i];
+ }
+ }
+ result += ")";
+ }
return result;
}
diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java
index b200a6d..7a3d9e2 100644
--- a/core/java/android/view/transition/TransitionManager.java
+++ b/core/java/android/view/transition/TransitionManager.java
@@ -17,6 +17,7 @@
package android.view.transition;
import android.util.ArrayMap;
+import android.util.Log;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -36,6 +37,8 @@
public class TransitionManager {
// TODO: how to handle enter/exit?
+ private static String LOG_TAG = "TransitionManager";
+
private static final Transition sDefaultTransition = new AutoTransition();
private Transition mDefaultTransition = new AutoTransition();
@@ -164,6 +167,7 @@
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ sPendingTransitions.remove(sceneRoot);
// Add to running list, handle end to remove it
sRunningTransitions.put(sceneRoot, transition);
transition.addListener(new Transition.TransitionListenerAdapter() {
@@ -316,8 +320,11 @@
* value of null causes the TransitionManager to use the default transition.
*/
public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
-
- if (!sPendingTransitions.contains(sceneRoot)) {
+ if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.hasLayout()) {
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
+ sceneRoot + ", " + transition);
+ }
sPendingTransitions.add(sceneRoot);
if (transition == null) {
transition = sDefaultTransition;
@@ -325,13 +332,7 @@
final Transition finalTransition = transition.clone();
sceneChangeSetup(sceneRoot, transition);
sceneRoot.setCurrentScene(null);
- sceneRoot.postOnAnimation(new Runnable() {
- @Override
- public void run() {
- sPendingTransitions.remove(sceneRoot);
- sceneChangeRunTransition(sceneRoot, finalTransition);
- }
- });
+ sceneChangeRunTransition(sceneRoot, finalTransition);
}
}
}
diff --git a/core/java/android/view/transition/TransitionValues.java b/core/java/android/view/transition/TransitionValues.java
index f361666..6e5d3d3 100644
--- a/core/java/android/view/transition/TransitionValues.java
+++ b/core/java/android/view/transition/TransitionValues.java
@@ -53,6 +53,23 @@
public final Map<String, Object> values = new ArrayMap<String, Object>();
@Override
+ public boolean equals(Object other) {
+ if (other instanceof TransitionValues) {
+ if (view == ((TransitionValues) other).view) {
+ if (values.equals(((TransitionValues) other).values)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31*view.hashCode() + values.hashCode();
+ }
+
+ @Override
public String toString() {
String returnValue = "TransitionValues@" + Integer.toHexString(hashCode()) + ":\n";
returnValue += " view = " + view + "\n";
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 8b51bf3..52433a5 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1207,15 +1207,13 @@
*/
public void setFastScrollEnabled(boolean enabled) {
mFastScrollEnabled = enabled;
- if (enabled) {
- if (mFastScroller == null) {
- mFastScroller = new FastScroller(getContext(), this);
- }
- } else {
- if (mFastScroller != null) {
- mFastScroller.stop();
- mFastScroller = null;
- }
+
+ if (enabled && mFastScroller == null) {
+ mFastScroller = new FastScroller(getContext(), this);
+ }
+
+ if (mFastScroller != null) {
+ mFastScroller.setEnabled(enabled);
}
}
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 594b130..f3c0687 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -175,6 +175,9 @@
/** Whether decorations should be laid out from right to left. */
private boolean mLayoutFromRight;
+ /** Whether the fast scroller is enabled. */
+ private boolean mEnabled;
+
/** Whether the scrollbar and decorations should always be shown. */
private boolean mAlwaysShow;
@@ -302,6 +305,39 @@
}
/**
+ * Removes this FastScroller overlay from the host view.
+ */
+ public void remove() {
+ mOverlay.remove(mTrackImage);
+ mOverlay.remove(mThumbImage);
+ mOverlay.remove(mPreviewImage);
+ mOverlay.remove(mPrimaryText);
+ mOverlay.remove(mSecondaryText);
+ }
+
+ /**
+ * @param enabled Whether the fast scroll thumb is enabled.
+ */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+
+ if (enabled) {
+ if (mAlwaysShow) {
+ setState(STATE_VISIBLE);
+ }
+ } else {
+ stop();
+ }
+ }
+
+ /**
+ * @return Whether the fast scroll thumb is enabled.
+ */
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ /**
* @param alwaysShow Whether the fast scroll thumb should always be shown
*/
public void setAlwaysShow(boolean alwaysShow) {
@@ -329,18 +365,6 @@
setState(STATE_NONE);
}
- /**
- * @return Whether the fast scroll thumb should be shown.
- */
- public boolean shouldShow() {
- // Don't show if the list is as tall as or shorter than the thumbnail.
- if (mList.getHeight() <= mThumbImage.getHeight()) {
- return false;
- }
-
- return true;
- }
-
public void setScrollbarPosition(int position) {
if (position == View.SCROLLBAR_POSITION_DEFAULT) {
position = mList.isLayoutRtl() ?
@@ -696,7 +720,7 @@
}
public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- if (!mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) {
+ if (!mEnabled || !mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) {
setState(STATE_NONE);
return;
}
@@ -1106,6 +1130,10 @@
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (!mEnabled) {
+ return false;
+ }
+
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (isPointInside(ev.getX(), ev.getY())) {
@@ -1134,6 +1162,10 @@
}
public boolean onTouchEvent(MotionEvent me) {
+ if (!mEnabled) {
+ return false;
+ }
+
switch (me.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
if (isPointInside(me.getX(), me.getY())) {
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 3d6b116..4d0a326 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -616,7 +616,7 @@
@Override
public boolean expandActionView() {
- if (hasCollapsibleActionView()) {
+ if (!hasCollapsibleActionView()) {
return false;
}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 753f5dc..3600b76 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -200,7 +200,8 @@
static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
jobject weakThiz, jboolean allowSynchronous)
{
- sp<GLConsumer> surfaceTexture(new GLConsumer(texName, allowSynchronous));
+ sp<BufferQueue> bq = new BufferQueue(allowSynchronous);
+ sp<GLConsumer> surfaceTexture(new GLConsumer(bq, texName));
if (surfaceTexture == 0) {
jniThrowException(env, OutOfResourcesException,
"Unable to create native SurfaceTexture");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1a73f42..942d33f 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -520,6 +520,10 @@
// regular write() or copy the data to the AudioTrack's shared memory?
if (track->sharedBuffer() == 0) {
written = track->write(data + offsetInBytes, sizeInBytes);
+ // for compatibility with earlier behavior of write(), return 0 in this case
+ if (written == (ssize_t) WOULD_BLOCK) {
+ written = 0;
+ }
} else {
if (audioFormat == javaAudioTrackFields.PCM16) {
// writing to shared memory, check for capacity
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 8b7f3dd..61ace4a 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -380,10 +380,11 @@
android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
}
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss)
{
char line[1024];
jlong pss = 0;
+ jlong uss = 0;
unsigned temp;
char tmp[128];
@@ -398,23 +399,42 @@
break;
}
- if (strncmp(line, "Pss: ", 5) == 0) {
- char* c = line + 5;
- while (*c != 0 && (*c < '0' || *c > '9')) {
- c++;
+ if (line[0] == 'P') {
+ if (strncmp(line, "Pss:", 4) == 0) {
+ char* c = line + 4;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ pss += atoi(c);
+ } else if (strncmp(line, "Private_Clean:", 14)
+ || strncmp(line, "Private_Dirty:", 14)) {
+ char* c = line + 14;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ uss += atoi(c);
}
- pss += atoi(c);
}
}
fclose(fp);
+ if (outUss != NULL) {
+ if (env->GetArrayLength(outUss) >= 1) {
+ jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
+ if (outUssArray != NULL) {
+ outUssArray[0] = uss;
+ }
+ env->ReleaseLongArrayElements(outUss, outUssArray, 0);
+ }
+ }
+
return pss;
}
static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
{
- return android_os_Debug_getPssPid(env, clazz, getpid());
+ return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
}
static jint read_binder_stat(const char* stat)
@@ -689,7 +709,7 @@
(void*) android_os_Debug_getDirtyPagesPid },
{ "getPss", "()J",
(void*) android_os_Debug_getPss },
- { "getPss", "(I)J",
+ { "getPss", "(I[J)J",
(void*) android_os_Debug_getPssPid },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 33ded03..6d97d01 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -33,6 +33,7 @@
#include <sys/errno.h>
#include <sys/resource.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
@@ -381,6 +382,32 @@
return false;
}
+jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
+ jint pid, jboolean is_increased)
+{
+ char text[64];
+
+ if (is_increased) {
+ strcpy(text, "/sys/fs/cgroup/memory/sw/tasks");
+ } else {
+ strcpy(text, "/sys/fs/cgroup/memory/tasks");
+ }
+
+ struct stat st;
+ if (stat(text, &st) || !S_ISREG(st.st_mode)) {
+ return false;
+ }
+
+ int fd = open(text, O_WRONLY);
+ if (fd >= 0) {
+ sprintf(text, "%d", pid);
+ write(fd, text, strlen(text));
+ close(fd);
+ }
+
+ return true;
+}
+
void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
{
if (name == NULL) {
@@ -1022,6 +1049,7 @@
{"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
{"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
{"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj},
+ {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
{"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
{"setUid", "(I)I", (void*)android_os_Process_setUid},
{"setGid", "(I)I", (void*)android_os_Process_setGid},
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 06a5e67..0d206d3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Laat die program toe om netwerkbeleide te bestuur en program-spesifieke reëls te definieer."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verander verrekening van netwerkgebruik"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 3796f73..be512f6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"የአውታረመረብ ቋሚ መመሪያዎችን እና ትግበራ ተኮር ደንቦችን ለማደራጀት ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"የአውታረ መረብ አጠቃቀም"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1820689..39320d7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"للسماح لتطبيق بإدارة سياسات الشبكة وتحديد قواعد متعلقة بالتطبيق."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"تعديل حساب استخدام الشبكة"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index becac6c..e27ba07 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прывязка да службы апавяшчэння слухача"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a4fa7f0..2a1c01d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Разрешава на приложението да управлява правилата на мрежата и да определя такива за конкретно приложение."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"промяна на отчетността на употребата на мрежа"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 05965b3..8348e0f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet que l\'aplicació gestioni les polítiques de la xarxa i que defineixi les regles específiques d\'aplicació."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificació del càlcul d\'ús de la xarxa"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 9f3a090..836715e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikaci spravovat zásady sítě a definovat pravidla pro konkrétní aplikace."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"upravit kontrolu používání sítě"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 80e14c8..9964272 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillader, at appen kan administrere netværkspolitikker og definere appspecifikke regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"skift afregning af netværksbrug"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"adgang til underretninger"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, herunder dem, der er sendt af andre apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index be81e63..fad1558 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ermöglicht der App, Netzwerkrichtlinien zu verwalten und anwendungsspezifische Regeln festzulegen"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Zuordnung für Netzwerknutzung ändern"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 961e15e..07df59f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Επιτρέπει στην εφαρμογή τη διαχείριση των πολιτικών δικτύου και τον ορισμό κανόνων για ορισμένες εφαρμογές."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"τροποποίηση υπολογισμού χρήσης δικτύου"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4825085..ac1ef54 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Allows the app to manage network policies and define app-specific rules."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modify network usage accounting"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 615fcbe..4a4dfd0 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre las políticas de red y defina reglas específicas de la aplicación."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modificar la administración del uso de redes"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2dbe795..5069333 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que la aplicación administre políticas de red y defina reglas específicas de la aplicación."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar cálculo de uso de red"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cd3d97c..1a2bc60 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d4b1cb7..697450d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"به برنامه اجازه میدهد تا خط مشیهای شبکه را مدیریت کند و قوانین خاص برنامه را تعیین کند."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"اصلاح محاسبه استفاده از شبکه"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه میدهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامههای عادی نیست."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلانهای دسترسی"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index bded5cc..34c5eff 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Sallii sovelluksen hallinnoida verkkokäytäntöjä ja määritellä sovelluskohtaisia sääntöjä."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verkon käytön seurannan muokkaaminen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 549c4ae..6245112 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permet à l\'application de gérer les stratégies du réseau et de définir celles qui sont spécifiques à l\'application."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifier le système de comptabilisation de l\'utilisation du réseau"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 768dbd1..c55cc2f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"एप्लिकेशन को नेटवर्क नीतियां प्रबंधित करने और एप्लिकेशन-विशिष्ट नियमों को परिभाषित करने देता है."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्य एप्लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 730fb21..a73f79f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Aplikaciji omogućuje upravljanje mrežnim pravilima i određivanje pravila za aplikacije."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmjena evidencije mrežne upotrebe"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 23f8e74..42ea215 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hálózati irányelveket és meghatározza az alkalmazásspecifikus szabályokat."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"hálózathasználat elszámolásának módosítása"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ee652c5..9f8881b 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Mengizinkan apl mengelola kebijakan jaringan dan menentukan peraturan khusus apl."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"mengubah penghitungan penggunaan jaringan"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4059ad5..83a0bb6 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Consente all\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 6168fdf..f864ba5 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"מאפשר ליישום לנהל מדיניות הרשת להגדיר כללים ספציפיים-ליישום."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"שנה ניהול חשבונות של שימוש ברשת"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index eb1556d..3dba541 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"ネットワークポリシーを管理しアプリ固有のルールを定義することをアプリに許可します。"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ネットワークの課金の変更"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"アプリに対するネットワーク利用の計算方法を変更することをアプリに許可します。通常のアプリでは使用しません。"</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"通知にアクセス"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8cd152d..8cafa31 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"앱이 네트워크 정책을 관리하고 앱별 규칙을 정의할 수 있도록 허용합니다."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"네트워크 사용량 계산 수정"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ea10f2f..6335bb7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Leidžiama programai valdyti tinklo politiką ir apibrėžti konkrečios programos taisykles."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"keisti tinklo naudojimo apskaitą"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3e3ab2c..6d14fed 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ļauj lietotnei pārvaldīt tīkla politikas un noteikt lietotnes kārtulas."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Tīkla lietojuma uzskaites mainīšana"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 9260061..aa6a553 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Membenarkan apl mengurus dasar rangkaian dan menentukan peraturan khusus apl."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ubah suai perakaunan penggunaan rangkaian"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b998377..fdcf826 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Lar appen administrere retningslinjene for nettverket og definere appspesifikke regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Modifisering av regnskapsføring av nettverksbruk"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index af72700..327337c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Hiermee kan de app het netwerkbeleid beheren en app-specifieke regels definiëren."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"verrekening van netwerkgebruik aanpassen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 588df6f..c63baab 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pozwala aplikacji na zarządzanie zasadami dotyczącymi sieci i definiowanie reguł aplikacji."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modyfikowanie sposobu naliczania użycia sieci"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4d22c52..abb2a95 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que a aplicação faça a gestão de políticas de rede e defina regras específicas de aplicações."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contabilização da utilização da rede"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d9a997e..5cd4710 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Permite que o aplicativo gerencie políticas de rede e definia regras específicas para o aplicativo."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modificar contagem de uso da rede"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index c5b4fd1..6e578c7 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1064,6 +1064,10 @@
<skip />
<!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
<skip />
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<!-- no translation found for permlab_accessNotifications (7673416487873432268) -->
<skip />
<!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index a058815..42c7ca3 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -639,6 +639,10 @@
<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_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>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b742263..b2dd07d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Приложение сможет управлять сетевыми политиками и определять правила для отдельных приложений."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"Изменение учета использования сети"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"Доступ к уведомлениям"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f6a62cd..dd30fb4 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Umožňuje aplikácii spravovať pravidlá siete a definovať pravidlá pre konkrétnu aplikáciu."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"zmeniť kontrolu používania siete"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ffbae22..46fa56a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7465798..79626f8 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозвољава апликацији да управља смерницама за мрежу и одређује посебна правила за апликацију."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"измените обрачунавање коришћења мреже"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5e39d66..1618e2f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Tillåter att appen hanterar nätverkspolicyer och definierar appspecifika regler."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ändra nätverksredovisningen"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 29ef9b3..14fbef8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Inaruhusu programu kudhibiti sera za mtandao na kufafanua sheria maalum za programu."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"badilisha uthibitishaji wa matumizi ya mtandao"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"fikia arifa"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9087783..7d804ca 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"อนุญาตให้แอปพลิเคชันจัดการนโยบายเครือข่ายและกำหนดกฎเฉพาะแอปพลิเคชัน"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"แก้ไขการบันทึกบัญชีการใช้งานเครือข่าย"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index d30fb77..50aea21 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Pinapayagan ang app na pamahalaan ang mga patakaran ng network at ilarawan ang mga patakarang tukoy sa app."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"baguhin ang pagkukuwenta sa paggamit ng network"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 30691d9..167b672 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Uygulamaya, ağ politikalarını yönetme ve uygulamaya özgü kuralları tanımlama izni verir."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"ağ kullanım hesaplamasını değiştir"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index db27c85..a94925c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дозволяє програмі керувати політикою мережі та визначити спеціальні правила для програм."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змінювати облік використання мережі"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3002bcd..373fe3a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Cho phép ứng dụng quản lý chính sách mạng và xác định quy tắc dành riêng cho ứng dụng."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"sửa đổi hạch toán sử dụng mạng"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Cho phép ứng dụng sửa đổi cách tính mức sử dụng mạng so với ứng dụng. Không dành cho các ứng dụng thông thường."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"truy cập thông báo"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 52526de..21fdaf16 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允许应用管理网络政策和定义专门针对应用的规则。"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改网络使用情况记录方式"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"访问通知"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 922a4f5..e627034 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"允許應用程式管理網路政策並定義應用程式專用規則。"</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"修改網路使用量計算方式"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允許應用程式修改應用程式網路使用量的計算方式 (不建議一般應用程式使用)。"</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"存取通知"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3eaf19f..af361ac 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -639,6 +639,10 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Ivumela insiza ukuthi yengamele iigomo iphinde ichaze imithetho ehambisana ngqo nensiza."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"lungisa ukubala kokusebenza kohleloxhumano"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
+ <!-- no translation found for permlab_markNetworkSocket (3658527214914959749) -->
+ <skip />
+ <!-- no translation found for permdesc_markNetworkSocket (7655568433696356578) -->
+ <skip />
<string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 37c5d48..eba3f42 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4169,88 +4169,93 @@
<!-- Printing -->
- <!-- ISO A0 media size: 33.11" × 46.81" -->
+ <!-- ISO (European standard) A0 media (paper) size: 33.11" × 46.81" -->
<string name="mediaSize_iso_a0">ISO A0</string>
- <!-- ISO A1 media size: 23.39" × 33.11" -->
+ <!-- ISO (European standard) A1 media (paper) size: 23.39" × 33.11" -->
<string name="mediaSize_iso_a1">ISO A1</string>
- <!-- ISO A2 media size: 16.54" x 23.39" -->
+ <!-- ISO (European standard) A2 media (paper) size: 16.54" x 23.39" -->
<string name="mediaSize_iso_a2">ISO A2</string>
- <!-- ISO A3 media size: 11.69" x 16.54" -->
+ <!-- ISO (European standard) A3 media (paper) size: 11.69" x 16.54" -->
<string name="mediaSize_iso_a3">ISO A3</string>
- <!-- ISO A4 media size: 8.27" x 11.69" -->
+ <!-- ISO (European standard) A4 media (paper) size: 8.27" x 11.69" -->
<string name="mediaSize_iso_a4">ISO A4</string>
- <!-- ISO A5 media size: 5.83" x 8.27" -->
+ <!-- ISO (European standard) A5 media (paper) size: 5.83" x 8.27" -->
<string name="mediaSize_iso_a5">ISO A5</string>
- <!-- ISO A6 media size: 4.13" x 5.83" -->
+ <!-- ISO (European standard) A6 media (paper) size: 4.13" x 5.83" -->
<string name="mediaSize_iso_a6">ISO A6</string>
- <!-- ISO A7 media size: 2.91" x 4.13" -->
+ <!-- ISO (European standard) A7 media (paper) size: 2.91" x 4.13" -->
<string name="mediaSize_iso_a7">ISO A7</string>
- <!-- ISO A8 media size: 2.05" x 2.91" -->
+ <!-- ISO (European standard) A8 media (paper) size: 2.05" x 2.91" -->
<string name="mediaSize_iso_a8">ISO A8</string>
- <!-- ISO A9 media size: 1.46" x 2.05" -->
+ <!-- ISO (European standard) A9 media (paper) size: 1.46" x 2.05" -->
<string name="mediaSize_iso_a9">ISO A9</string>
- <!-- ISO A10 media size: 1.02" x 1.46" -->
+ <!-- ISO (European standard) A10 media (paper) size: 1.02" x 1.46" -->
<string name="mediaSize_iso_a10">ISO A10</string>
- <!-- ISO B0 media size: 39.37" x 55.67" -->
+ <!-- ISO (European standard) B0 media (paper) size: 39.37" x 55.67" -->
<string name="mediaSize_iso_b0">ISO B0</string>
- <!-- ISO B1 media size: 27.83" x 39.37" -->
+ <!-- ISO (European standard) B1 media (paper) size: 27.83" x 39.37" -->
<string name="mediaSize_iso_b1">ISO B1</string>
- <!-- ISO B2 media size - 19.69" x 27.83" -->
+ <!-- ISO (European standard) B2 media (paper) size - 19.69" x 27.83" -->
<string name="mediaSize_iso_b2">ISO B2</string>
- <!-- ISO B3 media size: 13.90" x 19.69" -->
+ <!-- ISO (European standard) B3 media (paper) size: 13.90" x 19.69" -->
<string name="mediaSize_iso_b3">ISO B3</string>
- <!-- ISO B4 media size: 9.84" x 13.90" -->
+ <!-- ISO (European standard) B4 media (paper) size: 9.84" x 13.90" -->
<string name="mediaSize_iso_b4">ISO B4</string>
- <!-- ISO B5 media size: 6.93" x 9.84" -->
+ <!-- ISO (European standard) B5 media (paper) size: 6.93" x 9.84" -->
<string name="mediaSize_iso_b5">ISO B5</string>
- <!-- ISO B6 media size: 4.92" x 6.93" -->
+ <!-- ISO (European standard) B6 media (paper) size: 4.92" x 6.93" -->
<string name="mediaSize_iso_b6">ISO B6</string>
- <!-- ISO B7 media size: 3.46" x 4.92" -->
+ <!-- ISO (European standard) B7 media (paper) size: 3.46" x 4.92" -->
<string name="mediaSize_iso_b7">ISO B7</string>
- <!-- ISO B8 media size: 2.44" x 3.46" -->
+ <!-- ISO (European standard) B8 media (paper) size: 2.44" x 3.46" -->
<string name="mediaSize_iso_b8">ISO B8</string>
- <!-- ISO B9 media size: 1.73" x 2.44" -->
+ <!-- ISO (European standard) B9 media (paper) size: 1.73" x 2.44" -->
<string name="mediaSize_iso_b9">ISO B9</string>
- <!-- ISO B10 media size: 1.22" x 1.73" -->
+ <!-- ISO (European standard) B10 media (paper) size: 1.22" x 1.73" -->
<string name="mediaSize_iso_b10">ISO B10</string>
- <!-- ISO C0 media size: 36.10" x 51.06" -->
+ <!-- ISO (European standard) C0 media (paper) size: 36.10" x 51.06" -->
<string name="mediaSize_iso_c0">ISO C0</string>
- <!-- ISO C1 media size: 25.51" x 36.10" -->
+ <!-- ISO (European standard) C1 media (paper) size: 25.51" x 36.10" -->
<string name="mediaSize_iso_c1">ISO C1</string>
- <!-- ISO C2 media size: 18.03" x 25.51" -->
+ <!-- ISO (European standard) C2 media (paper) size: 18.03" x 25.51" -->
<string name="mediaSize_iso_c2">ISO C2</string>
- <!-- ISO C3 media size: 12.76" x 18.03" -->
+ <!-- ISO (European standard) C3 media (paper) size: 12.76" x 18.03" -->
<string name="mediaSize_iso_c3">ISO C3</string>
- <!-- ISO C4 media size: 9.02" x 12.76" -->
+ <!-- ISO (European standard) C4 media (paper) size: 9.02" x 12.76" -->
<string name="mediaSize_iso_c4">ISO C4</string>
- <!-- ISO C5 media size: 6.38" x 9.02" -->
+ <!-- ISO (European standard) C5 media (paper) size: 6.38" x 9.02" -->
<string name="mediaSize_iso_c5">ISO C5</string>
- <!-- ISO C6 media size: 4.49" x 6.38" -->
+ <!-- ISO (European standard) C6 media (paper) size: 4.49" x 6.38" -->
<string name="mediaSize_iso_c6">ISO C6</string>
- <!-- ISO C7 media size: 3.19" x 4.49" -->
+ <!-- ISO (European standard) C7 media (paper) size: 3.19" x 4.49" -->
<string name="mediaSize_iso_c7">ISO C7</string>
- <!-- ISO ISO C8 media size: 2.24" x 3.19" -->
+ <!-- ISO ISO C8 media (paper) size: 2.24" x 3.19" -->
<string name="mediaSize_iso_c8">ISO C8</string>
- <!-- ISO ISO C9 media size: 1.57" x 2.24" -->
+ <!-- ISO ISO C9 media (paper) size: 1.57" x 2.24" -->
<string name="mediaSize_iso_c9">ISO C9</string>
- <!-- ISO C10 media size: 1.10" x 1.57" -->
+ <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
<string name="mediaSize_iso_c10">ISO C10</string>
- <!-- North America Letter media size: 8.5" × 11" -->
+ <!-- North America Letter media (paper) size: 8.5" × 11" -->
<string name="mediaSize_na_letter">Letter</string>
- <!-- North America Government Letter media size: 8.0" × 10.5" -->
+ <!-- North America Government Letter media (paper) size: 8.0" × 10.5" -->
<string name="mediaSize_na_gvrnmt_letter">Government Letter</string>
- <!-- North America Legal media size: 8.5" × 14" -->
+ <!-- North America Legal media (paper) size: 8.5" × 14" -->
<string name="mediaSize_na_legal">Legal</string>
- <!-- North America Junior Legal media size: 8.0" × 5.0" -->
+ <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" -->
<string name="mediaSize_na_junior_legal">Junior Legal</string>
- <!-- North America Ledger media size: 17" × 11" -->
+ <!-- North America Ledger media (paper) size: 17" × 11" -->
<string name="mediaSize_na_ledger">Ledger</string>
- <!-- North America Tabloid media size: 11" × 17" -->
+ <!-- North America Tabloid media (paper) size: 11" × 17" -->
<string name="mediaSize_na_tabloid">Tabloid</string>
+ <!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
+ <string name="write_fail_reason_cancelled">Cancelled</string>
+ <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
+ <string name="write_fail_reason_cannot_write">Error writing content</string>
+
<!-- PIN creation dialog message [CHAR LIMIT=none] -->
<string name="restr_pin_create_pin">Create a PIN for modifying restrictions</string>
<!-- PIN entry dialog label for PIN [CHAR LIMIT=none] -->
@@ -4267,4 +4272,5 @@
<item quantity="one">Incorrect PIN. Try again in 1 second.</item>
<item quantity="other">Incorrect PIN. Try again in <xliff:g id="count">%d</xliff:g> seconds.</item>
</plurals>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b58fcfc..e29e82b 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -907,6 +907,8 @@
<java-symbol type="string" name="mediaSize_na_ledger" />
<java-symbol type="string" name="mediaSize_na_tabloid" />
<java-symbol type="string" name="restr_pin_enter_pin" />
+ <java-symbol type="string" name="write_fail_reason_cancelled" />
+ <java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="plurals" name="abbrev_in_num_days" />
<java-symbol type="plurals" name="abbrev_in_num_hours" />
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 14ac901..fdec22b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -513,12 +513,13 @@
public native void skew(float sx, float sy);
/**
- * Preconcat the current matrix with the specified matrix.
+ * Preconcat the current matrix with the specified matrix. If the specified
+ * matrix is null, this method does nothing.
*
* @param matrix The matrix to preconcatenate with the current matrix
*/
public void concat(Matrix matrix) {
- native_concat(mNativeCanvas, matrix.native_instance);
+ if (matrix != null) native_concat(mNativeCanvas, matrix.native_instance);
}
/**
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 2b6f4cd..5ac2511 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -468,7 +468,11 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ if (mMatrix) {
+ OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ } else {
+ OP_LOGS("SetMatrix (reset)");
+ }
}
virtual const char* name() { return "SetMatrix"; }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 03f50c8..d233150 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -269,11 +269,14 @@
}
inline SkMatrix* refMatrix(SkMatrix* matrix) {
- // Copying the matrix is cheap and prevents against the user changing the original
- // matrix before the operation that uses it
- SkMatrix* copy = new SkMatrix(*matrix);
- mMatrices.add(copy);
- return copy;
+ if (matrix) {
+ // Copying the matrix is cheap and prevents against the user changing
+ // the original matrix before the operation that uses it
+ SkMatrix* copy = new SkMatrix(*matrix);
+ mMatrices.add(copy);
+ return copy;
+ }
+ return matrix;
}
inline Layer* refLayer(Layer* layer) {
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 7866df4..5856057 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -541,7 +541,8 @@
nativeFormat = Image_getPixelFormat(env, format);
- sp<CpuConsumer> consumer = new CpuConsumer(maxImages);
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages);
// TODO: throw dvm exOutOfMemoryError?
if (consumer == NULL) {
jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index 73768fe..63fd16e 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -160,7 +160,8 @@
}
// Create dummy surface using a GLConsumer
- surfaceTexture_ = new GLConsumer(0);
+ sp<BufferQueue> bq = new BufferQueue();
+ surfaceTexture_ = new GLConsumer(bq, 0);
window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(
surfaceTexture_->getBufferQueue()));
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index ae11a8c..453ef45 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -22,7 +22,7 @@
</activity>
<!-- TODO: remove when we have real clients -->
- <activity android:name=".TestActivity">
+ <activity android:name=".TestActivity" android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index ae2fe5c..659102c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -24,20 +24,21 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.IBinder.DeathRecipient;
-import android.print.IPrintAdapter;
-import android.print.IPrintManager;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrinterDiscoveryObserver;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
import android.print.PrintAttributes.Tray;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
@@ -47,6 +48,7 @@
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
+import android.view.Choreographer;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -58,7 +60,6 @@
import android.widget.Spinner;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -78,9 +79,7 @@
private static final int MIN_COPIES = 1;
- private final List<QueuedAsyncTask<?>> mTaskQueue = new ArrayList<QueuedAsyncTask<?>>();
-
- private IPrintManager mPrintManager;
+ private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this);
private IPrinterDiscoveryObserver mPrinterDiscoveryObserver;
@@ -89,9 +88,7 @@
private PrintAttributes mPrintAttributes;
- private final PrintSpooler mPrintSpooler = PrintSpooler.getInstance(this);
-
- private RemotePrintAdapter mRemotePrintAdapter;
+ private RemotePrintDocumentAdapter mRemotePrintAdapter;
// UI elements
@@ -124,11 +121,11 @@
private Spinner mOrientationSpinner;
public ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
- private boolean mPrintStarted;
-
private boolean mPrintConfirmed;
- private IBinder mPrinable;
+ private boolean mStarted;
+
+ private IBinder mIPrintDocumentAdapter;
// TODO: Implement store/restore state.
@@ -231,9 +228,6 @@
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
| WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
- mPrintManager = (IPrintManager) IPrintManager.Stub.asInterface(
- ServiceManager.getService(PRINT_SERVICE));
-
Bundle extras = getIntent().getExtras();
mPrintJobId = extras.getInt(EXTRA_PRINT_JOB_ID, -1);
@@ -251,15 +245,16 @@
mPrintAttributes = new PrintAttributes.Builder().create();
}
- mPrinable = extras.getBinder(EXTRA_PRINTABLE);
- if (mPrinable == null) {
+ mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINTABLE);
+ if (mIPrintDocumentAdapter == null) {
throw new IllegalArgumentException("Printable cannot be null");
}
- mRemotePrintAdapter = new RemotePrintAdapter(IPrintAdapter.Stub.asInterface(mPrinable),
+ mRemotePrintAdapter = new RemotePrintDocumentAdapter(
+ IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
mPrintSpooler.generateFileForPrintJob(mPrintJobId));
try {
- mPrinable.linkToDeath(mDeathRecipient, 0);
+ mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException re) {
finish();
}
@@ -271,7 +266,7 @@
@Override
protected void onDestroy() {
- mPrinable.unlinkToDeath(mDeathRecipient, 0);
+ mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
super.onDestroy();
}
@@ -361,13 +356,12 @@
for (int i = 0; i < mediaSizeCount; i++) {
MediaSize mediaSize = mediaSizes.get(i);
mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
- mediaSize, mediaSize.getLabel(getPackageManager())));
+ mediaSize, mediaSize.getLabel()));
}
final int selectedMediaSizeIndex = mediaSizes.indexOf(
mPrintAttributes.getMediaSize());
mMediaSizeSpinner.setOnItemSelectedListener(null);
mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
- mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
// Resolution.
mResolutionSpinnerAdapter.clear();
@@ -382,33 +376,49 @@
mPrintAttributes.getResolution());
mResolutionSpinner.setOnItemSelectedListener(null);
mResolutionSpinner.setSelection(selectedResolutionIndex);
- mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+
+ // AdapterView has the weird behavior to notify the selection listener for a
+ // selection event that occurred *before* the listener was registered because
+ // it does the real selection change on the next layout pass. To avoid this
+ // behavior we re-attach the listener in the next traversal window - fun!
+ Choreographer.getInstance().postCallback(
+ Choreographer.CALLBACK_TRAVERSAL, new Runnable() {
+ @Override
+ public void run() {
+ mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ mResolutionSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ }
+ }, null);
// Input tray.
mInputTraySpinnerAdapter.clear();
List<Tray> inputTrays = printer.getInputTrays();
- final int inputTrayCount = inputTrays.size();
- for (int i = 0; i < inputTrayCount; i++) {
- Tray inputTray = inputTrays.get(i);
- mInputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
- inputTray, inputTray.getLabel(getPackageManager())));
+ if (inputTrays != null) {
+ final int inputTrayCount = inputTrays.size();
+ for (int i = 0; i < inputTrayCount; i++) {
+ Tray inputTray = inputTrays.get(i);
+ mInputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
+ inputTray, inputTray.getLabel(getPackageManager())));
+ }
+ final int selectedInputTrayIndex = inputTrays.indexOf(
+ mPrintAttributes.getInputTray());
+ mInputTraySpinner.setSelection(selectedInputTrayIndex);
}
- final int selectedInputTrayIndex = inputTrays.indexOf(
- mPrintAttributes.getInputTray());
- mInputTraySpinner.setSelection(selectedInputTrayIndex);
// Output tray.
mOutputTraySpinnerAdapter.clear();
List<Tray> outputTrays = printer.getOutputTrays();
- final int outputTrayCount = outputTrays.size();
- for (int i = 0; i < outputTrayCount; i++) {
- Tray outputTray = outputTrays.get(i);
- mOutputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
- outputTray, outputTray.getLabel(getPackageManager())));
+ if (outputTrays != null) {
+ final int outputTrayCount = outputTrays.size();
+ for (int i = 0; i < outputTrayCount; i++) {
+ Tray outputTray = outputTrays.get(i);
+ mOutputTraySpinnerAdapter.add(new SpinnerItem<Tray>(
+ outputTray, outputTray.getLabel(getPackageManager())));
+ }
+ final int selectedOutputTrayIndex = outputTrays.indexOf(
+ mPrintAttributes.getOutputTray());
+ mOutputTraySpinner.setSelection(selectedOutputTrayIndex);
}
- final int selectedOutputTrayIndex = outputTrays.indexOf(
- mPrintAttributes.getOutputTray());
- mOutputTraySpinner.setSelection(selectedOutputTrayIndex);
// Duplex mode.
final int duplexModes = printer.getDuplexModes();
@@ -482,22 +492,14 @@
@Override
protected void onResume() {
super.onResume();
- try {
- mPrintManager.startDiscoverPrinters(mPrinterDiscoveryObserver);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error starting printer discovery!", re);
- }
+ mPrintSpooler.startPrinterDiscovery(mPrinterDiscoveryObserver);
notifyPrintableStartIfNeeded();
}
@Override
protected void onPause() {
super.onPause();
- try {
- mPrintManager.stopDiscoverPrinters();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error starting printer discovery!", re);
- }
+ mPrintSpooler.stopPrinterDiscovery();
notifyPrintableFinishIfNeeded();
}
@@ -518,119 +520,83 @@
private void notifyPrintableStartIfNeeded() {
if (mDestinationSpinner.getSelectedItemPosition() < 0
- || mPrintStarted) {
+ || mStarted) {
return;
}
- mPrintStarted = true;
- new QueuedAsyncTask<Void>(mTaskQueue) {
- @Override
- protected Void doInBackground(Void... params) {
- try {
- mRemotePrintAdapter.start();
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error reading printed data!", ioe);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- super.onPostExecute(result);
- updatePrintableContentIfNeeded();
- }
- }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ mStarted = true;
+ mRemotePrintAdapter.start();
+ updatePrintableContentIfNeeded();
}
private void updatePrintableContentIfNeeded() {
- if (!mPrintStarted) {
+ if (!mStarted) {
return;
}
+ // TODO: Implement old attributes tracking
mPrintSpooler.setPrintJobAttributes(mPrintJobId, mPrintAttributes);
- // TODO: Implement page selector.
- final List<PageRange> pages = new ArrayList<PageRange>();
- pages.add(PageRange.ALL_PAGES);
-
- new QueuedAsyncTask<File>(mTaskQueue) {
+ mRemotePrintAdapter.layout(new PrintAttributes.Builder().create(),
+ mPrintAttributes, new LayoutResultCallback() {
@Override
- protected File doInBackground(Void... params) {
- try {
- mRemotePrintAdapter.printAttributesChanged(mPrintAttributes);
- mRemotePrintAdapter.cancelPrint();
- mRemotePrintAdapter.print(pages);
- return mRemotePrintAdapter.getFile();
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error reading printed data!", ioe);
- }
- return null;
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ // 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) {
+ updatePrintPreview(mRemotePrintAdapter.getFile());
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ Log.e(LOG_TAG, "Error write layout: " + error);
+ finishActivity(Activity.RESULT_CANCELED);
+ }
+ });
}
@Override
- protected void onPostExecute(File file) {
- super.onPostExecute(file);
- updatePrintPreview(file);
+ public void onLayoutFailed(CharSequence error) {
+ Log.e(LOG_TAG, "Error during layout: " + error);
+ finishActivity(Activity.RESULT_CANCELED);
}
- }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ });
}
private void notifyPrintableFinishIfNeeded() {
- if (!mPrintStarted) {
+ if (!mStarted) {
return;
}
- mPrintStarted = false;
- // Cancel all pending async tasks if the activity was canceled.
if (!mPrintConfirmed) {
- final int taskCount = mTaskQueue.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- mTaskQueue.remove(i).cancel();
- }
+ mRemotePrintAdapter.cancel();
+ }
+ mRemotePrintAdapter.finish();
+
+ // If canceled or no printer, nothing to do.
+ final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
+ if (!mPrintConfirmed || selectedIndex < 0) {
+ // Update the print job's status.
+ mPrintSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_CANCELED);
+ return;
}
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- // Notify the app that printing completed.
- try {
- mRemotePrintAdapter.finish();
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error reading printed data!", ioe);
- }
+ // Update the print job's printer.
+ SpinnerItem<PrinterInfo> printerItem =
+ mDestinationSpinnerAdapter.getItem(selectedIndex);
+ PrinterId printerId = printerItem.value.getId();
+ mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId);
- // If canceled, nothing to do.
- if (!mPrintConfirmed) {
- mPrintSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_CANCELED);
- return null;
- }
-
- // No printer, nothing to do.
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex < 0) {
- // Update the print job's status.
- mPrintSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_CANCELED);
- return null;
- }
-
- // Update the print job's printer.
- SpinnerItem<PrinterInfo> printerItem =
- mDestinationSpinnerAdapter.getItem(selectedIndex);
- PrinterId printerId = printerItem.value.getId();
- mPrintSpooler.setPrintJobPrinterId(mPrintJobId, printerId);
-
- // Update the print job's status.
- mPrintSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_QUEUED);
- return null;
- }
-
- // Important: If we are canceling, then we do not wait for the write
- // to complete since the result will be discarded anyway, we simply
- // execute the finish immediately which will interrupt the write.
- }.executeOnExecutor(mPrintConfirmed ? AsyncTask.SERIAL_EXECUTOR
- : AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ // Update the print job's status.
+ mPrintSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_QUEUED);
if (DEBUG) {
if (mPrintConfirmed) {
@@ -689,30 +655,7 @@
}
}
- private abstract class QueuedAsyncTask<T> extends AsyncTask<Void, Void, T> {
-
- private final List<QueuedAsyncTask<?>> mPendingOrRunningTasks;
-
- public QueuedAsyncTask(List<QueuedAsyncTask<?>> pendingOrRunningTasks) {
- mPendingOrRunningTasks = pendingOrRunningTasks;
- }
-
- @Override
- protected void onPreExecute() {
- mPendingOrRunningTasks.add(this);
- }
-
- @Override
- protected void onPostExecute(T result) {
- mPendingOrRunningTasks.remove(this);
- }
-
- public void cancel() {
- super.cancel(true);
- mPendingOrRunningTasks.remove(this);
- }
- }
-
+ // Caution: Use this only for debugging
private final class ViewSpooledFileAsyncTask extends AsyncTask<Void, Void, Void> {
private final File mFile;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
index 2b27b69..0546a43 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
@@ -16,30 +16,18 @@
package com.android.printspooler;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
import android.content.ComponentName;
import android.content.Context;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.print.IPrintClient;
-import android.print.IPrintManager;
+import android.print.IPrintSpoolerClient;
+import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
import android.print.PrintManager;
+import android.print.PrintDocumentInfo;
import android.print.PrinterId;
import android.util.AtomicFile;
import android.util.Log;
@@ -48,6 +36,22 @@
import com.android.internal.util.FastXmlSerializer;
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
public class PrintSpooler {
private static final String LOG_TAG = PrintSpooler.class.getSimpleName();
@@ -64,17 +68,17 @@
private static final Object sLock = new Object();
- private final Object mLock = new Object();
-
private static PrintSpooler sInstance;
+ private final Object mLock = new Object();
+
private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
private final PersistenceManager mPersistanceManager;
private final Context mContext;
- private final IPrintManager mPrintManager;
+ public IPrintSpoolerClient mClient;
public static PrintSpooler getInstance(Context context) {
synchronized (sLock) {
@@ -89,8 +93,40 @@
mContext = context;
mPersistanceManager = new PersistenceManager();
mPersistanceManager.readStateLocked();
- mPrintManager = IPrintManager.Stub.asInterface(
- ServiceManager.getService("print"));
+ }
+
+ public void setCleint(IPrintSpoolerClient client) {
+ synchronized (mLock) {
+ mClient = client;
+ }
+ }
+
+ public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ IPrintSpoolerClient client = null;
+ synchronized (mLock) {
+ client = mClient;
+ }
+ if (client != null) {
+ try {
+ client.onStartPrinterDiscovery(observer);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error notifying start printer discovery.", re);
+ }
+ }
+ }
+
+ 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);
+ }
+ }
}
public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId) {
@@ -102,7 +138,7 @@
PrinterId printerId = printJob.getPrinterId();
final boolean sameComponent = (componentName == null
|| (printerId != null
- && componentName.equals(printerId.getServiceComponentName())));
+ && componentName.equals(printerId.getService())));
final boolean sameAppId = appId == PrintManager.APP_ID_ANY
|| printJob.getAppId() == appId;
final boolean sameState = state == PrintJobInfo.STATE_ANY
@@ -137,15 +173,10 @@
PrintJobInfo printJob = getPrintJob(printJobId, appId);
if (printJob != null) {
switch (printJob.getState()) {
- case PrintJobInfo.STATE_CREATED: {
- removePrintJobLocked(printJob);
- } return true;
+ case PrintJobInfo.STATE_CREATED:
case PrintJobInfo.STATE_QUEUED: {
- removePrintJobLocked(printJob);
+ setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED);
} return true;
- default: {
- return false;
- }
}
}
return false;
@@ -169,6 +200,72 @@
}
}
+ public void notifyClientForActivteJobs() {
+ IPrintSpoolerClient client = null;
+ Map<ComponentName, List<PrintJobInfo>> activeJobsPerServiceMap =
+ new HashMap<ComponentName, List<PrintJobInfo>>();
+
+ synchronized(mLock) {
+ if (mClient == null) {
+ throw new IllegalStateException("Client cannot be null.");
+ }
+ client = mClient;
+
+ final int printJobCount = mPrintJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = mPrintJobs.get(i);
+ switch (printJob.getState()) {
+ case PrintJobInfo.STATE_CREATED: {
+ /* skip - not ready to be handled by a service */
+ } break;
+
+ case PrintJobInfo.STATE_QUEUED:
+ case PrintJobInfo.STATE_STARTED: {
+ ComponentName service = printJob.getPrinterId().getService();
+ List<PrintJobInfo> jobsPerService = activeJobsPerServiceMap.get(service);
+ if (jobsPerService == null) {
+ jobsPerService = new ArrayList<PrintJobInfo>();
+ activeJobsPerServiceMap.put(service, jobsPerService);
+ }
+ jobsPerService.add(printJob);
+ } break;
+
+ default: {
+ ComponentName service = printJob.getPrinterId().getService();
+ if (!activeJobsPerServiceMap.containsKey(service)) {
+ activeJobsPerServiceMap.put(service, null);
+ }
+ }
+ }
+ }
+ }
+
+ boolean allPrintJobsHandled = true;
+
+ for (Map.Entry<ComponentName, List<PrintJobInfo>> entry
+ : activeJobsPerServiceMap.entrySet()) {
+ ComponentName service = entry.getKey();
+ List<PrintJobInfo> printJobs = entry.getValue();
+
+ if (printJobs != null) {
+ allPrintJobsHandled = false;
+ final int printJobCount = printJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ if (printJob.getState() == PrintJobInfo.STATE_QUEUED) {
+ callOnPrintJobQueuedQuietly(client, printJob);
+ }
+ }
+ } else {
+ callOnAllPrintJobsForServiceHandledQuietly(client, service);
+ }
+ }
+
+ if (allPrintJobsHandled) {
+ callOnAllPrintJobsHandledQuietly(client);
+ }
+ }
+
private int generatePrintJobIdLocked() {
int printJobId = sPrintJobIdCounter++;
while (isDuplicatePrintJobId(printJobId)) {
@@ -213,24 +310,14 @@
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error writing print job data!", ioe);
} finally {
- closeIfNotNullNoException(in);
- closeIfNotNullNoException(out);
- closeIfNotNullNoException(fd);
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(fd);
}
}
return false;
}
- private void closeIfNotNullNoException(Closeable closeable) {
- if (closeable != null) {
- try {
- closeable.close();
- } catch (IOException ioe) {
- /* ignore */;
- }
- }
- }
-
public File generateFileForPrintJob(int printJobId) {
return new File(mContext.getFilesDir(), "print_job_"
+ printJobId + "." + PRINT_FILE_EXTENSION);
@@ -254,9 +341,20 @@
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 = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null && printJob.getState() < state) {
success = true;
@@ -265,8 +363,23 @@
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED: {
+ removedPrintJob = printJob;
removePrintJobLocked(printJob);
+
+ // No printer means creation of a print job was cancelled,
+ // therefore the state of the spooler did not change and no
+ // notifications are needed. We also do not need to persist
+ // the state.
+ PrinterId printerId = printJob.getPrinterId();
+ if (printerId == null) {
+ return true;
+ }
+
+ allPrintJobsHandled = !hasActivePrintJobsLocked();
+ allPrintJobsForServiceHandled = !hasActivePrintJobsForServiceLocked(
+ printerId.getService());
} break;
+
case PrintJobInfo.STATE_QUEUED: {
queuedPrintJob = new PrintJobInfo(printJob);
} break;
@@ -279,17 +392,77 @@
}
if (queuedPrintJob != null) {
- try {
- mPrintManager.onPrintJobQueued(queuedPrintJob.getPrinterId(),
- queuedPrintJob);
- } catch (RemoteException re) {
- /* ignore */
- }
+ 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(IPrintSpoolerClient client) {
+ try {
+ client.onAllPrintJobsHandled();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
+ 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;
+ }
+ }
+ return false;
+ }
+
public boolean setPrintJobTag(int printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
@@ -302,6 +475,18 @@
return false;
}
+ public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) {
+ synchronized (mLock) {
+ PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
+ if (printJob != null) {
+ printJob.setDocumentInfo(info);
+ mPersistanceManager.writeStateLocked();
+ return true;
+ }
+ }
+ return false;
+ }
+
public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 57c4557..050332c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -29,10 +29,11 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.print.IPrintAdapter;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
-import android.print.IPrintSpoolerService;
-import android.print.IPrintSpoolerServiceCallbacks;
+import android.print.IPrintSpoolerClient;
+import android.print.IPrintSpooler;
+import android.print.IPrintSpoolerCallbacks;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
import android.util.Slog;
@@ -64,21 +65,21 @@
@Override
public IBinder onBind(Intent intent) {
- return new IPrintSpoolerService.Stub() {
+ return new IPrintSpooler.Stub() {
@Override
- public void getPrintJobs(IPrintSpoolerServiceCallbacks callback,
+ public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
ComponentName componentName, int state, int appId, int sequence)
throws RemoteException {
List<PrintJobInfo> printJobs = null;
try {
printJobs = mSpooler.getPrintJobs(componentName, state, appId);
} finally {
- callback.onGetPrintJobsResult(printJobs, sequence);
+ callback.onGetPrintJobInfosResult(printJobs, sequence);
}
}
@Override
- public void getPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback,
+ public void getPrintJobInfo(int printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
@@ -89,7 +90,7 @@
}
@Override
- public void cancelPrintJob(int printJobId, IPrintSpoolerServiceCallbacks callback,
+ public void cancelPrintJob(int printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
boolean success = false;
try {
@@ -102,8 +103,8 @@
@SuppressWarnings("deprecation")
@Override
public void createPrintJob(String printJobName, IPrintClient client,
- IPrintAdapter printAdapter, PrintAttributes attributes,
- IPrintSpoolerServiceCallbacks callback, int appId, int sequence)
+ IPrintDocumentAdapter printAdapter, PrintAttributes attributes,
+ IPrintSpoolerCallbacks callback, int appId, int sequence)
throws RemoteException {
PrintJobInfo printJob = null;
try {
@@ -134,7 +135,7 @@
@Override
public void setPrintJobState(int printJobId, int state,
- IPrintSpoolerServiceCallbacks callback, int sequece)
+ IPrintSpoolerCallbacks callback, int sequece)
throws RemoteException {
boolean success = false;
try {
@@ -148,7 +149,7 @@
@Override
public void setPrintJobTag(int printJobId, String tag,
- IPrintSpoolerServiceCallbacks callback, int sequece)
+ IPrintSpoolerCallbacks callback, int sequece)
throws RemoteException {
boolean success = false;
try {
@@ -162,6 +163,16 @@
public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
mSpooler.writePrintJobData(fd, printJobId);
}
+
+ @Override
+ public void setClient(IPrintSpoolerClient client) {
+ mSpooler.setCleint(client);
+ }
+
+ @Override
+ public void notifyClientForActivteJobs() {
+ mSpooler.notifyClientForActivteJobs();
+ }
};
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java
deleted file mode 100644
index c81b00c..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintAdapter.java
+++ /dev/null
@@ -1,219 +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 com.android.printspooler;
-
-import android.os.ICancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.print.IPrintAdapter;
-import android.print.IPrintResultCallback;
-import android.print.PageRange;
-import android.print.PrintAdapterInfo;
-import android.print.PrintAttributes;
-import android.util.Log;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-
-/**
- * This class represents a remote print adapter instance.
- */
-final class RemotePrintAdapter {
- private static final String LOG_TAG = "RemotePrintAdapter";
-
- private static final boolean DEBUG = true;
-
- private final Object mLock = new Object();
-
- private final IPrintAdapter mRemoteInterface;
-
- private final File mFile;
-
- private final IPrintResultCallback mIPrintProgressListener;
-
- private PrintAdapterInfo mInfo;
-
- private ICancellationSignal mCancellationSignal;
-
- private Thread mWriteThread;
-
- public RemotePrintAdapter(IPrintAdapter printAdatper, File file) {
- mRemoteInterface = printAdatper;
- mFile = file;
- mIPrintProgressListener = new IPrintResultCallback.Stub() {
- @Override
- public void onPrintStarted(PrintAdapterInfo info,
- ICancellationSignal cancellationSignal) {
- if (DEBUG) {
- Log.i(LOG_TAG, "IPrintProgressListener#onPrintStarted()");
- }
- synchronized (mLock) {
- mInfo = info;
- mCancellationSignal = cancellationSignal;
- }
- }
-
- @Override
- public void onPrintFinished(List<PageRange> pages) {
- if (DEBUG) {
- Log.i(LOG_TAG, "IPrintProgressListener#onPrintFinished(" + pages + ")");
- }
- synchronized (mLock) {
- if (isPrintingLocked()) {
- mWriteThread.interrupt();
- mCancellationSignal = null;
- }
- }
- }
-
- @Override
- public void onPrintFailed(CharSequence error) {
- if (DEBUG) {
- Log.i(LOG_TAG, "IPrintProgressListener#onPrintFailed(" + error + ")");
- }
- synchronized (mLock) {
- if (isPrintingLocked()) {
- mWriteThread.interrupt();
- mCancellationSignal = null;
- }
- }
- }
- };
- }
-
- public File getFile() {
- if (DEBUG) {
- Log.i(LOG_TAG, "getFile()");
- }
- return mFile;
- }
-
- public void start() throws IOException {
- if (DEBUG) {
- Log.i(LOG_TAG, "start()");
- }
- try {
- mRemoteInterface.start();
- } catch (RemoteException re) {
- throw new IOException("Error reading file", re);
- }
- }
-
- public void printAttributesChanged(PrintAttributes attributes) throws IOException {
- if (DEBUG) {
- Log.i(LOG_TAG, "printAttributesChanged(" + attributes +")");
- }
- try {
- mRemoteInterface.printAttributesChanged(attributes);
- } catch (RemoteException re) {
- throw new IOException("Error reading file", re);
- }
- }
-
- public void print(List<PageRange> pages) throws IOException {
- if (DEBUG) {
- Log.i(LOG_TAG, "print(" + pages +")");
- }
- 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.print(pages, sink, mIPrintProgressListener);
-
- // 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);
- }
- } catch (RemoteException re) {
- throw new IOException("Error reading file", re);
- } catch (IOException ioe) {
- throw new IOException("Error reading file", ioe);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(sink);
- IoUtils.closeQuietly(source);
- }
- }
-
- public void cancelPrint() throws IOException {
- if (DEBUG) {
- Log.i(LOG_TAG, "cancelPrint()");
- }
- synchronized (mLock) {
- if (isPrintingLocked()) {
- try {
- mCancellationSignal.cancel();
- } catch (RemoteException re) {
- throw new IOException("Error cancelling print", re);
- }
- }
- }
- }
-
- public void finish() throws IOException {
- if (DEBUG) {
- Log.i(LOG_TAG, "finish()");
- }
- try {
- mRemoteInterface.finish();
- } catch (RemoteException re) {
- throw new IOException("Error reading file", re);
- }
- }
-
- public PrintAdapterInfo getInfo() {
- synchronized (mLock) {
- return mInfo;
- }
- }
-
- private boolean isPrintingLocked() {
- return mCancellationSignal != null;
- }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
new file mode 100644
index 0000000..912dd95
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -0,0 +1,448 @@
+/*
+ * 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.printspooler;
+
+import android.os.AsyncTask;
+import android.os.ICancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.ILayoutResultCallback;
+import android.print.IPrintDocumentAdapter;
+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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+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.
+ */
+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_COMPLETED = 2;
+ public static final int STATE_WRITE_COMPLETED = 3;
+ public static final int STATE_FINISH_COMPLETED = 4;
+
+ private final Object mLock = new Object();
+
+ private final List<QueuedAsyncTask> mTaskQueue = new ArrayList<QueuedAsyncTask>();
+
+ 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() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "getFile()");
+ }
+ synchronized (mLock) {
+ if (mState < STATE_WRITE_COMPLETED) {
+ throw new IllegalStateException("Write not completed");
+ }
+ return mFile;
+ }
+ }
+
+ public void cancel() {
+ synchronized (mLock) {
+ final int taskCount = mTaskQueue.size();
+ for (int i = 0; i < taskCount; i++) {
+ mTaskQueue.remove(i).cancel();
+ }
+ }
+ }
+
+ 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;
+ }
+ };
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }
+ }
+
+ public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ LayoutResultCallback callback) {
+ LayoutAsyncTask task = new LayoutAsyncTask(oldAttributes, newAttributes, callback);
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }
+ }
+
+ public void write(List<PageRange> pages, WriteResultCallback callback) {
+ WriteAsyncTask task = new WriteAsyncTask(pages, callback);
+ mTaskQueue.add(task);
+ task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }
+
+ public void finish() {
+ QueuedAsyncTask task = new QueuedAsyncTask() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "finish");
+ }
+ synchronized (mLock) {
+ if (mState != STATE_LAYOUT_COMPLETED
+ && mState != STATE_WRITE_COMPLETED) {
+ throw new IllegalStateException("Invalid state: " + mState);
+ }
+ }
+ try {
+ mRemoteInterface.finish();
+ synchronized (mLock) {
+ mState = STATE_FINISH_COMPLETED;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error reading file", re);
+ mState = STATE_INITIALIZED;
+ }
+ return null;
+ }
+ };
+ synchronized (mLock) {
+ mTaskQueue.add(task);
+ task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }
+ }
+
+ private abstract class QueuedAsyncTask extends AsyncTask<Void, Void, Void> {
+ public void cancel() {
+ super.cancel(true);
+ }
+ }
+
+ private final class LayoutAsyncTask extends QueuedAsyncTask {
+
+ private final PrintAttributes mOldAttributes;
+
+ private final PrintAttributes mNewAttributes;
+
+ private final LayoutResultCallback mCallback;
+
+ private final ILayoutResultCallback mILayoutResultCallback =
+ new ILayoutResultCallback.Stub() {
+ @Override
+ public void onLayoutStarted(ICancellationSignal cancellationSignal) {
+ synchronized (mLock) {
+ mCancellationSignal = cancellationSignal;
+ if (isCancelled()) {
+ cancelSignalQuietlyLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ synchronized (mLock) {
+ mCancellationSignal = null;
+ mCompleted = true;
+ mLock.notifyAll();
+ }
+ mCallback.onLayoutFinished(info, changed);
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error) {
+ synchronized (mLock) {
+ mCancellationSignal = null;
+ mCompleted = true;
+ mLock.notifyAll();
+ }
+ Slog.e(LOG_TAG, "Error laying out print document: " + error);
+ mCallback.onLayoutFailed(error);
+ }
+ };
+
+ private ICancellationSignal mCancellationSignal;
+
+ private boolean mCompleted;
+
+ public LayoutAsyncTask(PrintAttributes oldAttributes,
+ PrintAttributes newAttributes, LayoutResultCallback callback) {
+ mOldAttributes = oldAttributes;
+ mNewAttributes = newAttributes;
+ mCallback = callback;
+ }
+
+ @Override
+ public void cancel() {
+ synchronized (mLock) {
+ throwIfCancelledLocked();
+ cancelSignalQuietlyLocked();
+ }
+ super.cancel();
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ synchronized (mLock) {
+ if (mState != STATE_START_COMPLETED
+ && mState != STATE_LAYOUT_COMPLETED
+ && mState != STATE_WRITE_COMPLETED) {
+ throw new IllegalStateException("Invalid state: " + mState);
+ }
+ }
+ try {
+ mRemoteInterface.layout(mOldAttributes, mNewAttributes,
+ mILayoutResultCallback);
+ synchronized (mLock) {
+ while (true) {
+ if (isCancelled()) {
+ mState = STATE_INITIALIZED;
+ mTaskQueue.remove(this);
+ break;
+ }
+ if (mCompleted) {
+ mState = STATE_LAYOUT_COMPLETED;
+ mTaskQueue.remove(this);
+ break;
+ }
+ try {
+ mLock.wait();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error calling layout", re);
+ mState = STATE_INITIALIZED;
+ }
+ return null;
+ }
+
+ private void cancelSignalQuietlyLocked() {
+ if (mCancellationSignal != null) {
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error cancelling layout", re);
+ }
+ }
+ }
+
+ 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) {
+ synchronized (mLock) {
+ mCancellationSignal = cancellationSignal;
+ if (isCancelled()) {
+ cancelSignalQuietlyLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onWriteFinished(List<PageRange> pages) {
+ synchronized (mLock) {
+ mCancellationSignal = null;
+ mCompleted = true;
+ mLock.notifyAll();
+ }
+ mCallback.onWriteFinished(pages);
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ synchronized (mLock) {
+ mCancellationSignal = null;
+ mCompleted = true;
+ mLock.notifyAll();
+ }
+ Slog.e(LOG_TAG, "Error writing print document: " + error);
+ mCallback.onWriteFailed(error);
+ }
+ };
+
+ private ICancellationSignal mCancellationSignal;
+
+ private boolean mCompleted;
+
+ 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, "print()");
+ }
+ synchronized (mLock) {
+ if (mState != STATE_LAYOUT_COMPLETED) {
+ throw new IllegalStateException("Invalid state: " + mState);
+ }
+ }
+ 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 (isCancelled()) {
+ mState = STATE_INITIALIZED;
+ mTaskQueue.remove(this);
+ break;
+ }
+ if (mCompleted) {
+ mState = STATE_WRITE_COMPLETED;
+ mTaskQueue.remove(this);
+ break;
+ }
+ try {
+ mLock.wait();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error writing print document", re);
+ mState = STATE_INITIALIZED;
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "Error writing print document", ioe);
+ mState = STATE_INITIALIZED;
+ } 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);
+ }
+ }
+ }
+
+ private void throwIfCancelledLocked() {
+ if (isCancelled()) {
+ throw new IllegalStateException("Already cancelled");
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 69fc3cf..b1e38d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -621,9 +621,9 @@
int maxHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
StatusBarNotification sbn = entry.notification;
- RemoteViews oneU = sbn.getNotification().contentView;
- RemoteViews large = sbn.getNotification().bigContentView;
- if (oneU == null) {
+ RemoteViews contentView = sbn.getNotification().contentView;
+ RemoteViews bigContentView = sbn.getNotification().bigContentView;
+ if (contentView == null) {
return false;
}
@@ -657,13 +657,12 @@
content.setOnClickListener(null);
}
- // TODO(cwren) normalize variable names with those in updateNotification
- View expandedOneU = null;
- View expandedLarge = null;
+ View contentViewLocal = null;
+ View bigContentViewLocal = null;
try {
- expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler);
- if (large != null) {
- expandedLarge = large.apply(mContext, adaptive, mOnClickHandler);
+ contentViewLocal = contentView.apply(mContext, adaptive, mOnClickHandler);
+ if (bigContentView != null) {
+ bigContentViewLocal = bigContentView.apply(mContext, adaptive, mOnClickHandler);
}
}
catch (RuntimeException e) {
@@ -672,26 +671,24 @@
return false;
}
- if (expandedOneU != null) {
+ if (contentViewLocal != null) {
SizeAdaptiveLayout.LayoutParams params =
- new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
+ new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams());
params.minHeight = minHeight;
params.maxHeight = minHeight;
- adaptive.addView(expandedOneU, params);
+ adaptive.addView(contentViewLocal, params);
}
- if (expandedLarge != null) {
+ if (bigContentViewLocal != null) {
SizeAdaptiveLayout.LayoutParams params =
- new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
+ new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams());
params.minHeight = minHeight+1;
params.maxHeight = maxHeight;
- adaptive.addView(expandedLarge, params);
+ adaptive.addView(bigContentViewLocal, params);
}
row.setDrawingCacheEnabled(true);
applyLegacyRowBackground(sbn, content);
- row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null));
-
if (MULTIUSER_DEBUG) {
TextView debug = (TextView) row.findViewById(R.id.debug_info);
if (debug != null) {
@@ -701,8 +698,8 @@
}
entry.row = row;
entry.content = content;
- entry.expanded = expandedOneU;
- entry.setLargeView(expandedLarge);
+ entry.expanded = contentViewLocal;
+ entry.setBigContentView(bigContentViewLocal);
return true;
}
@@ -944,8 +941,8 @@
&& oldContentView.getLayoutId() == contentView.getLayoutId();
// large view may be null
boolean bigContentsUnchanged =
- (oldEntry.getLargeView() == null && bigContentView == null)
- || ((oldEntry.getLargeView() != null && bigContentView != null)
+ (oldEntry.getBigContentView() == null && bigContentView == null)
+ || ((oldEntry.getBigContentView() != null && bigContentView != null)
&& bigContentView.getPackage() != null
&& oldBigContentView.getPackage() != null
&& oldBigContentView.getPackage().equals(bigContentView.getPackage())
@@ -965,8 +962,8 @@
try {
// Reapply the RemoteViews
contentView.reapply(mContext, oldEntry.expanded, mOnClickHandler);
- if (bigContentView != null && oldEntry.getLargeView() != null) {
- bigContentView.reapply(mContext, oldEntry.getLargeView(), mOnClickHandler);
+ if (bigContentView != null && oldEntry.getBigContentView() != null) {
+ bigContentView.reapply(mContext, oldEntry.getBigContentView(), mOnClickHandler);
}
// update the contentIntent
final PendingIntent contentIntent = notification.getNotification().contentIntent;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 673ca6b..8f62ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -38,19 +38,19 @@
public View content; // takes the click events and sends the PendingIntent
public View expanded; // the inflated RemoteViews
public ImageView largeIcon;
- protected View expandedLarge;
+ private View expandedBig;
public Entry() {}
public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
this.key = key;
this.notification = n;
this.icon = ic;
}
- public void setLargeView(View expandedLarge) {
- this.expandedLarge = expandedLarge;
- writeBooleanTag(row, R.id.expandable_tag, expandedLarge != null);
+ public void setBigContentView(View bigContentView) {
+ this.expandedBig = bigContentView;
+ writeBooleanTag(row, R.id.expandable_tag, bigContentView != null);
}
- public View getLargeView() {
- return expandedLarge;
+ public View getBigContentView() {
+ return expandedBig;
}
/**
* Return whether the entry can be expanded.
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 5b76f39..203cca6 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -70,7 +70,7 @@
mAppWidgetServices.append(0, primary);
}
- public void systemReady(boolean safeMode) {
+ public void systemRunning(boolean safeMode) {
mSafeMode = safeMode;
mAppWidgetServices.get(0).systemReady(safeMode);
diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/java/com/android/server/AssetAtlasService.java
index 33f082c..26b4652 100644
--- a/services/java/com/android/server/AssetAtlasService.java
+++ b/services/java/com/android/server/AssetAtlasService.java
@@ -186,7 +186,7 @@
* Callback invoked by the server thread to indicate we can now run
* 3rd party code.
*/
- public void systemReady() {
+ public void systemRunning() {
}
/**
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java
index c316733..aa2c8b8 100644
--- a/services/java/com/android/server/CommonTimeManagementService.java
+++ b/services/java/com/android/server/CommonTimeManagementService.java
@@ -153,7 +153,7 @@
mContext = context;
}
- void systemReady() {
+ void systemRunning() {
if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
Log.i(TAG, "No common time service detected on this platform. " +
"Common time services will be unavailable.");
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/java/com/android/server/CountryDetectorService.java
index 8407fa4..4956dd5 100644
--- a/services/java/com/android/server/CountryDetectorService.java
+++ b/services/java/com/android/server/CountryDetectorService.java
@@ -166,7 +166,7 @@
}
}
- void systemReady() {
+ void systemRunning() {
// Shall we wait for the initialization finish.
BackgroundThread.getHandler().post(this);
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1c1b002..35656f8 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -823,7 +823,7 @@
}
}
- public void systemReady(StatusBarManagerService statusBar) {
+ public void systemRunning(StatusBarManagerService statusBar) {
synchronized (mMethodMap) {
if (DEBUG) {
Slog.d(TAG, "--- systemReady");
@@ -1210,7 +1210,7 @@
mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
- | Context.BIND_NOT_VISIBLE)) {
+ | Context.BIND_NOT_VISIBLE | Context.BIND_SHOWING_UI)) {
mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index c6c9845..bde9e1c 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -198,7 +198,7 @@
// most startup is deferred until systemReady()
}
- public void systemReady() {
+ public void systemRunning() {
synchronized (mLock) {
if (D) Log.d(TAG, "systemReady()");
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index 02b42b8..cbddf67 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -108,7 +108,7 @@
}
/** Initialize the receivers and initiate the first NTP request */
- public void systemReady() {
+ public void systemRunning() {
registerForTelephonyIntents();
registerForAlarms();
registerForConnectivityIntents();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 888064c..0bbdcfb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -351,6 +351,7 @@
LockSettingsService lockSettings = null;
DreamManagerService dreamy = null;
AssetAtlasService atlas = null;
+ PrintManagerService printManager = null;
// Bring up services needed for UI.
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
@@ -793,8 +794,8 @@
try {
Slog.i(TAG, "Print Service");
- ServiceManager.addService(Context.PRINT_SERVICE,
- new PrintManagerService(context));
+ printManager = new PrintManagerService(context);
+ ServiceManager.addService(Context.PRINT_SERVICE, printManager);
} catch (Throwable e) {
reportWtf("starting Print Service", e);
}
@@ -909,6 +910,7 @@
final AssetAtlasService atlasF = atlas;
final InputManagerService inputManagerF = inputManager;
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
+ final PrintManagerService printManagerF = printManager;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -988,66 +990,73 @@
// third party code...
try {
- if (appWidgetF != null) appWidgetF.systemReady(safeMode);
+ if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
} catch (Throwable e) {
- reportWtf("making App Widget Service ready", e);
+ reportWtf("Notifying AppWidgetService running", e);
}
try {
- if (wallpaperF != null) wallpaperF.systemReady();
+ if (wallpaperF != null) wallpaperF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Wallpaper Service ready", e);
+ reportWtf("Notifying WallpaperService running", e);
}
try {
- if (immF != null) immF.systemReady(statusBarF);
+ if (immF != null) immF.systemRunning(statusBarF);
} catch (Throwable e) {
- reportWtf("making Input Method Service ready", e);
+ reportWtf("Notifying InputMethodService running", e);
}
try {
- if (locationF != null) locationF.systemReady();
+ if (locationF != null) locationF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Location Service ready", e);
+ reportWtf("Notifying Location Service running", e);
}
try {
- if (countryDetectorF != null) countryDetectorF.systemReady();
+ if (countryDetectorF != null) countryDetectorF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Country Detector Service ready", e);
+ reportWtf("Notifying CountryDetectorService running", e);
}
try {
- if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
+ if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Network Time Service ready", e);
+ reportWtf("Notifying NetworkTimeService running", e);
}
try {
- if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady();
+ if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Common time management service ready", e);
+ reportWtf("Notifying CommonTimeManagementService running", e);
}
try {
- if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
+ if (textServiceManagerServiceF != null)
+ textServiceManagerServiceF.systemRunning();
} catch (Throwable e) {
- reportWtf("making Text Services Manager Service ready", e);
+ reportWtf("Notifying TextServicesManagerService running", e);
}
try {
- if (dreamyF != null) dreamyF.systemReady();
+ if (dreamyF != null) dreamyF.systemRunning();
} catch (Throwable e) {
- reportWtf("making DreamManagerService ready", e);
+ reportWtf("Notifying DreamManagerService running", e);
}
try {
- if (atlasF != null) atlasF.systemReady();
+ if (atlasF != null) atlasF.systemRunning();
} catch (Throwable e) {
- reportWtf("making AssetAtlasService ready", e);
+ reportWtf("Notifying AssetAtlasService running", e);
}
try {
// TODO(BT) Pass parameter to input manager
- if (inputManagerF != null) inputManagerF.systemReady();
+ if (inputManagerF != null) inputManagerF.systemRunning();
} catch (Throwable e) {
- reportWtf("making InputManagerService ready", e);
+ reportWtf("Notifying InputManagerService running", e);
}
try {
- if (telephonyRegistryF != null) telephonyRegistryF.systemReady();
+ if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
} catch (Throwable e) {
- reportWtf("making TelephonyRegistry ready", e);
+ reportWtf("Notifying TelephonyRegistry running", e);
+ }
+
+ try {
+ if (printManagerF != null) printManagerF.systemRuning();
+ } catch (Throwable e) {
+ reportWtf("Notifying PrintManagerService running", e);
}
}
});
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 17260d5..699d79e 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -178,7 +178,7 @@
mConnectedApns = new ArrayList<String>();
}
- public void systemReady() {
+ public void systemRunning() {
// Watch for interesting updates
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 7dd9988..6587c41 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -76,7 +76,7 @@
new HashMap<String, SpellCheckerBindGroup>();
private final TextServicesSettings mSettings;
- public void systemReady() {
+ public void systemRunning() {
if (!mSystemReady) {
mSystemReady = true;
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 6823f136..d677f24 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -449,7 +449,7 @@
}
}
- public void systemReady() {
+ public void systemRunning() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);
switchWallpaper(wallpaper, null);
@@ -885,7 +885,8 @@
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
0, null, new UserHandle(serviceUserId)));
- if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE,
+ if (!mContext.bindServiceAsUser(intent, newConn,
+ Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,
new UserHandle(serviceUserId))) {
String msg = "Unable to bind service: "
+ componentName;
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 5d72102..795e142 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -421,7 +421,8 @@
private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
boolean anyForeground = false;
- for (ServiceRecord sr : proc.services) {
+ for (int i=proc.services.size()-1; i>=0; i--) {
+ ServiceRecord sr = proc.services.valueAt(i);
if (sr.isForeground) {
anyForeground = true;
break;
@@ -1670,78 +1671,72 @@
}
// Clean up any connections this application has to other services.
- if (app.connections.size() > 0) {
- Iterator<ConnectionRecord> it = app.connections.iterator();
- while (it.hasNext()) {
- ConnectionRecord r = it.next();
- removeConnectionLocked(r, app, null);
- }
+ for (int i=app.connections.size()-1; i>=0; i--) {
+ ConnectionRecord r = app.connections.valueAt(i);
+ removeConnectionLocked(r, app, null);
}
app.connections.clear();
- if (app.services.size() != 0) {
+ for (int i=app.services.size()-1; i>=0; i--) {
// Any services running in the application need to be placed
// back in the pending list.
- Iterator<ServiceRecord> it = app.services.iterator();
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
- synchronized (sr.stats.getBatteryStats()) {
- sr.stats.stopLaunchedLocked();
- }
- sr.app = null;
- sr.isolatedProc = null;
- sr.executeNesting = 0;
- if (sr.tracker != null) {
- sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
- SystemClock.uptimeMillis());
- }
- if (mStoppingServices.remove(sr)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
- }
+ ServiceRecord sr = app.services.valueAt(i);
+ synchronized (sr.stats.getBatteryStats()) {
+ sr.stats.stopLaunchedLocked();
+ }
+ sr.app = null;
+ sr.isolatedProc = null;
+ sr.executeNesting = 0;
+ if (sr.tracker != null) {
+ sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
+ if (mStoppingServices.remove(sr)) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
+ }
- final int numClients = sr.bindings.size();
- for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
- IntentBindRecord b = sr.bindings.valueAt(bindingi);
- if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
- + ": shouldUnbind=" + b.hasBound);
- b.binder = null;
- b.requested = b.received = b.hasBound = false;
- }
+ final int numClients = sr.bindings.size();
+ for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
+ IntentBindRecord b = sr.bindings.valueAt(bindingi);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+ + ": shouldUnbind=" + b.hasBound);
+ b.binder = null;
+ b.requested = b.received = b.hasBound = false;
+ }
- if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
- &ApplicationInfo.FLAG_PERSISTENT) == 0) {
- Slog.w(TAG, "Service crashed " + sr.crashCount
- + " times, stopping: " + sr);
- EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
- sr.userId, sr.crashCount, sr.shortName, app.pid);
- bringDownServiceLocked(sr);
- } else if (!allowRestart) {
- bringDownServiceLocked(sr);
- } else {
- boolean canceled = scheduleServiceRestartLocked(sr, true);
+ if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+ &ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ Slog.w(TAG, "Service crashed " + sr.crashCount
+ + " times, stopping: " + sr);
+ EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
+ sr.userId, sr.crashCount, sr.shortName, app.pid);
+ bringDownServiceLocked(sr);
+ } else if (!allowRestart) {
+ bringDownServiceLocked(sr);
+ } else {
+ boolean canceled = scheduleServiceRestartLocked(sr, true);
- // Should the service remain running? Note that in the
- // extreme case of so many attempts to deliver a command
- // that it failed we also will stop it here.
- if (sr.startRequested && (sr.stopIfKilled || canceled)) {
- if (sr.pendingStarts.size() == 0) {
- sr.startRequested = false;
- if (sr.tracker != null) {
- sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
- SystemClock.uptimeMillis());
- }
- if (!sr.hasAutoCreateConnections()) {
- // Whoops, no reason to restart!
- bringDownServiceLocked(sr);
- }
+ // Should the service remain running? Note that in the
+ // extreme case of so many attempts to deliver a command
+ // that it failed we also will stop it here.
+ if (sr.startRequested && (sr.stopIfKilled || canceled)) {
+ if (sr.pendingStarts.size() == 0) {
+ sr.startRequested = false;
+ if (sr.tracker != null) {
+ sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
+ if (!sr.hasAutoCreateConnections()) {
+ // Whoops, no reason to restart!
+ bringDownServiceLocked(sr);
}
}
}
}
+ }
- if (!allowRestart) {
- app.services.clear();
- }
+ if (!allowRestart) {
+ app.services.clear();
}
// Make sure we have no more records on the stopping list.
@@ -1880,11 +1875,10 @@
return;
}
long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
- Iterator<ServiceRecord> it = proc.executingServices.iterator();
ServiceRecord timeout = null;
long nextTime = 0;
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
+ for (int i=proc.executingServices.size()-1; i>=0; i--) {
+ ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index c41c23e..b51415f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1505,6 +1505,7 @@
case COLLECT_PSS_BG_MSG: {
int i=0;
long start = SystemClock.uptimeMillis();
+ long[] tmp = new long[1];
do {
ProcessRecord proc;
int oomAdj;
@@ -1528,10 +1529,10 @@
i++;
}
if (proc != null) {
- long pss = Debug.getPss(pid);
+ long pss = Debug.getPss(pid, tmp);
synchronized (ActivityManagerService.this) {
if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) {
- proc.baseProcessTracker.addPss(pss, true);
+ proc.baseProcessTracker.addPss(pss, tmp[0], true);
}
}
}
@@ -2157,13 +2158,12 @@
// If the app is currently using a content provider or service,
// bump those processes as well.
- if (app.connections.size() > 0) {
- for (ConnectionRecord cr : app.connections) {
- if (cr.binding != null && cr.binding.service != null
- && cr.binding.service.app != null
- && cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app, i+1);
- }
+ for (int j=app.connections.size()-1; j>=0; j--) {
+ ConnectionRecord cr = app.connections.valueAt(j);
+ if (cr.binding != null && cr.binding.service != null
+ && cr.binding.service.app != null
+ && cr.binding.service.app.lruSeq != mLruSeq) {
+ updateLruProcessInternalLocked(cr.binding.service.app, i+1);
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
@@ -4010,7 +4010,8 @@
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(infos[i].getTotalPss(), false);
+ proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
+ infos[i].getTotalUss(), false);
}
}
}
@@ -4031,12 +4032,13 @@
oomAdj = proc != null ? proc.setAdj : 0;
}
}
- pss[i] = Debug.getPss(pids[i]);
+ long[] tmpUss = new long[1];
+ pss[i] = Debug.getPss(pids[i], tmpUss);
if (proc != null) {
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(pss[i], false);
+ proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false);
}
}
}
@@ -8802,14 +8804,11 @@
}
// Bump up the crash count of any services currently running in the proc.
- if (app.services.size() != 0) {
+ for (int i=app.services.size()-1; i>=0; i--) {
// Any services running in the application need to be placed
// back in the pending list.
- Iterator<ServiceRecord> it = app.services.iterator();
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
- sr.crashCount++;
- }
+ ServiceRecord sr = app.services.valueAt(i);
+ sr.crashCount++;
}
// If the crashing process is what we consider to be the "home process" and it has been
@@ -10269,8 +10268,8 @@
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(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_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);
@@ -10772,10 +10771,10 @@
oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
} else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ);
- } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
- oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
oomAdj = buildOomTag("hvy ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
+ oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
} else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
@@ -10820,29 +10819,38 @@
case ActivityManager.PROCESS_STATE_TOP:
procState = "T ";
break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE:
- procState = "IP";
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procState = "IF";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
procState = "IB";
break;
- case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "R ";
- break;
case ActivityManager.PROCESS_STATE_BACKUP:
procState = "BU";
break;
+ case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+ procState = "HW";
+ break;
case ActivityManager.PROCESS_STATE_SERVICE:
procState = "S ";
break;
+ case ActivityManager.PROCESS_STATE_RECEIVER:
+ procState = "R ";
+ break;
case ActivityManager.PROCESS_STATE_HOME:
- procState = "H ";
+ procState = "HO";
break;
case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
procState = "LA";
break;
- case ActivityManager.PROCESS_STATE_CACHED:
- procState = "C ";
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ procState = "CA";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ procState = "Ca";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+ procState = "CE";
break;
default:
procState = "??";
@@ -10895,9 +10903,6 @@
pw.print(prefix);
pw.print(" ");
pw.print("oom: max="); pw.print(r.maxAdj);
- pw.print(" cached="); pw.print(r.cachedAdj);
- pw.print(" client="); pw.print(r.clientCachedAdj);
- pw.print(" empty="); pw.print(r.emptyAdj);
pw.print(" curRaw="); pw.print(r.curRawAdj);
pw.print(" setRaw="); pw.print(r.setRawAdj);
pw.print(" cur="); pw.print(r.curAdj);
@@ -11139,21 +11144,24 @@
static final int[] DUMP_MEM_OOM_ADJ = new int[] {
ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
- ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
- ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
+ ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
+ ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+ ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
};
static final String[] DUMP_MEM_OOM_LABEL = new String[] {
"System", "Persistent", "Foreground",
- "Visible", "Perceptible", "Heavy Weight",
- "Backup", "A Services", "Home", "Previous",
- "B Services", "Cached"
+ "Visible", "Perceptible",
+ "Heavy Weight", "Backup",
+ "A Services", "Home",
+ "Previous", "B Services", "Cached"
};
static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
"sys", "pers", "fore",
- "vis", "percept", "heavy",
- "backup", "servicea", "home", "prev",
- "serviceb", "cached"
+ "vis", "percept",
+ "heavy", "backup",
+ "servicea", "home",
+ "prev", "serviceb", "cached"
};
final void dumpApplicationMemoryUsage(FileDescriptor fd,
@@ -11225,6 +11233,7 @@
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
new ArrayList[DUMP_MEM_OOM_LABEL.length];
+ final long[] tmpLong = new long[1];
long totalPss = 0;
long cachedPss = 0;
@@ -11264,16 +11273,18 @@
if (!brief && !oomOnly) {
Debug.getMemoryInfo(pid, mi);
} else {
- mi.dalvikPss = (int)Debug.getPss(pid);
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
}
}
final long myTotalPss = mi.getTotalPss();
+ final long myTotalUss = mi.getTotalUss();
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- r.baseProcessTracker.addPss(myTotalPss, true);
+ r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true);
}
}
@@ -11642,14 +11653,11 @@
skipCurrentReceiverLocked(app);
// Unregister any receivers.
- if (app.receivers.size() > 0) {
- Iterator<ReceiverList> it = app.receivers.iterator();
- while (it.hasNext()) {
- removeReceiverLocked(it.next());
- }
- app.receivers.clear();
+ for (int i=app.receivers.size()-1; i>=0; i--) {
+ removeReceiverLocked(app.receivers.valueAt(i));
}
-
+ app.receivers.clear();
+
// If the app is undergoing backup, tell the backup manager about it
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App "
@@ -13409,29 +13417,17 @@
return null;
}
- private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, int clientCachedAdj,
- int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
+ private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+ boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed. If we are calling
- // from the top, we may have already computed our adjustment with
- // an earlier cached adjustment that isn't really for us... if
- // so, use the new cached adjustment.
- if (!recursed && app.cached) {
- if (app.hasActivities) {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = cachedAdj;
- } else if (app.hasClientActivities) {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientCachedAdj;
- } else {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj;
- }
- }
+ // This adjustment has already been computed.
return app.curRawAdj;
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.curProcState = ActivityManager.PROCESS_STATE_CACHED;
+ app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
@@ -13449,7 +13445,7 @@
// below foreground, so it is not worth doing work for it.
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
- app.curRawAdj = app.nonStoppingAdj = app.maxAdj;
+ app.curRawAdj = app.maxAdj;
app.hasActivities = false;
app.foregroundActivities = false;
app.keeping = true;
@@ -13507,7 +13503,7 @@
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
interesting = true;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
} else if ((queue = isReceivingBroadcast(app)) != null) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
@@ -13526,33 +13522,39 @@
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
} else {
- // Assume process is cached (has activities); we will correct
- // later if this is not the case.
- adj = cachedAdj;
+ // As far as we know the process is empty. We may change our mind later.
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ // At this point we don't actually know the adjustment. Use the cached adj
+ // value that the caller wants us to.
+ adj = cachedAdj;
+ procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
app.cached = true;
- app.adjType = "cch-act";
- procState = ActivityManager.PROCESS_STATE_CACHED;
+ app.empty = true;
+ app.adjType = "cch-empty";
}
- boolean hasStoppingActivities = false;
-
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
+ if (r.app != app) {
+ Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
+ + app + "?!?");
+ continue;
+ }
+ app.hasActivities = true;
if (r.visible) {
// App has a visible activity; only upgrade adjustment.
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "visible";
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_TOP) {
+ procState = ActivityManager.PROCESS_STATE_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
- app.hasActivities = true;
+ app.empty = false;
foregroundActivities = true;
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
@@ -13560,38 +13562,39 @@
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pausing";
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_TOP) {
+ procState = ActivityManager.PROCESS_STATE_TOP;
}
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
+ app.empty = false;
foregroundActivities = true;
} else if (r.state == ActivityState.STOPPING) {
- // We will apply the actual adjustment later, because
- // we want to allow this process to immediately go through
- // any memory trimming that is in effect.
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.adjType = "stopping";
+ }
+ // For the process state, we will at this point consider the
+ // process to be cached. It will be cached either as an activity
+ // or empty depending on whether the activity is finishing. We do
+ // this so that we can treat the process as cached for purposes of
+ // memory trimming (determing current memory level, trim command to
+ // send to process) since there can be an arbitrary number of stopping
+ // processes and they should soon all go into the cached state.
+ if (!r.finishing) {
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ }
}
app.cached = false;
+ app.empty = false;
foregroundActivities = true;
- hasStoppingActivities = true;
+ } else {
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ app.adjType = "cch-act";
+ }
}
- if (r.app == app) {
- app.hasActivities = true;
- }
- }
- }
-
- if (adj == cachedAdj && !app.hasActivities) {
- if (app.hasClientActivities) {
- adj = clientCachedAdj;
- app.adjType = "cch-client-act";
- } else {
- // Whoops, this process is completely empty as far as we know
- // at this point.
- adj = emptyAdj;
- app.empty = true;
- app.adjType = "cch-empty";
}
}
@@ -13599,14 +13602,14 @@
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "fg-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
@@ -13618,12 +13621,17 @@
interesting = true;
}
- if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
- // We don't want to kill the current heavy-weight process.
- adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.cached = false;
- app.adjType = "heavy";
+ if (app == mHeavyWeightProcess) {
+ if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ // We don't want to kill the current heavy-weight process.
+ adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.cached = false;
+ app.adjType = "heavy";
+ }
+ if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
+ procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+ }
}
if (app == mHomeProcess) {
@@ -13663,7 +13671,7 @@
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
app.adjSeq = mAdjSeq;
- app.curRawAdj = app.nonStoppingAdj = adj;
+ app.curRawAdj = adj;
app.hasStartedServices = false;
if (mBackupTarget != null && app == mBackupTarget.app) {
@@ -13682,243 +13690,220 @@
}
}
- if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
- final long now = SystemClock.uptimeMillis();
- // This process is more important if the top activity is
- // bound to the service.
- Iterator<ServiceRecord> jt = app.services.iterator();
- while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
- ServiceRecord s = jt.next();
- if (s.startRequested) {
- app.hasStartedServices = true;
- if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
- procState = ActivityManager.PROCESS_STATE_SERVICE;
- }
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-ui-services";
- }
- } else {
- if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has seen some activity within
- // recent memory, so we will keep its process ahead
- // of the background processes.
- if (adj > ProcessList.SERVICE_ADJ) {
- adj = ProcessList.SERVICE_ADJ;
- app.adjType = "started-services";
- app.cached = false;
- }
- }
- // If we have let the service slide into the background
- // state, still have some text describing what it is doing
- // even though the service no longer has an impact.
- if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-services";
- }
- }
- // Don't kill this process because it is doing work; it
- // has said it is doing work.
- app.keeping = true;
+ for (int is = app.services.size()-1;
+ is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ is--) {
+ ServiceRecord s = app.services.valueAt(is);
+ if (s.startRequested) {
+ app.hasStartedServices = true;
+ if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
+ procState = ActivityManager.PROCESS_STATE_SERVICE;
}
- for (int conni = s.connections.size()-1;
- conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
- conni--) {
- ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
- for (int i = 0;
- i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
- i++) {
- // XXX should compute this based on the max of
- // all connected clients.
- ConnectionRecord cr = clist.get(i);
- if (cr.binding.client == app) {
- // Binding to ourself is not interesting.
- continue;
+ if (app.hasShownUi && app != mHomeProcess) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > ProcessList.SERVICE_ADJ) {
+ app.adjType = "cch-started-ui-services";
+ }
+ } else {
+ if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ // This service has seen some activity within
+ // recent memory, so we will keep its process ahead
+ // of the background processes.
+ if (adj > ProcessList.SERVICE_ADJ) {
+ adj = ProcessList.SERVICE_ADJ;
+ app.adjType = "started-services";
+ app.cached = false;
}
- if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
- ProcessRecord client = cr.binding.client;
- int myCachedAdj = cachedAdj;
- if (myCachedAdj > client.cachedAdj) {
- if (client.cachedAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myCachedAdj = client.cachedAdj;
- } else {
- myCachedAdj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- int myClientCachedAdj = clientCachedAdj;
- if (myClientCachedAdj > client.clientCachedAdj) {
- if (client.clientCachedAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myClientCachedAdj = client.clientCachedAdj;
- } else {
- myClientCachedAdj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- int myEmptyAdj = emptyAdj;
- if (myEmptyAdj > client.emptyAdj) {
- if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myEmptyAdj = client.emptyAdj;
- } else {
- myEmptyAdj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- int clientAdj = computeOomAdjLocked(client, myCachedAdj,
- myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll);
- int clientProcState = client.curProcState;
- String adjType = null;
- if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
- // Not doing bind OOM management, so treat
- // this guy more like a started service.
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-ui-services";
- }
- app.cached = false;
- clientAdj = adj;
- clientProcState = procState;
- } else {
- if (now >= (s.lastActivity
- + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has not seen activity within
- // recent memory, so allow it to drop to the
- // LRU list if there is no other reason to keep
- // it around. We'll also tag it with a label just
- // to help debug and undertand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-services";
- }
- clientAdj = adj;
- }
- }
- } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
- if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
- // If this connection is keeping the service
- // created, then we want to try to better follow
- // its memory management semantics for activities.
- // That is, if it is sitting in the background
- // LRU list as a cached process (with activities),
- // we don't want the service it is connected to
- // to go into the empty LRU and quickly get killed,
- // because all we'll do is just end up restarting
- // the service.
- app.hasClientActivities |= client.hasActivities;
- }
- }
- if (adj > clientAdj) {
- // If this process has recently shown UI, and
- // the process that is binding to it is less
- // important than being visible, then we don't
- // care about the binding as much as we care
- // about letting this process get into the LRU
- // list to be killed and restarted if needed for
- // memory.
- if (app.hasShownUi && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-bound-ui-services";
- } else {
- if ((cr.flags&(Context.BIND_ABOVE_CLIENT
- |Context.BIND_IMPORTANT)) != 0) {
- adj = clientAdj;
- } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
- && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
- && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
- adj = clientAdj;
- } else {
- app.pendingUiClean = true;
- if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- if (!client.cached) {
- app.cached = false;
- }
- if (client.keeping) {
- app.keeping = true;
- }
- adjType = "service";
- }
- }
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- if (clientProcState <
- ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
- }
- } else {
- if (clientProcState <
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
- }
- }
- if (procState > clientProcState) {
- procState = clientProcState;
- }
- if (adjType != null) {
- app.adjType = adjType;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = cr.binding.client;
- app.adjSourceOom = clientAdj;
- app.adjTarget = s.name;
- }
- }
- final ActivityRecord a = cr.activity;
- if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = ProcessList.FOREGROUND_APP_ADJ;
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- app.cached = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjSourceOom = adj;
- app.adjTarget = s.name;
- }
- }
+ }
+ // If we have let the service slide into the background
+ // state, still have some text describing what it is doing
+ // even though the service no longer has an impact.
+ if (adj > ProcessList.SERVICE_ADJ) {
+ app.adjType = "cch-started-services";
}
}
+ // Don't kill this process because it is doing work; it
+ // has said it is doing work.
+ app.keeping = true;
}
-
- // Finally, if this process has active services running in it, we
- // would like to avoid killing it unless it would prevent the current
- // application from running. By default we put the process in
- // with the rest of the background processes; as we scan through
- // its services we may bump it up from there.
- if (adj > cachedAdj) {
- adj = cachedAdj;
- app.cached = false;
- app.adjType = "cch-services";
+ for (int conni = s.connections.size()-1;
+ conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ conni--) {
+ ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+ for (int i = 0;
+ i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ i++) {
+ // XXX should compute this based on the max of
+ // all connected clients.
+ ConnectionRecord cr = clist.get(i);
+ if (cr.binding.client == app) {
+ // Binding to ourself is not interesting.
+ continue;
+ }
+ if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
+ ProcessRecord client = cr.binding.client;
+ int clientAdj = computeOomAdjLocked(client, cachedAdj,
+ TOP_APP, doingAll, now);
+ int clientProcState = client.curProcState;
+ String adjType = null;
+ if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+ // Not doing bind OOM management, so treat
+ // this guy more like a started service.
+ if (app.hasShownUi && app != mHomeProcess) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-ui-services";
+ }
+ app.cached = false;
+ clientAdj = adj;
+ clientProcState = procState;
+ } else {
+ if (now >= (s.lastActivity
+ + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ // This service has not seen activity within
+ // recent memory, so allow it to drop to the
+ // LRU list if there is no other reason to keep
+ // it around. We'll also tag it with a label just
+ // to help debug and undertand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-services";
+ }
+ clientAdj = adj;
+ }
+ }
+ } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
+ // If this connection is keeping the service
+ // created, then we want to try to better follow
+ // its memory management semantics for activities.
+ // That is, if it is sitting in the background
+ // LRU list as a cached process (with activities),
+ // we don't want the service it is connected to
+ // to go into the empty LRU and quickly get killed,
+ // because all we'll do is just end up restarting
+ // the service.
+ if (client.hasActivities) {
+ if (procState >
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT) {
+ procState =
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+ app.adjType = "cch-client-act";
+ }
+ }
+ app.hasClientActivities |= client.hasActivities;
+ }
+ }
+ if (adj > clientAdj) {
+ // If this process has recently shown UI, and
+ // the process that is binding to it is less
+ // important than being visible, then we don't
+ // care about the binding as much as we care
+ // about letting this process get into the LRU
+ // list to be killed and restarted if needed for
+ // memory.
+ if (app.hasShownUi && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adjType = "cch-bound-ui-services";
+ } else {
+ if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+ |Context.BIND_IMPORTANT)) != 0) {
+ adj = clientAdj;
+ } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
+ && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
+ adj = clientAdj;
+ } else {
+ if (adj > ProcessList.VISIBLE_APP_ADJ) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ }
+ }
+ if (!client.cached) {
+ app.cached = false;
+ }
+ if (client.keeping) {
+ app.keeping = true;
+ }
+ adjType = "service";
+ }
+ }
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ }
+ } else {
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ }
+ }
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ }
+ if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
+ app.pendingUiClean = true;
+ }
+ if (adjType != null) {
+ app.adjType = adjType;
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = cr.binding.client;
+ app.adjSourceOom = clientAdj;
+ app.adjTarget = s.name;
+ }
+ }
+ final ActivityRecord a = cr.activity;
+ if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
+ (a.visible || a.state == ActivityState.RESUMED
+ || a.state == ActivityState.PAUSING)) {
+ adj = ProcessList.FOREGROUND_APP_ADJ;
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ app.cached = false;
+ app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = a;
+ app.adjSourceOom = adj;
+ app.adjTarget = s.name;
+ }
+ }
+ }
}
}
for (int provi = app.pubProviders.size()-1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
provi--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
for (int i = cpr.connections.size()-1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
i--) {
ContentProviderConnection conn = cpr.connections.get(i);
ProcessRecord client = conn.client;
@@ -13926,32 +13911,7 @@
// Being our own client is not interesting.
continue;
}
- int myCachedAdj = cachedAdj;
- if (myCachedAdj > client.cachedAdj) {
- if (client.cachedAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myCachedAdj = client.cachedAdj;
- } else {
- myCachedAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int myClientCachedAdj = clientCachedAdj;
- if (myClientCachedAdj > client.clientCachedAdj) {
- if (client.clientCachedAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- myClientCachedAdj = client.clientCachedAdj;
- } else {
- myClientCachedAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int myEmptyAdj = emptyAdj;
- if (myEmptyAdj > client.emptyAdj) {
- if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myEmptyAdj = client.emptyAdj;
- } else {
- myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int clientAdj = computeOomAdjLocked(client, myCachedAdj,
- myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll);
+ int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -13961,12 +13921,8 @@
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
app.adjType = "provider";
}
- if (!client.cached) {
- app.cached = false;
- }
- if (client.keeping) {
- app.keeping = true;
- }
+ app.cached &= client.cached;
+ app.keeping |= client.keeping;
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
@@ -13974,7 +13930,10 @@
app.adjTarget = cpr.name;
}
if (procState > client.curProcState) {
- procState = client.curProcState;
+ procState = client.curProcState >
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ ? client.curProcState
+ : ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13992,8 +13951,8 @@
app.adjType = "provider";
app.adjTarget = cpr.name;
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
}
@@ -14010,16 +13969,6 @@
app.serviceb = false;
}
- app.nonStoppingAdj = adj;
-
- if (hasStoppingActivities) {
- // Only upgrade adjustment.
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "stopping";
- }
- }
-
app.curRawAdj = adj;
//Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
@@ -14034,24 +13983,12 @@
app.keeping = true;
}
- if (app.hasAboveClient) {
- // If this process has bound to any services with BIND_ABOVE_CLIENT,
- // then we need to drop its adjustment to be lower than the service's
- // in order to honor the request. We want to drop it by one adjustment
- // level... but there is special meaning applied to various levels so
- // we will skip some of them.
- if (adj < ProcessList.FOREGROUND_APP_ADJ) {
- // System process will not get dropped, ever
- } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
- adj = ProcessList.CACHED_APP_MIN_ADJ;
- } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
- adj++;
- }
- }
+ // Do final modification to adj. Everything we do between here and applying
+ // the final setAdj must be done in this function, because we will also use
+ // it when computing the final cached adj later. Note that we don't need to
+ // worry about this for max adj above, since max adj will always be used to
+ // keep it out of the cached vaues.
+ adj = app.modifyRawOomAdj(adj);
app.curProcState = procState;
@@ -14407,23 +14344,10 @@
}
}
- private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
- int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll,
- boolean doingProcessState, long now) {
- app.cachedAdj = cachedAdj;
- app.clientCachedAdj = clientCachedAdj;
- app.emptyAdj = emptyAdj;
-
- if (app.thread == null) {
- return false;
- }
-
- final boolean wasKeeping = app.keeping;
-
+ private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
+ ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
boolean success = true;
- computeOomAdjLocked(app, cachedAdj, clientCachedAdj, emptyAdj, TOP_APP, false, doingAll);
-
if (app.curRawAdj != app.setRawAdj) {
if (wasKeeping && !app.keeping) {
// This app is no longer something we want to keep. Note
@@ -14467,11 +14391,6 @@
requestPssLocked(app, now, true);
}
app.setAdj = app.curAdj;
- app.setAdjChanged = true;
- if (!doingAll) {
- app.setProcessTrackerState(TOP_APP, mProcessTracker.getMemFactorLocked(),
- now, mProcessList);
- }
} else {
success = false;
Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
@@ -14510,11 +14429,13 @@
}
}
}
+ Process.setSwappiness(app.pid,
+ app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE);
}
}
if (app.repProcState != app.curProcState) {
app.repProcState = app.curProcState;
- if (!doingProcessState && app.thread != null) {
+ if (!reportingProcessState && app.thread != null) {
try {
if (false) {
//RuntimeException h = new RuntimeException("here");
@@ -14526,9 +14447,33 @@
}
}
}
+ if (app.setProcState != app.curProcState) {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Proc state change of " + app.processName
+ + " to " + app.curProcState);
+ app.setProcState = app.curProcState;
+ app.procStateChanged = true;
+ if (!doingAll) {
+ app.setProcessTrackerState(mProcessTracker.getMemFactorLocked(), now);
+ }
+ }
return success;
}
+ private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
+ ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+ if (app.thread == null) {
+ return false;
+ }
+
+ final boolean wasKeeping = app.keeping;
+
+ computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
+
+ return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll,
+ reportingProcessState, now);
+ }
+
private final ActivityRecord resumedAppLocked() {
return mStackSupervisor.resumedAppLocked();
}
@@ -14540,17 +14485,19 @@
final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
- int curAdj = app.curAdj;
- final boolean wasCached = curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && curAdj <= ProcessList.CACHED_APP_MAX_ADJ;
+ final boolean wasCached = app.cached;
mAdjSeq++;
- boolean success = updateOomAdjLocked(app, app.cachedAdj, app.clientCachedAdj,
- app.emptyAdj, TOP_APP, false, doingProcessState, SystemClock.uptimeMillis());
- final boolean nowCached = app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ;
- if (nowCached != wasCached) {
+ // This is the desired cached adjusment we want to tell it to use.
+ // If our app is currently cached, we know it, and that is it. Otherwise,
+ // we don't know it yet, and it needs to now be cached we will then
+ // need to do a complete oom adj.
+ final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
+ ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
+ boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState,
+ SystemClock.uptimeMillis());
+ if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked();
@@ -14563,6 +14510,7 @@
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final long now = SystemClock.uptimeMillis();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
+ final int N = mLruProcesses.size();
if (false) {
RuntimeException e = new RuntimeException();
@@ -14591,7 +14539,7 @@
// them.
int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
- ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
- int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedHiddenProcs;
+ int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
if (numEmptyProcs > cachedProcessLimit) {
// If there are more empty processes than our limit on cached
// processes, then use the cached process limit for the factor.
@@ -14616,80 +14564,97 @@
// First update the OOM adjustment for each of the
// application processes based on their current state.
- int i = mLruProcesses.size();
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
int curClientCachedAdj = curEmptyAdj;
- boolean changed = false;
- while (i > 0) {
- i--;
+ for (int i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
- //Slog.i(TAG, "OOM " + app + ": cur cached=" + curCachedAdj);
- app.setAdjChanged = false;
- updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP,
- true, false, now);
- changed |= app.setAdjChanged;
- if (!app.killedBackground) {
- if (app.curRawAdj == curCachedAdj && app.hasActivities) {
- // This process was assigned as a cached process... step the
- // cached level.
- mNumCachedHiddenProcs++;
- if (curCachedAdj != nextCachedAdj) {
- stepCached++;
- if (stepCached >= cachedFactor) {
- stepCached = 0;
- curCachedAdj = nextCachedAdj;
- nextCachedAdj += 2;
- if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
- }
- if (curClientCachedAdj <= curCachedAdj) {
- curClientCachedAdj = curCachedAdj + 1;
- if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ if (!app.killedBackground && app.thread != null) {
+ app.procStateChanged = false;
+ final boolean wasKeeping = app.keeping;
+ computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+
+ // If we haven't yet assigned the final cached adj
+ // to the process, do that now.
+ if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
+ switch (app.curProcState) {
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ // This process is a cached process holding activities...
+ // assign it the next cached value for that type, and then
+ // step that cached level.
+ app.curRawAdj = curCachedAdj;
+ app.curAdj = app.modifyRawOomAdj(curCachedAdj);
+ if (curCachedAdj != nextCachedAdj) {
+ stepCached++;
+ if (stepCached >= cachedFactor) {
+ stepCached = 0;
+ curCachedAdj = nextCachedAdj;
+ nextCachedAdj += 2;
+ if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ if (curClientCachedAdj <= curCachedAdj) {
+ curClientCachedAdj = curCachedAdj + 1;
+ if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ }
}
}
- }
- }
- numCached++;
- if (numCached > cachedProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): cached #" + numCached);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
- }
- } else if (app.curRawAdj == curCachedAdj && app.hasClientActivities) {
- // This process has a client that has activities. We will have
- // given it the current cached adj; here we will just leave it
- // without stepping the cached adj.
- curClientCachedAdj++;
- if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
- }
- } else {
- if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curCachedAdj) {
- // This process was assigned as an empty process... step the
- // empty level.
- if (curEmptyAdj != nextEmptyAdj) {
- stepEmpty++;
- if (stepEmpty >= emptyFactor) {
- stepEmpty = 0;
- curEmptyAdj = nextEmptyAdj;
- nextEmptyAdj += 2;
- if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ // Special case for cached client processes... just step
+ // down from after regular cached processes.
+ app.curRawAdj = curClientCachedAdj;
+ app.curAdj = app.modifyRawOomAdj(curClientCachedAdj);
+ curClientCachedAdj++;
+ if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ break;
+ default:
+ // For everything else, assign next empty cached process
+ // level and bump that up. Note that this means that
+ // long-running services that have dropped down to the
+ // cached level will be treated as empty (since their process
+ // state is still as a service), which is what we want.
+ app.curRawAdj = curEmptyAdj;
+ app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
+ if (curEmptyAdj != nextEmptyAdj) {
+ stepEmpty++;
+ if (stepEmpty >= emptyFactor) {
+ stepEmpty = 0;
+ curEmptyAdj = nextEmptyAdj;
+ nextEmptyAdj += 2;
+ if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
}
}
- }
- } else if (app.curRawAdj < ProcessList.CACHED_APP_MIN_ADJ) {
- mNumNonCachedProcs++;
+ break;
}
- if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && !app.hasClientActivities) {
+ }
+
+ applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);
+
+ // Count the number of process types.
+ switch (app.curProcState) {
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ mNumCachedHiddenProcs++;
+ numCached++;
+ if (numCached > cachedProcessLimit) {
+ Slog.i(TAG, "No longer want " + app.processName
+ + " (pid " + app.pid + "): cached #" + numCached);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ }
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
Slog.i(TAG, "No longer want " + app.processName
@@ -14711,8 +14676,12 @@
Process.killProcessQuiet(app.pid);
}
}
- }
+ break;
+ default:
+ mNumNonCachedProcs++;
+ break;
}
+
if (app.isolated && app.services.size() <= 0) {
// If this is an isolated process, and there are no
// services running in it, then the process is no longer
@@ -14727,8 +14696,8 @@
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
}
- if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
- && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
+
+ if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedBackground) {
numTrimming++;
}
@@ -14743,11 +14712,10 @@
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- int memFactor = ProcessTracker.ADJ_MEM_FACTOR_NORMAL;
+ boolean allChanged;
if (numCached <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
final int numCachedAndEmpty = numCached + numEmpty;
- final int N = mLruProcesses.size();
int factor = numTrimming/3;
int minFactor = 2;
if (mHomeProcess != null) minFactor++;
@@ -14755,6 +14723,7 @@
if (factor < minFactor) factor = minFactor;
int step = 0;
int fgTrimLevel;
+ int memFactor;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
memFactor = ProcessTracker.ADJ_MEM_FACTOR_CRITICAL;
@@ -14766,13 +14735,19 @@
memFactor = ProcessTracker.ADJ_MEM_FACTOR_MODERATE;
}
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- for (i=0; i<N; i++) {
+ allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now);
+ for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
- && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
+ if (allChanged || app.procStateChanged) {
+ app.setProcessTrackerState(memFactor, now);
+ }
+ if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedBackground) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of " + app.processName
+ + " to " + curLevel);
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
@@ -14803,10 +14778,13 @@
break;
}
}
- } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of heavy-weight " + app.processName
+ + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
@@ -14814,14 +14792,17 @@
}
app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {
- if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
- && app.pendingUiClean) {
+ if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || app.systemNoUi) && app.pendingUiClean) {
// If this application is now in the background and it
// had done UI, then give it the special trim level to
// have it free UI resources.
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
if (app.trimMemoryLevel < level && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of bg-ui " + app.processName
+ + " to " + level);
app.thread.scheduleTrimMemory(level);
} catch (RemoteException e) {
}
@@ -14830,6 +14811,9 @@
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of fg " + app.processName
+ + " to " + fgTrimLevel);
app.thread.scheduleTrimMemory(fgTrimLevel);
} catch (RemoteException e) {
}
@@ -14838,14 +14822,21 @@
}
}
} else {
- final int N = mLruProcesses.size();
- for (i=0; i<N; i++) {
+ allChanged = mProcessTracker.setMemFactorLocked(
+ ProcessTracker.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
- && app.pendingUiClean) {
+ if (allChanged || app.procStateChanged) {
+ app.setProcessTrackerState(ProcessTracker.ADJ_MEM_FACTOR_NORMAL, now);
+ }
+ if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || app.systemNoUi) && app.pendingUiClean) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of ui hidden " + app.processName
+ + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
} catch (RemoteException e) {
@@ -14863,16 +14854,6 @@
mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
}
- boolean allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now);
- if (changed || allChanged) {
- memFactor = mProcessTracker.getMemFactorLocked();
- for (i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- if (allChanged || app.setAdjChanged) {
- app.setProcessTrackerState(TOP_APP, memFactor, now, mProcessList);
- }
- }
- }
if (allChanged) {
requestPssAllProcsLocked(now, false);
}
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index 6c84b9f..21cf266 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.util.ArrayMap;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -33,8 +34,8 @@
/** The intent that is bound.*/
final Intent.FilterComparison intent; //
/** All apps that have bound to this Intent. */
- final HashMap<ProcessRecord, AppBindRecord> apps
- = new HashMap<ProcessRecord, AppBindRecord>();
+ final ArrayMap<ProcessRecord, AppBindRecord> apps
+ = new ArrayMap<ProcessRecord, AppBindRecord>();
/** Binder published from service. */
IBinder binder;
/** Set when we have initiated a request for this binder. */
@@ -62,15 +63,12 @@
pw.print(" received="); pw.print(received);
pw.print(" hasBound="); pw.print(hasBound);
pw.print(" doRebind="); pw.println(doRebind);
- if (apps.size() > 0) {
- Iterator<AppBindRecord> it = apps.values().iterator();
- while (it.hasNext()) {
- AppBindRecord a = it.next();
- pw.print(prefix); pw.print("* Client AppBindRecord{");
- pw.print(Integer.toHexString(System.identityHashCode(a)));
- pw.print(' '); pw.print(a.client); pw.println('}');
- a.dumpInIntentBind(pw, prefix + " ");
- }
+ for (int i=0; i<apps.size(); i++) {
+ AppBindRecord a = apps.valueAt(i);
+ pw.print(prefix); pw.print("* Client AppBindRecord{");
+ pw.print(Integer.toHexString(System.identityHashCode(a)));
+ pw.print(' '); pw.print(a.client); pw.println('}');
+ a.dumpInIntentBind(pw, prefix + " ");
}
}
@@ -81,12 +79,11 @@
int collectFlags() {
int flags = 0;
- if (apps.size() > 0) {
- for (AppBindRecord app : apps.values()) {
- if (app.connections.size() > 0) {
- for (ConnectionRecord conn : app.connections) {
- flags |= conn.flags;
- }
+ for (int i=apps.size()-1; i>=0; i--) {
+ AppBindRecord app = apps.valueAt(i);
+ if (app.connections.size() > 0) {
+ for (ConnectionRecord conn : app.connections) {
+ flags |= conn.flags;
}
}
}
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index 6a72e44f..8b0466f 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -36,6 +36,11 @@
// OOM adjustments for processes in various states:
+ // Adjustment used in certain places where we don't know it yet.
+ // (Generally this is something that is going to be cached, but we
+ // don't know the exact value in the cached range to assign yet.)
+ static final int UNKNOWN_ADJ = 16;
+
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 15;
@@ -62,14 +67,14 @@
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 5;
- // This is a process currently hosting a backup operation. Killing it
- // is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 4;
-
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 3;
+ static final int HEAVY_WEIGHT_APP_ADJ = 4;
+
+ // This is a process currently hosting a backup operation. Killing it
+ // is not entirely fatal but is generally a bad idea.
+ static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
@@ -163,34 +168,11 @@
private boolean mHaveDisplaySize;
- private final int[] mAdjToTrackedState = new int[CACHED_APP_MAX_ADJ+1];
-
ProcessList() {
MemInfoReader minfo = new MemInfoReader();
minfo.readMemInfo();
mTotalMemMb = minfo.getTotalSize()/(1024*1024);
updateOomLevels(0, 0, false);
- for (int i=0; i<=CACHED_APP_MAX_ADJ; i++) {
- if (i <= FOREGROUND_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_FOREGROUND;
- } else if (i <= VISIBLE_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_VISIBLE;
- } else if (i <= PERCEPTIBLE_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_PERCEPTIBLE;
- } else if (i <= BACKUP_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_BACKUP;
- } else if (i <= SERVICE_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE;
- } else if (i <= HOME_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_HOME;
- } else if (i <= PREVIOUS_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_PREVIOUS;
- } else if (i <= SERVICE_B_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE;
- } else {
- mAdjToTrackedState[i] = ProcessTracker.STATE_CACHED;
- }
- }
}
void applyDisplaySize(WindowManagerService wm) {
@@ -256,11 +238,6 @@
return mOomMinFree[mOomAdj.length-1] * 1024;
}
- int adjToTrackedState(int adj) {
- return adj >= FOREGROUND_APP_ADJ
- ? mAdjToTrackedState[adj] : ProcessTracker.STATE_PERSISTENT;
- }
-
private void writeFile(String path, String data) {
FileOutputStream fos = null;
try {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index cb9a76d..5c1b7f24 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.util.ArraySet;
import com.android.internal.os.BatteryStatsImpl;
import android.app.ActivityManager;
@@ -64,12 +65,8 @@
long lruWeight; // Weight for ordering in LRU list
long lastPssTime; // Last time we requested PSS data
int maxAdj; // Maximum OOM adjustment for this process
- int cachedAdj; // If cached, this is the adjustment to use
- int clientCachedAdj; // If empty but cached client, this is the adjustment to use
- int emptyAdj; // If empty, this is the adjustment to use
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
- int nonStoppingAdj; // Adjustment not counting any stopping activities
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
int curSchedGroup; // Currently desired scheduling class
@@ -78,6 +75,7 @@
int memImportance; // Importance constant computed from curAdj
int curProcState = -1; // Currently computed process state: ActivityManager.PROCESS_STATE_*
int repProcState = -1; // Last reported process state
+ int setProcState = -1; // Last set process state in process tracker
boolean serviceb; // Process currently is on the service B list
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
@@ -92,7 +90,7 @@
boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean bad; // True if disabled in the bad process list
boolean killedBackground; // True when proc has been killed due to too many bg
- boolean setAdjChanged; // Keep track of whether we changed 'setAdj'.
+ boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
@@ -125,15 +123,15 @@
// contains HistoryRecord objects
final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
// all ServiceRecord running in this process
- final HashSet<ServiceRecord> services = new HashSet<ServiceRecord>();
+ final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>();
// services that are currently executing code (need to remain foreground).
- final HashSet<ServiceRecord> executingServices
- = new HashSet<ServiceRecord>();
+ final ArraySet<ServiceRecord> executingServices
+ = new ArraySet<ServiceRecord>();
// All ConnectionRecord this process holds
- final HashSet<ConnectionRecord> connections
- = new HashSet<ConnectionRecord>();
+ final ArraySet<ConnectionRecord> connections
+ = new ArraySet<ConnectionRecord>();
// all IIntentReceivers that are registered from this process.
- final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>();
+ final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>();
// class (String) -> ContentProviderRecord
final ArrayMap<String, ContentProviderRecord> pubProviders
= new ArrayMap<String, ContentProviderRecord>();
@@ -215,12 +213,8 @@
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
- pw.print(" cached="); pw.print(cachedAdj);
- pw.print(" client="); pw.print(clientCachedAdj);
- pw.print(" empty="); pw.print(emptyAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
- pw.print(" nonStopping="); pw.print(nonStoppingAdj);
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
@@ -228,7 +222,8 @@
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
- pw.print(" repProcState="); pw.println(repProcState);
+ pw.print(" repProcState="); pw.print(repProcState);
+ pw.print(" setProcState="); pw.println(setProcState);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.print(lruSeq);
pw.print(" lastPssTime="); pw.println(lastPssTime);
@@ -301,20 +296,20 @@
}
if (services.size() > 0) {
pw.print(prefix); pw.println("Services:");
- for (ServiceRecord sr : services) {
- pw.print(prefix); pw.print(" - "); pw.println(sr);
+ for (int i=0; i<services.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(services.valueAt(i));
}
}
if (executingServices.size() > 0) {
pw.print(prefix); pw.println("Executing Services:");
- for (ServiceRecord sr : executingServices) {
- pw.print(prefix); pw.print(" - "); pw.println(sr);
+ for (int i=0; i<executingServices.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(executingServices.valueAt(i));
}
}
if (connections.size() > 0) {
pw.print(prefix); pw.println("Connections:");
- for (ConnectionRecord cr : connections) {
- pw.print(prefix); pw.print(" - "); pw.println(cr);
+ for (int i=0; i<connections.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(connections.valueAt(i));
}
}
if (pubProviders.size() > 0) {
@@ -335,8 +330,8 @@
}
if (receivers.size() > 0) {
pw.print(prefix); pw.println("Receivers:");
- for (ReceiverList rl : receivers) {
- pw.print(prefix); pw.print(" - "); pw.println(rl);
+ for (int i=0; i<receivers.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(receivers.valueAt(i));
}
}
}
@@ -353,8 +348,7 @@
baseProcessTracker = tracker;
pkgList.put(_info.packageName, tracker);
thread = _thread;
- maxAdj = ProcessList.CACHED_APP_MAX_ADJ;
- cachedAdj = clientCachedAdj = emptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
+ maxAdj = ProcessList.UNKNOWN_ADJ;
curRawAdj = setRawAdj = -100;
curAdj = setAdj = -100;
persistent = false;
@@ -400,16 +394,37 @@
void updateHasAboveClientLocked() {
hasAboveClient = false;
- if (connections.size() > 0) {
- for (ConnectionRecord cr : connections) {
- if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
- hasAboveClient = true;
- break;
- }
+ for (int i=connections.size()-1; i>=0; i--) {
+ ConnectionRecord cr = connections.valueAt(i);
+ if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ hasAboveClient = true;
+ break;
}
}
}
+ int modifyRawOomAdj(int adj) {
+ if (hasAboveClient) {
+ // If this process has bound to any services with BIND_ABOVE_CLIENT,
+ // then we need to drop its adjustment to be lower than the service's
+ // in order to honor the request. We want to drop it by one adjustment
+ // level... but there is special meaning applied to various levels so
+ // we will skip some of them.
+ if (adj < ProcessList.FOREGROUND_APP_ADJ) {
+ // System process will not get dropped, ever
+ } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
+ adj = ProcessList.CACHED_APP_MIN_ADJ;
+ } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
+ adj++;
+ }
+ }
+ return adj;
+ }
+
public String toShortString() {
if (shortStringName != null) {
return shortStringName;
@@ -483,11 +498,8 @@
}
}
- public void setProcessTrackerState(ProcessRecord TOP_APP, int memFactor, long now,
- ProcessList plist) {
- int state = this == TOP_APP ? ProcessTracker.STATE_TOP
- : plist.adjToTrackedState(getSetAdjWithServices());
- baseProcessTracker.setState(state, memFactor, now, pkgList);
+ public void setProcessTrackerState(int memFactor, long now) {
+ baseProcessTracker.setState(repProcState, memFactor, now, pkgList);
}
/*
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index 0ea93e8..ef032ba 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -52,26 +52,34 @@
public static final int STATE_NOTHING = -1;
public static final int STATE_PERSISTENT = 0;
public static final int STATE_TOP = 1;
- public static final int STATE_FOREGROUND = 2;
- public static final int STATE_VISIBLE = 3;
- public static final int STATE_PERCEPTIBLE = 4;
- public static final int STATE_BACKUP = 5;
+ public static final int STATE_IMPORTANT_FOREGROUND = 2;
+ public static final int STATE_IMPORTANT_BACKGROUND = 3;
+ public static final int STATE_BACKUP = 4;
+ public static final int STATE_HEAVY_WEIGHT = 5;
public static final int STATE_SERVICE = 6;
- public static final int STATE_HOME = 7;
- public static final int STATE_PREVIOUS = 8;
- public static final int STATE_CACHED = 9;
- public static final int STATE_COUNT = STATE_CACHED+1;
+ public static final int STATE_RECEIVER = 7;
+ public static final int STATE_HOME = 8;
+ public static final int STATE_LAST_ACTIVITY = 9;
+ public static final int STATE_CACHED_ACTIVITY = 10;
+ public static final int STATE_CACHED_ACTIVITY_CLIENT = 11;
+ public static final int STATE_CACHED_EMPTY = 12;
+ public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
- static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, STATE_TOP,
- STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, STATE_BACKUP,
- STATE_SERVICE, STATE_HOME, STATE_PREVIOUS, STATE_CACHED
+ static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+ STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND,
+ STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_RECEIVER,
+ STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+ STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
};
public static final int PSS_SAMPLE_COUNT = 0;
public static final int PSS_MINIMUM = 1;
public static final int PSS_AVERAGE = 2;
public static final int PSS_MAXIMUM = 3;
- public static final int PSS_COUNT = PSS_MAXIMUM+1;
+ public static final int PSS_USS_MINIMUM = 4;
+ public static final int PSS_USS_AVERAGE = 5;
+ public static final int PSS_USS_MAXIMUM = 6;
+ public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
public static final int ADJ_NOTHING = -1;
public static final int ADJ_MEM_FACTOR_NORMAL = 0;
@@ -106,8 +114,9 @@
static int OFFSET_INDEX_MASK = 0xffff;
static final String[] STATE_NAMES = new String[] {
- "Persistent ", "Top ", "Foreground ", "Visible ", "Perceptible",
- "Backup ", "Service ", "Home ", "Previous ", "Cached "
+ "Persistent", "Top ", "Imp Fg ", "Imp Bg ",
+ "Backup ", "Heavy Wght", "Service ", "Receiver ", "Home ",
+ "Last Act ", "Cch Actvty", "Cch Client", "Cch Empty "
};
static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
@@ -119,8 +128,9 @@
};
static final String[] STATE_NAMES_CSV = new String[] {
- "pers", "top", "fore", "vis", "percept",
- "backup", "service", "home", "prev", "cached"
+ "pers", "top", "impfg", "impbg", "backup", "heavy",
+ "service", "receiver", "home", "lastact",
+ "cch-activity", "cch-aclient", "cch-empty"
};
static final String[] ADJ_SCREEN_TAGS = new String[] {
@@ -132,8 +142,26 @@
};
static final String[] STATE_TAGS = new String[] {
- "y", "t", "f", "v", "r",
- "b", "s", "h", "p", "c"
+ "p", "t", "f", "b", "u", "w",
+ "s", "r", "h", "l", "a", "c", "e"
+ };
+
+ // Map from process states to the states we track.
+ static final int[] PROCESS_STATE_TO_STATE = new int[] {
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+ STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
+ STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
+ STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
+ STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
+ STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+ STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+ STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
static final String CSV_SEP = "\t";
@@ -322,10 +350,20 @@
return true;
}
+ /**
+ * Update the current state of the given list of processes.
+ *
+ * @param state Current ActivityManager.PROCESS_STATE_*
+ * @param memFactor Current mem factor constant.
+ * @param now Current time.
+ * @param pkgList Processes to update.
+ */
public void setState(int state, int memFactor, long now,
ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
- if (state != STATE_NOTHING) {
- state += memFactor*STATE_COUNT;
+ if (state < 0) {
+ state = STATE_NOTHING;
+ } else {
+ state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
}
// First update the common process.
@@ -370,7 +408,7 @@
mStartTime = now;
}
- public void addPss(long pss, boolean always) {
+ public void addPss(long pss, long uss, boolean always) {
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
< (mLastPssTime+(30*1000))) {
@@ -399,16 +437,27 @@
longs[idx+PSS_MINIMUM] = pss;
longs[idx+PSS_AVERAGE] = pss;
longs[idx+PSS_MAXIMUM] = pss;
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ longs[idx+PSS_USS_AVERAGE] = uss;
+ longs[idx+PSS_USS_MAXIMUM] = uss;
} else {
longs[idx+PSS_SAMPLE_COUNT] = count+1;
if (longs[idx+PSS_MINIMUM] > pss) {
longs[idx+PSS_MINIMUM] = pss;
}
- longs[idx+PSS_AVERAGE] = (long)( ((longs[idx+PSS_AVERAGE]*(double)count)+pss)
- / (count+1) );
+ longs[idx+PSS_AVERAGE] = (long)(
+ ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) );
if (longs[idx+PSS_MAXIMUM] < pss) {
longs[idx+PSS_MAXIMUM] = pss;
}
+ if (longs[idx+PSS_USS_MINIMUM] > uss) {
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ }
+ longs[idx+PSS_USS_AVERAGE] = (long)(
+ ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) );
+ if (longs[idx+PSS_USS_MAXIMUM] < uss) {
+ longs[idx+PSS_USS_MAXIMUM] = uss;
+ }
}
}
}
@@ -480,6 +529,21 @@
int idx = State.binarySearch(mPssTable, mPssTableSize, state);
return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
}
+
+ long getPssUssMinimum(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
+ }
+
+ long getPssUssAverage(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
+ }
+
+ long getPssUssMaximum(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
+ }
}
public static final class ServiceState {
@@ -589,10 +653,13 @@
static final class State {
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 3;
+ private static final int PARCEL_VERSION = 6;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535453;
+ static final int FLAG_COMPLETE = 1<<0;
+ static final int FLAG_SHUTDOWN = 1<<1;
+
final File mBaseDir;
final ProcessTracker mProcessTracker;
AtomicFile mFile;
@@ -603,6 +670,7 @@
long mTimePeriodStartRealtime;
long mTimePeriodEndRealtime;
boolean mRunning;
+ int mFlags;
final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>();
final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
@@ -690,6 +758,7 @@
Arrays.fill(mMemFactorDurations, 0);
mMemFactor = STATE_NOTHING;
mStartTime = 0;
+ mReadError = null;
}
private void buildTimePeriodStartClockStr() {
@@ -724,7 +793,7 @@
}
}
- void readLocked() {
+ boolean readLocked() {
try {
FileInputStream stream = mFile.openRead();
@@ -770,11 +839,14 @@
}
}
}
+ return false;
}
} catch (Throwable e) {
- mReadError = "error reading: " + e;
+ mReadError = "caught exception: " + e;
Slog.e(TAG, "Error reading process statistics", e);
+ return false;
}
+ return true;
}
private void writeStateLocked(boolean sync, final boolean commit) {
@@ -848,6 +920,7 @@
out.writeLong(mTimePeriodStartClock);
out.writeLong(mTimePeriodStartRealtime);
out.writeLong(mTimePeriodEndRealtime);
+ out.writeInt(mFlags);
out.writeInt(mLongs.size());
out.writeInt(mNextLong);
@@ -920,7 +993,7 @@
private boolean readCheckedInt(Parcel in, int val, String what) {
int got;
if ((got=in.readInt()) != val) {
- mReadError = "bad " + ": " + got;
+ mReadError = "bad " + what + ": " + got;
return false;
}
return true;
@@ -956,6 +1029,7 @@
buildTimePeriodStartClockStr();
mTimePeriodStartRealtime = in.readLong();
mTimePeriodEndRealtime = in.readLong();
+ mFlags = in.readInt();
final int NLONGS = in.readInt();
final int NEXTLONG = in.readInt();
@@ -1365,8 +1439,9 @@
void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- new int[] { STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS },
+ new int[] { STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+ STATE_SERVICE, STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY },
now, reqPackage);
pw.println();
pw.println("Run time Stats:");
@@ -1379,6 +1454,9 @@
TimeUtils.formatDuration(
(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
- mTimePeriodStartRealtime, pw);
+ if ((mFlags&FLAG_COMPLETE) != 0) pw.print(" (complete)");
+ else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(" (shutdown)");
+ else pw.print(" (partial)");
pw.println();
}
@@ -1452,10 +1530,13 @@
void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
final long now = SystemClock.uptimeMillis();
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- pw.println("vers,1");
+ pw.println("vers,2");
pw.print("period,"); pw.print(mTimePeriodStartClockStr);
pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+ if ((mFlags&FLAG_COMPLETE) != 0) pw.print(",complete");
+ else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(",shutdown");
+ else pw.print(",partial");
pw.println();
for (int ip=0; ip<pkgMap.size(); ip++) {
String pkgName = pkgMap.keyAt(ip);
@@ -1629,6 +1710,7 @@
if (now > (mState.mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime() > (mState.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
mCommitPending = true;
+ mState.mFlags |= State.FLAG_COMPLETE;
}
return true;
}
@@ -1637,6 +1719,7 @@
public void shutdownLocked() {
Slog.w(TAG, "Writing process stats before shutdown...");
+ mState.mFlags |= State.FLAG_SHUTDOWN;
writeStateSyncLocked();
mShuttingDown = true;
}
@@ -1841,6 +1924,9 @@
long minPss;
long avgPss;
long maxPss;
+ long minUss;
+ long avgUss;
+ long maxUss;
ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
screenStates = _screenStates;
@@ -1857,6 +1943,12 @@
printSizeValue(pw, avgPss * 1024);
pw.print("-");
printSizeValue(pw, maxPss * 1024);
+ pw.print("/");
+ printSizeValue(pw, minUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, avgUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, maxUss * 1024);
if (full) {
pw.print(" over ");
pw.print(numPss);
@@ -1868,7 +1960,8 @@
static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
data.totalTime = 0;
- data.numPss = data.minPss = data.avgPss = data.maxPss = 0;
+ data.numPss = data.minPss = data.avgPss = data.maxPss =
+ data.minUss = data.avgUss = data.maxUss = 0;
for (int is=0; is<data.screenStates.length; is++) {
for (int im=0; im<data.memStates.length; im++) {
for (int ip=0; ip<data.procStates.length; ip++) {
@@ -1880,10 +1973,16 @@
long minPss = proc.getPssMinimum(bucket);
long avgPss = proc.getPssAverage(bucket);
long maxPss = proc.getPssMaximum(bucket);
+ long minUss = proc.getPssUssMinimum(bucket);
+ long avgUss = proc.getPssUssAverage(bucket);
+ long maxUss = proc.getPssUssMaximum(bucket);
if (data.numPss == 0) {
data.minPss = minPss;
data.avgPss = avgPss;
data.maxPss = maxPss;
+ data.minUss = minUss;
+ data.avgUss = avgUss;
+ data.maxUss = maxUss;
} else {
if (minPss < data.minPss) {
data.minPss = minPss;
@@ -1893,6 +1992,14 @@
if (maxPss > data.maxPss) {
data.maxPss = maxPss;
}
+ if (minUss < data.minUss) {
+ data.minUss = minUss;
+ }
+ data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+ + (avgUss*(double)samples)) / (data.numPss+samples) );
+ if (maxUss > data.maxUss) {
+ data.maxUss = maxUss;
+ }
}
data.numPss += samples;
}
@@ -1989,7 +2096,7 @@
if (count > 0) {
if (!printedHeader) {
pw.print(prefix);
- pw.print("PSS (");
+ pw.print("PSS/USS (");
pw.print(proc.mPssTableSize);
pw.println(" entries):");
printedHeader = true;
@@ -2013,6 +2120,12 @@
printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
pw.print(" ");
printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+ pw.print(" / ");
+ printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
pw.println();
}
}
@@ -2148,21 +2261,28 @@
dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
procStates, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
- new int[] {STATE_PERSISTENT}, now, true);
+ new int[] { STATE_PERSISTENT }, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
new int[] {STATE_TOP}, now, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Foreground: ", screenStates, memStates,
- new int[] {STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates,
+ new int[] { STATE_IMPORTANT_FOREGROUND }, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates,
+ new int[] {STATE_IMPORTANT_BACKGROUND}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
new int[] {STATE_BACKUP}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates,
+ new int[] {STATE_HEAVY_WEIGHT}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
new int[] {STATE_SERVICE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates,
+ new int[] {STATE_RECEIVER}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates,
new int[] {STATE_HOME}, now, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Previous: ", screenStates, memStates,
- new int[] {STATE_PREVIOUS}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Last Act: ", screenStates, memStates,
+ new int[] {STATE_LAST_ACTIVITY}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
- new int[] {STATE_CACHED}, now, true);
+ new int[] {STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_ACTIVITY_CLIENT,
+ STATE_CACHED_EMPTY}, now, true);
}
}
@@ -2193,9 +2313,9 @@
if (result < 1) {
value = String.format("%.2f", result);
} else if (result < 10) {
- value = String.format("%.2f", result);
+ value = String.format("%.1f", result);
} else if (result < 100) {
- value = String.format("%.2f", result);
+ value = String.format("%.0f", result);
} else {
value = String.format("%.0f", result);
}
@@ -2300,6 +2420,9 @@
long min = proc.mState.getLong(off, PSS_MINIMUM);
long avg = proc.mState.getLong(off, PSS_AVERAGE);
long max = proc.mState.getLong(off, PSS_MAXIMUM);
+ long umin = proc.mState.getLong(off, PSS_USS_MINIMUM);
+ long uavg = proc.mState.getLong(off, PSS_USS_AVERAGE);
+ long umax = proc.mState.getLong(off, PSS_USS_MAXIMUM);
pw.print(',');
printProcStateTag(pw, type);
pw.print(':');
@@ -2310,6 +2433,12 @@
pw.print(avg);
pw.print(':');
pw.print(max);
+ pw.print(':');
+ pw.print(umin);
+ pw.print(':');
+ pw.print(uavg);
+ pw.print(':');
+ pw.print(umax);
}
}
@@ -2391,9 +2520,10 @@
int[] csvMemStats = new int[] {ADJ_MEM_FACTOR_CRITICAL};
boolean csvSepProcStats = true;
int[] csvProcStats = new int[] {
- STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
- STATE_PREVIOUS, STATE_CACHED };
+ STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE,
+ STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY,
+ STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY };
if (args != null) {
for (int i=0; i<args.length; i++) {
String arg = args[i];
@@ -2457,6 +2587,7 @@
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
+ mState.mFlags |= State.FLAG_COMPLETE;
mState.writeStateLocked(true, true);
pw.println("Process stats committed.");
return;
@@ -2557,6 +2688,13 @@
if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
try {
State state = new State(files.get(i));
+ if (state.mReadError != null) {
+ pw.print("Failure reading "); pw.print(files.get(i));
+ pw.print("; "); pw.println(state.mReadError);
+ if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
+ (new File(files.get(i))).delete();
+ continue;
+ }
String fileStr = state.mFile.getBaseFile().getPath();
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
@@ -2588,7 +2726,6 @@
pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
e.printStackTrace(pw);
}
- if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
}
}
} finally {
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 9e2e841..2da95c3 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -1273,7 +1273,7 @@
for (int i = 0; i < settings.periodicSyncs.size(); i++) {
final Pair<Bundle, Long> pair = settings.periodicSyncs.get(i);
final String period = String.valueOf(pair.second);
- final String extras = pair.first.size() > 0 ? pair.first.toString() : "";
+ final String extras = pair.first.size() > 0 ? " " + pair.first.toString() : "";
final String next = formatTime(status.getPeriodicSyncTime(i)
+ pair.second * 1000);
table.set(row + i * 2, 12, period + extras);
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
index c9e0da5..21e54fe 100644
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -73,7 +73,7 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
}
- public void systemReady() {
+ public void systemRunning() {
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 5e4907e..7b4c077 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -283,7 +283,7 @@
}
// TODO(BT) Pass in paramter for bluetooth system
- public void systemReady() {
+ public void systemRunning() {
if (DEBUG) {
Slog.d(TAG, "System ready.");
}
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
index 5173998..86e7685 100644
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ b/services/java/com/android/server/print/PrintManagerService.java
@@ -22,118 +22,111 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
-import android.print.IPrintAdapter;
import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrinterId;
-import android.print.PrinterInfo;
-import android.printservice.IPrintService;
-import android.printservice.IPrintServiceClient;
-import android.printservice.PrintServiceInfo;
import android.provider.Settings;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
import java.util.Set;
public final class PrintManagerService extends IPrintManager.Stub {
- private static final String LOG_TAG = PrintManagerService.class.getSimpleName();
-
private static final char COMPONENT_NAME_SEPARATOR = ':';
private final Object mLock = new Object();
- private final SimpleStringSplitter mStringColonSplitter =
- new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
-
- private final Map<ComponentName, PrintServiceClient> mServices =
- new HashMap<ComponentName, PrintServiceClient>();
-
- private final List<PrintServiceInfo> mInstalledServices = new ArrayList<PrintServiceInfo>();
-
- private final Set<ComponentName> mEnabledServiceNames = new HashSet<ComponentName>();
-
private final Context mContext;
- private final RemoteSpooler mSpooler;
-
- private final int mMyUid;
+ private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
private int mCurrentUserId = UserHandle.USER_OWNER;
- private IPrinterDiscoveryObserver mPrinterDiscoveryObserver;
-
public PrintManagerService(Context context) {
mContext = context;
- mSpooler = new RemoteSpooler(context);
- mMyUid = android.os.Process.myUid();
registerContentObservers();
- registerBoradcastreceivers();
+ registerBoradcastReceivers();
+ }
+
+ public void systemRuning() {
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ UserState userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
+ userState.getSpoolerLocked().notifyClientForActivteJobs();
+ }
+ }
+ });
}
@Override
- public PrintJobInfo print(String printJobName, IPrintClient client, IPrintAdapter printAdapter,
- PrintAttributes attributes, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId);
- final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId);
+ public PrintJobInfo print(String printJobName, IPrintClient client,
+ IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId,
+ int userId) {
+ final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ final RemotePrintSpooler spooler;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ spooler = userState.getSpoolerLocked();
+ }
final long identity = Binder.clearCallingIdentity();
try {
- return mSpooler.createPrintJob(printJobName, client, printAdapter,
- attributes, resolvedAppId, resolvedUserId);
+ return spooler.createPrintJob(printJobName, client, documentAdapter,
+ attributes, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public List<PrintJobInfo> getPrintJobs(int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId);
- final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId);
- // TODO: Do we want to return jobs in STATE_CREATED? We should probably
- // have additional argument for the types to get
+ public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
+ final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ final RemotePrintSpooler spooler;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ spooler = userState.getSpoolerLocked();
+ }
final long identity = Binder.clearCallingIdentity();
try {
- return mSpooler.getPrintJobs(null, PrintJobInfo.STATE_ANY,
- resolvedAppId, resolvedUserId);
+ return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY,
+ resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public PrintJobInfo getPrintJob(int printJobId, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId);
- final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId);
+ public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
+ final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ final RemotePrintSpooler spooler;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ spooler = userState.getSpoolerLocked();
+ }
final long identity = Binder.clearCallingIdentity();
try {
- return mSpooler.getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
+ return spooler.getPrintJobInfo(printJobId, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -141,93 +134,32 @@
@Override
public void cancelPrintJob(int printJobId, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissionsLocked(appId);
- final int resolvedUserId = resolveCallingUserEnforcingPermissionsIdLocked(userId);
+ final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ final RemotePrintSpooler spooler;
+ synchronized (mLock) {
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ spooler = userState.getSpoolerLocked();
+ }
final long identity = Binder.clearCallingIdentity();
try {
- if (mSpooler.cancelPrintJob(printJobId, resolvedAppId, resolvedUserId)) {
+ if (spooler.cancelPrintJob(printJobId, resolvedAppId)) {
return;
}
- PrintJobInfo printJob = getPrintJob(printJobId, resolvedAppId, resolvedUserId);
- if (printJob == null) {
+ PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
+ if (printJobInfo == null) {
return;
}
- ComponentName printServiceName = printJob.getPrinterId().getServiceComponentName();
- PrintServiceClient printService = null;
+ ComponentName printServiceName = printJobInfo.getPrinterId().getService();
+ RemotePrintService printService = null;
synchronized (mLock) {
- printService = mServices.get(printServiceName);
+ printService = userState.getActiveServices().get(printServiceName);
}
if (printService == null) {
return;
}
- printService.requestCancelPrintJob(printJob);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- // Called only from the spooler.
- @Override
- public void onPrintJobQueued(PrinterId printerId, PrintJobInfo printJob) {
- throwIfCallerNotSignedWithSystemKey();
- PrintServiceClient printService = null;
- synchronized (mLock) {
- ComponentName printServiceName = printerId.getServiceComponentName();
- printService = mServices.get(printServiceName);
- }
- if (printService != null) {
- final long identity = Binder.clearCallingIdentity();
- try {
- printService.notifyPrintJobQueued(printJob);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- // Called only from the spooler.
- @Override
- public void startDiscoverPrinters(IPrinterDiscoveryObserver observer) {
- throwIfCallerNotSignedWithSystemKey();
- List<PrintServiceClient> services = new ArrayList<PrintServiceClient>();
- synchronized (mLock) {
- mPrinterDiscoveryObserver = observer;
- services.addAll(mServices.values());
- }
- final int serviceCount = services.size();
- if (serviceCount <= 0) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- for (int i = 0; i < serviceCount; i++) {
- PrintServiceClient service = services.get(i);
- service.startPrinterDiscovery();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- // Called only from the spooler.
- @Override
- public void stopDiscoverPrinters() {
- throwIfCallerNotSignedWithSystemKey();
- List<PrintServiceClient> services = new ArrayList<PrintServiceClient>();
- synchronized (mLock) {
- mPrinterDiscoveryObserver = null;
- services.addAll(mServices.values());
- }
- final int serviceCount = services.size();
- if (serviceCount <= 0) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- for (int i = 0; i < serviceCount; i++) {
- PrintServiceClient service = services.get(i);
- service.stopPrintersDiscovery();
- }
+ printService.onRequestCancelPrintJob(printJobInfo);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -237,14 +169,13 @@
final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
Settings.Secure.ENABLED_PRINT_SERVICES);
- ContentObserver observer = new ContentObserver(new Handler(mContext.getMainLooper())) {
+ ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
if (enabledPrintServicesUri.equals(uri)) {
synchronized (mLock) {
- if (readEnabledPrintServicesChangedLocked()) {
- onUserStateChangedLocked();
- }
+ UserState userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
}
}
}
@@ -254,32 +185,37 @@
false, observer, UserHandle.USER_ALL);
}
- private void registerBoradcastreceivers() {
+ private void registerBoradcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
@Override
- public void onSomePackagesChanged() {
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
synchronized (mLock) {
- if (getChangingUserId() != mCurrentUserId) {
- return;
- }
- if (readConfigurationForUserStateLocked()) {
- onUserStateChangedLocked();
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+ Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
+ while (iterator.hasNext()) {
+ ComponentName componentName = iterator.next();
+ if (packageName.equals(componentName.getPackageName())) {
+ userState.updateIfNeededLocked();
+ return true;
+ }
}
}
+ return false;
}
@Override
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
- if (getChangingUserId() != mCurrentUserId) {
- return;
- }
- Iterator<ComponentName> iterator = mEnabledServiceNames.iterator();
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+ Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
while (iterator.hasNext()) {
ComponentName componentName = iterator.next();
if (packageName.equals(componentName.getPackageName())) {
iterator.remove();
- onEnabledServiceNamesChangedLocked();
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.ENABLED_PRINT_SERVICES,
+ userState.getEnabledServices(), getChangingUserId());
+ userState.updateIfNeededLocked();
return;
}
}
@@ -290,10 +226,9 @@
public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
int uid, boolean doit) {
synchronized (mLock) {
- if (getChangingUserId() != mCurrentUserId) {
- return false;
- }
- Iterator<ComponentName> iterator = mEnabledServiceNames.iterator();
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+ boolean stoppedSomePackages = false;
+ Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
while (iterator.hasNext()) {
ComponentName componentName = iterator.next();
String componentPackage = componentName.getPackageName();
@@ -302,27 +237,35 @@
if (!doit) {
return true;
}
- iterator.remove();
- onEnabledServiceNamesChangedLocked();
+ stoppedSomePackages = true;
+ break;
}
}
}
+ if (stoppedSomePackages) {
+ userState.updateIfNeededLocked();
+ }
return false;
}
}
- private void onEnabledServiceNamesChangedLocked() {
- // Update the enabled services setting.
- persistComponentNamesToSettingLocked(
- Settings.Secure.ENABLED_PRINT_SERVICES,
- mEnabledServiceNames, mCurrentUserId);
- // Update the current user state.
- onUserStateChangedLocked();
+ private void persistComponentNamesToSettingLocked(String settingName,
+ Set<ComponentName> componentNames, int userId) {
+ StringBuilder builder = new StringBuilder();
+ for (ComponentName componentName : componentNames) {
+ if (builder.length() > 0) {
+ builder.append(COMPONENT_NAME_SEPARATOR);
+ }
+ builder.append(componentName.flattenToShortString());
+ }
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ settingName, builder.toString(), userId);
}
};
// package changes
- monitor.register(mContext, null, UserHandle.ALL, true);
+ monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+ UserHandle.ALL, true);
// user changes
IntentFilter intentFilter = new IntentFilter();
@@ -334,179 +277,67 @@
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
}
}
- }, UserHandle.ALL, intentFilter, null, null);
+ }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
}
- private void throwIfCallerNotSignedWithSystemKey() {
- if (mContext.getPackageManager().checkSignatures(
- mMyUid, Binder.getCallingUid()) != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException("Caller must be signed with the system key!");
+ private UserState getCurrentUserStateLocked() {
+ return getOrCreateUserStateLocked(mCurrentUserId);
+ }
+
+ private UserState getOrCreateUserStateLocked(int userId) {
+ UserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ userState = new UserState(mContext, userId, mLock);
+ mUserStates.put(userId, userState);
}
- }
-
- private void onUserStateChangedLocked() {
- manageServicesLocked();
- }
-
- private void manageServicesLocked() {
- final int installedCount = mInstalledServices.size();
- for (int i = 0; i < installedCount; i++) {
- ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo();
- ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name);
- if (mEnabledServiceNames.contains(serviceName)) {
- if (!mServices.containsKey(serviceName)) {
- new PrintServiceClient(serviceName, mCurrentUserId).ensureBoundLocked();
- }
- } else {
- PrintServiceClient service = mServices.get(serviceName);
- if (service != null) {
- service.ensureUnboundLocked();
- }
- }
- }
- }
-
- private boolean readConfigurationForUserStateLocked() {
- boolean somethingChanged = false;
- somethingChanged |= readInstalledPrintServiceLocked();
- somethingChanged |= readEnabledPrintServicesChangedLocked();
- return somethingChanged;
- }
-
- private boolean readEnabledPrintServicesChangedLocked() {
- Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
- readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
- mCurrentUserId, tempEnabledServiceNameSet);
- if (!tempEnabledServiceNameSet.equals(mEnabledServiceNames)) {
- mEnabledServiceNames.clear();
- mEnabledServiceNames.addAll(tempEnabledServiceNameSet);
- return true;
- }
- return false;
- }
-
- private boolean readInstalledPrintServiceLocked() {
- Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
-
- List<ResolveInfo> installedServices = mContext.getPackageManager()
- .queryIntentServicesAsUser(
- new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
- mCurrentUserId);
-
- final int installedCount = installedServices.size();
- for (int i = 0, count = installedCount; i < count; i++) {
- ResolveInfo installedService = installedServices.get(i);
- if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals(
- installedService.serviceInfo.permission)) {
- ComponentName serviceName = new ComponentName(
- installedService.serviceInfo.packageName,
- installedService.serviceInfo.name);
- Slog.w(LOG_TAG, "Skipping print service "
- + serviceName.flattenToShortString()
- + " since it does not require permission "
- + android.Manifest.permission.BIND_PRINT_SERVICE);
- continue;
- }
- tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
- }
-
- if (!tempPrintServices.equals(mInstalledServices)) {
- mInstalledServices.clear();
- mInstalledServices.addAll(tempPrintServices);
- return true;
- }
- return false;
- }
-
- private void readComponentNamesFromSettingLocked(String settingName, int userId,
- Set<ComponentName> outComponentNames) {
- String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- settingName, userId);
- outComponentNames.clear();
- if (!TextUtils.isEmpty(settingValue)) {
- TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
- splitter.setString(settingValue);
- while (splitter.hasNext()) {
- String string = splitter.next();
- if (TextUtils.isEmpty(string)) {
- continue;
- }
- ComponentName componentName = ComponentName.unflattenFromString(string);
- if (componentName != null) {
- outComponentNames.add(componentName);
- }
- }
- }
- }
-
- private void persistComponentNamesToSettingLocked(String settingName,
- Set<ComponentName> componentNames, int userId) {
- StringBuilder builder = new StringBuilder();
- for (ComponentName componentName : componentNames) {
- if (builder.length() > 0) {
- builder.append(COMPONENT_NAME_SEPARATOR);
- }
- builder.append(componentName.flattenToShortString());
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- settingName, builder.toString(), userId);
+ return userState;
}
private void switchUser(int newUserId) {
synchronized (mLock) {
- // Disconnect services for the old user.
- mEnabledServiceNames.clear();
- onUserStateChangedLocked();
-
- // The user changed.
+ if (newUserId == mCurrentUserId) {
+ return;
+ }
mCurrentUserId = newUserId;
-
- // Update the user state based on current settings.
- readConfigurationForUserStateLocked();
- onUserStateChangedLocked();
- }
-
- // Unbind the spooler for the old user).
- mSpooler.unbind();
-
- // If we have queued jobs, advertise it, or we do
- // not need the spooler for now.
- if (notifyQueuedPrintJobs()) {
- mSpooler.unbind();
+ UserState userState = getCurrentUserStateLocked();
+ userState.updateIfNeededLocked();
+ userState.getSpoolerLocked().notifyClientForActivteJobs();
}
}
- private boolean notifyQueuedPrintJobs() {
- Map<PrintServiceClient, List<PrintJobInfo>> notifications =
- new HashMap<PrintServiceClient, List<PrintJobInfo>>();
+ private void removeUser(int removedUserId) {
synchronized (mLock) {
- for (PrintServiceClient service : mServices.values()) {
- List<PrintJobInfo> printJobs = mSpooler.getPrintJobs(
- service.mComponentName, PrintJobInfo.STATE_QUEUED,
- PrintManager.APP_ID_ANY, service.mUserId);
- notifications.put(service, printJobs);
+ UserState userState = mUserStates.get(removedUserId);
+ if (userState != null) {
+ userState.destroyLocked();
+ mUserStates.remove(removedUserId);
}
}
- if (notifications.isEmpty()) {
- return false;
- }
- for (Map.Entry<PrintServiceClient, List<PrintJobInfo>> notification
- : notifications.entrySet()) {
- PrintServiceClient service = notification.getKey();
- List<PrintJobInfo> printJobs = notification.getValue();
- final int printJobIdCount = printJobs.size();
- for (int i = 0; i < printJobIdCount; i++) {
- service.notifyPrintJobQueued(printJobs.get(i));
- }
- }
- return true;
}
- private int resolveCallingUserEnforcingPermissionsIdLocked(int userId) {
+ private int resolveCallingAppEnforcingPermissions(int appId) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID) {
+ return appId;
+ }
+ final int callingAppId = UserHandle.getAppId(callingUid);
+ if (appId == callingAppId) {
+ return appId;
+ }
+ if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Call from app " + callingAppId + " as app "
+ + appId + " without permission ACCESS_ALL_PRINT_JOBS");
+ }
+ return appId;
+ }
+
+ private int resolveCallingUserEnforcingPermissions(int userId) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0 || callingUid == Process.SYSTEM_UID
|| callingUid == Process.SHELL_UID) {
@@ -524,8 +355,8 @@
return callingUserId;
}
throw new SecurityException("Call from user " + callingUserId + " as user "
- + userId + " without permission INTERACT_ACROSS_USERS or "
- + "INTERACT_ACROSS_USERS_FULL not allowed.");
+ + userId + " without permission INTERACT_ACROSS_USERS or "
+ + "INTERACT_ACROSS_USERS_FULL not allowed.");
}
if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
return mCurrentUserId;
@@ -533,257 +364,4 @@
throw new IllegalArgumentException("Calling user can be changed to only "
+ "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
}
-
- private int resolveCallingAppEnforcingPermissionsLocked(int appId) {
- final int callingUid = Binder.getCallingUid();
- if (callingUid == 0 || callingUid == Process.SYSTEM_UID
- || callingUid == Process.SHELL_UID) {
- return appId;
- }
- final int callingAppId = UserHandle.getAppId(callingUid);
- if (appId == callingAppId) {
- return appId;
- }
- if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Call from app " + callingAppId + " as app "
- + appId + " without permission INTERACT_ACROSS_APPS");
- }
- return appId;
- }
-
- private final class PrintServiceClient extends IPrintServiceClient.Stub
- implements ServiceConnection, DeathRecipient {
-
- private final ComponentName mComponentName;
-
- private final Intent mIntent;
-
- private final int mUserId;
-
- private IPrintService mInterface;
-
- private boolean mBinding;
-
- private boolean mWasConnectedAndDied;
-
- public PrintServiceClient(ComponentName componentName, int userId) {
- mComponentName = componentName;
- mIntent = new Intent().setComponent(mComponentName);
- mUserId = userId;
- }
-
- @Override
- public List<PrintJobInfo> getPrintJobs() {
- return mSpooler.getPrintJobs(mComponentName, PrintJobInfo.STATE_ANY,
- PrintManager.APP_ID_ANY, mUserId);
- }
-
- @Override
- public PrintJobInfo getPrintJob(int printJobId) {
- return mSpooler.getPrintJobInfo(printJobId,
- PrintManager.APP_ID_ANY, mUserId);
- }
-
- @Override
- public boolean setPrintJobState(int printJobId, int state) {
- return mSpooler.setPrintJobState(printJobId, state, mUserId);
- }
-
- @Override
- public boolean setPrintJobTag(int printJobId, String tag) {
- return mSpooler.setPrintJobTag(printJobId, tag, mUserId);
- }
-
- @Override
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
- mSpooler.writePrintJobData(fd, printJobId, mUserId);
- }
-
- @Override
- public void addDiscoveredPrinters(List<PrinterInfo> printers) {
- throwIfPrinterIdsForPrinterInfoTampered(printers);
- synchronized (mLock) {
- if (mPrinterDiscoveryObserver != null) {
- try {
- mPrinterDiscoveryObserver.addDiscoveredPrinters(printers);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
- }
-
- @Override
- public void removeDiscoveredPrinters(List<PrinterId> printerIds) {
- throwIfPrinterIdsTampered(printerIds);
- synchronized (mLock) {
- if (mPrinterDiscoveryObserver != null) {
- try {
- mPrinterDiscoveryObserver.removeDiscoveredPrinters(printerIds);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
- }
-
- public void requestCancelPrintJob(PrintJobInfo printJob) {
- synchronized (mLock) {
- try {
- mInterface.requestCancelPrintJob(printJob);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error canceling pring job!", re);
- }
- }
- }
-
- public void notifyPrintJobQueued(PrintJobInfo printJob) {
- IPrintService service = mInterface;
- if (service != null) {
- try {
- service.onPrintJobQueued(printJob);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
-
- public void startPrinterDiscovery() {
- IPrintService service = mInterface;
- if (service != null) {
- try {
- service.startPrinterDiscovery();
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
-
- public void stopPrintersDiscovery() {
- IPrintService service = mInterface;
- if (service != null) {
- try {
- service.stopPrinterDiscovery();
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
-
- public void ensureBoundLocked() {
- if (mBinding) {
- return;
- }
- if (mInterface == null) {
- mBinding = true;
- mContext.bindServiceAsUser(mIntent, this,
- Context.BIND_AUTO_CREATE, new UserHandle(mUserId));
- }
- }
-
- public void ensureUnboundLocked() {
- if (mBinding) {
- mBinding = false;
- return;
- }
- if (mInterface != null) {
- mContext.unbindService(this);
- destroyLocked();
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- mInterface = IPrintService.Stub.asInterface(service);
- mServices.put(mComponentName, this);
- try {
- mInterface.asBinder().linkToDeath(this, 0);
- } catch (RemoteException re) {
- destroyLocked();
- return;
- }
- if (mUserId != mCurrentUserId) {
- destroyLocked();
- return;
- }
- if (mBinding || mWasConnectedAndDied) {
- mBinding = false;
- mWasConnectedAndDied = false;
- onUserStateChangedLocked();
- try {
- mInterface.setClient(this);
- } catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error while setting client for service: "
- + service, re);
- }
- } else {
- destroyLocked();
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- /* do nothing - #binderDied takes care */
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- if (isConnectedLocked()) {
- mWasConnectedAndDied = true;
- }
- destroyLocked();
- }
- }
-
- private void destroyLocked() {
- if (mServices.remove(mComponentName) == null) {
- return;
- }
- if (isConnectedLocked()) {
- try {
- mInterface.asBinder().unlinkToDeath(this, 0);
- } catch (NoSuchElementException nse) {
- /* ignore */
- }
- try {
- mInterface.setClient(null);
- } catch (RemoteException re) {
- /* ignore */
- }
- mInterface = null;
- }
- mBinding = false;
- }
-
- private boolean isConnectedLocked() {
- return (mInterface != null);
- }
-
- private void throwIfPrinterIdsForPrinterInfoTampered(List<PrinterInfo> printerInfos) {
- final int printerInfoCount = printerInfos.size();
- for (int i = 0; i < printerInfoCount; i++) {
- PrinterId printerId = printerInfos.get(i).getId();
- throwIfPrinterIdTampered(printerId);
- }
- }
-
- private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) {
- final int printerIdCount = printerIds.size();
- for (int i = 0; i < printerIdCount; i++) {
- PrinterId printerId = printerIds.get(i);
- throwIfPrinterIdTampered(printerId);
- }
- }
-
- private void throwIfPrinterIdTampered(PrinterId printerId) {
- if (printerId == null || printerId.getServiceComponentName() == null
- || !printerId.getServiceComponentName().equals(mComponentName)) {
- throw new IllegalArgumentException("Invalid printer id: " + printerId);
- }
- }
- }
}
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
new file mode 100644
index 0000000..b9e0280
--- /dev/null
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -0,0 +1,466 @@
+/*
+ * 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.server.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.IPrintService;
+import android.printservice.IPrintServiceClient;
+import android.util.Slog;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a remote print service. It abstracts away the binding
+ * 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 {
+
+ private static final String LOG_TAG = "RemotePrintService";
+
+ private static final boolean DEBUG = true;
+
+ private final Context mContext;
+
+ private final ComponentName mComponentName;
+
+ private final Intent mIntent;
+
+ private final RemotePrintSpooler mSpooler;
+
+ private final int mUserId;
+
+ private final List<Runnable> mPendingCommands = new ArrayList<Runnable>();
+
+ private final ServiceConnection mServiceConnection = new RemoteServiceConneciton();
+
+ private final RemotePrintServiceClient mPrintServiceClient;
+
+ private final Handler mHandler;
+
+ private IPrintService mPrintService;
+
+ private boolean mBinding;
+
+ private boolean mDestroyed;
+
+ public RemotePrintService(Context context, ComponentName componentName, int userId,
+ RemotePrintSpooler spooler) {
+ mContext = context;
+ mComponentName = componentName;
+ mIntent = new Intent().setComponent(mComponentName);
+ mUserId = userId;
+ mSpooler = spooler;
+ mHandler = new MyHandler(context.getMainLooper());
+ mPrintServiceClient = new RemotePrintServiceClient(this);
+ }
+
+ public void destroy() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY);
+ }
+
+ private void handleDestroy() {
+ throwIfDestroyed();
+ ensureUnbound();
+ mDestroyed = true;
+ }
+
+ public void onAllPrintJobsHandled() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_ALL_PRINT_JOBS_HANDLED);
+ }
+
+ private void handleOnAllPrintJobsHandled() {
+ throwIfDestroyed();
+ if (isBound()) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled");
+ }
+ // If bound and all the work is completed, then unbind.
+ ensureUnbound();
+ }
+ }
+
+ public void onRequestCancelPrintJob(PrintJobInfo printJob) {
+ mHandler.obtainMessage(MyHandler.MSG_REQUEST_CANCEL_PRINT_JOB,
+ printJob).sendToTarget();
+ }
+
+ private void handleOnRequestCancelPrintJob(final PrintJobInfo printJob) {
+ throwIfDestroyed();
+ // If we are not bound, then we have no print jobs to handle
+ // which means that there are no print jobs to be cancelled.
+ if (isBound()) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnRequestCancelPrintJob()");
+ }
+ try {
+ mPrintService.requestCancelPrintJob(printJob);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error canceling pring job.", re);
+ }
+ }
+ }
+
+ public void onPrintJobQueued(PrintJobInfo printJob) {
+ mHandler.obtainMessage(MyHandler.MSG_PRINT_JOB_QUEUED,
+ printJob).sendToTarget();
+ }
+
+ private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
+ throwIfDestroyed();
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleOnPrintJobQueued(printJob);
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnPrintJobQueued()");
+ }
+ try {
+ mPrintService.onPrintJobQueued(printJob);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error announcing queued pring job.", re);
+ }
+ }
+ }
+
+ public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, observer).sendToTarget();
+ }
+
+ private void handleOnStartPrinterDiscovery(final IPrinterDiscoveryObserver observer) {
+ throwIfDestroyed();
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleOnStartPrinterDiscovery(observer);
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] onStartPrinterDiscovery()");
+ }
+ try {
+ mPrintService.startPrinterDiscovery(observer);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re);
+ }
+ }
+ }
+
+ public void onStopPrinterDiscovery() {
+ mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY);
+ }
+
+ private void handleStopPrinterDiscovery() {
+ throwIfDestroyed();
+ if (!isBound()) {
+ ensureBound();
+ mPendingCommands.add(new Runnable() {
+ @Override
+ public void run() {
+ handleStopPrinterDiscovery();
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] onStopPrinterDiscovery()");
+ }
+ try {
+ mPrintService.stopPrinterDiscovery();
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error announcing stop printer dicovery.", re);
+ }
+ }
+ }
+
+ private boolean isBound() {
+ return mPrintService != null;
+ }
+
+ private void ensureBound() {
+ if (isBound() || mBinding) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
+ }
+ mBinding = true;
+ mContext.bindServiceAsUser(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUserId));
+ }
+
+ private void ensureUnbound() {
+ if (!isBound() && !mBinding) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()");
+ }
+ mBinding = false;
+ mPendingCommands.clear();
+ if (isBound()) {
+ try {
+ mPrintService.setClient(null);
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ mPrintService = null;
+ mContext.unbindService(mServiceConnection);
+ }
+ }
+
+ private void throwIfDestroyed() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Cannot interact with a destroyed service");
+ }
+ }
+
+ private class RemoteServiceConneciton implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (mDestroyed || !mBinding) {
+ return;
+ }
+ mBinding = false;
+ mPrintService = IPrintService.Stub.asInterface(service);
+ try {
+ mPrintService.setClient(mPrintServiceClient);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error setting client for: " + service, re);
+ handleDestroy();
+ return;
+ }
+ final int pendingCommandCount = mPendingCommands.size();
+ for (int i = 0; i < pendingCommandCount; i++) {
+ Runnable pendingCommand = mPendingCommands.get(i);
+ pendingCommand.run();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinding = true;
+ }
+ }
+
+ 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 MyHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ALL_PRINT_JOBS_HANDLED: {
+ handleOnAllPrintJobsHandled();
+ } break;
+
+ case MSG_REQUEST_CANCEL_PRINT_JOB: {
+ PrintJobInfo printJob = (PrintJobInfo) message.obj;
+ handleOnRequestCancelPrintJob(printJob);
+ } break;
+
+ case MSG_PRINT_JOB_QUEUED: {
+ PrintJobInfo printJob = (PrintJobInfo) message.obj;
+ handleOnPrintJobQueued(printJob);
+ } break;
+
+ case MSG_START_PRINTER_DISCOVERY: {
+ IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) message.obj;
+ handleOnStartPrinterDiscovery(new SecurePrinterDiscoveryObserver(
+ mComponentName, observer));
+ } break;
+
+ case MSG_STOP_PRINTER_DISCOVERY: {
+ handleStopPrinterDiscovery();
+ } break;
+
+ case MSG_DESTROY: {
+ handleDestroy();
+ } break;
+ }
+ }
+ }
+
+ private static final class RemotePrintServiceClient extends IPrintServiceClient.Stub {
+ private final WeakReference<RemotePrintService> mWeakService;
+
+ public RemotePrintServiceClient(RemotePrintService service) {
+ mWeakService = new WeakReference<RemotePrintService>(service);
+ }
+
+ @Override
+ public List<PrintJobInfo> getPrintJobInfos() {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return service.mSpooler.getPrintJobInfos(service.mComponentName,
+ PrintJobInfo.STATE_ANY, PrintManager.APP_ID_ANY);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public PrintJobInfo getPrintJobInfo(int printJobId) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return service.mSpooler.getPrintJobInfo(printJobId,
+ PrintManager.APP_ID_ANY);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean setPrintJobState(int printJobId, int state) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return service.mSpooler.setPrintJobState(printJobId, state);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean setPrintJobTag(int printJobId, String tag) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return service.mSpooler.setPrintJobTag(printJobId, tag);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ service.mSpooler.writePrintJobData(fd, printJobId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+ }
+
+ private static final class SecurePrinterDiscoveryObserver
+ extends IPrinterDiscoveryObserver.Stub {
+ private final ComponentName mComponentName;
+
+ private final IPrinterDiscoveryObserver mDecoratedObsever;
+
+ public SecurePrinterDiscoveryObserver(ComponentName componentName,
+ IPrinterDiscoveryObserver observer) {
+ mComponentName = componentName;
+ mDecoratedObsever = observer;
+ }
+
+ @Override
+ public void addDiscoveredPrinters(List<PrinterInfo> printers) {
+ throwIfPrinterIdsForPrinterInfoTampered(printers);
+ try {
+ mDecoratedObsever.addDiscoveredPrinters(printers);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error delegating to addDiscoveredPrinters", re);
+ }
+ }
+
+ @Override
+ public void removeDiscoveredPrinters(List<PrinterId> printerIds) {
+ throwIfPrinterIdsTampered(printerIds);
+ try {
+ mDecoratedObsever.removeDiscoveredPrinters(printerIds);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error delegating to removeDiscoveredPrinters", re);
+ }
+ }
+
+ private void throwIfPrinterIdsForPrinterInfoTampered(
+ List<PrinterInfo> printerInfos) {
+ final int printerInfoCount = printerInfos.size();
+ for (int i = 0; i < printerInfoCount; i++) {
+ PrinterId printerId = printerInfos.get(i).getId();
+ throwIfPrinterIdTampered(printerId);
+ }
+ }
+
+ private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) {
+ final int printerIdCount = printerIds.size();
+ for (int i = 0; i < printerIdCount; i++) {
+ PrinterId printerId = printerIds.get(i);
+ throwIfPrinterIdTampered(printerId);
+ }
+ }
+
+ private void throwIfPrinterIdTampered(PrinterId printerId) {
+ if (printerId == null || printerId.getService() == null
+ || !printerId.getService().equals(mComponentName)) {
+ throw new IllegalArgumentException("Invalid printer id: " + printerId);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
new file mode 100644
index 0000000..bf2c8e7
--- /dev/null
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -0,0 +1,613 @@
+/*
+ * 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.server.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.print.IPrintClient;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintSpooler;
+import android.print.IPrintSpoolerCallbacks;
+import android.print.IPrintSpoolerClient;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobInfo;
+import android.util.Slog;
+import android.util.TimedRemoteCaller;
+
+import libcore.io.IoUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This represents the remote print spooler as a local object to the
+ * PrintManagerSerivce. It is responsible to connecting to the remote
+ * spooler if needed, to make the timed remote calls, to handle
+ * remote exceptions, and to bind/unbind to the remote instance as
+ * needed.
+ */
+final class RemotePrintSpooler {
+
+ private static final String LOG_TAG = "RemotePrintSpooler";
+
+ private static final boolean DEBUG = true;
+
+ private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
+
+ private final Object mLock = new Object();
+
+ private final GetPrintJobInfosCaller mGetPrintJobInfosCaller = new GetPrintJobInfosCaller();
+
+ private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller();
+
+ private final CancelPrintJobCaller mCancelPrintJobCaller = new CancelPrintJobCaller();
+
+ private final GetPrintJobInfoCaller mGetPrintJobInfoCaller = new GetPrintJobInfoCaller();
+
+ private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
+
+ private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
+
+ private final ServiceConnection mServiceConnection = new MyServiceConnection();
+
+ private final Context mContext;
+
+ private final UserHandle mUserHandle;
+
+ private final PrintSpoolerClient mClient;
+
+ private final Intent mIntent;
+
+ private final PrintSpoolerCallbacks mCallbacks;
+
+ private IPrintSpooler mRemoteInstance;
+
+ private boolean mDestroyed;
+
+ public static interface PrintSpoolerCallbacks {
+ public void onPrintJobQueued(PrintJobInfo printJob);
+ public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer);
+ public void onStopPrinterDiscovery();
+ public void onAllPrintJobsForServiceHandled(ComponentName printService);
+ }
+
+ public RemotePrintSpooler(Context context, int userId,
+ PrintSpoolerCallbacks callbacks) {
+ mContext = context;
+ mUserHandle = new UserHandle(userId);
+ mCallbacks = callbacks;
+ mClient = new PrintSpoolerClient(this);
+ mIntent = new Intent();
+ mIntent.setComponent(new ComponentName("com.android.printspooler",
+ "com.android.printspooler.PrintSpoolerService"));
+ }
+
+ public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
+ int appId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfos()");
+ }
+ try {
+ return mGetPrintJobInfosCaller.getPrintJobInfos(getRemoteInstanceLazy(),
+ componentName, state, appId);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error getting print jobs.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error getting print jobs.", te);
+ }
+ return null;
+ }
+
+ public final PrintJobInfo createPrintJob(String printJobName, IPrintClient client,
+ IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] createPrintJob()");
+ }
+ try {
+ return mCreatePrintJobCaller.createPrintJob(getRemoteInstanceLazy(),
+ printJobName, client, documentAdapter, attributes, appId);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error creating print job.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error creating print job.", te);
+ }
+ return null;
+ }
+
+ public final boolean cancelPrintJob(int printJobId, int appId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] cancelPrintJob()");
+ }
+ try {
+ return mCancelPrintJobCaller.cancelPrintJob(getRemoteInstanceLazy(),
+ printJobId, appId);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error canceling print job.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error canceling print job.", te);
+ }
+ return false;
+ }
+
+ public final void writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] writePrintJobData()");
+ }
+ try {
+ getRemoteInstanceLazy().writePrintJobData(fd, printJobId);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error writing print job data.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error writing print job data.", te);
+ } finally {
+ // We passed the file descriptor across and now the other
+ // side is responsible to close it, so close the local copy.
+ IoUtils.closeQuietly(fd);
+ }
+ }
+
+ public final PrintJobInfo getPrintJobInfo(int printJobId, int appId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] getPrintJobInfo()");
+ }
+ try {
+ return mGetPrintJobInfoCaller.getPrintJobInfo(getRemoteInstanceLazy(),
+ printJobId, appId);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error getting print job info.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error getting print job info.", te);
+ }
+ return null;
+ }
+
+ public final boolean setPrintJobState(int printJobId, int state) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobState()");
+ }
+ try {
+ return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstanceLazy(),
+ printJobId, state);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error setting print job state.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error setting print job state.", te);
+ }
+ return false;
+ }
+
+ public final boolean setPrintJobTag(int printJobId, String tag) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] setPrintJobTag()");
+ }
+ try {
+ return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstanceLazy(),
+ printJobId, tag);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error setting print job tag.", re);
+ } catch (TimeoutException te) {
+ Slog.e(LOG_TAG, "Error setting print job tag.", te);
+ }
+ return false;
+ }
+
+ public final void notifyClientForActivteJobs() {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ }
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ + "] notifyClientForActivteJobs()");
+ }
+ try {
+ getRemoteInstanceLazy().notifyClientForActivteJobs();
+ } catch (RemoteException re) {
+ 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);
+ }
+ }
+
+ public final void destroy() {
+ throwIfCalledOnMainThread();
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] destroy()");
+ }
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ unbindLocked();
+ mDestroyed = true;
+ }
+ }
+
+ private void onAllPrintJobsHandled() {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ unbindLocked();
+ }
+ }
+
+ private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
+ synchronized (mLock) {
+ if (mRemoteInstance != null) {
+ return mRemoteInstance;
+ }
+ bindLocked();
+ return mRemoteInstance;
+ }
+ }
+
+ private void bindLocked() throws TimeoutException {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] bindLocked()");
+ }
+
+ mContext.bindServiceAsUser(mIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT,
+ mUserHandle);
+
+ final long startMillis = SystemClock.uptimeMillis();
+ while (true) {
+ if (mRemoteInstance != null) {
+ break;
+ }
+ final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
+ final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
+ if (remainingMillis <= 0) {
+ throw new TimeoutException("Cannot get spooler!");
+ }
+ try {
+ mLock.wait(remainingMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+
+ private void unbindLocked() {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + "] unbindLocked()");
+ }
+ clearClientLocked();
+ mRemoteInstance = null;
+ mContext.unbindService(mServiceConnection);
+ }
+
+ private void setClientLocked() {
+ try {
+ mRemoteInstance.setClient(mClient);
+ } catch (RemoteException re) {
+ Slog.d(LOG_TAG, "Error setting print spooler client", re);
+ }
+ }
+
+ private void clearClientLocked() {
+ try {
+ mRemoteInstance.setClient(null);
+ } catch (RemoteException re) {
+ Slog.d(LOG_TAG, "Error clearing print spooler client", re);
+ }
+
+ }
+
+ private void throwIfDestroyedLocked() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Cannot interact with a destroyed instance.");
+ }
+ }
+
+ private void throwIfCalledOnMainThread() {
+ if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
+ throw new RuntimeException("Cannot invoke on the main thread");
+ }
+ }
+
+ private final class MyServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mRemoteInstance = IPrintSpooler.Stub.asInterface(service);
+ setClientLocked();
+ mLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ clearClientLocked();
+ mRemoteInstance = null;
+ }
+ }
+ }
+
+ private static final class GetPrintJobInfosCaller
+ extends TimedRemoteCaller<List<PrintJobInfo>> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public GetPrintJobInfosCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobs, int sequence) {
+ onRemoteMethodResult(printJobs, sequence);
+ }
+ };
+ }
+
+ public List<PrintJobInfo> getPrintJobInfos(IPrintSpooler target,
+ ComponentName componentName, int state, int appId)
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.getPrintJobInfos(mCallback, componentName, state, appId, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public CreatePrintJobCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
+ onRemoteMethodResult(printJob, sequence);
+ }
+ };
+ }
+
+ public PrintJobInfo createPrintJob(IPrintSpooler target, String printJobName,
+ IPrintClient client, IPrintDocumentAdapter documentAdapter,
+ PrintAttributes attributes, int appId) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.createPrintJob(printJobName, client, documentAdapter, attributes,
+ mCallback, appId, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class CancelPrintJobCaller extends TimedRemoteCaller<Boolean> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public CancelPrintJobCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onCancelPrintJobResult(boolean canceled, int sequence) {
+ onRemoteMethodResult(canceled, sequence);
+ }
+ };
+ }
+
+ public boolean cancelPrintJob(IPrintSpooler target, int printJobId,
+ int appId) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.cancelPrintJob(printJobId, mCallback, appId, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class GetPrintJobInfoCaller extends TimedRemoteCaller<PrintJobInfo> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public GetPrintJobInfoCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
+ onRemoteMethodResult(printJob, sequence);
+ }
+ };
+ }
+
+ public PrintJobInfo getPrintJobInfo(IPrintSpooler target, int printJobId,
+ int appId) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.getPrintJobInfo(printJobId, mCallback, appId, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public SetPrintJobStateCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onSetPrintJobStateResult(boolean success, int sequence) {
+ onRemoteMethodResult(success, sequence);
+ }
+ };
+ }
+
+ public boolean setPrintJobState(IPrintSpooler target, int printJobId,
+ int status) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.setPrintJobState(printJobId, status, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public SetPrintJobTagCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onSetPrintJobTagResult(boolean success, int sequence) {
+ onRemoteMethodResult(success, sequence);
+ }
+ };
+ }
+
+ public boolean setPrintJobTag(IPrintSpooler target, int printJobId,
+ String tag) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.setPrintJobTag(printJobId, tag, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static abstract class BasePrintSpoolerServiceCallbacks
+ extends IPrintSpoolerCallbacks.Stub {
+ @Override
+ public void onGetPrintJobInfosResult(List<PrintJobInfo> printJobIds, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onCancelPrintJobResult(boolean canceled, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onSetPrintJobStateResult(boolean success, int sequece) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onSetPrintJobTagResult(boolean success, int sequence) {
+ /* do nothing */
+ }
+ }
+
+ private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
+
+ private final WeakReference<RemotePrintSpooler> mWeakSpooler;
+
+ public PrintSpoolerClient(RemotePrintSpooler spooler) {
+ mWeakSpooler = new WeakReference<RemotePrintSpooler>(spooler);
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJobInfo printJob) {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.mCallbacks.onPrintJobQueued(printJob);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onAllPrintJobsForServiceHandled(ComponentName printService) {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.mCallbacks.onAllPrintJobsForServiceHandled(printService);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onAllPrintJobsHandled() {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.onAllPrintJobsHandled();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.mCallbacks.onStartPrinterDiscovery(observer);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() throws RemoteException {
+ RemotePrintSpooler spooler = mWeakSpooler.get();
+ if (spooler != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ spooler.mCallbacks.onStopPrinterDiscovery();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/print/RemoteSpooler.java b/services/java/com/android/server/print/RemoteSpooler.java
deleted file mode 100644
index fef5818..0000000
--- a/services/java/com/android/server/print/RemoteSpooler.java
+++ /dev/null
@@ -1,416 +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 com.android.server.print;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.IBinder.DeathRecipient;
-import android.print.IPrintAdapter;
-import android.print.IPrintClient;
-import android.print.IPrintSpoolerService;
-import android.print.IPrintSpoolerServiceCallbacks;
-import android.print.PrintAttributes;
-import android.print.PrintJobInfo;
-import android.util.Slog;
-import android.util.TimedRemoteCaller;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This represents the remote print spooler as a local object to the
- * PrintManagerSerivce. It is responsible to connecting to the remove
- * spooler if needed, to make the timed out remote calls, and to handle
- * remove exceptions.
- */
-final class RemoteSpooler implements ServiceConnection, DeathRecipient {
-
- private static final String LOG_TAG = "Spooler";
-
- private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
-
- private final Object mLock = new Object();
-
- private final Context mContext;
-
- private final Intent mIntent;
-
- private final GetPrintJobsCaller mGetPrintJobsCaller = new GetPrintJobsCaller();
-
- private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller();
-
- private final CancelPrintJobCaller mCancelPrintJobCaller = new CancelPrintJobCaller();
-
- private final GetPrintJobCaller mGetPrintJobCaller = new GetPrintJobCaller();
-
- private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller();
-
- private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
-
- private IPrintSpoolerService mRemoteInterface;
-
- private int mUserId = UserHandle.USER_NULL;
-
- public RemoteSpooler(Context context) {
- mContext = context;
- mIntent = new Intent();
- mIntent.setComponent(new ComponentName("com.android.printspooler",
- "com.android.printspooler.PrintSpoolerService"));
- }
-
- public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId,
- int userId) {
- try {
- return mGetPrintJobsCaller.getPrintJobs(getRemoteInstance(userId),
- componentName, state, appId);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error getting print jobs!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error getting print jobs!", te);
- }
- return null;
- }
-
- public PrintJobInfo createPrintJob(String printJobName, IPrintClient client,
- IPrintAdapter printAdapter, PrintAttributes attributes, int appId, int userId) {
- try {
- return mCreatePrintJobCaller.createPrintJob(getRemoteInstance(userId),
- printJobName, client, printAdapter, attributes, appId);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error creating print job!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error creating print job!", te);
- }
- return null;
- }
-
- public boolean cancelPrintJob(int printJobId, int appId, int userId) {
- try {
- return mCancelPrintJobCaller.cancelPrintJob(getRemoteInstance(userId),
- printJobId, appId);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error canceling print job!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error canceling print job!", te);
- }
- return false;
- }
-
- public void writePrintJobData(ParcelFileDescriptor fd, int printJobId, int userId) {
- try {
- getRemoteInstance(userId).writePrintJobData(fd, printJobId);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error writing print job data!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error writing print job data!", te);
- } finally {
- // We passed the file descriptor across and now the other
- // side is responsible to close it, so close the local copy.
- try {
- fd.close();
- } catch (IOException ioe) {
- /* ignore */
- }
- }
- }
-
- public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
- try {
- return mGetPrintJobCaller.getPrintJobInfo(getRemoteInstance(userId),
- printJobId, appId);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error getting print job!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error getting print job!", te);
- }
- return null;
- }
-
- public boolean setPrintJobState(int printJobId, int state, int userId) {
- try {
- return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstance(userId),
- printJobId, state);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error setting print job status!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error setting print job status!", te);
- }
- return false;
- }
-
- public boolean setPrintJobTag(int printJobId, String tag, int userId) {
- try {
- return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstance(userId),
- printJobId, tag);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error setting print job tag!", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error setting print job tag!", te);
- }
- return false;
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- binderDied();
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- try {
- service.linkToDeath(this, 0);
- mRemoteInterface = IPrintSpoolerService.Stub.asInterface(service);
- } catch (RemoteException re) {
- /* ignore */
- }
- }
- }
-
- private IPrintSpoolerService getRemoteInstance(int userId) throws TimeoutException {
- synchronized (mLock) {
- if (mRemoteInterface != null && mUserId == userId) {
- return mRemoteInterface;
- }
-
- final long identity = Binder.clearCallingIdentity();
- try {
- if (mUserId != UserHandle.USER_NULL && mUserId != userId) {
- unbind();
- }
-
- mContext.bindServiceAsUser(mIntent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT,
- UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- final long startMillis = SystemClock.uptimeMillis();
- while (true) {
- if (mRemoteInterface != null) {
- break;
- }
- final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
- final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis;
- if (remainingMillis <= 0) {
- throw new TimeoutException("Cannot get spooler!");
- }
- try {
- mLock.wait(remainingMillis);
- } catch (InterruptedException ie) {
- /* ignore */
- }
- }
-
- mUserId = userId;
-
- return mRemoteInterface;
- }
- }
-
- public void unbind() {
- synchronized (mLock) {
- if (mRemoteInterface != null) {
- mContext.unbindService(this);
- mRemoteInterface = null;
- mUserId = UserHandle.USER_NULL;
- }
- }
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- if (mRemoteInterface != null) {
- mRemoteInterface.asBinder().unlinkToDeath(this, 0);
- mRemoteInterface = null;
- }
- }
- }
-
- private final class GetPrintJobsCaller extends TimedRemoteCaller<List<PrintJobInfo>> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public GetPrintJobsCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onGetPrintJobsResult(List<PrintJobInfo> printJobs, int sequence) {
- onRemoteMethodResult(printJobs, sequence);
- }
- };
- }
-
- public List<PrintJobInfo> getPrintJobs(IPrintSpoolerService target,
- ComponentName componentName, int state, int appId)
- throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.getPrintJobs(mCallback, componentName, state, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public CreatePrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- onRemoteMethodResult(printJob, sequence);
- }
- };
- }
-
- public PrintJobInfo createPrintJob(IPrintSpoolerService target, String printJobName,
- IPrintClient client, IPrintAdapter printAdapter, PrintAttributes attributes,
- int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.createPrintJob(printJobName, client, printAdapter, attributes,
- mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private final class CancelPrintJobCaller extends TimedRemoteCaller<Boolean> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public CancelPrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onCancelPrintJobResult(boolean canceled, int sequence) {
- onRemoteMethodResult(canceled, sequence);
- }
- };
- }
-
- public boolean cancelPrintJob(IPrintSpoolerService target, int printJobId,
- int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.cancelPrintJob(printJobId, mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private final class GetPrintJobCaller extends TimedRemoteCaller<PrintJobInfo> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public GetPrintJobCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
- onRemoteMethodResult(printJob, sequence);
- }
- };
- }
-
- public PrintJobInfo getPrintJobInfo(IPrintSpoolerService target, int printJobId,
- int appId) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.getPrintJob(printJobId, mCallback, appId, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public SetPrintJobStateCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onSetPrintJobStateResult(boolean success, int sequence) {
- onRemoteMethodResult(success, sequence);
- }
- };
- }
-
- public boolean setPrintJobState(IPrintSpoolerService target, int printJobId,
- int status) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.setPrintJobState(printJobId, status, mCallback, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> {
- private final IPrintSpoolerServiceCallbacks mCallback;
-
- public SetPrintJobTagCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
- mCallback = new BasePrintSpoolerServiceCallbacks() {
- @Override
- public void onSetPrintJobTagResult(boolean success, int sequence) {
- onRemoteMethodResult(success, sequence);
- }
- };
- }
-
- public boolean setPrintJobTag(IPrintSpoolerService target, int printJobId,
- String tag) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- target.setPrintJobTag(printJobId, tag, mCallback, sequence);
- return getResultTimed(sequence);
- }
- }
-
- private abstract class BasePrintSpoolerServiceCallbacks
- extends IPrintSpoolerServiceCallbacks.Stub {
- @Override
- public void onGetPrintJobsResult(List<PrintJobInfo> printJobIds, int sequence) {
- /** do nothing */
- }
-
- @Override
- public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) {
- /** do nothing */
- }
-
- @Override
- public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) {
- /** do nothing */
- }
-
- @Override
- public void onCancelPrintJobResult(boolean canceled, int sequence) {
- /** do nothing */
- }
-
- @Override
- public void onSetPrintJobStateResult(boolean success, int sequece) {
- /** do nothing */
- }
-
- @Override
- public void onSetPrintJobTagResult(boolean success, int sequence) {
- /** do nothing */
- }
- }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
new file mode 100644
index 0000000..5cef4d3
--- /dev/null
+++ b/services/java/com/android/server/print/UserState.java
@@ -0,0 +1,274 @@
+/*
+ * 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.server.print;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintJobInfo;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Slog;
+
+import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents the print state for a user.
+ */
+final class UserState implements PrintSpoolerCallbacks {
+
+ private static final String LOG_TAG = "UserState";
+
+ private static final char COMPONENT_NAME_SEPARATOR = ':';
+
+ private final SimpleStringSplitter mStringColonSplitter =
+ new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
+
+ private final Intent mQueryIntent =
+ new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+
+ private final Map<ComponentName, RemotePrintService> mActiveServices =
+ new HashMap<ComponentName, RemotePrintService>();
+
+ private final List<PrintServiceInfo> mInstalledServices =
+ new ArrayList<PrintServiceInfo>();
+
+ private final Set<ComponentName> mEnabledServices =
+ new HashSet<ComponentName>();
+
+ private final Object mLock;
+
+ private final Context mContext;
+
+ private final int mUserId;
+
+ private final RemotePrintSpooler mSpooler;
+
+ private boolean mDestroyed;
+
+ public UserState(Context context, int userId, Object lock) {
+ mContext = context;
+ mUserId = userId;
+ mLock = lock;
+ mSpooler = new RemotePrintSpooler(context, userId, this);
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJobInfo printJob) {
+ final RemotePrintService service;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ ComponentName printServiceName = printJob.getPrinterId().getService();
+ service = mActiveServices.get(printServiceName);
+ }
+ if (service != null) {
+ service.onPrintJobQueued(printJob);
+ }
+ }
+
+ @Override
+ public void onAllPrintJobsForServiceHandled(ComponentName printService) {
+ final RemotePrintService service;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ service = mActiveServices.get(printService);
+ }
+ if (service != null) {
+ service.onAllPrintJobsHandled();
+ }
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ final List<RemotePrintService> services;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mActiveServices.isEmpty()) {
+ return;
+ }
+ services = new ArrayList<RemotePrintService>(mActiveServices.values());
+ }
+ final int serviceCount = services.size();
+ for (int i = 0; i < serviceCount; i++) {
+ RemotePrintService service = services.get(i);
+ service.onStartPrinterDiscovery(observer);
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() {
+ final List<RemotePrintService> services;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mActiveServices.isEmpty()) {
+ return;
+ }
+ services = new ArrayList<RemotePrintService>(mActiveServices.values());
+ }
+ final int serviceCount = services.size();
+ for (int i = 0; i < serviceCount; i++) {
+ RemotePrintService service = services.get(i);
+ service.onStopPrinterDiscovery();
+ }
+ }
+
+ public void updateIfNeededLocked() {
+ throwIfDestroyedLocked();
+ if (readConfigurationLocked()) {
+ onConfigurationChangedLocked();
+ }
+ }
+
+ public RemotePrintSpooler getSpoolerLocked() {
+ throwIfDestroyedLocked();
+ return mSpooler;
+ }
+
+ public Map<ComponentName, RemotePrintService> getActiveServices() {
+ synchronized(mLock) {
+ throwIfDestroyedLocked();
+ return mActiveServices;
+ }
+ }
+
+ public Set<ComponentName> getEnabledServices() {
+ synchronized(mLock) {
+ throwIfDestroyedLocked();
+ return mEnabledServices;
+ }
+ }
+
+ public void destroyLocked() {
+ throwIfDestroyedLocked();
+ mSpooler.destroy();
+ for (RemotePrintService service : mActiveServices.values()) {
+ service.destroy();
+ }
+ mActiveServices.clear();
+ mInstalledServices.clear();
+ mEnabledServices.clear();
+ mDestroyed = true;
+ }
+
+ private boolean readConfigurationLocked() {
+ boolean somethingChanged = false;
+ somethingChanged |= readInstalledPrintServicesLocked();
+ somethingChanged |= readEnabledPrintServicesLocked();
+ return somethingChanged;
+ }
+
+ private boolean readInstalledPrintServicesLocked() {
+ Set<PrintServiceInfo> tempPrintServices = new HashSet<PrintServiceInfo>();
+
+ List<ResolveInfo> installedServices = mContext.getPackageManager()
+ .queryIntentServicesAsUser(mQueryIntent, PackageManager.GET_SERVICES
+ | PackageManager.GET_META_DATA, mUserId);
+
+ final int installedCount = installedServices.size();
+ for (int i = 0, count = installedCount; i < count; i++) {
+ ResolveInfo installedService = installedServices.get(i);
+ if (!android.Manifest.permission.BIND_PRINT_SERVICE.equals(
+ installedService.serviceInfo.permission)) {
+ ComponentName serviceName = new ComponentName(
+ installedService.serviceInfo.packageName,
+ installedService.serviceInfo.name);
+ Slog.w(LOG_TAG, "Skipping print service "
+ + serviceName.flattenToShortString()
+ + " since it does not require permission "
+ + android.Manifest.permission.BIND_PRINT_SERVICE);
+ continue;
+ }
+ tempPrintServices.add(PrintServiceInfo.create(installedService, mContext));
+ }
+
+ if (!tempPrintServices.equals(mInstalledServices)) {
+ mInstalledServices.clear();
+ mInstalledServices.addAll(tempPrintServices);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean readEnabledPrintServicesLocked() {
+ Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
+
+ String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
+ if (!TextUtils.isEmpty(settingValue)) {
+ TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(settingValue);
+ while (splitter.hasNext()) {
+ String string = splitter.next();
+ if (TextUtils.isEmpty(string)) {
+ continue;
+ }
+ ComponentName componentName = ComponentName.unflattenFromString(string);
+ if (componentName != null) {
+ tempEnabledServiceNameSet.add(componentName);
+ }
+ }
+ }
+
+ if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
+ mEnabledServices.clear();
+ mEnabledServices.addAll(tempEnabledServiceNameSet);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void onConfigurationChangedLocked() {
+ final int installedCount = mInstalledServices.size();
+ for (int i = 0; i < installedCount; i++) {
+ ResolveInfo resolveInfo = mInstalledServices.get(i).getResolveInfo();
+ ComponentName serviceName = new ComponentName(resolveInfo.serviceInfo.packageName,
+ resolveInfo.serviceInfo.name);
+ if (mEnabledServices.contains(serviceName)) {
+ if (!mActiveServices.containsKey(serviceName)) {
+ mActiveServices.put(serviceName, new RemotePrintService(
+ mContext, serviceName, mUserId, mSpooler));
+ }
+ } else {
+ RemotePrintService service = mActiveServices.remove(serviceName);
+ if (service != null) {
+ service.destroy();
+ }
+ }
+ }
+ }
+
+ private void throwIfDestroyedLocked() {
+ if (mDestroyed) {
+ throw new IllegalStateException("Cannot interact with a destroyed instance.");
+ }
+ }
+}
+
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index cacc723..d22178d 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -19,7 +19,6 @@
import com.android.server.input.InputManagerService;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.AllWindowsIterator;
import android.app.ActivityManagerNative;
import android.graphics.Rect;
@@ -259,45 +258,47 @@
}
// Add all windows on the default display.
- final AllWindowsIterator iterator = mService.new AllWindowsIterator(
- WindowManagerService.REVERSE_ITERATOR);
- while (iterator.hasNext()) {
- final WindowState child = iterator.next();
- final InputChannel inputChannel = child.mInputChannel;
- final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
- if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
- // Skip this window because it cannot possibly receive input.
- continue;
- }
-
- final int flags = child.mAttrs.flags;
- final int type = child.mAttrs.type;
-
- final boolean hasFocus = (child == mInputFocus);
- final boolean isVisible = child.isVisibleLw();
- final boolean hasWallpaper = (child == mService.mWallpaperTarget)
- && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
- final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
-
- // If there's a drag in progress and 'child' is a potential drop target,
- // make sure it's been told about the drag
- if (inDrag && isVisible && onDefaultDisplay) {
- mService.mDragState.sendDragStartedIfNeededLw(child);
- }
-
- if (universeBackground != null && !addedUniverse
- && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) {
- final WindowState u = universeBackground.mWin;
- if (u.mInputChannel != null && u.mInputWindowHandle != null) {
- addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags,
- u.mAttrs.type, true, u == mInputFocus, false);
+ final int numDisplays = mService.mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState child = windows.get(winNdx);
+ final InputChannel inputChannel = child.mInputChannel;
+ final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+ if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
+ // Skip this window because it cannot possibly receive input.
+ continue;
}
- addedUniverse = true;
- }
- if (child.mWinAnimator != universeBackground) {
- addInputWindowHandleLw(inputWindowHandle, child, flags, type,
- isVisible, hasFocus, hasWallpaper);
+ final int flags = child.mAttrs.flags;
+ final int type = child.mAttrs.type;
+
+ final boolean hasFocus = (child == mInputFocus);
+ final boolean isVisible = child.isVisibleLw();
+ final boolean hasWallpaper = (child == mService.mWallpaperTarget)
+ && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
+ final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
+
+ // If there's a drag in progress and 'child' is a potential drop target,
+ // make sure it's been told about the drag
+ if (inDrag && isVisible && onDefaultDisplay) {
+ mService.mDragState.sendDragStartedIfNeededLw(child);
+ }
+
+ if (universeBackground != null && !addedUniverse
+ && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) {
+ final WindowState u = universeBackground.mWin;
+ if (u.mInputChannel != null && u.mInputWindowHandle != null) {
+ addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags,
+ u.mAttrs.type, true, u == mInputFocus, false);
+ }
+ addedUniverse = true;
+ }
+
+ if (child.mWinAnimator != universeBackground) {
+ addInputWindowHandleLw(inputWindowHandle, child, flags, type,
+ isVisible, hasFocus, hasWallpaper);
+ }
}
}
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 3fc3ac6..afdbc87 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -24,7 +24,6 @@
import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
-import com.android.server.wm.WindowManagerService.DisplayContentsIterator;
import com.android.server.wm.WindowManagerService.LayoutFields;
import java.io.PrintWriter;
@@ -442,7 +441,7 @@
setAppLayoutChanges(appAnimator,
WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
"testTokenMayBeDrawnLocked");
-
+
// We can now show all of the drawn windows!
if (!mService.mOpeningApps.contains(wtoken)) {
mAnimating |= appAnimator.showAllWindowsLocked();
@@ -541,9 +540,9 @@
}
boolean hasPendingLayoutChanges = false;
- DisplayContentsIterator iterator = mService.new DisplayContentsIterator();
- while (iterator.hasNext()) {
- final DisplayContent displayContent = iterator.next();
+ final int numDisplays = mService.mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mService.mDisplayContents.get(displayNdx);
final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 7784b16..3e7509a 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -150,7 +150,6 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.NoSuchElementException;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -426,9 +425,7 @@
String mLastANRState;
/** All DisplayContents in the world, kept here */
- private SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2);
-
- private final AllWindowsIterator mTmpWindowsIterator = new AllWindowsIterator();
+ SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2);
int mRotation = 0;
int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -2537,13 +2534,17 @@
public void updateAppOpsState() {
synchronized(mWindowMap) {
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState win = mTmpWindowsIterator.next();
- if (win.mAppOp != AppOpsManager.OP_NONE) {
- final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
- win.getOwningPackage());
- win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState win = windows.get(winNdx);
+ if (win.mAppOp != AppOpsManager.OP_NONE) {
+ final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
+ win.getOwningPackage());
+ win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+ }
}
}
}
@@ -4551,9 +4552,9 @@
}
void dumpAppTokensLocked() {
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- DisplayContent displayContent = iterator.next();
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
Slog.v(TAG, " Display " + displayContent.getDisplayId());
final ArrayList<Task> tasks = displayContent.getTasks();
int i = displayContent.numTokens();
@@ -4569,10 +4570,12 @@
void dumpWindowsLocked() {
int i = 0;
- mTmpWindowsIterator.reset(REVERSE_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- Slog.v(TAG, " #" + i++ + ": " + w);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ Slog.v(TAG, " #" + i++ + ": " + windows.get(winNdx));
+ }
}
}
@@ -4823,9 +4826,9 @@
"createStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
STACK_WEIGHT_MAX + ", weight=" + weight);
}
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- final DisplayContent displayContent = iterator.next();
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
TaskStack stack = displayContent.createStack(this, stackId, relativeStackBoxId,
position, weight);
if (stack != null) {
@@ -4888,9 +4891,9 @@
STACK_WEIGHT_MAX + ", weight=" + weight);
}
synchronized (mWindowMap) {
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- if (iterator.next().resizeStack(stackBoxId, weight)) {
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) {
performLayoutAndPlaceSurfacesLocked();
return;
}
@@ -4907,9 +4910,9 @@
}
public Rect getStackBounds(int stackId) {
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- Rect bounds = iterator.next().getStackBounds(stackId);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId);
if (bounds != null) {
return bounds;
}
@@ -5036,13 +5039,17 @@
@Override
public void closeSystemDialogs(String reason) {
synchronized(mWindowMap) {
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- if (w.mHasSurface) {
- try {
- w.mClient.closeSystemDialogs(reason);
- } catch (RemoteException e) {
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState w = windows.get(winNdx);
+ if (w.mHasSurface) {
+ try {
+ w.mClient.closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
}
}
}
@@ -5180,9 +5187,9 @@
mPolicy.setCurrentUserLw(newUserId);
// Hide windows that should not be seen by the new user.
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- DisplayContent displayContent = iterator.next();
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
displayContent.switchUserStacks(oldUserId, newUserId);
rebuildAppWindowListLocked(displayContent);
}
@@ -5432,12 +5439,16 @@
// the background..)
if (on) {
boolean isVisible = false;
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState ws = mTmpWindowsIterator.next();
- if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
- isVisible = true;
- break;
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState ws = windows.get(winNdx);
+ if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
+ isVisible = true;
+ break;
+ }
}
}
if (!isVisible) {
@@ -6197,9 +6208,10 @@
WindowList windows = new WindowList();
synchronized (mWindowMap) {
//noinspection unchecked
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while(iterator.hasNext()) {
- windows.addAll(iterator.next().getWindowList());
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ windows.addAll(displayContent.getWindowList());
}
}
@@ -6427,11 +6439,15 @@
}
synchronized (mWindowMap) {
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- if (System.identityHashCode(w) == hashCode) {
- return w;
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState w = windows.get(winNdx);
+ if (System.identityHashCode(w) == hashCode) {
+ return w;
+ }
}
}
}
@@ -6982,12 +6998,16 @@
// TODO(multidisplay): Call isScreenOn for each display.
private void sendScreenStatusToClientsLocked() {
final boolean on = mPowerManager.isScreenOn();
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- try {
- mTmpWindowsIterator.next().mClient.dispatchScreenState(on);
- } catch (RemoteException e) {
- // Ignored
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ try {
+ windows.get(winNdx).mClient.dispatchScreenState(on);
+ } catch (RemoteException e) {
+ // Ignored
+ }
}
}
}
@@ -7849,9 +7869,10 @@
}
final void rebuildAppWindowListLocked() {
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- rebuildAppWindowListLocked(iterator.next());
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ rebuildAppWindowListLocked(displayContent);
}
}
@@ -8800,9 +8821,9 @@
}
// Initialize state of exiting tokens.
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- final DisplayContent displayContent = iterator.next();
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
displayContent.mExitingTokens.get(i).hasVisible = false;
}
@@ -8840,10 +8861,9 @@
boolean focusDisplayed = false;
- iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
boolean updateAllDrawn = false;
- final DisplayContent displayContent = iterator.next();
WindowList windows = displayContent.getWindowList();
DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int displayId = displayContent.getDisplayId();
@@ -9255,9 +9275,8 @@
}
// Time to remove any exiting tokens?
- iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- final DisplayContent displayContent = iterator.next();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
for (i = exitingTokens.size() - 1; i >= 0; i--) {
WindowToken token = exitingTokens.get(i);
@@ -9306,9 +9325,8 @@
defaultDisplay.layoutNeeded = true;
}
- iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- DisplayContent displayContent = iterator.next();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
if (displayContent.pendingLayoutChanges != 0) {
displayContent.layoutNeeded = true;
}
@@ -9489,9 +9507,10 @@
}
private boolean needsLayout() {
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- if (iterator.next().layoutNeeded) {
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ if (displayContent.layoutNeeded) {
return true;
}
}
@@ -9570,35 +9589,39 @@
// window list to make sure we haven't left any dangling surfaces
// around.
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
Slog.i(TAG, "Out of memory for surface! Looking for leaks...");
- while (mTmpWindowsIterator.hasNext()) {
- WindowState ws = mTmpWindowsIterator.next();
- WindowStateAnimator wsa = ws.mWinAnimator;
- if (wsa.mSurfaceControl != null) {
- if (!mSessions.contains(wsa.mSession)) {
- Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
- + ws + " surface=" + wsa.mSurfaceControl
- + " token=" + ws.mToken
- + " pid=" + ws.mSession.mPid
- + " uid=" + ws.mSession.mUid);
- if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
- wsa.mSurfaceControl.destroy();
- wsa.mSurfaceShown = false;
- wsa.mSurfaceControl = null;
- ws.mHasSurface = false;
- mForceRemoves.add(ws);
- leakedSurface = true;
- } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
- Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
- + ws + " surface=" + wsa.mSurfaceControl
- + " token=" + ws.mAppToken);
- if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
- wsa.mSurfaceControl.destroy();
- wsa.mSurfaceShown = false;
- wsa.mSurfaceControl = null;
- ws.mHasSurface = false;
- leakedSurface = true;
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState ws = windows.get(winNdx);
+ WindowStateAnimator wsa = ws.mWinAnimator;
+ if (wsa.mSurfaceControl != null) {
+ if (!mSessions.contains(wsa.mSession)) {
+ Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
+ + ws + " surface=" + wsa.mSurfaceControl
+ + " token=" + ws.mToken
+ + " pid=" + ws.mSession.mPid
+ + " uid=" + ws.mSession.mUid);
+ if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
+ wsa.mSurfaceControl.destroy();
+ wsa.mSurfaceShown = false;
+ wsa.mSurfaceControl = null;
+ ws.mHasSurface = false;
+ mForceRemoves.add(ws);
+ leakedSurface = true;
+ } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
+ Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
+ + ws + " surface=" + wsa.mSurfaceControl
+ + " token=" + ws.mAppToken);
+ if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
+ wsa.mSurfaceControl.destroy();
+ wsa.mSurfaceShown = false;
+ wsa.mSurfaceControl = null;
+ ws.mHasSurface = false;
+ leakedSurface = true;
+ }
}
}
}
@@ -9606,27 +9629,30 @@
if (!leakedSurface) {
Slog.w(TAG, "No leaked surfaces; killing applicatons!");
SparseIntArray pidCandidates = new SparseIntArray();
- mTmpWindowsIterator.reset(FORWARD_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- WindowState ws = mTmpWindowsIterator.next();
- if (mForceRemoves.contains(ws)) {
- continue;
- }
- WindowStateAnimator wsa = ws.mWinAnimator;
- if (wsa.mSurfaceControl != null) {
- pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
- }
- }
- if (pidCandidates.size() > 0) {
- int[] pids = new int[pidCandidates.size()];
- for (int i=0; i<pids.length; i++) {
- pids[i] = pidCandidates.keyAt(i);
- }
- try {
- if (mActivityManager.killPids(pids, "Free memory", secure)) {
- killedApps = true;
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ final int numWindows = windows.size();
+ for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
+ final WindowState ws = windows.get(winNdx);
+ if (mForceRemoves.contains(ws)) {
+ continue;
}
- } catch (RemoteException e) {
+ WindowStateAnimator wsa = ws.mWinAnimator;
+ if (wsa.mSurfaceControl != null) {
+ pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
+ }
+ }
+ if (pidCandidates.size() > 0) {
+ int[] pids = new int[pidCandidates.size()];
+ for (int i=0; i<pids.length; i++) {
+ pids[i] = pidCandidates.keyAt(i);
+ }
+ try {
+ if (mActivityManager.killPids(pids, "Free memory", secure)) {
+ killedApps = true;
+ }
+ } catch (RemoteException e) {
+ }
}
}
}
@@ -10225,9 +10251,10 @@
void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
if (mDisplayReady) {
- DisplayContentsIterator dCIterator = new DisplayContentsIterator();
- while (dCIterator.hasNext()) {
- dCIterator.next().dump(" ", pw);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+ displayContent.dump(" ", pw);
}
} else {
pw.println(" NO DISPLAY");
@@ -10243,13 +10270,16 @@
void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
int j = 0;
- mTmpWindowsIterator.reset(REVERSE_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- if (windows == null || windows.contains(w)) {
- pw.print(" Window #"); pw.print(j++); pw.print(' ');
- pw.print(w); pw.println(":");
- w.dump(pw, " ", dumpAll || windows != null);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState w = windowList.get(winNdx);
+ if (windows == null || windows.contains(w)) {
+ pw.print(" Window #"); pw.print(j++); pw.print(' ');
+ pw.print(w); pw.println(":");
+ w.dump(pw, " ", dumpAll || windows != null);
+ }
}
}
if (mInputMethodDialogs.size() > 0) {
@@ -10402,9 +10432,8 @@
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
if (needsLayout()) {
pw.print(" layoutNeeded on displays=");
- DisplayContentsIterator dcIterator = new DisplayContentsIterator();
- while (dcIterator.hasNext()) {
- final DisplayContent displayContent = dcIterator.next();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
if (displayContent.layoutNeeded) {
pw.print(displayContent.getDisplayId());
}
@@ -10438,11 +10467,15 @@
WindowList windows = new WindowList();
if ("visible".equals(name)) {
synchronized(mWindowMap) {
- mTmpWindowsIterator.reset(REVERSE_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- if (w.mWinAnimator.mSurfaceShown) {
- windows.add(w);
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windowList =
+ mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState w = windowList.get(winNdx);
+ if (w.mWinAnimator.mSurfaceShown) {
+ windows.add(w);
+ }
}
}
}
@@ -10455,15 +10488,19 @@
} catch (RuntimeException e) {
}
synchronized(mWindowMap) {
- mTmpWindowsIterator.reset(REVERSE_ITERATOR);
- while (mTmpWindowsIterator.hasNext()) {
- final WindowState w = mTmpWindowsIterator.next();
- if (name != null) {
- if (w.mAttrs.getTitle().toString().contains(name)) {
+ final int numDisplays = mDisplayContents.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final WindowList windowList =
+ mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState w = windowList.get(winNdx);
+ if (name != null) {
+ if (w.mAttrs.getTitle().toString().contains(name)) {
+ windows.add(w);
+ }
+ } else if (System.identityHashCode(w) == objectId) {
windows.add(w);
}
- } else if (System.identityHashCode(w) == objectId) {
- windows.add(w);
}
}
}
@@ -10715,104 +10752,6 @@
return displayContent;
}
- class DisplayContentsIterator implements Iterator<DisplayContent> {
- private int cur;
-
- void reset() {
- cur = 0;
- }
-
- @Override
- public boolean hasNext() {
- return cur < mDisplayContents.size();
- }
-
- @Override
- public DisplayContent next() {
- if (hasNext()) {
- return mDisplayContents.valueAt(cur++);
- }
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented");
- }
- }
-
- class AllWindowsIterator implements Iterator<WindowState> {
- private DisplayContent mDisplayContent;
- private DisplayContentsIterator mDisplayContentsIterator;
- private WindowList mWindowList;
- private int mWindowListIndex;
- private boolean mReverse;
-
- AllWindowsIterator() {
- this(false);
- }
-
- AllWindowsIterator(boolean reverse) {
- mDisplayContentsIterator = new DisplayContentsIterator();
- reset(reverse);
- }
-
- void reset(boolean reverse) {
- mReverse = reverse;
- mDisplayContentsIterator.reset();
- if (mDisplayContentsIterator.hasNext()) {
- mDisplayContent = mDisplayContentsIterator.next();
- mWindowList = mDisplayContent.getWindowList();
- mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
- } else {
- mDisplayContent = null;
- mWindowList = null;
- mWindowListIndex = 0;
- }
- }
-
- @Override
- public boolean hasNext() {
- if (mDisplayContent == null) {
- return false;
- }
- if (mReverse) {
- return mWindowListIndex >= 0;
- }
- return mWindowListIndex < mWindowList.size();
- }
-
- @Override
- public WindowState next() {
- if (hasNext()) {
- WindowState win = mWindowList.get(mWindowListIndex);
- if (mReverse) {
- mWindowListIndex--;
- if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) {
- mDisplayContent = mDisplayContentsIterator.next();
- mWindowList = mDisplayContent.getWindowList();
- mWindowListIndex = mWindowList.size() - 1;
- }
- } else {
- mWindowListIndex++;
- if (mWindowListIndex >= mWindowList.size()
- && mDisplayContentsIterator.hasNext()) {
- mDisplayContent = mDisplayContentsIterator.next();
- mWindowList = mDisplayContent.getWindowList();
- mWindowListIndex = 0;
- }
- }
- return win;
- }
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- throw new IllegalArgumentException("AllWindowsIterator.remove not implemented");
- }
- }
-
// There is an inherent assumption that this will never return null.
public DisplayContent getDefaultDisplayContentLocked() {
return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index 17a1585..192c50c 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -66,7 +66,7 @@
public void testAddRemoveListener() throws RemoteException {
CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext());
- serviceTester.systemReady();
+ serviceTester.systemRunning();
waitForSystemReady(serviceTester);
CountryListenerTester listenerTester = new CountryListenerTester();
serviceTester.addCountryListener(listenerTester);
@@ -80,7 +80,7 @@
CountryListenerTester listenerTesterA = new CountryListenerTester();
CountryListenerTester listenerTesterB = new CountryListenerTester();
Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK);
- serviceTester.systemReady();
+ serviceTester.systemRunning();
waitForSystemReady(serviceTester);
serviceTester.addCountryListener(listenerTesterA);
serviceTester.addCountryListener(listenerTesterB);
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 7ee7085..b1dd2ce 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -371,10 +371,12 @@
}
public void startTdls(String macAddr, boolean enable) {
- if (enable)
+ if (enable) {
+ doBooleanCommand("TDLS_DISCOVER " + macAddr);
doBooleanCommand("TDLS_SETUP " + macAddr);
- else
+ } else {
doBooleanCommand("TDLS_TEARDOWN " + macAddr);
+ }
}
/** Example output: