summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityThread.java428
-rw-r--r--core/java/android/app/AlarmManager.java189
-rw-r--r--core/java/android/os/Bundle.java56
-rw-r--r--core/java/android/os/IPowerManager.aidl3
-rw-r--r--core/java/android/os/Parcel.java15
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java52
-rw-r--r--core/java/android/print/PageRange.java5
-rw-r--r--core/java/android/print/PrintAttributes.java59
-rw-r--r--core/java/android/print/PrintDocumentAdapter.java83
-rw-r--r--core/java/android/print/PrintDocumentInfo.java76
-rw-r--r--core/java/android/print/PrintJob.java12
-rw-r--r--core/java/android/print/PrintJobInfo.java138
-rw-r--r--core/java/android/print/PrintManager.java94
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java32
-rw-r--r--core/java/android/print/PrinterInfo.java23
-rw-r--r--core/java/android/print/package.html46
-rw-r--r--core/java/android/printservice/PrintJob.java6
-rw-r--r--core/java/android/printservice/PrintService.java8
-rw-r--r--core/java/android/printservice/PrintServiceInfo.java30
-rw-r--r--core/java/android/provider/DocumentsContract.java3
-rw-r--r--core/java/android/transition/Scene.java2
-rw-r--r--core/java/android/transition/TransitionManager.java12
-rw-r--r--core/java/android/widget/ActivityChooserModel.java30
-rw-r--r--core/java/android/widget/ActivityChooserView.java29
24 files changed, 991 insertions, 440 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 347850a..5e3dc02 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -534,17 +534,10 @@ public final class ActivityThread {
private native void dumpGraphicsInfo(FileDescriptor fd);
private class ApplicationThread extends ApplicationThreadNative {
- private static final String HEAP_FULL_COLUMN
- = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
- private static final String HEAP_COLUMN
- = "%13s %8s %8s %8s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%21s %8d";
private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
- // Formatting for checkin service - update version if row format changes
- private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
-
private int mLastProcessState = -1;
private void updatePendingConfiguration(Configuration config) {
@@ -929,82 +922,14 @@ public final class ActivityThread {
long openSslSocketCount = Debug.countInstancesOfClass(OpenSSLSocketImpl.class);
SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
- // For checkin, we print one long comma-separated list of values
+ dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, Process.myPid(),
+ (mBoundApplication != null) ? mBoundApplication.processName : "unknown",
+ nativeMax, nativeAllocated, nativeFree,
+ dalvikMax, dalvikAllocated, dalvikFree);
+
if (checkin) {
// NOTE: if you change anything significant below, also consider changing
// ACTIVITY_THREAD_CHECKIN_VERSION.
- String processName = (mBoundApplication != null)
- ? mBoundApplication.processName : "unknown";
-
- // Header
- pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
- pw.print(Process.myPid()); pw.print(',');
- pw.print(processName); pw.print(',');
-
- // Heap info - max
- pw.print(nativeMax); pw.print(',');
- pw.print(dalvikMax); pw.print(',');
- pw.print("N/A,");
- pw.print(nativeMax + dalvikMax); pw.print(',');
-
- // Heap info - allocated
- pw.print(nativeAllocated); pw.print(',');
- pw.print(dalvikAllocated); pw.print(',');
- pw.print("N/A,");
- pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
-
- // Heap info - free
- pw.print(nativeFree); pw.print(',');
- pw.print(dalvikFree); pw.print(',');
- pw.print("N/A,");
- pw.print(nativeFree + dalvikFree); pw.print(',');
-
- // Heap info - proportional set size
- pw.print(memInfo.nativePss); pw.print(',');
- pw.print(memInfo.dalvikPss); pw.print(',');
- pw.print(memInfo.otherPss); pw.print(',');
- pw.print(memInfo.getTotalPss()); pw.print(',');
-
- // Heap info - swappable set size
- pw.print(memInfo.nativeSwappablePss); pw.print(',');
- pw.print(memInfo.dalvikSwappablePss); pw.print(',');
- pw.print(memInfo.otherSwappablePss); pw.print(',');
- pw.print(memInfo.getTotalSwappablePss()); pw.print(',');
-
- // Heap info - shared dirty
- pw.print(memInfo.nativeSharedDirty); pw.print(',');
- pw.print(memInfo.dalvikSharedDirty); pw.print(',');
- pw.print(memInfo.otherSharedDirty); pw.print(',');
- pw.print(memInfo.getTotalSharedDirty()); pw.print(',');
-
- // Heap info - shared clean
- pw.print(memInfo.nativeSharedClean); pw.print(',');
- pw.print(memInfo.dalvikSharedClean); pw.print(',');
- pw.print(memInfo.otherSharedClean); pw.print(',');
- pw.print(memInfo.getTotalSharedClean()); pw.print(',');
-
- // Heap info - private Dirty
- pw.print(memInfo.nativePrivateDirty); pw.print(',');
- pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
- pw.print(memInfo.otherPrivateDirty); pw.print(',');
- pw.print(memInfo.getTotalPrivateDirty()); pw.print(',');
-
- // Heap info - private Clean
- pw.print(memInfo.nativePrivateClean); pw.print(',');
- pw.print(memInfo.dalvikPrivateClean); pw.print(',');
- pw.print(memInfo.otherPrivateClean); pw.print(',');
- pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
-
- // Heap info - other areas
- for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
- pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
- pw.print(memInfo.getOtherPss(i)); pw.print(',');
- pw.print(memInfo.getOtherSwappablePss(i)); pw.print(',');
- pw.print(memInfo.getOtherSharedDirty(i)); pw.print(',');
- pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
- pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
- pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
- }
// Object counts
pw.print(viewInstanceCount); pw.print(',');
@@ -1039,128 +964,6 @@ public final class ActivityThread {
return;
}
- // otherwise, show human-readable format
- if (dumpFullInfo) {
- printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
- "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
- printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
- "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
- printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
- "------", "------", "------", "------", "------", "------");
- printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
- memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
- memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
- memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
- nativeMax, nativeAllocated, nativeFree);
- printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
- memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
- memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
- memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
- dalvikMax, dalvikAllocated, dalvikFree);
- } else {
- printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
- "Private", "Swapped", "Heap", "Heap", "Heap");
- printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
- "Clean", "Dirty", "Size", "Alloc", "Free");
- printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
- "------", "------", "------", "------", "------");
- printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
- memInfo.nativePrivateDirty,
- memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
- nativeMax, nativeAllocated, nativeFree);
- printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
- memInfo.dalvikPrivateDirty,
- memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
- dalvikMax, dalvikAllocated, dalvikFree);
- }
-
- int otherPss = memInfo.otherPss;
- int otherSwappablePss = memInfo.otherSwappablePss;
- int otherSharedDirty = memInfo.otherSharedDirty;
- int otherPrivateDirty = memInfo.otherPrivateDirty;
- int otherSharedClean = memInfo.otherSharedClean;
- int otherPrivateClean = memInfo.otherPrivateClean;
- int otherSwappedOut = memInfo.otherSwappedOut;
-
- for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
- final int myPss = memInfo.getOtherPss(i);
- final int mySwappablePss = memInfo.getOtherSwappablePss(i);
- final int mySharedDirty = memInfo.getOtherSharedDirty(i);
- final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
- final int mySharedClean = memInfo.getOtherSharedClean(i);
- final int myPrivateClean = memInfo.getOtherPrivateClean(i);
- final int mySwappedOut = memInfo.getOtherSwappedOut(i);
- if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
- || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
- if (dumpFullInfo) {
- printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
- } else {
- printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, myPrivateDirty,
- myPrivateClean, mySwappedOut, "", "", "");
- }
- otherPss -= myPss;
- otherSwappablePss -= mySwappablePss;
- otherSharedDirty -= mySharedDirty;
- otherPrivateDirty -= myPrivateDirty;
- otherSharedClean -= mySharedClean;
- otherPrivateClean -= myPrivateClean;
- otherSwappedOut -= mySwappedOut;
- }
- }
-
- if (dumpFullInfo) {
- printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
- otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
- otherSwappedOut, "", "", "");
- printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
- memInfo.getTotalSwappablePss(),
- memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
- memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
- memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
- nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
- } else {
- printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
- otherPrivateDirty, otherPrivateClean, otherSwappedOut,
- "", "", "");
- printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
- memInfo.getTotalPrivateDirty(),
- memInfo.getTotalPrivateClean(),
- memInfo.getTotalSwappedOut(),
- nativeMax+dalvikMax,
- nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
- }
-
- if (dumpDalvik) {
- pw.println(" ");
- pw.println(" Dalvik Details");
-
- for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
- i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
- final int myPss = memInfo.getOtherPss(i);
- final int mySwappablePss = memInfo.getOtherSwappablePss(i);
- final int mySharedDirty = memInfo.getOtherSharedDirty(i);
- final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
- final int mySharedClean = memInfo.getOtherSharedClean(i);
- final int myPrivateClean = memInfo.getOtherPrivateClean(i);
- final int mySwappedOut = memInfo.getOtherSwappedOut(i);
- if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
- || mySharedClean != 0 || myPrivateClean != 0) {
- if (dumpFullInfo) {
- printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
- } else {
- printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
- myPss, myPrivateDirty,
- myPrivateClean, mySwappedOut, "", "", "");
- }
- }
- }
- }
-
pw.println(" ");
pw.println(" Objects");
printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRootImpl:",
@@ -1238,10 +1041,6 @@ public final class ActivityThread {
sendMessage(H.REQUEST_ASSIST_CONTEXT_EXTRAS, cmd);
}
- private void printRow(PrintWriter pw, String format, Object...objs) {
- pw.println(String.format(format, objs));
- }
-
public void setCoreSettings(Bundle coreSettings) {
sendMessage(H.SET_CORE_SETTINGS, coreSettings);
}
@@ -1959,6 +1758,223 @@ public final class ActivityThread {
}
}
+ private static final String HEAP_FULL_COLUMN
+ = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
+ private static final String HEAP_COLUMN
+ = "%13s %8s %8s %8s %8s %8s %8s %8s";
+
+ // Formatting for checkin service - update version if row format changes
+ private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
+
+ static void printRow(PrintWriter pw, String format, Object...objs) {
+ pw.println(String.format(format, objs));
+ }
+
+ public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
+ boolean dumpFullInfo, boolean dumpDalvik, int pid, String processName,
+ long nativeMax, long nativeAllocated, long nativeFree,
+ long dalvikMax, long dalvikAllocated, long dalvikFree) {
+
+ // For checkin, we print one long comma-separated list of values
+ if (checkin) {
+ // NOTE: if you change anything significant below, also consider changing
+ // ACTIVITY_THREAD_CHECKIN_VERSION.
+
+ // Header
+ pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
+ pw.print(pid); pw.print(',');
+ pw.print(processName); pw.print(',');
+
+ // Heap info - max
+ pw.print(nativeMax); pw.print(',');
+ pw.print(dalvikMax); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeMax + dalvikMax); pw.print(',');
+
+ // Heap info - allocated
+ pw.print(nativeAllocated); pw.print(',');
+ pw.print(dalvikAllocated); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
+
+ // Heap info - free
+ pw.print(nativeFree); pw.print(',');
+ pw.print(dalvikFree); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeFree + dalvikFree); pw.print(',');
+
+ // Heap info - proportional set size
+ pw.print(memInfo.nativePss); pw.print(',');
+ pw.print(memInfo.dalvikPss); pw.print(',');
+ pw.print(memInfo.otherPss); pw.print(',');
+ pw.print(memInfo.getTotalPss()); pw.print(',');
+
+ // Heap info - swappable set size
+ pw.print(memInfo.nativeSwappablePss); pw.print(',');
+ pw.print(memInfo.dalvikSwappablePss); pw.print(',');
+ pw.print(memInfo.otherSwappablePss); pw.print(',');
+ pw.print(memInfo.getTotalSwappablePss()); pw.print(',');
+
+ // Heap info - shared dirty
+ pw.print(memInfo.nativeSharedDirty); pw.print(',');
+ pw.print(memInfo.dalvikSharedDirty); pw.print(',');
+ pw.print(memInfo.otherSharedDirty); pw.print(',');
+ pw.print(memInfo.getTotalSharedDirty()); pw.print(',');
+
+ // Heap info - shared clean
+ pw.print(memInfo.nativeSharedClean); pw.print(',');
+ pw.print(memInfo.dalvikSharedClean); pw.print(',');
+ pw.print(memInfo.otherSharedClean); pw.print(',');
+ pw.print(memInfo.getTotalSharedClean()); pw.print(',');
+
+ // Heap info - private Dirty
+ pw.print(memInfo.nativePrivateDirty); pw.print(',');
+ pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
+ pw.print(memInfo.otherPrivateDirty); pw.print(',');
+ pw.print(memInfo.getTotalPrivateDirty()); pw.print(',');
+
+ // Heap info - private Clean
+ pw.print(memInfo.nativePrivateClean); pw.print(',');
+ pw.print(memInfo.dalvikPrivateClean); pw.print(',');
+ pw.print(memInfo.otherPrivateClean); pw.print(',');
+ pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
+
+ // Heap info - other areas
+ for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
+ pw.print(memInfo.getOtherPss(i)); pw.print(',');
+ pw.print(memInfo.getOtherSwappablePss(i)); pw.print(',');
+ pw.print(memInfo.getOtherSharedDirty(i)); pw.print(',');
+ pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
+ pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
+ pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
+ }
+ return;
+ }
+
+ // otherwise, show human-readable format
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
+ "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
+ "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
+ "------", "------", "------", "------", "------", "------");
+ printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
+ memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
+ memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+ nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+ memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+ memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+ dalvikMax, dalvikAllocated, dalvikFree);
+ } else {
+ printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
+ "Private", "Swapped", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
+ "Clean", "Dirty", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
+ "------", "------", "------", "------", "------");
+ printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
+ memInfo.nativePrivateDirty,
+ memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+ nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+ memInfo.dalvikPrivateDirty,
+ memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+ dalvikMax, dalvikAllocated, dalvikFree);
+ }
+
+ int otherPss = memInfo.otherPss;
+ int otherSwappablePss = memInfo.otherSwappablePss;
+ int otherSharedDirty = memInfo.otherSharedDirty;
+ int otherPrivateDirty = memInfo.otherPrivateDirty;
+ int otherSharedClean = memInfo.otherSharedClean;
+ int otherPrivateClean = memInfo.otherPrivateClean;
+ int otherSwappedOut = memInfo.otherSwappedOut;
+
+ for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ final int myPss = memInfo.getOtherPss(i);
+ final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+ final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+ final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+ final int mySharedClean = memInfo.getOtherSharedClean(i);
+ final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+ final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+ || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+ } else {
+ printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, myPrivateDirty,
+ myPrivateClean, mySwappedOut, "", "", "");
+ }
+ otherPss -= myPss;
+ otherSwappablePss -= mySwappablePss;
+ otherSharedDirty -= mySharedDirty;
+ otherPrivateDirty -= myPrivateDirty;
+ otherSharedClean -= mySharedClean;
+ otherPrivateClean -= myPrivateClean;
+ otherSwappedOut -= mySwappedOut;
+ }
+ }
+
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
+ otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+ otherSwappedOut, "", "", "");
+ printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSwappablePss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+ memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
+ nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ } else {
+ printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
+ otherPrivateDirty, otherPrivateClean, otherSwappedOut,
+ "", "", "");
+ printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalPrivateDirty(),
+ memInfo.getTotalPrivateClean(),
+ memInfo.getTotalSwappedOut(),
+ nativeMax+dalvikMax,
+ nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ }
+
+ if (dumpDalvik) {
+ pw.println(" ");
+ pw.println(" Dalvik Details");
+
+ for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
+ i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
+ final int myPss = memInfo.getOtherPss(i);
+ final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+ final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+ final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+ final int mySharedClean = memInfo.getOtherSharedClean(i);
+ final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+ final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+ || mySharedClean != 0 || myPrivateClean != 0) {
+ if (dumpFullInfo) {
+ printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+ mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+ } else {
+ printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+ myPss, myPrivateDirty,
+ myPrivateClean, mySwappedOut, "", "", "");
+ }
+ }
+ }
+ }
+ }
+
public void registerOnActivityPausedListener(Activity activity,
OnActivityPausedListener listener) {
synchronized (mOnPauseListeners) {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 5c3a3e5..0cf7ad0 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -48,6 +48,15 @@ import android.os.WorkSource;
* etc) it is easier and much more efficient to use
* {@link android.os.Handler}.</b>
*
+ * <p class="caution"><strong>Note:</strong> Beginning with API 19
+ * ({@link android.os.Build.VERSION_CODES#KITKAT}) alarm delivery is inexact:
+ * the OS will shift alarms in order to minimize wakeups and battery use. There are
+ * new APIs to support applications which need strict delivery guarantees; see
+ * {@link #setWindow(int, long, long, PendingIntent)} and
+ * {@link #setExact(int, long, PendingIntent)}. Applications whose {@code targetSdkVersion}
+ * is earlier than API 19 will continue to see the previous behavior in which all
+ * alarms are delivered exactly when requested.
+ *
* <p>You do not
* instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService
@@ -109,21 +118,19 @@ public class AlarmManager
}
/**
- * TBW: discussion of fuzzy nature of alarms in KLP+.
- *
* <p>Schedule an alarm. <b>Note: for timing operations (ticks, timeouts,
- * etc) it is easier and much more efficient to use
- * {@link android.os.Handler}.</b> If there is already an alarm scheduled
- * for the same IntentSender, it will first be canceled.
+ * etc) it is easier and much more efficient to use {@link android.os.Handler}.</b>
+ * If there is already an alarm scheduled for the same IntentSender, that previous
+ * alarm will first be canceled.
*
- * <p>If the time occurs in the past, the alarm will be triggered
+ * <p>If the stated trigger time is in the past, the alarm will be triggered
* immediately. If there is already an alarm for this Intent
* scheduled (with the equality of two intents being defined by
* {@link Intent#filterEquals}), then it will be removed and replaced by
* this one.
*
* <p>
- * The alarm is an intent broadcast that goes to a broadcast receiver that
+ * The alarm is an Intent broadcast that goes to a broadcast receiver that
* you registered with {@link android.content.Context#registerReceiver}
* or through the &lt;receiver&gt; tag in an AndroidManifest.xml file.
*
@@ -133,9 +140,34 @@ public class AlarmManager
* how many past alarm events have been accumulated into this intent
* broadcast. Recurring alarms that have gone undelivered because the
* phone was asleep may have a count greater than one when delivered.
- *
- * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
- * RTC_WAKEUP.
+ *
+ * <div class="note">
+ * <p>
+ * <b>Note:</b> Beginning in API 19, the trigger time passed to this method
+ * is treated as inexact: the alarm will not be delivered before this time, but
+ * may be deferred and delivered some time later. The OS will use
+ * this policy in order to "batch" alarms together across the entire system,
+ * minimizing the number of times the device needs to "wake up" and minimizing
+ * battery use. In general, alarms scheduled in the near future will not
+ * be deferred as long as alarms scheduled far in the future.
+ *
+ * <p>
+ * With the new batching policy, delivery ordering guarantees are not as
+ * strong as they were previously. If the application sets multiple alarms,
+ * it is possible that these alarms' <em>actual</em> delivery ordering may not match
+ * the order of their <em>requested</em> delivery times. If your application has
+ * strong ordering requirements there are other APIs that you can use to get
+ * the necessary behavior; see {@link #setWindow(int, long, long, PendingIntent)}
+ * and {@link #setExact(int, long, PendingIntent)}.
+ *
+ * <p>
+ * Applications whose {@code targetSdkVersion} is before API 19 will
+ * continue to get the previous alarm behavior: all of their scheduled alarms
+ * will be treated as exact.
+ * </div>
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param triggerAtMillis time in milliseconds that the alarm should go
* off, using the appropriate clock (depending on the alarm type).
* @param operation Action to perform when the alarm goes off;
@@ -165,10 +197,10 @@ public class AlarmManager
* {@link android.os.Handler}.</b> If there is already an alarm scheduled
* for the same IntentSender, it will first be canceled.
*
- * <p>Like {@link #set}, except you can also
- * supply a rate at which the alarm will repeat. This alarm continues
- * repeating until explicitly removed with {@link #cancel}. If the time
- * occurs in the past, the alarm will be triggered immediately, with an
+ * <p>Like {@link #set}, except you can also supply a period at which
+ * the alarm will automatically repeat. This alarm continues
+ * repeating until explicitly removed with {@link #cancel}. If the stated
+ * trigger time is in the past, the alarm will be triggered immediately, with an
* alarm count depending on how far in the past the trigger time is relative
* to the repeat interval.
*
@@ -185,8 +217,15 @@ public class AlarmManager
* between alarms, then the approach to take is to use one-time alarms,
* scheduling the next one yourself when handling each alarm delivery.
*
- * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
- * RTC_WAKEUP.
+ * <p class="note">
+ * <b>Note:</b> as of API 19, all repeating alarms are inexact. If your
+ * application needs precise delivery times then it must use one-time
+ * exact alarms, rescheduling each time as described above. Legacy applications
+ * whose {@code targetSdkVersion} is earlier than API 19 will continue to have all
+ * of their alarms, including repeating alarms, treated as exact.
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param triggerAtMillis time in milliseconds that the alarm should first
* go off, using the appropriate clock (depending on the alarm type).
* @param intervalMillis interval in milliseconds between subsequent repeats
@@ -214,18 +253,33 @@ public class AlarmManager
}
/**
- * Schedule an alarm to be delivered within a given window of time.
+ * Schedule an alarm to be delivered within a given window of time. This method
+ * is similar to {@link #set(int, long, PendingIntent)}, but allows the
+ * application to precisely control the degree to which its delivery might be
+ * adjusted by the OS. This method allows an application to take advantage of the
+ * battery optimizations that arise from delivery batching even when it has
+ * modest timeliness requirements for its alarms.
*
- * TBW: clean up these docs
+ * <p>
+ * This method can also be used to achieve strict ordering guarantees among
+ * multiple alarms by ensuring that the windows requested for each alarm do
+ * not intersect.
+ *
+ * <p>
+ * When precise delivery is not required, applications should use the standard
+ * {@link #set(int, long, PendingIntent)} method. This will give the OS the most
+ * flexibility to minimize wakeups and battery use. For alarms that must be delivered
+ * at precisely-specified times with no acceptable variation, applications can use
+ * {@link #setExact(int, long, PendingIntent)}.
*
- * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
- * RTC_WAKEUP.
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param windowStartMillis The earliest time, in milliseconds, that the alarm should
* be delivered, expressed in the appropriate clock's units (depending on the alarm
* type).
* @param windowLengthMillis The length of the requested delivery window,
* in milliseconds. The alarm will be delivered no later than this many
- * milliseconds after the windowStartMillis time. Note that this parameter
+ * milliseconds after {@code windowStartMillis}. Note that this parameter
* is a <i>duration,</i> not the timestamp of the end of the window.
* @param operation Action to perform when the alarm goes off;
* typically comes from {@link PendingIntent#getBroadcast
@@ -249,8 +303,38 @@ public class AlarmManager
}
/**
- * TBW: new 'exact' alarm that must be delivered as nearly as possible
- * to the precise time specified.
+ * Schedule an alarm to be delivered precisely at the stated time.
+ *
+ * <p>
+ * This method is like {@link #set(int, long, PendingIntent)}, but does not permit
+ * the OS to adjust the delivery time. The alarm will be delivered as nearly as
+ * possible to the requested trigger time.
+ *
+ * <p>
+ * <b>Note:</b> only alarms for which there is a strong demand for exact-time
+ * delivery (such as an alarm clock ringing at the requested time) should be
+ * scheduled as exact. Applications are strongly discouraged from using exact
+ * alarms unnecessarily as they reduce the OS's ability to minimize battery use.
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
+ * @param triggerAtMillis time in milliseconds that the alarm should go
+ * off, using the appropriate clock (depending on the alarm type).
+ * @param operation Action to perform when the alarm goes off;
+ * typically comes from {@link PendingIntent#getBroadcast
+ * IntentSender.getBroadcast()}.
+ *
+ * @see #set
+ * @see #setRepeating
+ * @see #setWindow
+ * @see #cancel
+ * @see android.content.Context#sendBroadcast
+ * @see android.content.Context#registerReceiver
+ * @see android.content.Intent#filterEquals
+ * @see #ELAPSED_REALTIME
+ * @see #ELAPSED_REALTIME_WAKEUP
+ * @see #RTC
+ * @see #RTC_WAKEUP
*/
public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation, null);
@@ -283,74 +367,82 @@ public class AlarmManager
}
/**
- * @deprecated setInexactRepeating() is deprecated; as of API 19 all
- * repeating alarms are inexact.
+ * Available inexact recurrence interval recognized by
+ * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+ * when running on Android prior to API 19.
*/
- @Deprecated
public static final long INTERVAL_FIFTEEN_MINUTES = 15 * 60 * 1000;
/**
- * @deprecated setInexactRepeating() is deprecated; as of API 19 all
- * repeating alarms are inexact.
+ * Available inexact recurrence interval recognized by
+ * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+ * when running on Android prior to API 19.
*/
- @Deprecated
public static final long INTERVAL_HALF_HOUR = 2*INTERVAL_FIFTEEN_MINUTES;
/**
- * @deprecated setInexactRepeating() is deprecated; as of API 19 all
- * repeating alarms are inexact.
+ * Available inexact recurrence interval recognized by
+ * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+ * when running on Android prior to API 19.
*/
- @Deprecated
public static final long INTERVAL_HOUR = 2*INTERVAL_HALF_HOUR;
/**
- * @deprecated setInexactRepeating() is deprecated; as of API 19 all
- * repeating alarms are inexact.
+ * Available inexact recurrence interval recognized by
+ * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+ * when running on Android prior to API 19.
*/
- @Deprecated
public static final long INTERVAL_HALF_DAY = 12*INTERVAL_HOUR;
/**
- * @deprecated setInexactRepeating() is deprecated; as of API 19 all
- * repeating alarms are inexact.
+ * Available inexact recurrence interval recognized by
+ * {@link #setInexactRepeating(int, long, long, PendingIntent)}
+ * when running on Android prior to API 19.
*/
- @Deprecated
public static final long INTERVAL_DAY = 2*INTERVAL_HALF_DAY;
/**
* Schedule a repeating alarm that has inexact trigger time requirements;
* for example, an alarm that repeats every hour, but not necessarily at
* the top of every hour. These alarms are more power-efficient than
- * the strict recurrences supplied by {@link #setRepeating}, since the
- * system can adjust alarms' phase to cause them to fire simultaneously,
+ * the strict recurrences traditionally supplied by {@link #setRepeating}, since the
+ * system can adjust alarms' delivery times to cause them to fire simultaneously,
* avoiding waking the device from sleep more than necessary.
- *
+ *
* <p>Your alarm's first trigger will not be before the requested time,
* but it might not occur for almost a full interval after that time. In
* addition, while the overall period of the repeating alarm will be as
* requested, the time between any two successive firings of the alarm
* may vary. If your application demands very low jitter, use
- * {@link #setRepeating} instead.
+ * one-shot alarms with an appropriate window instead; see {@link
+ * #setWindow(int, long, long, PendingIntent)} and
+ * {@link #setExact(int, long, PendingIntent)}.
*
- * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or
- * RTC_WAKEUP.
+ * <p class="note">
+ * As of API 19, all repeating alarms are inexact. Because this method has
+ * been available since API 3, your application can safely call it and be
+ * assured that it will get similar behavior on both current and older versions
+ * of Android.
+ *
+ * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+ * {@link #RTC}, or {@link #RTC_WAKEUP}.
* @param triggerAtMillis time in milliseconds that the alarm should first
* go off, using the appropriate clock (depending on the alarm type). This
* is inexact: the alarm will not fire before this time, but there may be a
* delay of almost an entire alarm interval before the first invocation of
* the alarm.
* @param intervalMillis interval in milliseconds between subsequent repeats
- * of the alarm. If this is one of INTERVAL_FIFTEEN_MINUTES,
+ * of the alarm. Prior to API 19, if this is one of INTERVAL_FIFTEEN_MINUTES,
* INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY
* then the alarm will be phase-aligned with other alarms to reduce the
* number of wakeups. Otherwise, the alarm will be set as though the
- * application had called {@link #setRepeating}.
+ * application had called {@link #setRepeating}. As of API 19, all repeating
+ * alarms will be inexact and subject to batching with other alarms regardless
+ * of their stated repeat interval.
* @param operation Action to perform when the alarm goes off;
* typically comes from {@link PendingIntent#getBroadcast
* IntentSender.getBroadcast()}.
*
- * @deprecated As of API 19, all repeating alarms are inexact.
- *
* @see android.os.Handler
* @see #set
* @see #cancel
@@ -367,7 +459,6 @@ public class AlarmManager
* @see #INTERVAL_HALF_DAY
* @see #INTERVAL_DAY
*/
- @Deprecated
public void setInexactRepeating(int type, long triggerAtMillis,
long intervalMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation, null);
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 5a919fb..f9c1d31 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -35,10 +35,12 @@ public final class Bundle implements Parcelable, Cloneable {
public static final Bundle EMPTY;
static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ static final Parcel EMPTY_PARCEL;
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
+ EMPTY_PARCEL = Parcel.obtain();
}
// Invariant - exactly one of mMap / mParcelledData will be null
@@ -115,9 +117,13 @@ public final class Bundle implements Parcelable, Cloneable {
*/
public Bundle(Bundle b) {
if (b.mParcelledData != null) {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
+ if (b.mParcelledData == EMPTY_PARCEL) {
+ mParcelledData = EMPTY_PARCEL;
+ } else {
+ mParcelledData = Parcel.obtain();
+ mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
+ mParcelledData.setDataPosition(0);
+ }
} else {
mParcelledData = null;
}
@@ -216,6 +222,18 @@ public final class Bundle implements Parcelable, Cloneable {
return;
}
+ if (mParcelledData == EMPTY_PARCEL) {
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + ": empty");
+ if (mMap == null) {
+ mMap = new ArrayMap<String, Object>(1);
+ } else {
+ mMap.erase();
+ }
+ mParcelledData = null;
+ return;
+ }
+
int N = mParcelledData.readInt();
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ ": reading " + N + " maps");
@@ -1652,11 +1670,20 @@ public final class Bundle implements Parcelable, Cloneable {
final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
try {
if (mParcelledData != null) {
- int length = mParcelledData.dataSize();
- parcel.writeInt(length);
- parcel.writeInt(BUNDLE_MAGIC);
- parcel.appendFrom(mParcelledData, 0, length);
+ if (mParcelledData == EMPTY_PARCEL) {
+ parcel.writeInt(0);
+ } else {
+ int length = mParcelledData.dataSize();
+ parcel.writeInt(length);
+ parcel.writeInt(BUNDLE_MAGIC);
+ parcel.appendFrom(mParcelledData, 0, length);
+ }
} else {
+ // Special case for empty bundles.
+ if (mMap == null || mMap.size() <= 0) {
+ parcel.writeInt(0);
+ return;
+ }
int lengthPos = parcel.dataPosition();
parcel.writeInt(-1); // dummy, will hold length
parcel.writeInt(BUNDLE_MAGIC);
@@ -1690,6 +1717,13 @@ public final class Bundle implements Parcelable, Cloneable {
}
void readFromParcelInner(Parcel parcel, int length) {
+ if (length == 0) {
+ // Empty Bundle or end of data.
+ mParcelledData = EMPTY_PARCEL;
+ mHasFds = false;
+ mFdsKnown = true;
+ return;
+ }
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
@@ -1716,8 +1750,12 @@ public final class Bundle implements Parcelable, Cloneable {
@Override
public synchronized String toString() {
if (mParcelledData != null) {
- return "Bundle[mParcelledData.dataSize=" +
- mParcelledData.dataSize() + "]";
+ if (mParcelledData == EMPTY_PARCEL) {
+ return "Bundle[EMPTY_PARCEL]";
+ } else {
+ return "Bundle[mParcelledData.dataSize=" +
+ mParcelledData.dataSize() + "]";
+ }
}
return "Bundle[" + mMap.toString() + "]";
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4c7bbb4..56176a4 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,11 +23,12 @@ import android.os.WorkSource;
interface IPowerManager
{
- // WARNING: The first three methods must remain the first three methods because their
+ // WARNING: The first four methods must remain the first three methods because their
// transaction numbers must not change unless IPowerManager.cpp is also updated.
void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws);
void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, int uidtoblame);
void releaseWakeLock(IBinder lock, int flags);
+ void updateWakeLockUids(IBinder lock, in int[] uids);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
boolean isWakeLockLevelSupported(int level);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 02b1998..94b9617 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -611,11 +611,15 @@ public final class Parcel {
here.fillInStackTrace();
Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
}
+ int startPos;
for (int i=0; i<N; i++) {
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Write #" + i + ": key=0x"
- + (val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0) + " " + val.keyAt(i));
+ if (DEBUG_ARRAY_MAP) startPos = dataPosition();
writeValue(val.keyAt(i));
writeValue(val.valueAt(i));
+ if (DEBUG_ARRAY_MAP) Log.d(TAG, " Write #" + i + " "
+ + (dataPosition()-startPos) + " bytes: key=0x"
+ + Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
+ + " " + val.keyAt(i));
}
}
@@ -2303,11 +2307,14 @@ public final class Parcel {
here.fillInStackTrace();
Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
}
+ int startPos;
while (N > 0) {
+ if (DEBUG_ARRAY_MAP) startPos = dataPosition();
Object key = readValue(loader);
- if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + ": key=0x"
- + (key != null ? key.hashCode() : 0) + " " + key);
Object value = readValue(loader);
+ if (DEBUG_ARRAY_MAP) Log.d(TAG, " Read #" + (N-1) + " "
+ + (dataPosition()-startPos) + " bytes: key=0x"
+ + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
outVal.append(key, value);
N--;
}
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 1456387..5273c20 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -231,10 +231,11 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
final FileDescriptor fd = openInternal(file, mode);
if (fd == null) return null;
- final FileDescriptor[] comm = createCommSocketPair(true);
+ final FileDescriptor[] comm = createCommSocketPair();
final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
// Kick off thread to watch for status updates
+ IoUtils.setBlocking(comm[1], true);
final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
bridge.start();
@@ -378,7 +379,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
*/
public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
try {
- final FileDescriptor[] comm = createCommSocketPair(false);
+ final FileDescriptor[] comm = createCommSocketPair();
final FileDescriptor[] fds = Libcore.os.pipe();
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fds[0], comm[0]),
@@ -416,7 +417,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
*/
public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
try {
- final FileDescriptor[] comm = createCommSocketPair(false);
+ final FileDescriptor[] comm = createCommSocketPair();
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
@@ -428,13 +429,13 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
}
}
- private static FileDescriptor[] createCommSocketPair(boolean blocking) throws IOException {
+ private static FileDescriptor[] createCommSocketPair() throws IOException {
try {
final FileDescriptor comm1 = new FileDescriptor();
final FileDescriptor comm2 = new FileDescriptor();
Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
- IoUtils.setBlocking(comm1, blocking);
- IoUtils.setBlocking(comm2, blocking);
+ IoUtils.setBlocking(comm1, false);
+ IoUtils.setBlocking(comm2, false);
return new FileDescriptor[] { comm1, comm2 };
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -670,34 +671,35 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
}
try {
- try {
- if (status != Status.SILENCE) {
- final byte[] buf = getOrCreateStatusBuffer();
- int writePtr = 0;
+ if (status == Status.SILENCE) return;
+
+ // Since we're about to close, read off any remote status. It's
+ // okay to remember missing here.
+ mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
- Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
- writePtr += 4;
+ // Skip writing status when other end has already gone away.
+ if (mStatus != null) return;
+
+ try {
+ final byte[] buf = getOrCreateStatusBuffer();
+ int writePtr = 0;
- if (msg != null) {
- final byte[] rawMsg = msg.getBytes();
- final int len = Math.min(rawMsg.length, buf.length - writePtr);
- System.arraycopy(rawMsg, 0, buf, writePtr, len);
- writePtr += len;
- }
+ Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
+ writePtr += 4;
- Libcore.os.write(mCommFd, buf, 0, writePtr);
+ if (msg != null) {
+ final byte[] rawMsg = msg.getBytes();
+ final int len = Math.min(rawMsg.length, buf.length - writePtr);
+ System.arraycopy(rawMsg, 0, buf, writePtr, len);
+ writePtr += len;
}
+
+ Libcore.os.write(mCommFd, buf, 0, writePtr);
} catch (ErrnoException e) {
// Reporting status is best-effort
Log.w(TAG, "Failed to report status: " + e);
}
- if (status != Status.SILENCE) {
- // Since we're about to close, read off any remote status. It's
- // okay to remember missing here.
- mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
- }
-
} finally {
IoUtils.closeQuietly(mCommFd);
mCommFd = null;
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index cdcd0c7..d6320f0 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -39,9 +39,8 @@ public final class PageRange implements Parcelable {
* @param start The start page index (zero based and inclusive).
* @param end The end page index (zero based and inclusive).
*
- * @throws IllegalArgumentException If start is less than zero.
- * @throws IllegalArgumentException If end is less than zero.
- * @throws IllegalArgumentException If start greater than end.
+ * @throws IllegalArgumentException If start is less than zero or end
+ * is less than zero or start greater than end.
*/
public PageRange(int start, int end) {
if (start < 0) {
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index e1a9cb7..c6254e0 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -30,7 +30,11 @@ import com.android.internal.R;
import java.util.Map;
/**
- * This class represents the attributes of a print job.
+ * This class represents the attributes of a print job. These attributes
+ * describe how the printed content should be laid out. For example, the
+ * print attributes may state that the content should be laid out on a
+ * letter size with 300 DPI (dots per inch) resolution, have a margin of
+ * 10 mills (thousand of an inch) on all sides, and be black and white.
*/
public final class PrintAttributes implements Parcelable {
/** Color mode: Monochrome color scheme, for example one color is used. */
@@ -277,7 +281,7 @@ public final class PrintAttributes implements Parcelable {
* Unknown media size in portrait mode.
* <p>
* <strong>Note: </strong>This is for specifying orientation without media
- * size. You should not use the dimensions reported by this class.
+ * size. You should not use the dimensions reported by this instance.
* </p>
*/
public static final MediaSize UNKNOWN_PORTRAIT =
@@ -288,7 +292,7 @@ public final class PrintAttributes implements Parcelable {
* Unknown media size in landscape mode.
* <p>
* <strong>Note: </strong>This is for specifying orientation without media
- * size. You should not use the dimensions reported by this class.
+ * size. You should not use the dimensions reported by this instance.
* </p>
*/
public static final MediaSize UNKNOWN_LANDSCAPE =
@@ -615,9 +619,7 @@ public final class PrintAttributes implements Parcelable {
private final int mHeightMils;
/**
- * Creates a new instance. This is the preferred constructor since
- * it enables the media size label to be shown in a localized fashion
- * on a locale change.
+ * Creates a new instance.
*
* @param id The unique media size id.
* @param packageName The name of the creating package.
@@ -625,10 +627,9 @@ public final class PrintAttributes implements Parcelable {
* @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.
+ * @throws IllegalArgumentException If the id is empty or the label
+ * is empty or the widthMils is less than or equal to zero or the
+ * heightMils is less than or equal to zero.
*
* @hide
*/
@@ -667,14 +668,13 @@ public final class PrintAttributes implements Parcelable {
*
* @param id The unique media size id. It is unique amongst other media sizes
* supported by the printer.
- * @param label The <strong>internationalized</strong> human readable label.
+ * @param label The <strong>localized</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.
+ * @throws IllegalArgumentException If the id is empty or the label is empty
+ * or the widthMils is less than or equal to zero or the heightMils is less
+ * than or equal to zero.
*/
public MediaSize(String id, String label, int widthMils, int heightMils) {
if (TextUtils.isEmpty(id)) {
@@ -776,12 +776,16 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Returns a new media size in a portrait orientation
+ * Returns a new media size instance in a portrait orientation,
* which is the height is the greater dimension.
*
- * @return New instance in landscape orientation.
+ * @return New instance in landscape orientation if this one
+ * is in landscape, otherwise this instance.
*/
public MediaSize asPortrait() {
+ if (isPortrait()) {
+ return this;
+ }
return new MediaSize(mId, mLabel, mPackageName,
Math.min(mWidthMils, mHeightMils),
Math.max(mWidthMils, mHeightMils),
@@ -789,12 +793,16 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Returns a new media size in a landscape orientation
+ * Returns a new media size instance in a landscape orientation,
* which is the height is the lesser dimension.
*
- * @return New instance in landscape orientation.
+ * @return New instance in landscape orientation if this one
+ * is in portrait, otherwise this instance.
*/
public MediaSize asLandscape() {
+ if (!isPortrait()) {
+ return this;
+ }
return new MediaSize(mId, mLabel, mPackageName,
Math.max(mWidthMils, mHeightMils),
Math.min(mWidthMils, mHeightMils),
@@ -881,8 +889,8 @@ public final class PrintAttributes implements Parcelable {
* This class specifies a supported resolution in DPI (dots per inch).
* Resolution defines how many points with different color can be placed
* on one inch in horizontal or vertical direction of the target media.
- * For example, a printer with 600DIP can produce higher quality images
- * the one with 300DPI resolution.
+ * For example, a printer with 600 DPI can produce higher quality images
+ * the one with 300 DPI resolution.
*/
public static final class Resolution {
private final String mId;
@@ -895,14 +903,13 @@ public final class PrintAttributes implements Parcelable {
*
* @param id The unique resolution id. It is unique amongst other resolutions
* supported by the printer.
- * @param label The <strong>internationalized</strong> human readable label.
+ * @param label The <strong>localized</strong> human readable label.
* @param horizontalDpi The horizontal resolution in DPI (dots per inch).
* @param verticalDpi The vertical resolution in DPI (dots per inch).
*
- * @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.
+ * @throws IllegalArgumentException If the id is empty or the label is empty
+ * or the horizontalDpi is less than or equal to zero or the verticalDpi is
+ * less than or equal to zero.
*/
public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
if (TextUtils.isEmpty(id)) {
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 4113ac7..9e811a6 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -38,15 +38,46 @@ import android.os.ParcelFileDescriptor;
* </li>
* <li>
* After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
- * CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
- * {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
- * asking you to write a PDF file with the content for specific pages.
+ * CancellationSignal, LayoutResultCallback, Bundle)}, you <strong>may</strong> get
+ * a call to {@link #onWrite(PageRange[], ParcelFileDescriptor, 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>
+ * The {@link #onStart()} callback is always the first call you will receive and
+ * is useful for doing one time setup or resource allocation before printing. You
+ * will not receive a subsequent call here.
+ * </p>
+ * <p>
+ * The {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} callback requires that you layout the content
+ * based on the current {@link PrintAttributes}. The execution of this method is
+ * not considered completed until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods.
+ * </p>
+ * <p>
+ * The {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
+ * WriteResultCallback)} requires that you render and write the content of some
+ * pages to the provided destination. The execution of this method is not
+ * considered complete until you invoke one of the methods on the passed in
+ * callback instance. Hence, you will not receive a subsequent call to any other
+ * method of this class until the execution of this method is complete by invoking
+ * one of the callback methods. You will never receive a sequence of one or more
+ * calls to this method without a previous call to {@link #onLayout(PrintAttributes,
+ * PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)}.
+ * </p>
+ * <p>
+ * The {@link #onFinish()} callback is always the last call you will receive and
+ * is useful for doing one time cleanup or resource deallocation after printing.
+ * You will not receive a subsequent call here.
+ * </p>
* </p>
* <h3>Implementation</h3>
* <p>
@@ -54,7 +85,11 @@ import android.os.ParcelFileDescriptor;
* of the work on an arbitrary thread. For example, if the printed content
* does not depend on the UI state, i.e. on what is shown on the screen, then
* you can offload the entire work on a dedicated thread, thus making your
- * application interactive while the print work is being performed.
+ * application interactive while the print work is being performed. Note that
+ * while your activity is covered by the system print UI and a user cannot
+ * interact with it, doing the printing work on the main application thread
+ * may affect the performance of your other application components as they
+ * are also executed on that thread.
* </p>
* <p>
* You can also do work on different threads, for example if you print UI
@@ -64,7 +99,7 @@ import android.os.ParcelFileDescriptor;
* This will ensure that the UI does not change while you are laying out the
* printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
* CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
- * thread. This will ensure that the UI is frozen for the minimal amount of
+ * thread. This will ensure that the main thread is busy for a minimal amount of
* time. Also this assumes that you will generate the printed content in
* {@link #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
* LayoutResultCallback, Bundle)} which is not mandatory. If you use multiple
@@ -76,6 +111,12 @@ public abstract class PrintDocumentAdapter {
/**
* Extra: mapped to a boolean value that is <code>true</code> if
* the current layout is for a print preview, <code>false</code> otherwise.
+ * This extra is provided in the {@link Bundle} argument of the {@link
+ * #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)} callback.
+ *
+ * @see #onLayout(PrintAttributes, PrintAttributes, CancellationSignal,
+ * LayoutResultCallback, Bundle)
*/
public static final String EXTRA_PRINT_PREVIEW = "EXTRA_PRINT_PREVIEW";
@@ -95,17 +136,20 @@ public abstract class PrintDocumentAdapter {
* After you are done laying out, you <strong>must</strong> 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.
- * Note that you must call one of the methods of the given callback.
+ * whether the layout changed the content or not, respectively; or {@link
+ * LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred;
+ * or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
+ * cancelled in a response to a cancellation request via the passed in
+ * {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+ * the methods of the given callback for this method to be considered complete.
* </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.
+ * layout. The cancellation callback <strong>will not</strong> be made on
+ * the main thread.
* </p>
*
* @param oldAttributes The old print attributes.
@@ -128,10 +172,12 @@ public abstract class PrintDocumentAdapter {
* on the main thread.
*<p>
* After you are done writing, you should close the file descriptor and
- * invoke {@link WriteResultCallback #onWriteFinished(PageRange[]), if writing
+ * invoke {@link WriteResultCallback#onWriteFinished(PageRange[])}, if writing
* completed successfully; or {@link WriteResultCallback#onWriteFailed(
- * CharSequence)}, if an error occurred. Note that you must call one of
- * the methods of the given callback.
+ * CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
+ * if writing was cancelled in a response to a cancellation request via the passed
+ * in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
+ * the methods of the given callback for this method to be considered complete.
* </p>
* <p>
* <strong>Note:</strong> If the printed content is large, it is a good
@@ -178,7 +224,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that all the data was written.
*
- * @param pages The pages that were written. Cannot be null or empty.
+ * @param pages The pages that were written. Cannot be <code>null</code>
+ * or empty.
*/
public void onWriteFinished(PageRange[] pages) {
/* do nothing - stub */
@@ -187,7 +234,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that an error occurred while writing the data.
*
- * @param error Error message. May be null if error is unknown.
+ * @param error The <strong>localized</strong> error message.
+ * shown to the user. May be <code>null</code> if error is unknown.
*/
public void onWriteFailed(CharSequence error) {
/* do nothing - stub */
@@ -218,7 +266,7 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that the layout finished and whether the content changed.
*
- * @param info An info object describing the document. Cannot be null.
+ * @param info An info object describing the document. Cannot be <code>null</code>.
* @param changed Whether the layout changed.
*
* @see PrintDocumentInfo
@@ -230,7 +278,8 @@ public abstract class PrintDocumentAdapter {
/**
* Notifies that an error occurred while laying out the document.
*
- * @param error Error message. May be null if error is unknown.
+ * @param error The <strong>localized</strong> error message.
+ * shown to the user. May be <code>null</code> if error is unknown.
*/
public void onLayoutFailed(CharSequence error) {
/* do nothing - stub */
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index b721ef4..928be6c 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -21,12 +21,56 @@ import android.os.Parcelable;
import android.text.TextUtils;
/**
- * This class encapsulates information about a printed document.
+ * This class encapsulates information about a document for printing
+ * purposes. This meta-data is used by the platform and print services,
+ * components that interact with printers. For example, this class
+ * contains the number of pages contained in the document it describes and
+ * this number of pages is shown to the user allowing him/her to select
+ * the range to print. Also a print service may optimize the printing
+ * process based on the content type, such as document or photo.
+ * <p>
+ * Instances of this class are created by the printing application and
+ * passed to the {@link PrintDocumentAdapter.LayoutResultCallback#onLayoutFinished(
+ * PrintDocumentInfo, boolean) PrintDocumentAdapter.LayoutResultCallback.onLayoutFinished(
+ * PrintDocumentInfo, boolean)} callback after successfully laying out the
+ * content which is performed in {@link PrintDocumentAdapter#onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal, PrintDocumentAdapter.LayoutResultCallback,
+ * android.os.Bundle) PrintDocumentAdapter.onLayout(PrintAttributes,
+ * PrintAttributes, android.os.CancellationSignal,
+ * PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle)}.
+ * </p>
+ * <p>
+ * An example usage looks like this:
+ * <pre>
+ *
+ * . . .
+ *
+ * public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ * CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ * Bundle metadata) {
+ *
+ * // Assume the app defined a LayoutResult class which contains
+ * // the layout result data and that the content is a document.
+ * LayoutResult result = doSomeLayoutWork();
+ *
+ * PrintDocumentInfo info = new PrintDocumentInfo
+ * .Builder("printed_file.pdf")
+ * .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ * .setPageCount(result.getPageCount())
+ * .build();
+ *
+ * callback.onLayoutFinished(info, result.getContentChanged());
+ * }
+ *
+ * . . .
+ *
+ * </pre>
+ * </p>
*/
public final class PrintDocumentInfo implements Parcelable {
/**
- * Constant for unknown page count..
+ * Constant for unknown page count.
*/
public static final int PAGE_COUNT_UNKNOWN = -1;
@@ -37,11 +81,23 @@ public final class PrintDocumentInfo implements Parcelable {
/**
* Content type: document.
+ * <p>
+ * A print service may use normal paper to print the content instead
+ * of dedicated photo paper. Also it may use a lower quality printing
+ * process as the content is not as sensitive to print quality variation
+ * as a photo is.
+ * </p>
*/
public static final int CONTENT_TYPE_DOCUMENT = 0;
/**
* Content type: photo.
+ * <p>
+ * A print service may use dedicated photo paper to print the content
+ * instead of normal paper. Also it may use a higher quality printing
+ * process as the content is more sensitive to print quality variation
+ * than a document.
+ * </p>
*/
public static final int CONTENT_TYPE_PHOTO = 1;
@@ -82,7 +138,8 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Gets the document name.
+ * Gets the document name. This name may be shown to
+ * the user.
*
* @return The document name.
*/
@@ -213,20 +270,23 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Builder for creating an {@link PrintDocumentInfo}.
+ * Builder for creating a {@link PrintDocumentInfo}.
*/
public static final class Builder {
private final PrintDocumentInfo mPrototype;
/**
* Constructor.
+ *
* <p>
- * The values of the relevant properties are initialized with default
- * values. Please refer to the documentation of the individual setters
- * for information about the default values.
+ * The values of the relevant properties are initialized with defaults.
+ * Please refer to the documentation of the individual setters for
+ * information about the default values.
* </p>
*
- * @param name The document name. Cannot be empty.
+ * @param name The document name which may be shown to the user and
+ * is the file name if the content it describes is saved as a PDF.
+ * Cannot be empty.
*/
public Builder(String name) {
if (TextUtils.isEmpty(name)) {
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 535ae43..0abe219 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -17,8 +17,13 @@
package android.print;
/**
- * This class represents a print job from the perspective of
- * an application.
+ * This class represents a print job from the perspective of an
+ * application. It contains behavior methods for performing operations
+ * on it as well as methods for querying its state. A snapshot of the
+ * print job state is represented by the {@link PrintJobInfo} class.
+ * The state of a print job may change over time. An application receives
+ * instances of this class when creating a print job or querying for
+ * its print jobs.
*/
public final class PrintJob {
@@ -145,11 +150,12 @@ public final class PrintJob {
/**
* Gets whether this print job is failed. Such a print job is
* not successfully printed due to an error. You can request
- * a restart via {@link #restart()}.
+ * a restart via {@link #restart()} or cancel via {@link #cancel()}.
*
* @return Whether the print job is failed.
*
* @see #restart()
+ * @see #cancel()
*/
public boolean isFailed() {
return getInfo().getState() == PrintJobInfo.STATE_FAILED;
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index c6f0a68..63f94fe 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -16,13 +16,17 @@
package android.print;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
/**
- * This class represents the description of a print job.
+ * This class represents the description of a print job. The print job
+ * state includes properties such as its id, print attributes used for
+ * generating the content, and so on. Note that the print jobs state may
+ * change over time and this class represents a snapshot of this state.
*/
public final class PrintJobInfo implements Parcelable {
@@ -93,7 +97,7 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_BLOCKED = 4;
/**
- * Print job state: The print job was successfully printed.
+ * Print job state: The print job is successfully printed.
* This is a terminal state.
* <p>
* Next valid states: None
@@ -103,15 +107,14 @@ public final class PrintJobInfo implements Parcelable {
/**
* Print job state: The print job was printing but printing failed.
- * This is a terminal state.
* <p>
- * Next valid states: None
+ * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
* </p>
*/
public static final int STATE_FAILED = 6;
/**
- * Print job state: The print job was canceled.
+ * Print job state: The print job is canceled.
* This is a terminal state.
* <p>
* Next valid states: None
@@ -158,6 +161,9 @@ public final class PrintJobInfo implements Parcelable {
/** Information about the printed document. */
private PrintDocumentInfo mDocumentInfo;
+ /** Advanced printer specific options. */
+ private Bundle mAdvancedOptions;
+
/** Whether we are trying to cancel this print job. */
private boolean mCanceling;
@@ -182,6 +188,7 @@ public final class PrintJobInfo implements Parcelable {
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
mCanceling = other.mCanceling;
+ mAdvancedOptions = other.mAdvancedOptions;
}
private PrintJobInfo(Parcel parcel) {
@@ -195,20 +202,17 @@ public final class PrintJobInfo implements Parcelable {
mCreationTime = parcel.readLong();
mCopies = parcel.readInt();
mStateReason = parcel.readString();
- if (parcel.readInt() == 1) {
- Parcelable[] parcelables = parcel.readParcelableArray(null);
+ Parcelable[] parcelables = parcel.readParcelableArray(null);
+ if (parcelables != null) {
mPageRanges = new PageRange[parcelables.length];
for (int i = 0; i < parcelables.length; i++) {
mPageRanges[i] = (PageRange) parcelables[i];
}
}
- if (parcel.readInt() == 1) {
- mAttributes = PrintAttributes.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() == 1) {
- mDocumentInfo = PrintDocumentInfo.CREATOR.createFromParcel(parcel);
- }
+ mAttributes = (PrintAttributes) parcel.readParcelable(null);
+ mDocumentInfo = (PrintDocumentInfo) parcel.readParcelable(null);
mCanceling = (parcel.readInt() == 1);
+ mAdvancedOptions = parcel.readBundle();
}
/**
@@ -297,6 +301,14 @@ public final class PrintJobInfo implements Parcelable {
* Gets the current job state.
*
* @return The job state.
+ *
+ * @see #STATE_CREATED
+ * @see #STATE_QUEUED
+ * @see #STATE_STARTED
+ * @see #STATE_COMPLETED
+ * @see #STATE_BLOCKED
+ * @see #STATE_FAILED
+ * @see #STATE_CANCELED
*/
public int getState() {
return mState;
@@ -511,6 +523,71 @@ public final class PrintJobInfo implements Parcelable {
mCanceling = cancelling;
}
+ /**
+ * Gets whether this job has a given advanced (printer specific) print
+ * option.
+ *
+ * @param key The option key.
+ * @return Whether the option is present.
+ *
+ * @hide
+ */
+ public boolean hasAdvancedOption(String key) {
+ return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
+ }
+
+ /**
+ * Gets the value of an advanced (printer specific) print option.
+ *
+ * @param key The option key.
+ * @return The option value.
+ *
+ * @hide
+ */
+ public String getAdvancedStringOption(String key) {
+ if (mAdvancedOptions != null) {
+ return mAdvancedOptions.getString(key);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the value of an advanced (printer specific) print option.
+ *
+ * @param key The option key.
+ * @return The option value.
+ *
+ * @hide
+ */
+ public int getAdvancedIntOption(String key) {
+ if (mAdvancedOptions != null) {
+ return mAdvancedOptions.getInt(key);
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the advanced options.
+ *
+ * @return The advanced options.
+ *
+ * @hide
+ */
+ public Bundle getAdvancedOptions() {
+ return mAdvancedOptions;
+ }
+
+ /**
+ * Sets the advanced options.
+ *
+ * @param options The advanced options.
+ *
+ * @hide
+ */
+ public void setAdvancedOptions(Bundle options) {
+ mAdvancedOptions = options;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -528,25 +605,11 @@ public final class PrintJobInfo implements Parcelable {
parcel.writeLong(mCreationTime);
parcel.writeInt(mCopies);
parcel.writeString(mStateReason);
- if (mPageRanges != null) {
- parcel.writeInt(1);
- parcel.writeParcelableArray(mPageRanges, flags);
- } else {
- parcel.writeInt(0);
- }
- if (mAttributes != null) {
- parcel.writeInt(1);
- mAttributes.writeToParcel(parcel, flags);
- } else {
- parcel.writeInt(0);
- }
- if (mDocumentInfo != null) {
- parcel.writeInt(1);
- mDocumentInfo.writeToParcel(parcel, flags);
- } else {
- parcel.writeInt(0);
- }
+ parcel.writeParcelableArray(mPageRanges, flags);
+ parcel.writeParcelable(mAttributes, flags);
+ parcel.writeParcelable(mDocumentInfo, 0);
parcel.writeInt(mCanceling ? 1 : 0);
+ parcel.writeBundle(mAdvancedOptions);
}
@Override
@@ -567,6 +630,7 @@ public final class PrintJobInfo implements Parcelable {
builder.append(", cancelling: " + mCanceling);
builder.append(", pages: " + (mPageRanges != null
? Arrays.toString(mPageRanges) : null));
+ builder.append(", hasAdvancedOptions: " + (mAdvancedOptions != null));
builder.append("}");
return builder.toString();
}
@@ -611,7 +675,7 @@ public final class PrintJobInfo implements Parcelable {
* Constructor.
*
* @param prototype Prototype to use as a starting point.
- * Can be null.
+ * Can be <code>null</code>.
*/
public Builder(PrintJobInfo prototype) {
mPrototype = (prototype != null)
@@ -653,7 +717,10 @@ public final class PrintJobInfo implements Parcelable {
* @param value The option value.
*/
public void putAdvancedOption(String key, String value) {
-
+ if (mPrototype.mAdvancedOptions == null) {
+ mPrototype.mAdvancedOptions = new Bundle();
+ }
+ mPrototype.mAdvancedOptions.putString(key, value);
}
/**
@@ -663,7 +730,10 @@ public final class PrintJobInfo implements Parcelable {
* @param value The option value.
*/
public void putAdvancedOption(String key, int value) {
-
+ if (mPrototype.mAdvancedOptions == null) {
+ mPrototype.mAdvancedOptions = new Bundle();
+ }
+ mPrototype.mAdvancedOptions.putInt(key, value);
}
/**
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 955b4d8..bbfc307 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -55,6 +55,49 @@ import java.util.Map;
* PrintManager printManager =
* (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
* </pre>
+ *
+ * <h3>Print mechanics</h3>
+ * <p>
+ * The key idea behind printing on the platform is that the content to be printed
+ * should be laid out for the currently selected print options resulting in an
+ * optimized output and higher user satisfaction. To achieve this goal the platform
+ * declares a contract that the printing application has to follow which is defined
+ * by the {@link PrintDocumentAdapter} class. At a higher level the contract is that
+ * when the user selects some options from the print UI that may affect the way
+ * content is laid out, for example page size, the application receives a callback
+ * allowing it to layout the content to better fit these new constraints. After a
+ * layout pass the system may ask the application to render one or more pages one
+ * or more times. For example, an application may produce a single column list for
+ * smaller page sizes and a multi-column table for larger page sizes.
+ * </p>
+ * <h3>Print jobs</h3>
+ * <p>
+ * Print jobs are started by calling the {@link #print(String, PrintDocumentAdapter,
+ * PrintAttributes)} from an activity which results in bringing up the system print
+ * UI. Once the print UI is up, when the user changes a selected print option that
+ * affects the way content is laid out the system starts to interact with the
+ * application following the mechanics described the section above.
+ * </p>
+ * <p>
+ * Print jobs can be in {@link PrintJobInfo#STATE_CREATED created}, {@link
+ * PrintJobInfo#STATE_QUEUED queued}, {@link PrintJobInfo#STATE_STARTED started},
+ * {@link PrintJobInfo#STATE_BLOCKED blocked}, {@link PrintJobInfo#STATE_COMPLETED
+ * completed}, {@link PrintJobInfo#STATE_FAILED failed}, and {@link
+ * PrintJobInfo#STATE_CANCELED canceled} state. Print jobs are stored in dedicated
+ * system spooler until they are handled which is they are cancelled or completed.
+ * Active print jobs, ones that are not cancelled or completed, are considered failed
+ * if the device reboots as the new boot may be after a very long time. The user may
+ * choose to restart such print jobs. Once a print job is queued all relevant content
+ * is stored in the system spooler and its lifecycle becomes detached from this of
+ * the application that created it.
+ * </p>
+ * <p>
+ * An applications can query the print spooler for current print jobs it created
+ * but not print jobs created by other applications.
+ * </p>
+ *
+ * @see PrintJob
+ * @see PrintJobInfo
*/
public final class PrintManager {
@@ -292,20 +335,54 @@ public final class PrintManager {
/**
* Creates a print job for printing a {@link PrintDocumentAdapter} with
* default print attributes.
- *
- * @param printJobName A name for the new print job.
+ * <p>
+ * Calling this method brings the print UI allowing the user to customize
+ * the print job and returns a {@link PrintJob} object without waiting for the
+ * user to customize or confirm the print job. The returned print job instance
+ * is in a {@link PrintJobInfo#STATE_CREATED created} state.
+ * <p>
+ * This method can be called only from an {@link Activity}. The rationale is that
+ * printing from a service will create an inconsistent user experience as the print
+ * UI would appear without any context.
+ * </p>
+ * <p>
+ * Also the passed in {@link PrintDocumentAdapter} will be considered invalid if
+ * your activity is finished. The rationale is that once the activity that
+ * initiated printing is finished, the provided adapter may be in an inconsistent
+ * state as it may depend on the UI presented by the activity.
+ * </p>
+ * <p>
+ * The default print attributes are a hint to the system how the data is to
+ * be printed. For example, a photo editor may look at the photo aspect ratio
+ * to determine the default orientation and provide a hint whether the printing
+ * should be in portrait or landscape. The system will do a best effort to
+ * selected the hinted options in the print dialog, given the current printer
+ * supports them.
+ * </p>
+ *
+ * @param printJobName A name for the new print job which is shown to the user.
* @param documentAdapter An adapter that emits the document to print.
- * @param attributes The default print job attributes.
+ * @param attributes The default print job attributes or <code>null</code>.
* @return The created print job on success or null on failure.
+ * @throws IllegalStateException If not called from an {@link Activity}.
+ * @throws IllegalArgumentException If the print job name is empty or the
+ * document adapter is null.
+ *
* @see PrintJob
*/
public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
PrintAttributes attributes) {
+ if (!(mContext instanceof Activity)) {
+ throw new IllegalStateException("Can print only from an activity");
+ }
if (TextUtils.isEmpty(printJobName)) {
- throw new IllegalArgumentException("priintJobName cannot be empty");
+ throw new IllegalArgumentException("printJobName cannot be empty");
+ }
+ if (documentAdapter == null) {
+ throw new IllegalArgumentException("documentAdapter cannot be null");
}
PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(
- mContext, documentAdapter);
+ (Activity) mContext, documentAdapter);
try {
Bundle result = mService.print(printJobName, delegate,
attributes, mContext.getPackageName(), mAppId, mUserId);
@@ -398,12 +475,9 @@ public final class PrintManager {
private boolean mDestroyed;
- public PrintDocumentAdapterDelegate(Context context,
+ public PrintDocumentAdapterDelegate(Activity activity,
PrintDocumentAdapter documentAdapter) {
- if (!(context instanceof Activity)) {
- throw new IllegalStateException("Can print only from an activity");
- }
- mActivity = (Activity) context;
+ mActivity = activity;
mDocumentAdapter = documentAdapter;
mHandler = new MyHandler(mActivity.getMainLooper());
mActivity.getApplication().registerActivityLifecycleCallbacks(this);
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index df51ec1..b615600 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -24,10 +24,17 @@ import android.print.PrintAttributes.Resolution;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
- * This class represents the capabilities of a printer.
+ * This class represents the capabilities of a printer. Instances
+ * of this class are created by a print service to report the
+ * capabilities of a printer it manages. The capabilities of a
+ * printer specify how it can print content. For example, what
+ * are the media sizes supported by the printer, what are the
+ * minimal margins of the printer based on its technical design,
+ * etc.
*/
public final class PrinterCapabilitiesInfo implements Parcelable {
/**
@@ -112,7 +119,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @return The media sizes.
*/
public List<MediaSize> getMediaSizes() {
- return mMediaSizes;
+ return Collections.unmodifiableList(mMediaSizes);
}
/**
@@ -121,7 +128,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
* @return The resolutions.
*/
public List<Resolution> getResolutions() {
- return mResolutions;
+ return Collections.unmodifiableList(mResolutions);
}
/**
@@ -135,9 +142,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Gets the supported color modes.
+ * Gets the bit mask of supported color modes.
*
- * @return The color modes.
+ * @return The bit mask of supported color modes.
*
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
@@ -355,9 +362,10 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Builder for creating of a {@link PrinterInfo}. This class is responsible
- * to enforce that all required attributes have at least one default value.
- * In other words, this class creates only well-formed {@link PrinterInfo}s.
+ * Builder for creating of a {@link PrinterCapabilitiesInfo}. This class is
+ * responsible to enforce that all required attributes have at least one
+ * default value. In other words, this class creates only well-formed {@link
+ * PrinterCapabilitiesInfo}s.
* <p>
* Look at the individual methods for a reference whether a property is
* required or if it is optional.
@@ -369,9 +377,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
/**
* Creates a new instance.
*
- * @param printerId The printer id. Cannot be null.
+ * @param printerId The printer id. Cannot be <code>null</code>.
*
- * @throws IllegalArgumentException If the printer id is null.
+ * @throws IllegalArgumentException If the printer id is <code>null</code>.
*/
public Builder(PrinterId printerId) {
if (printerId == null) {
@@ -492,7 +500,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
/**
* Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
- * required properties have need specified. See individual methods
+ * required properties have been specified. See individual methods
* in this class for reference about required attributes.
*
* @return A new {@link PrinterCapabilitiesInfo}.
@@ -521,7 +529,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
if (mPrototype.mMinMargins == null) {
throw new IllegalArgumentException("margins cannot be null");
}
- return new PrinterCapabilitiesInfo(mPrototype);
+ return mPrototype;
}
private void throwIfDefaultAlreadySpecified(int propertyIndex) {
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index ad79a38..7fcc81f 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -21,7 +21,12 @@ import android.os.Parcelable;
import android.text.TextUtils;
/**
- * This class represents the description of a printer.
+ * This class represents the description of a printer. Instances of
+ * this class are created by print services to report to the system
+ * the printers they manage. The information of this class has two
+ * major components, printer properties such as name, id, status,
+ * description and printer capabilities which describe the various
+ * print modes a printer supports such as media sizes, margins, etc.
*/
public final class PrinterInfo implements Parcelable {
@@ -96,6 +101,10 @@ public final class PrinterInfo implements Parcelable {
* Gets the printer status.
*
* @return The status.
+ *
+ * @see #STATUS_BUSY
+ * @see #STATUS_IDLE
+ * @see #STATUS_UNAVAILABLE
*/
public int getStatus() {
return mStatus;
@@ -216,6 +225,8 @@ public final class PrinterInfo implements Parcelable {
* @param printerId The printer id. Cannot be null.
* @param name The printer name. Cannot be empty.
* @param status The printer status. Must be a valid status.
+ * @throws IllegalArgumentException If the printer id is null, or the
+ * printer name is empty or the status is not a valid one.
*/
public Builder(PrinterId printerId, String name, int status) {
if (printerId == null) {
@@ -259,7 +270,8 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Sets the printer name.
+ * Sets the <strong>localized</strong> printer name which
+ * is shown to the user
*
* @param name The name.
* @return This builder.
@@ -270,7 +282,8 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Sets the printer description.
+ * Sets the <strong>localized</strong> printer description
+ * which is shown to the user
*
* @param description The description.
* @return This builder.
@@ -292,12 +305,12 @@ public final class PrinterInfo implements Parcelable {
}
/**
- * Crates a new {@link PrinterInfo}.
+ * Creates a new {@link PrinterInfo}.
*
* @return A new {@link PrinterInfo}.
*/
public PrinterInfo build() {
- return new PrinterInfo(mPrototype);
+ return mPrototype;
}
private boolean isValidStatus(int status) {
diff --git a/core/java/android/print/package.html b/core/java/android/print/package.html
new file mode 100644
index 0000000..579567d
--- /dev/null
+++ b/core/java/android/print/package.html
@@ -0,0 +1,46 @@
+<HTML>
+<BODY>
+<h3>Overview</h3>
+<p>
+Provides classes for implementing print support in applications and also contains all
+base classes and abstractions involved in printing. These base classes are also used
+by other more specialized printing related packages.
+</p>
+<p>
+The entry point for interacting with the print system is the {@link android.print.PrintManager}
+which is a system service that can be obtained from the current context. The print manager
+provides APIs for printing, querying the state of print jobs, etc.
+<p/>
+<h3>Print contract</h3>
+<p>
+An application that wants to implement printing must extend
+{@link android.print.PrintDocumentAdapter} which defines the contract between the system
+and the application.The key idea behind this adapter is that the printed content may change
+based on the selected print options, such as media size, orientation, which
+requires the content to be re-laid out. The constraints according to which the content has
+to be laid out are encapsulated in the {@link android.print.PrintAttributes} class. Once
+layout is completed the application calls back to the system passing a
+{@link android.print.PrintDocumentInfo} instance which describes the generated content. After
+the content has been laid out the application may be asked to render some pages of that content
+for preview or printing. The range of pages that have to be rendered is abstracted by the
+{@link android.print.PageRange} class.
+</p>
+<h3>Print jobs</h3>
+<p>
+A print job is represented by the {@link android.print.PrintJob} class which has behavior
+methods as well as methods for querying its state. Each print job has a unique id represented
+by the {@link android.print.PrintJobId} class and exposes APIs for obtaining a {@link
+android.print.PrintJobInfo} which is a snapshot of its state. The print job state may
+change over time.
+</p>
+<h3>Printers</h3>
+<p>
+An available printer represented by the {@link android.print.PrinterInfo} class has a
+unique id which is abstracted by the {@link android.print.PrinterId} class. The {@link
+android.print.PrinterInfo} contains printer properties such as id, name, description, status,
+and printer capabilities encapsulated in the {@link android.print.PrinterCapabilitiesInfo}
+class. Printer capabilities describe how a printer can print content, for example what are
+the supported media sizes, color modes, resolutions, etc.
+<p>
+</BODY>
+</HTML>
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index fdeb373..6fa0bdd 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -321,7 +321,7 @@ public final class PrintJob {
*/
public String getAdvancedStringOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
- return null;
+ return getInfo().getAdvancedStringOption(key);
}
/**
@@ -333,7 +333,7 @@ public final class PrintJob {
*/
public boolean hasAdvancedOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
- return false;
+ return getInfo().hasAdvancedOption(key);
}
/**
@@ -344,7 +344,7 @@ public final class PrintJob {
*/
public int getAdvancedIntOption(String key) {
PrintService.throwIfNotCalledOnMainThread();
- return 0;
+ return getInfo().getAdvancedIntOption(key);
}
@Override
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 0fc5f7f..eb0ac2e 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -209,6 +209,14 @@ public abstract class PrintService extends Service {
* PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
* and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
* </p>
+ * <p>
+ * If the advanced print options activity offers changes to the standard print
+ * options, you can get the current {@link android.print.PrinterInfo} using the
+ * "android.intent.extra.print.EXTRA_PRINTER_INFO" extra which will allow you to
+ * present the user with UI options supported by the current printer. For example,
+ * if the current printer does not support a give media size, you should not
+ * offer it in the advanced print options dialog.
+ * </p>
*/
public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 8e9636c..a2c6c09 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -60,6 +60,8 @@ public final class PrintServiceInfo implements Parcelable {
private final String mAddPrintersActivityName;
+ private final String mAdvancedPrintOptionsActivityName;
+
/**
* Creates a new instance.
*
@@ -70,6 +72,7 @@ public final class PrintServiceInfo implements Parcelable {
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mAddPrintersActivityName = parcel.readString();
+ mAdvancedPrintOptionsActivityName = parcel.readString();
}
/**
@@ -78,14 +81,16 @@ public final class PrintServiceInfo implements Parcelable {
* @param resolveInfo The service resolve info.
* @param settingsActivityName Optional settings activity name.
* @param addPrintersActivityName Optional add printers activity name.
+ * @param advancedPrintOptionsActivityName Optional advanced print options activity.
*/
public PrintServiceInfo(ResolveInfo resolveInfo, String settingsActivityName,
- String addPrintersActivityName) {
+ String addPrintersActivityName, String advancedPrintOptionsActivityName) {
mId = new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name).flattenToString();
mResolveInfo = resolveInfo;
mSettingsActivityName = settingsActivityName;
mAddPrintersActivityName = addPrintersActivityName;
+ mAdvancedPrintOptionsActivityName = advancedPrintOptionsActivityName;
}
/**
@@ -99,6 +104,7 @@ public final class PrintServiceInfo implements Parcelable {
public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
String settingsActivityName = null;
String addPrintersActivityName = null;
+ String advancedPrintOptionsActivityName = null;
XmlResourceParser parser = null;
PackageManager packageManager = context.getPackageManager();
@@ -128,6 +134,9 @@ public final class PrintServiceInfo implements Parcelable {
addPrintersActivityName = attributes.getString(
com.android.internal.R.styleable.PrintService_addPrintersActivity);
+ advancedPrintOptionsActivityName = attributes.getString(com.android.internal
+ .R.styleable.PrintService_advancedPrintOptionsActivity);
+
attributes.recycle();
}
} catch (IOException ioe) {
@@ -144,7 +153,8 @@ public final class PrintServiceInfo implements Parcelable {
}
}
- return new PrintServiceInfo(resolveInfo, settingsActivityName, addPrintersActivityName);
+ return new PrintServiceInfo(resolveInfo, settingsActivityName,
+ addPrintersActivityName, advancedPrintOptionsActivityName);
}
/**
@@ -195,6 +205,19 @@ public final class PrintServiceInfo implements Parcelable {
}
/**
+ * The advanced print options activity name.
+ * <p>
+ * <strong>Statically set from
+ * {@link PrintService#SERVICE_META_DATA meta-data}.</strong>
+ * </p>
+ *
+ * @return The advanced print options activity name.
+ */
+ public String getAdvancedOptionsActivityName() {
+ return mAdvancedPrintOptionsActivityName;
+ }
+
+ /**
* {@inheritDoc}
*/
public int describeContents() {
@@ -206,6 +229,7 @@ public final class PrintServiceInfo implements Parcelable {
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeString(mAddPrintersActivityName);
+ parcel.writeString(mAdvancedPrintOptionsActivityName);
}
@Override
@@ -243,6 +267,8 @@ public final class PrintServiceInfo implements Parcelable {
builder.append(", resolveInfo=").append(mResolveInfo);
builder.append(", settingsActivityName=").append(mSettingsActivityName);
builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
+ builder.append(", advancedPrintOptionsActivityName=")
+ .append(mAdvancedPrintOptionsActivityName);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 7f8dca2..09f5fe3 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -81,6 +81,9 @@ public final class DocumentsContract {
/** {@hide} */
public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
+ /** {@hide} */
+ public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
+
/**
* Included in {@link AssetFileDescriptor#getExtras()} when returned
* thumbnail should be rotated.
diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java
index 5800bd5..e1f1896 100644
--- a/core/java/android/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -57,7 +57,7 @@ public final class Scene {
com.android.internal.R.id.scene_layoutid_cache);
if (scenes == null) {
scenes = new SparseArray<Scene>();
- sceneRoot.setTag(com.android.internal.R.id.scene_layoutid_cache, scenes);
+ sceneRoot.setTagInternal(com.android.internal.R.id.scene_layoutid_cache, scenes);
}
Scene scene = scenes.get(layoutId);
if (scene != null) {
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 9b1494d..3bf6790 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -82,6 +82,8 @@ public class TransitionManager {
* an {@link AutoTransition} instance.
*
* @param transition The default transition to be used for scene changes.
+ *
+ * @hide pending later changes
*/
public void setDefaultTransition(Transition transition) {
sDefaultTransition = transition;
@@ -93,6 +95,8 @@ public class TransitionManager {
*
* @return The current default transition.
* @see #setDefaultTransition(Transition)
+ *
+ * @hide pending later changes
*/
public static Transition getDefaultTransition() {
return sDefaultTransition;
@@ -105,7 +109,7 @@ public class TransitionManager {
* transition to run.
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using the {@link #getDefaultTransition() default transition} instead.
+ * using the default transition instead.
*/
public void setTransition(Scene scene, Transition transition) {
mSceneTransitions.put(scene, transition);
@@ -121,7 +125,7 @@ public class TransitionManager {
* be run
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using the {@link #getDefaultTransition() default transition} instead.
+ * using the default transition instead.
*/
public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
@@ -139,8 +143,8 @@ public class TransitionManager {
*
* @param scene The scene being entered
* @return The Transition to be used for the given scene change. If no
- * Transition was specified for this scene change, the {@link #getDefaultTransition()
- * default transition} will be used instead.
+ * Transition was specified for this scene change, the default transition
+ * will be used instead.
*/
private Transition getTransition(Scene scene) {
Transition transition = null;
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 736566e..61df922 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -16,9 +16,12 @@
package android.widget;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.DataSetObservable;
import android.os.AsyncTask;
@@ -708,7 +711,12 @@ public class ActivityChooserModel extends DataSetObservable {
final int resolveInfoCount = resolveInfos.size();
for (int i = 0; i < resolveInfoCount; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
- mActivities.add(new ActivityResolveInfo(resolveInfo));
+ ActivityInfo activityInfo = resolveInfo.activityInfo;
+ if (ActivityManager.checkComponentPermission(activityInfo.permission,
+ android.os.Process.myUid(), activityInfo.applicationInfo.uid,
+ activityInfo.exported) == PackageManager.PERMISSION_GRANTED) {
+ mActivities.add(new ActivityResolveInfo(resolveInfo));
+ }
}
return true;
}
@@ -930,29 +938,31 @@ public class ActivityChooserModel extends DataSetObservable {
private final class DefaultSorter implements ActivitySorter {
private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f;
- private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap =
- new HashMap<String, ActivityResolveInfo>();
+ private final Map<ComponentName, ActivityResolveInfo> mPackageNameToActivityMap =
+ new HashMap<ComponentName, ActivityResolveInfo>();
public void sort(Intent intent, List<ActivityResolveInfo> activities,
List<HistoricalRecord> historicalRecords) {
- Map<String, ActivityResolveInfo> packageNameToActivityMap =
- mPackageNameToActivityMap;
- packageNameToActivityMap.clear();
+ Map<ComponentName, ActivityResolveInfo> componentNameToActivityMap =
+ mPackageNameToActivityMap;
+ componentNameToActivityMap.clear();
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
ActivityResolveInfo activity = activities.get(i);
activity.weight = 0.0f;
- String packageName = activity.resolveInfo.activityInfo.packageName;
- packageNameToActivityMap.put(packageName, activity);
+ ComponentName componentName = new ComponentName(
+ activity.resolveInfo.activityInfo.packageName,
+ activity.resolveInfo.activityInfo.name);
+ componentNameToActivityMap.put(componentName, activity);
}
final int lastShareIndex = historicalRecords.size() - 1;
float nextRecordWeight = 1;
for (int i = lastShareIndex; i >= 0; i--) {
HistoricalRecord historicalRecord = historicalRecords.get(i);
- String packageName = historicalRecord.activity.getPackageName();
- ActivityResolveInfo activity = packageNameToActivityMap.get(packageName);
+ ComponentName componentName = historicalRecord.activity;
+ ActivityResolveInfo activity = componentNameToActivityMap.get(componentName);
if (activity != null) {
activity.weight += historicalRecord.weight * nextRecordWeight;
nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index dff1531..8612964 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -18,6 +18,7 @@ package android.widget;
import com.android.internal.R;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -27,6 +28,7 @@ import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -63,6 +65,8 @@ import android.widget.ListPopupWindow.ForwardingListener;
*/
public class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient {
+ private static final String LOG_TAG = "ActivityChooserView";
+
/**
* An adapter for displaying the activities in an {@link AdapterView}.
*/
@@ -543,9 +547,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
// Activity chooser content.
if (mDefaultActivityButton.getVisibility() == VISIBLE) {
- mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
+ mActivityChooserContent.setBackground(mActivityChooserContentBackground);
} else {
- mActivityChooserContent.setBackgroundDrawable(null);
+ mActivityChooserContent.setBackground(null);
}
}
@@ -577,7 +581,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
if (launchIntent != null) {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- mContext.startActivity(launchIntent);
+ ResolveInfo resolveInfo = mAdapter.getDataModel().getActivity(position);
+ startActivity(launchIntent, resolveInfo);
}
}
} break;
@@ -595,7 +600,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
if (launchIntent != null) {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- mContext.startActivity(launchIntent);
+ startActivity(launchIntent, defaultActivity);
}
} else if (view == mExpandActivityOverflowButton) {
mIsSelectingDefaultActivity = false;
@@ -632,6 +637,18 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
mOnDismissListener.onDismiss();
}
}
+
+ private void startActivity(Intent intent, ResolveInfo resolveInfo) {
+ try {
+ mContext.startActivity(intent);
+ } catch (RuntimeException re) {
+ CharSequence appLabel = resolveInfo.loadLabel(mContext.getPackageManager());
+ String message = mContext.getString(
+ R.string.activitychooserview_choose_application_error, appLabel);
+ Log.e(LOG_TAG, message);
+ Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
+ }
+ }
}
/**
@@ -805,10 +822,6 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
return mDataModel.getHistorySize();
}
- public int getMaxActivityCount() {
- return mMaxActivityCount;
- }
-
public ActivityChooserModel getDataModel() {
return mDataModel;
}