diff --git a/Android.mk b/Android.mk
index 1802239d25bde..3d52f44f3f93f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -165,6 +165,7 @@ LOCAL_SRC_FILES += \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
+ core/java/android/print/IPrintDocumentAdapterObserver.aidl \
core/java/android/print/IPrintJobStateChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \
@@ -250,10 +251,14 @@ LOCAL_SRC_FILES += \
media/java/android/media/IAudioService.aidl \
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IAudioRoutesObserver.aidl \
+ media/java/android/media/IMediaRouterClient.aidl \
+ media/java/android/media/IMediaRouterService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
media/java/android/media/IRemoteControlClient.aidl \
media/java/android/media/IRemoteControlDisplay.aidl \
+ media/java/android/media/IRemoteDisplayCallback.aidl \
+ media/java/android/media/IRemoteDisplayProvider.aidl \
media/java/android/media/IRemoteVolumeObserver.aidl \
media/java/android/media/IRingtonePlayer.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
@@ -537,31 +542,89 @@ framework_docs_LOCAL_ADDITIONAL_JAVA_DIR:= \
framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES := \
frameworks/base/docs/knowntags.txt
-sample_dir := development/samples
+sample_dir := development/samples/browseable
new_sample_dir := developers/samples/android
# Whitelist of valid groups, used for default TOC grouping. Each sample must
# belong to one (and only one) group. Assign samples to groups by setting
# a sample.group var to one of these groups in the sample's _index.jd.
-sample_groups := -samplegroup Input \
- -samplegroup Sensors \
- -samplegroup Connectivity
+sample_groups := -samplegroup Background \
+ -samplegroup Connectivity \
+ -samplegroup Content \
+ -samplegroup Input \
+ -samplegroup Media \
+ -samplegroup Security \
+ -samplegroup Testing \
+ -samplegroup UI \
+ -samplegroup Views
# the list here should match the list of samples included in the sdk samples package
# (see development/build/sdk.atree)
# remove htmlified samples for now -- samples are still available through the SDK
web_docs_sample_code_flags := \
-hdf android.hasSamples 1 \
- -samplecode $(new_sample_dir)/input/gestures/BasicGestureDetect/BasicGestureDetect \
- samples/BasicGestureDetect/ "Basic Gestures" \
- -samplecode $(sample_dir)/AccelerometerPlay \
- samples/AccelerometerPlay "Accelerometer Play" \
- -samplecode $(sample_dir)/ActionBarCompat \
- samples/ActionBarCompat "Action Bar Compatibility" \
- -samplecode $(sample_dir)/BluetoothHDP \
- samples/BluetoothHDP "Bluetooth HDP Demo" \
- -samplecode $(sample_dir)/BluetoothLeGatt \
- samples/BluetoothLeGatt "Bluetooth HDP Demo"
+ -samplecode $(sample_dir)/BasicAccessibility \
+ samples/BasicAccessibility "" \
+ -samplecode $(sample_dir)/HorizontalPaging \
+ samples/HorizontalPaging "" \
+ -samplecode $(sample_dir)/ShareActionProvider \
+ samples/ShareActionProvider "" \
+ -samplecode $(sample_dir)/Styled \
+ samples/Styled "" \
+ -samplecode $(sample_dir)/BasicAndroidKeyStore \
+ samples/BasicAndroidKeyStore "" \
+ -samplecode $(sample_dir)/Basic \
+ samples/Basic "" \
+ -samplecode $(sample_dir)/ImmersiveMode \
+ samples/ImmersiveMode "" \
+ -samplecode $(sample_dir)/repeatingAlarm \
+ samples/repeatingAlarm "" \
+ -samplecode $(sample_dir)/TextLinkify \
+ samples/TextLinkify "" \
+ -samplecode $(sample_dir)/BasicMediaRouter \
+ samples/BasicMediaRouter "" \
+ -samplecode $(sample_dir)/BasicMultitouch \
+ samples/BasicMultitouch "" \
+ -samplecode $(sample_dir)/TextSwitcher \
+ samples/TextSwitcher "" \
+ -samplecode $(sample_dir)/ActivityInstrumentation \
+ samples/ActivityInstrumentation "" \
+ -samplecode $(sample_dir)/BorderlessButtons \
+ samples/BorderlessButtons "" \
+ -samplecode $(sample_dir)/BasicNotifications \
+ samples/BasicNotifications "" \
+ -samplecode $(sample_dir)/AdvancedImmersiveMode \
+ samples/AdvancedImmersiveMode "" \
+ -samplecode $(sample_dir)/BluetoothLeGatt \
+ samples/BluetoothLeGatt "" \
+ -samplecode $(sample_dir)/NetworkConnect \
+ samples/NetworkConnect "" \
+ -samplecode $(sample_dir)/BasicNetworking \
+ samples/BasicNetworking "" \
+ -samplecode $(sample_dir)/BasicMediaDecoder \
+ samples/BasicMediaDecoder "" \
+ -samplecode $(sample_dir)/BasicImmersiveMode \
+ samples/BasicImmersiveMode "" \
+ -samplecode $(sample_dir)/CustomChoiceList \
+ samples/CustomChoiceList "" \
+ -samplecode $(sample_dir)/BasicContactables \
+ samples/BasicContactables "" \
+ -samplecode $(sample_dir)/BasicGestureDetect \
+ samples/BasicGestureDetect "" \
+ -samplecode $(sample_dir)/DoneBar \
+ samples/DoneBar "" \
+ -samplecode $(sample_dir)/ListPopupMenu \
+ samples/ListPopupMenu "" \
+ -samplecode $(sample_dir)/AppRestrictions \
+ samples/AppRestrictions "" \
+ -samplecode $(sample_dir)/CustomNotifications \
+ samples/CustomNotifications "" \
+ -samplecode $(sample_dir)/BasicSyncAdapter \
+ samples/BasicSyncAdapter "" \
+ -samplecode $(sample_dir)/StorageClient \
+ samples/StorageClient "" \
+ -samplecode $(sample_dir)/StorageProvider \
+ samples/StorageProvider ""
# -samplecode $(sample_dir)/AndroidBeamDemo \
# samples/AndroidBeamDemo "Android Beam Demo" \
# -samplecode $(sample_dir)/ApiDemos \
@@ -780,9 +843,9 @@ LOCAL_MODULE := online-sdk
LOCAL_DROIDDOC_OPTIONS:= \
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-toroot / \
- -hdf android.whichdoc online
-# $(sample_groups) \
-# $(web_docs_sample_code_flags)
+ -hdf android.whichdoc online \
+ $(sample_groups) \
+ $(web_docs_sample_code_flags)
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
diff --git a/api/current.txt b/api/current.txt
index ff48db0efdbe9..8e69592ecabcd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22,6 +22,7 @@ package android {
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+ field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
@@ -3083,18 +3084,18 @@ package android.app {
method public void cancel(android.app.PendingIntent);
method public void set(int, long, android.app.PendingIntent);
method public void setExact(int, long, android.app.PendingIntent);
- method public deprecated void setInexactRepeating(int, long, long, android.app.PendingIntent);
+ method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
method public void setRepeating(int, long, long, android.app.PendingIntent);
method public void setTime(long);
method public void setTimeZone(java.lang.String);
method public void setWindow(int, long, long, android.app.PendingIntent);
field public static final int ELAPSED_REALTIME = 3; // 0x3
field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
- field public static final deprecated long INTERVAL_DAY = 86400000L; // 0x5265c00L
- field public static final deprecated long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
- field public static final deprecated long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
- field public static final deprecated long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
- field public static final deprecated long INTERVAL_HOUR = 3600000L; // 0x36ee80L
+ field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L
+ field public static final long INTERVAL_FIFTEEN_MINUTES = 900000L; // 0xdbba0L
+ field public static final long INTERVAL_HALF_DAY = 43200000L; // 0x2932e00L
+ field public static final long INTERVAL_HALF_HOUR = 1800000L; // 0x1b7740L
+ field public static final long INTERVAL_HOUR = 3600000L; // 0x36ee80L
field public static final int RTC = 1; // 0x1
field public static final int RTC_WAKEUP = 0; // 0x0
}
@@ -13227,6 +13228,7 @@ package android.media.audiofx {
field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB;
field public static final java.util.UUID EFFECT_TYPE_EQUALIZER;
+ field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER;
field public static final java.util.UUID EFFECT_TYPE_NS;
field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB;
field public static final java.util.UUID EFFECT_TYPE_VIRTUALIZER;
@@ -13384,6 +13386,7 @@ package android.media.audiofx {
}
public class LoudnessEnhancer extends android.media.audiofx.AudioEffect {
+ ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException;
method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public void setTargetGain(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
field public static final int PARAM_TARGET_GAIN_MB = 0; // 0x0
@@ -25632,10 +25635,8 @@ package android.transition {
ctor public TransitionManager();
method public static void beginDelayedTransition(android.view.ViewGroup);
method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
- method public static android.transition.Transition getDefaultTransition();
method public static void go(android.transition.Scene);
method public static void go(android.transition.Scene, android.transition.Transition);
- method public void setDefaultTransition(android.transition.Transition);
method public void setTransition(android.transition.Scene, android.transition.Transition);
method public void setTransition(android.transition.Scene, android.transition.Scene, android.transition.Transition);
method public void transitionTo(android.transition.Scene);
@@ -25794,6 +25795,7 @@ package android.util {
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_DEFAULT = 160; // 0xa0
field public static final int DENSITY_HIGH = 240; // 0xf0
field public static final int DENSITY_LOW = 120; // 0x78
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c18f54259678e..0344d261fd35f 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -107,7 +107,7 @@ public class Am extends BaseCommand {
" am switch-user Note: 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.
+ *
* 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+.
- *
* Schedule an alarm. Note: for timing operations (ticks, timeouts,
- * etc) it is easier and much more efficient to use
- * {@link android.os.Handler}. 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}.
+ * If there is already an alarm scheduled for the same IntentSender, that previous
+ * alarm will first be canceled.
*
- * If the time occurs in the past, the alarm will be triggered
+ * 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.
*
*
- * 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 <receiver> 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.
+ *
+ *
+ * Note: 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.
+ *
+ *
+ * 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' actual delivery ordering may not match
+ * the order of their requested 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)}.
+ *
+ *
+ * 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.
+ * 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
+ * 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.
+ *
+ * Note: 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
+ *
+ * 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.
*
- * @param type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or
- * RTC_WAKEUP.
+ *
+ * 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 {@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 duration, 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.
+ *
+ *
+ * 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.
+ *
+ *
+ * Note: 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.
- *
+ *
* 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.
+ *
+ * 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/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b741cc5c85b35..2ed8b0fbe24ce 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1011,15 +1011,15 @@ public class DownloadManager {
}
/**
- * Returns {@link Uri} for the given downloaded file id, if the file is
- * downloaded successfully. otherwise, null is returned.
+ * Returns the {@link Uri} of the given downloaded file id, if the file is
+ * downloaded successfully. Otherwise, null is returned.
*
* If the specified downloaded file is in external storage (for example, /sdcard dir),
* then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
* to the filepath on sdcard.
*
* @param id the id of the downloaded file.
- * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+ * @return the {@link Uri} of the given downloaded file id, if download was successful. null
* otherwise.
*/
public Uri getUriForDownloadedFile(long id) {
@@ -1064,15 +1064,11 @@ public class DownloadManager {
}
/**
- * Returns {@link Uri} for the given downloaded file id, if the file is
- * downloaded successfully. otherwise, null is returned.
- *
- * If the specified downloaded file is in external storage (for example, /sdcard dir),
- * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
- * to the filepath on sdcard.
+ * Returns the media type of the given downloaded file id, if the file was
+ * downloaded successfully. Otherwise, null is returned.
*
* @param id the id of the downloaded file.
- * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+ * @return the media type of the given downloaded file id, if download was successful. null
* otherwise.
*/
public String getMimeTypeForDownloadedFile(long id) {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index a307a73d52b3a..028fa6816b96a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1213,8 +1213,8 @@ public class Instrumentation {
}
/**
- * Perform calling of an activity's {@link Activity#onPause} method. The
- * default implementation simply calls through to that method.
+ * Perform calling of an activity's {@link Activity#onSaveInstanceState}
+ * method. The default implementation simply calls through to that method.
*
* @param activity The activity being saved.
* @param outState The bundle to pass to the call.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 22a21cdf829da..aab6ed83b11fd 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -205,7 +205,9 @@ public class KeyguardManager {
try {
mWM.exitKeyguardSecurely(new IOnKeyguardExitResult.Stub() {
public void onKeyguardExitResult(boolean success) throws RemoteException {
- callback.onKeyguardExitResult(success);
+ if (callback != null) {
+ callback.onKeyguardExitResult(success);
+ }
}
});
} catch (RemoteException e) {
diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java
index 63b641cb708e9..dffa969a7148a 100644
--- a/core/java/android/app/MediaRouteActionProvider.java
+++ b/core/java/android/app/MediaRouteActionProvider.java
@@ -16,10 +16,7 @@
package android.app;
-import com.android.internal.app.MediaRouteChooserDialogFragment;
-
import android.content.Context;
-import android.content.ContextWrapper;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.util.Log;
@@ -30,22 +27,38 @@ import android.view.ViewGroup;
import java.lang.ref.WeakReference;
+/**
+ * The media route action provider displays a {@link MediaRouteButton media route button}
+ * in the application's {@link ActionBar} to allow the user to select routes and
+ * to control the currently selected route.
+ *
+ * The application must specify the kinds of routes that the user should be allowed
+ * to select by specifying the route types with the {@link #setRouteTypes} method.
+ *
+ * Refer to {@link MediaRouteButton} for a description of the button that will
+ * appear in the action bar menu. Note that instead of disabling the button
+ * when no routes are available, the action provider will instead make the
+ * menu item invisible. In this way, the button will only be visible when it
+ * is possible for the user to discover and select a matching route.
+ *
+ * If the default route is selected or if the currently selected route does
+ * not match the {@link #getRouteTypes route types}, then shows the route chooser dialog.
+ * Otherwise, shows the route controller dialog to offer the user
+ * a choice to disconnect from the route or perform other control actions
+ * such as setting the route's volume.
+ *
+ * This will attach a {@link DialogFragment} to the containing Activity.
+ * Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} to
+ * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
* receive.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -465,7 +465,7 @@ public final class BluetoothDevice implements Parcelable {
/**
* The user will be prompted to enter a pin or
- * a privileged app will enter a pin for user.
+ * an app will enter a pin for user.
*/
public static final int PAIRING_VARIANT_PIN = 0;
@@ -477,7 +477,7 @@ public final class BluetoothDevice implements Parcelable {
/**
* The user will be prompted to confirm the passkey displayed on the screen or
- * a privileged app will confirm the passkey for the user.
+ * an app will confirm the passkey for the user.
*/
public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
@@ -725,7 +725,7 @@ public final class BluetoothDevice implements Parcelable {
* the bonding process completes, and its result.
* Android system services will handle the necessary user interactions
* to confirm and complete the bonding process.
- * Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @return false on immediate error, true if bonding will begin
*/
@@ -965,7 +965,7 @@ public final class BluetoothDevice implements Parcelable {
/**
* Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
- * Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @return true pin has been set
* false for error
@@ -993,7 +993,7 @@ public final class BluetoothDevice implements Parcelable {
/**
* Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
- * Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+ * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @return true confirmation has been sent out
* false for error
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a9d055988862e..ddde3fb00d69d 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -398,67 +398,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return AppOpsManager.MODE_ALLOWED;
}
- private void enforceReadPermissionInner(Uri uri) throws SecurityException {
- final Context context = getContext();
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- String missingPerm = null;
-
- if (UserHandle.isSameApp(uid, mMyUid)) {
- return;
- }
-
- if (mExported) {
- final String componentPerm = getReadPermission();
- if (componentPerm != null) {
- if (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED) {
- return;
- } else {
- missingPerm = componentPerm;
- }
- }
-
- // track if unprotected read is allowed; any denied
- //
+ * If set to 1, the HAL will always split result
+ * metadata for a single capture into multiple buffers,
+ * returned using multiple process_capture_result calls.
+ *
+ * Does not need to be listed in static
+ * metadata. Support for partial results will be reworked in
+ * future versions of camera service. This quirk will stop
+ * working at that point; DO NOT USE without careful
+ * consideration of future support.
+ *
* How many output streams can be allocated at
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 7095e4d498ab6..9e8d7d19e288b 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -630,6 +630,36 @@ public interface CameraDevice extends AutoCloseable {
// default empty implementation
}
+ /**
+ * This method is called when some results from an image capture are
+ * available.
+ *
+ * The result provided here will contain some subset of the fields of
+ * a full result. Multiple onCapturePartial calls may happen per
+ * capture; a given result field will only be present in one partial
+ * capture at most. The final onCaptureCompleted call will always
+ * contain all the fields, whether onCapturePartial was called or
+ * not. The default implementation of this method does nothing.
+ * Whether a result given to the framework is the
+ * final one for the capture, or only a partial that contains a
+ * subset of the full set of dynamic metadata
+ * values.
+ *
+ * The entries in the result metadata buffers for a
+ * single capture may not overlap, except for this entry. The
+ * FINAL buffers must retain FIFO ordering relative to the
+ * requests that generate them, so the FINAL buffer for frame 3 must
+ * always be sent to the framework after the FINAL buffer for frame 2, and
+ * before the FINAL buffer for frame 4. PARTIAL buffers may be returned
+ * in any order relative to other frames, but all PARTIAL buffers for a given
+ * capture must arrive before the FINAL buffer for that capture. This entry may
+ * only be used by the HAL if quirks.usePartialResult is set to 1.
+ *
* A frame counter set by the framework. This value monotonically
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index c5d0999213068..40586f0efcd96 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -19,27 +19,24 @@ package android.hardware.camera2.impl;
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
-import android.os.IBinder;
-import android.os.RemoteException;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
-import java.util.Stack;
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -49,6 +46,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
private final String TAG;
private final boolean DEBUG;
+ private static final int REQUEST_ID_NONE = -1;
+
// TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
private ICameraDeviceUser mRemoteDevice;
@@ -63,7 +62,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
private final SparseArray
+ * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
+ *
- * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
- * to unknown displays. No permissions are required to connect to already known displays.
+ * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
* For more information about using NFC, read the
* Near Field Communication developer guide. To perform basic file sharing between devices, read
+ * Sharing Files with NFC.
*
*/
public final class NfcAdapter {
@@ -309,8 +311,12 @@ public final class NfcAdapter {
final Context mContext;
/**
- * A callback to be invoked when the system has found a tag in
- * reader mode.
+ * A callback to be invoked when the system finds a tag while the foreground activity is
+ * operating in reader mode.
+ * Register your {@code ReaderCallback} implementation with {@link
+ * NfcAdapter#enableReaderMode} and disable it with {@link
+ * NfcAdapter#disableReaderMode}.
+ * @see NfcAdapter#enableReaderMode
*/
public interface ReaderCallback {
public void onTagDiscovered(Tag tag);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bc98a0b504255..b1a9ea300d741 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -105,6 +105,11 @@ public abstract class BatteryStats implements Parcelable {
*/
public static final int FOREGROUND_ACTIVITY = 10;
+ /**
+ * A constant indicating a wifi batched scan is active
+ */
+ public static final int WIFI_BATCHED_SCAN = 11;
+
/**
* Include all of the data in the stats, including previously saved data.
*/
@@ -270,6 +275,8 @@ public abstract class BatteryStats implements Parcelable {
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteWifiScanStartedLocked();
public abstract void noteWifiScanStoppedLocked();
+ public abstract void noteWifiBatchedScanStartedLocked(int csph);
+ public abstract void noteWifiBatchedScanStoppedLocked();
public abstract void noteWifiMulticastEnabledLocked();
public abstract void noteWifiMulticastDisabledLocked();
public abstract void noteAudioTurnedOnLocked();
@@ -281,6 +288,7 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getWifiRunningTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getWifiScanTime(long batteryRealtime, int which);
+ public abstract long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which);
public abstract long getWifiMulticastTime(long batteryRealtime,
int which);
public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
@@ -288,6 +296,8 @@ public abstract class BatteryStats implements Parcelable {
public abstract Timer getForegroundActivityTimer();
public abstract Timer getVibratorOnTimer();
+ public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5;
+
/**
* Note that these must match the constants in android.os.PowerManager.
* Also, if the user activity types change, the BatteryStatsImpl.VERSION must
@@ -844,12 +854,13 @@ public abstract class BatteryStats implements Parcelable {
public static final int DATA_CONNECTION_EVDO_B = 12;
public static final int DATA_CONNECTION_LTE = 13;
public static final int DATA_CONNECTION_EHRPD = 14;
- public static final int DATA_CONNECTION_OTHER = 15;
+ public static final int DATA_CONNECTION_HSPAP = 15;
+ public static final int DATA_CONNECTION_OTHER = 16;
static final String[] DATA_CONNECTION_NAMES = {
"none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A",
"1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte",
- "ehrpd", "other"
+ "ehrpd", "hspap", "other"
};
public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1;
@@ -2080,9 +2091,11 @@ public abstract class BatteryStats implements Parcelable {
TimeUtils.formatDuration(ew.usedTime, pw);
pw.print(" over ");
TimeUtils.formatDuration(ew.overTime, pw);
- pw.print(" (");
- pw.print((ew.usedTime*100)/ew.overTime);
- pw.println("%)");
+ if (ew.overTime != 0) {
+ pw.print(" (");
+ pw.print((ew.usedTime*100)/ew.overTime);
+ pw.println("%)");
+ }
}
}
uidActivity = true;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 114a1ea69035c..bc51a60992805 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -457,6 +457,13 @@ public class Build {
* margins correctly.
* This tracing mechanism is independent of the method tracing mechanism
* offered by {@link Debug#startMethodTracing}. In particular, it enables
* tracing of events that occur across multiple processes.
+ * For information about using the Systrace tool, read Analyzing Display and Performance
+ * with Systrace.
*/
public final class Trace {
/*
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 177a9554191aa..0285cb9321142 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -21,6 +21,9 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.CharArrayWriter;
import java.io.File;
/**
@@ -46,6 +49,10 @@ public class StorageVolume implements Parcelable {
/** When set, indicates exclusive ownership of this volume */
private final UserHandle mOwner;
+ private String mUuid;
+ private String mUserLabel;
+ private String mState;
+
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
// ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED,
// ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
@@ -76,6 +83,9 @@ public class StorageVolume implements Parcelable {
mAllowMassStorage = in.readInt() != 0;
mMaxFileSize = in.readLong();
mOwner = in.readParcelable(null);
+ mUuid = in.readString();
+ mUserLabel = in.readString();
+ mState = in.readString();
}
public static StorageVolume fromTemplate(StorageVolume template, File path, UserHandle owner) {
@@ -189,6 +199,45 @@ public class StorageVolume implements Parcelable {
return mOwner;
}
+ public void setUuid(String uuid) {
+ mUuid = uuid;
+ }
+
+ public String getUuid() {
+ return mUuid;
+ }
+
+ /**
+ * Parse and return volume UUID as FAT volume ID, or return -1 if unable to
+ * parse or UUID is unknown.
+ */
+ public int getFatVolumeId() {
+ if (mUuid == null || mUuid.length() != 9) {
+ return -1;
+ }
+ try {
+ return Integer.parseInt(mUuid.replace("-", ""), 16);
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
+ public void setUserLabel(String userLabel) {
+ mUserLabel = userLabel;
+ }
+
+ public String getUserLabel() {
+ return mUserLabel;
+ }
+
+ public void setState(String state) {
+ mState = state;
+ }
+
+ public String getState() {
+ return mState;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj instanceof StorageVolume && mPath != null) {
@@ -205,19 +254,28 @@ public class StorageVolume implements Parcelable {
@Override
public String toString() {
- final StringBuilder builder = new StringBuilder("StorageVolume [");
- builder.append("mStorageId=").append(mStorageId);
- builder.append(" mPath=").append(mPath);
- builder.append(" mDescriptionId=").append(mDescriptionId);
- builder.append(" mPrimary=").append(mPrimary);
- builder.append(" mRemovable=").append(mRemovable);
- builder.append(" mEmulated=").append(mEmulated);
- builder.append(" mMtpReserveSpace=").append(mMtpReserveSpace);
- builder.append(" mAllowMassStorage=").append(mAllowMassStorage);
- builder.append(" mMaxFileSize=").append(mMaxFileSize);
- builder.append(" mOwner=").append(mOwner);
- builder.append("]");
- return builder.toString();
+ final CharArrayWriter writer = new CharArrayWriter();
+ dump(new IndentingPrintWriter(writer, " ", 80));
+ return writer.toString();
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("StorageVolume:");
+ pw.increaseIndent();
+ pw.printPair("mStorageId", mStorageId);
+ pw.printPair("mPath", mPath);
+ pw.printPair("mDescriptionId", mDescriptionId);
+ pw.printPair("mPrimary", mPrimary);
+ pw.printPair("mRemovable", mRemovable);
+ pw.printPair("mEmulated", mEmulated);
+ pw.printPair("mMtpReserveSpace", mMtpReserveSpace);
+ pw.printPair("mAllowMassStorage", mAllowMassStorage);
+ pw.printPair("mMaxFileSize", mMaxFileSize);
+ pw.printPair("mOwner", mOwner);
+ pw.printPair("mUuid", mUuid);
+ pw.printPair("mUserLabel", mUserLabel);
+ pw.printPair("mState", mState);
+ pw.decreaseIndent();
}
public static final Creator
* Note: 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.
*
* Note: 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.
*
+ * 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.
+ *
+ * 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.
+ *
+ * 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)}.
+ *
+ * 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.
+ *
@@ -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.
*
* 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
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current layout operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a layout operation. In such a case the system will make
+ * an attempt to cancel the current layout as another one will have to be performed.
+ * Typically, you should register a cancellation callback in the cancellation
+ * signal. The cancellation callback will not be made on the
+ * main thread and can be registered as follows:
+ *
* Note: 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.
*
* 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 must call one of
+ * the methods of the given callback for this method to be considered complete which
+ * is you will not receive any calls to this adapter until the current write
+ * operation is complete by invoking a method on the callback instance. The callback
+ * methods can be invoked from an arbitrary thread.
*
+ * One of the arguments passed to this method is a {@link CancellationSignal}
+ * which is used to propagate requests from the system to your application for
+ * canceling the current write operation. For example, a cancellation may be
+ * requested if the user changes a print option that may affect layout while
+ * you are performing a write operation. In such a case the system will make
+ * an attempt to cancel the current write as a layout will have to be performed
+ * which then may be followed by a write. Typically, you should register a
+ * cancellation callback in the cancellation signal. The cancellation callback
+ * will not be made on the main thread and can be registered
+ * as follows:
+ *
* Note: If the printed content is large, it is a good
* practice to schedule writing it on a dedicated thread and register an
* observer in the provided {@link CancellationSignal} upon invocation of
- * which you should stop writing. The cancellation callback will not be
- * made on the main thread.
+ * which you should stop writing.
*
+ * 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)}.
+ *
+ * An example usage looks like this:
+ *
+ * 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.
+ *
+ * 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.
+ *
- * 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.
*
* 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.
*
- * Next valid states: None
+ * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED}
*
* 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
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * An applications can query the print spooler for current print jobs it created
+ * but not print jobs created by other applications.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
* 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
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+
+
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index fdeb3730b90e1..6fa0bddb43f48 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 0fc5f7f035a6a..eb0ac2e631b84 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)}.
*
+ * 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.
+ *
+ * Statically set from
+ * {@link PrintService#SERVICE_META_DATA meta-data}.
+ * Developer Guides
* Implementation
* true if
* the current layout is for a print preview, false 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,41 @@ public abstract class PrintDocumentAdapter {
* After you are done laying out, you must invoke: {@link
* LayoutResultCallback#onLayoutFinished(PrintDocumentInfo, boolean)} with
* the last argument true or false 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 must call one of
+ * the methods of the given callback for this method to be considered complete
+ * which is you will not receive any calls to this adapter until the current
+ * layout operation is complete by invoking a method on the callback instance.
+ * The callback methods can be invoked from an arbitrary thread.
*
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * @Override
+ * public void onCancel() {
+ * // Cancel layout
+ * }
+ * });
+ *
+ *
+ * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+ * @Override
+ * public void onCancel() {
+ * // Cancel write
+ * }
+ * });
+ *
+ * null
+ * or empty.
*/
public void onWriteFinished(PageRange[] pages) {
/* do nothing - stub */
@@ -187,7 +277,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 localized error message.
+ * shown to the user. May be null if error is unknown.
*/
public void onWriteFailed(CharSequence error) {
/* do nothing - stub */
@@ -218,7 +309,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 null.
* @param changed Whether the layout changed.
*
* @see PrintDocumentInfo
@@ -230,7 +321,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 localized error message.
+ * shown to the user. May be null 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 b721ef4e0dfef..928be6cae90ad 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.
+ *
+ *
+ * . . .
+ *
+ * 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());
+ * }
+ *
+ * . . .
+ *
+ *
+ * null.
*/
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 dbd8278d3a1fb..d1bb8fd20a4c9 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -16,6 +16,8 @@
package android.print;
+import android.app.Activity;
+import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
@@ -53,6 +55,49 @@ import java.util.Map;
* PrintManager printManager =
* (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
*
+ *
+ * Print mechanics
+ * Print jobs
+ * null.
* @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 (TextUtils.isEmpty(printJobName)) {
- throw new IllegalArgumentException("priintJobName cannot be empty");
+ if (!(mContext instanceof Activity)) {
+ throw new IllegalStateException("Can print only from an activity");
}
- PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
- mContext.getMainLooper());
+ if (TextUtils.isEmpty(printJobName)) {
+ throw new IllegalArgumentException("printJobName cannot be empty");
+ }
+ if (documentAdapter == null) {
+ throw new IllegalArgumentException("documentAdapter cannot be null");
+ }
+ PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(
+ (Activity) mContext, documentAdapter);
try {
Bundle result = mService.print(printJobName, delegate,
attributes, mContext.getPackageName(), mAppId, mUserId);
@@ -369,17 +448,21 @@ public final class PrintManager {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
- private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
+ private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
+ implements ActivityLifecycleCallbacks {
private final Object mLock = new Object();
private CancellationSignal mLayoutOrWriteCancellation;
- private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK -
- // cleared in finish()
+ private Activity mActivity; // Strong reference OK - cleared in finish()
+
+ private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish
private Handler mHandler; // Strong reference OK - cleared in finish()
+ private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in finish
+
private LayoutSpec mLastLayoutSpec;
private WriteSpec mLastWriteSpec;
@@ -390,16 +473,39 @@ public final class PrintManager {
private boolean mFinishRequested;
private boolean mFinished;
- public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
+ private boolean mDestroyed;
+
+ public PrintDocumentAdapterDelegate(Activity activity,
+ PrintDocumentAdapter documentAdapter) {
+ mActivity = activity;
mDocumentAdapter = documentAdapter;
- mHandler = new MyHandler(looper);
+ mHandler = new MyHandler(mActivity.getMainLooper());
+ mActivity.getApplication().registerActivityLifecycleCallbacks(this);
+ }
+
+ @Override
+ public void setObserver(IPrintDocumentAdapterObserver observer) {
+ final boolean destroyed;
+ synchronized (mLock) {
+ if (!mDestroyed) {
+ mObserver = observer;
+ }
+ destroyed = mDestroyed;
+ }
+ if (destroyed) {
+ try {
+ observer.onDestroy();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error announcing destroyed state", re);
+ }
+ }
}
@Override
public void start() {
synchronized (mLock) {
- // Started or finished - nothing to do.
- if (mStartReqeusted || mFinishRequested) {
+ // Started called or finish called or destroyed - nothing to do.
+ if (mStartReqeusted || mFinishRequested || mDestroyed) {
return;
}
@@ -412,71 +518,85 @@ public final class PrintManager {
@Override
public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
ILayoutResultCallback callback, Bundle metadata, int sequence) {
+ final boolean destroyed;
synchronized (mLock) {
- // Start not called or finish called - nothing to do.
- if (!mStartReqeusted || mFinishRequested) {
- return;
+ destroyed = mDestroyed;
+ // If start called and not finished called and not destroyed - do some work.
+ if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
+ // Layout cancels write and overrides layout.
+ if (mLastWriteSpec != null) {
+ IoUtils.closeQuietly(mLastWriteSpec.fd);
+ mLastWriteSpec = null;
+ }
+
+ mLastLayoutSpec = new LayoutSpec();
+ mLastLayoutSpec.callback = callback;
+ mLastLayoutSpec.oldAttributes = oldAttributes;
+ mLastLayoutSpec.newAttributes = newAttributes;
+ mLastLayoutSpec.metadata = metadata;
+ mLastLayoutSpec.sequence = sequence;
+
+ // Cancel the previous cancellable operation.When the
+ // cancellation completes we will do the pending work.
+ if (cancelPreviousCancellableOperationLocked()) {
+ return;
+ }
+
+ doPendingWorkLocked();
}
-
- // Layout cancels write and overrides layout.
- if (mLastWriteSpec != null) {
- IoUtils.closeQuietly(mLastWriteSpec.fd);
- mLastWriteSpec = null;
+ }
+ if (destroyed) {
+ try {
+ callback.onLayoutFailed(null, sequence);
+ } catch (RemoteException re) {
+ Log.i(LOG_TAG, "Error notifying for cancelled layout", re);
}
-
- mLastLayoutSpec = new LayoutSpec();
- mLastLayoutSpec.callback = callback;
- mLastLayoutSpec.oldAttributes = oldAttributes;
- mLastLayoutSpec.newAttributes = newAttributes;
- mLastLayoutSpec.metadata = metadata;
- mLastLayoutSpec.sequence = sequence;
-
- // Cancel the previous cancellable operation.When the
- // cancellation completes we will do the pending work.
- if (cancelPreviousCancellableOperationLocked()) {
- return;
- }
-
- doPendingWorkLocked();
}
}
@Override
public void write(PageRange[] pages, ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence) {
+ final boolean destroyed;
synchronized (mLock) {
- // Start not called or finish called - nothing to do.
- if (!mStartReqeusted || mFinishRequested) {
- return;
+ destroyed = mDestroyed;
+ // If start called and not finished called and not destroyed - do some work.
+ if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
+ // Write cancels previous writes.
+ if (mLastWriteSpec != null) {
+ IoUtils.closeQuietly(mLastWriteSpec.fd);
+ mLastWriteSpec = null;
+ }
+
+ mLastWriteSpec = new WriteSpec();
+ mLastWriteSpec.callback = callback;
+ mLastWriteSpec.pages = pages;
+ mLastWriteSpec.fd = fd;
+ mLastWriteSpec.sequence = sequence;
+
+ // Cancel the previous cancellable operation.When the
+ // cancellation completes we will do the pending work.
+ if (cancelPreviousCancellableOperationLocked()) {
+ return;
+ }
+
+ doPendingWorkLocked();
}
-
- // Write cancels previous writes.
- if (mLastWriteSpec != null) {
- IoUtils.closeQuietly(mLastWriteSpec.fd);
- mLastWriteSpec = null;
+ }
+ if (destroyed) {
+ try {
+ callback.onWriteFailed(null, sequence);
+ } catch (RemoteException re) {
+ Log.i(LOG_TAG, "Error notifying for cancelled write", re);
}
-
- mLastWriteSpec = new WriteSpec();
- mLastWriteSpec.callback = callback;
- mLastWriteSpec.pages = pages;
- mLastWriteSpec.fd = fd;
- mLastWriteSpec.sequence = sequence;
-
- // Cancel the previous cancellable operation.When the
- // cancellation completes we will do the pending work.
- if (cancelPreviousCancellableOperationLocked()) {
- return;
- }
-
- doPendingWorkLocked();
}
}
@Override
public void finish() {
synchronized (mLock) {
- // Start not called or finish called - nothing to do.
- if (!mStartReqeusted || mFinishRequested) {
+ // Start not called or finish called or destroyed - nothing to do.
+ if (!mStartReqeusted || mFinishRequested || mDestroyed) {
return;
}
@@ -495,15 +615,90 @@ public final class PrintManager {
}
}
+ @Override
+ public void cancel() {
+ // Start not called or finish called or destroyed - nothing to do.
+ if (!mStartReqeusted || mFinishRequested || mDestroyed) {
+ return;
+ }
+ // Request cancellation of pending work if needed.
+ synchronized (mLock) {
+ cancelPreviousCancellableOperationLocked();
+ }
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ // We really care only if the activity is being destroyed to
+ // notify the the print spooler so it can close the print dialog.
+ // Note the the spooler has a death recipient that observes if
+ // this process gets killed so we cover the case of onDestroy not
+ // being called due to this process being killed to reclaim memory.
+ final IPrintDocumentAdapterObserver observer;
+ synchronized (mLock) {
+ if (activity == mActivity) {
+ mDestroyed = true;
+ observer = mObserver;
+ clearLocked();
+ } else {
+ observer = null;
+ activity = null;
+ }
+ }
+ if (observer != null) {
+ activity.getApplication().unregisterActivityLifecycleCallbacks(
+ PrintDocumentAdapterDelegate.this);
+ try {
+ observer.onDestroy();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error announcing destroyed state", re);
+ }
+ }
+ }
+
private boolean isFinished() {
return mDocumentAdapter == null;
}
- private void doFinish() {
+ private void clearLocked() {
+ mActivity = null;
mDocumentAdapter = null;
mHandler = null;
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
+ mLayoutOrWriteCancellation = null;
+ mLastLayoutSpec = null;
+ if (mLastWriteSpec != null) {
+ IoUtils.closeQuietly(mLastWriteSpec.fd);
+ mLastWriteSpec = null;
}
}
@@ -564,63 +759,81 @@ public final class PrintManager {
}
switch (message.what) {
case MSG_START: {
- mDocumentAdapter.onStart();
- }
- break;
+ final PrintDocumentAdapter adapter;
+ synchronized (mLock) {
+ adapter = mDocumentAdapter;
+ }
+ if (adapter != null) {
+ adapter.onStart();
+ }
+ } break;
case MSG_LAYOUT: {
+ final PrintDocumentAdapter adapter;
final CancellationSignal cancellation;
final LayoutSpec layoutSpec;
synchronized (mLock) {
+ adapter = mDocumentAdapter;
layoutSpec = mLastLayoutSpec;
mLastLayoutSpec = null;
cancellation = new CancellationSignal();
mLayoutOrWriteCancellation = cancellation;
}
- if (layoutSpec != null) {
+ if (layoutSpec != null && adapter != null) {
if (DEBUG) {
Log.i(LOG_TAG, "Performing layout");
}
- mDocumentAdapter.onLayout(layoutSpec.oldAttributes,
+ adapter.onLayout(layoutSpec.oldAttributes,
layoutSpec.newAttributes, cancellation,
new MyLayoutResultCallback(layoutSpec.callback,
layoutSpec.sequence), layoutSpec.metadata);
}
- }
- break;
+ } break;
case MSG_WRITE: {
+ final PrintDocumentAdapter adapter;
final CancellationSignal cancellation;
final WriteSpec writeSpec;
synchronized (mLock) {
+ adapter = mDocumentAdapter;
writeSpec = mLastWriteSpec;
mLastWriteSpec = null;
cancellation = new CancellationSignal();
mLayoutOrWriteCancellation = cancellation;
}
- if (writeSpec != null) {
+ if (writeSpec != null && adapter != null) {
if (DEBUG) {
Log.i(LOG_TAG, "Performing write");
}
- mDocumentAdapter.onWrite(writeSpec.pages, writeSpec.fd,
+ adapter.onWrite(writeSpec.pages, writeSpec.fd,
cancellation, new MyWriteResultCallback(writeSpec.callback,
writeSpec.fd, writeSpec.sequence));
}
- }
- break;
+ } break;
case MSG_FINISH: {
if (DEBUG) {
Log.i(LOG_TAG, "Performing finish");
}
- mDocumentAdapter.onFinish();
- doFinish();
- }
- break;
+ final PrintDocumentAdapter adapter;
+ final Activity activity;
+ synchronized (mLock) {
+ adapter = mDocumentAdapter;
+ activity = mActivity;
+ clearLocked();
+ }
+ if (adapter != null) {
+ adapter.onFinish();
+ }
+ if (activity != null) {
+ activity.getApplication().unregisterActivityLifecycleCallbacks(
+ PrintDocumentAdapterDelegate.this);
+ }
+ } break;
default: {
throw new IllegalArgumentException("Unknown message: "
@@ -647,6 +860,11 @@ public final class PrintManager {
}
final ILayoutResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -663,6 +881,11 @@ public final class PrintManager {
public void onLayoutFailed(CharSequence error) {
final ILayoutResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -678,6 +901,11 @@ public final class PrintManager {
@Override
public void onLayoutCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
@@ -705,6 +933,11 @@ public final class PrintManager {
public void onWriteFinished(PageRange[] pages) {
final IWriteResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -727,6 +960,11 @@ public final class PrintManager {
public void onWriteFailed(CharSequence error) {
final IWriteResultCallback callback;
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
callback = mCallback;
clearLocked();
}
@@ -742,6 +980,11 @@ public final class PrintManager {
@Override
public void onWriteCancelled() {
synchronized (mLock) {
+ if (mDestroyed) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion?");
+ return;
+ }
clearLocked();
}
}
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index df51ec10fb790..b615600d33ae8 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 Listnull.
*
- * @throws IllegalArgumentException If the printer id is null.
+ * @throws IllegalArgumentException If the printer id is null.
*/
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 ad79a38acb97a..7fcc81f410068 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 localized 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 localized 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 0000000000000..579567d686bb9
--- /dev/null
+++ b/core/java/android/print/package.html
@@ -0,0 +1,46 @@
+
+Overview
+Print contract
+Print jobs
+Printers
+
@@ -91,8 +91,8 @@ import java.io.FileNotFoundException; *
* Each document can have different capabilities, as described by * {@link Document#COLUMN_FLAGS}. For example, if a document can be represented - * as a thumbnail, a provider can set {@link Document#FLAG_SUPPORTS_THUMBNAIL} - * and implement + * as a thumbnail, your provider can set + * {@link Document#FLAG_SUPPORTS_THUMBNAIL} and implement * {@link #openDocumentThumbnail(String, Point, CancellationSignal)} to return * that thumbnail. *
@@ -102,7 +102,7 @@ import java.io.FileNotFoundException; * single document can be included in multiple directories when responding to * {@link #queryChildDocuments(String, String[], String)}. For example, a * provider might surface a single photo in multiple locations: once in a - * directory of locations, and again in a directory of dates. + * directory of geographic locations, and again in a directory of dates. * *@@ -162,7 +162,7 @@ public abstract class DocumentsProvider extends ContentProvider { /** * Create a new document and return its newly generated - * {@link Document#COLUMN_DOCUMENT_ID}. A provider must allocate a new + * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new * {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must * not change once returned. * @@ -194,16 +194,17 @@ public abstract class DocumentsProvider extends ContentProvider { } /** - * Return all roots currently provided. A provider must define at least one - * root to display to users, and it should avoid making network requests to - * keep this request fast. + * Return all roots currently provided. To display to users, you must define + * at least one root. You should avoid making network requests to keep this + * request fast. *
* Each root is defined by the metadata columns described in {@link Root}, * including {@link Root#COLUMN_DOCUMENT_ID} which points to a directory * representing a tree of documents to display under that root. *
* If this set of roots changes, you must call {@link ContentResolver#notifyChange(Uri, - * android.database.ContentObserver)} to notify the system. + * android.database.ContentObserver, boolean)} with + * {@link DocumentsContract#buildRootsUri(String)} to notify the system. * * @param projection list of {@link Root} columns to put into the cursor. If * {@code null} all supported columns should be included. @@ -216,6 +217,8 @@ public abstract class DocumentsProvider extends ContentProvider { * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and * limited to only return the 64 most recently modified documents. + *
+ * Recent documents do not support change notifications. * * @param projection list of {@link Document} columns to put into the * cursor. If {@code null} all supported columns should be @@ -229,8 +232,8 @@ public abstract class DocumentsProvider extends ContentProvider { } /** - * Return metadata for the single requested document. A provider should - * avoid making network requests to keep this request fast. + * Return metadata for the single requested document. You should avoid + * making network requests to keep this request fast. * * @param documentId the document to return. * @param projection list of {@link Document} columns to put into the @@ -248,10 +251,18 @@ public abstract class DocumentsProvider extends ContentProvider { * If your provider is cloud-based, and you have some data cached or pinned * locally, you may return the local data immediately, setting * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that - * your provider is still fetching additional data. Then, when the network - * data is available, you can call {@link ContentResolver#notifyChange(Uri, - * android.database.ContentObserver)} to trigger a requery and return the - * complete contents. + * you are still fetching additional data. Then, when the network data is + * available, you can send a change notification to trigger a requery and + * return the complete contents. To return a Cursor with extras, you need to + * extend and override {@link Cursor#getExtras()}. + *
+ * To support change notifications, you must + * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant + * Uri, such as + * {@link DocumentsContract#buildChildDocumentsUri(String, String)}. Then + * you can call {@link ContentResolver#notifyChange(Uri, + * android.database.ContentObserver, boolean)} with that Uri to send change + * notifications. * * @param parentDocumentId the directory to return children for. * @param projection list of {@link Document} columns to put into the @@ -289,6 +300,20 @@ public abstract class DocumentsProvider extends ContentProvider { *
* Only documents may be returned; directories are not supported in search * results. + *
+ * If your provider is cloud-based, and you have some data cached or pinned + * locally, you may return the local data immediately, setting + * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that + * you are still fetching additional data. Then, when the network data is + * available, you can send a change notification to trigger a requery and + * return the complete contents. + *
+ * To support change notifications, you must + * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant + * Uri, such as {@link DocumentsContract#buildSearchDocumentsUri(String, + * String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri, + * android.database.ContentObserver, boolean)} with that Uri to send change + * notifications. * * @param rootId the root to search under. * @param query string to match documents against. @@ -327,22 +352,19 @@ public abstract class DocumentsProvider extends ContentProvider { /** * Open and return the requested document. *
- * A provider should return a reliable {@link ParcelFileDescriptor} to + * Your provider should return a reliable {@link ParcelFileDescriptor} to * detect when the remote caller has finished reading or writing the - * document. A provider may return a pipe or socket pair if the mode is - * exclusively {@link ParcelFileDescriptor#MODE_READ_ONLY} or - * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, but complex modes like - * {@link ParcelFileDescriptor#MODE_READ_WRITE} require a normal file on - * disk. + * document. You may return a pipe or socket pair if the mode is exclusively + * "r" or "w", but complex modes like "rw" imply a normal file on disk that + * supports seeking. *
- * If a provider blocks while downloading content, it should periodically - * check {@link CancellationSignal#isCanceled()} to abort abandoned open - * requests. + * If you block while downloading content, you should periodically check + * {@link CancellationSignal#isCanceled()} to abort abandoned open requests. * * @param documentId the document to return. * @param mode the mode to open with, such as 'r', 'w', or 'rw'. * @param signal used by the caller to signal if the request should be - * cancelled. + * cancelled. May be null. * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler, * OnCloseListener) * @see ParcelFileDescriptor#createReliablePipe() @@ -359,15 +381,14 @@ public abstract class DocumentsProvider extends ContentProvider { * attempting to serve from a local cache if possible. A provider should * never return images more than double the hinted size. *
- * If a provider performs expensive operations to download or generate a - * thumbnail, it should periodically check - * {@link CancellationSignal#isCanceled()} to abort abandoned thumbnail - * requests. + * If you perform expensive operations to download or generate a thumbnail, + * you should periodically check {@link CancellationSignal#isCanceled()} to + * abort abandoned thumbnail requests. * * @param documentId the document to return. * @param sizeHint hint of the optimal thumbnail dimensions. * @param signal used by the caller to signal if the request should be - * cancelled. + * cancelled. May be null. * @see Document#FLAG_SUPPORTS_THUMBNAIL */ @SuppressWarnings("unused") @@ -495,10 +516,7 @@ public abstract class DocumentsProvider extends ContentProvider { final boolean callerHasManage = context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS) == PackageManager.PERMISSION_GRANTED; - if (!callerHasManage) { - getContext().enforceCallingOrSelfUriPermission( - documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method); - } + enforceWritePermissionInner(documentUri); final Bundle out = new Bundle(); try { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7f245394d2462..04f3f0aad84dc 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3252,9 +3252,14 @@ public final class Settings { /** * A 64-bit number (as a hex string) that is randomly - * generated on the device's first boot and should remain - * constant for the lifetime of the device. (The value may - * change if a factory reset is performed on the device.) + * generated when the user first sets up the device and should remain + * constant for the lifetime of the user's device. The value may + * change if a factory reset is performed on the device. + *
Note: When a device has multiple users + * (available on certain devices running Android 4.2 or higher), each user appears as a + * completely separate device, so the {@code ANDROID_ID} value is unique to each + * user.
*/ public static final String ANDROID_ID = "android_id"; diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index b8083632bc4fc..2752085a427e0 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -993,8 +993,16 @@ public class TextToSpeech { return runAction(new ActionIME authors: If the class is not one you * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation - * or flags. + * or flags.
*/ public static final int TYPE_MASK_CLASS = 0x0000000f; @@ -69,7 +69,10 @@ public interface InputType { * This should be interpreted to mean that the target input connection * is not rich, it can not process and show things like candidate text nor * retrieve the current text, so the input method will need to run in a - * limited "generate key events" mode. + * limited "generate key events" mode, if it supports it. Note that some + * input methods may not support it, for example a voice-based input + * method will likely not be able to generate key events even if this + * flag is set. */ public static final int TYPE_NULL = 0x00000000; @@ -94,48 +97,70 @@ public interface InputType { * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. + * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. Of course, + * this only affects languages where there are upper-case and lower-case letters. */ public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000; /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of - * all words. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of + * every word. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This * value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_WORDS}. + * to be the same as {@link TextUtils#CAP_MODE_WORDS}. Of course, + * this only affects languages where there are upper-case and lower-case letters. */ public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000; /** - * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of + * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of * each sentence. This value is explicitly defined - * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. + * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. For example + * in English it means to capitalize after a period and a space (note that other + * languages may have different characters for period, or not use spaces, + * or use different grammatical rules). Of course, + * this only affects languages where there are upper-case and lower-case letters. */ public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000; /** * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form - * text that should have auto-correction applied to it. + * text that should have auto-correction applied to it. Without this flag, + * the IME will not try to correct typos. You should always set this flag + * unless you really expect users to type non-words in this field, for + * example to choose a name for a character in a game. + * Contrast this with {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE} and + * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: + * {@code TYPE_TEXT_FLAG_AUTO_CORRECT} means that the IME will try to + * auto-correct typos as the user is typing, but does not define whether + * the IME offers an interface to show suggestions. */ public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000; /** - * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing - * auto-completion of the text being entered based on its own semantics, - * which it will present to the user as they type. This generally means - * that the input method should not be showing candidates itself, but can - * expect for the editor to supply its own completions/candidates from + * Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means + * the application) is performing auto-completion of the text being entered + * based on its own semantics, which it will present to the user as they type. + * This generally means that the input method should not be showing + * candidates itself, but can expect the editor to supply its own + * completions/candidates from * {@link android.view.inputmethod.InputMethodSession#displayCompletions * InputMethodSession.displayCompletions()} as a result of the editor calling * {@link android.view.inputmethod.InputMethodManager#displayCompletions * InputMethodManager.displayCompletions()}. + * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and + * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}: + * {@code TYPE_TEXT_FLAG_AUTO_COMPLETE} means the editor should show an + * interface for displaying suggestions, but instead of supplying its own + * it will rely on the Editor to pass completions/corrections. */ public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000; /** * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be * entered into the field. If this flag is not set, the text field - * will be constrained to a single line. + * will be constrained to a single line. The IME may also choose not to + * display an enter key when this flag is not set, as there should be no + * need to create new lines. */ public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000; @@ -152,6 +177,16 @@ public interface InputType { * do not contain words from the language and do not benefit from any * dictionary-based completions or corrections. It overrides the * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set. + * Please avoid using this unless you are certain this is what you want. + * Many input methods need suggestions to work well, for example the ones + * based on gesture typing. Consider clearing + * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} instead if you just do not + * want the IME to correct typos. + * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and + * {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE}: + * {@code TYPE_TEXT_FLAG_NO_SUGGESTIONS} means the IME should never + * show an interface to display suggestions. Most IMEs will also take this to + * mean they should not try to auto-correct what the user is typing. */ public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000; @@ -224,7 +259,9 @@ public interface InputType { /** * Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic - * pronunciation, such as a phonetic name field in contacts. + * pronunciation, such as a phonetic name field in contacts. This is mostly + * useful for languages where one spelling may have several phonetic + * readings, like Japanese. */ public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0; @@ -255,12 +292,13 @@ public interface InputType { // ---------------------------------------------------------------------- /** - * Class for numeric text. This class supports the following flag: + * Class for numeric text. This class supports the following flags: * {@link #TYPE_NUMBER_FLAG_SIGNED} and * {@link #TYPE_NUMBER_FLAG_DECIMAL}. It also supports the following * variations: {@link #TYPE_NUMBER_VARIATION_NORMAL} and - * {@link #TYPE_NUMBER_VARIATION_PASSWORD}. If you do not recognize - * the variation, normal should be assumed. + * {@link #TYPE_NUMBER_VARIATION_PASSWORD}. + *
IME authors: If you do not recognize + * the variation, normal should be assumed.
*/ public static final int TYPE_CLASS_NUMBER = 0x00000002; @@ -318,7 +356,7 @@ public interface InputType { * following variations: * {@link #TYPE_DATETIME_VARIATION_NORMAL} * {@link #TYPE_DATETIME_VARIATION_DATE}, and - * {@link #TYPE_DATETIME_VARIATION_TIME},. + * {@link #TYPE_DATETIME_VARIATION_TIME}. */ public static final int TYPE_CLASS_DATETIME = 0x00000004; diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java index d798abec5a33b..e1f1896f5e9da 100644 --- a/core/java/android/transition/Scene.java +++ b/core/java/android/transition/Scene.java @@ -36,27 +36,28 @@ public final class Scene { private ViewGroup mSceneRoot; private ViewGroup mLayout; // alternative to layoutId Runnable mEnterAction, mExitAction; - private static ThreadLocallayoutId parameter. If such a Scene has already been created,
- * that same Scene will be returned. This caching of layoutId-based scenes enables
- * sharing of common scenes between those created in code and those referenced
- * by {@link TransitionManager} XML resource files.
+ * layoutId parameter. If such a Scene has already been created for
+ * the given sceneRoot, that same Scene will be returned.
+ * This caching of layoutId-based scenes enables sharing of common scenes
+ * between those created in code and those referenced by {@link TransitionManager}
+ * XML resource files.
*
* @param sceneRoot The root of the hierarchy in which scene changes
* and transitions will take place.
* @param layoutId The id of a standard layout resource file.
* @param context The context used in the process of inflating
* the layout resource.
- * @return
+ * @return The scene for the given root and layout id
*/
public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
- SparseArray
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 354ea6613a397..7d310a2549908 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -643,6 +643,15 @@ public final class Display {
|| uid == 0;
}
+ /**
+ * Returns true if the display is a public presentation display.
+ * @hide
+ */
+ public boolean isPublicPresentation() {
+ return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) ==
+ Display.FLAG_PRESENTATION;
+ }
+
private void updateDisplayInfoLocked() {
// Note: The display manager caches display info objects on our behalf.
DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index 9a89fa58d4573..324a1ae3e6062 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -123,7 +123,7 @@ public class Gravity
public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
/**
- * Apply a gravity constant to an object. This suppose that the layout direction is LTR.
+ * Apply a gravity constant to an object. This supposes that the layout direction is LTR.
*
* @param gravity The desired placement of the object, as defined by the
* constants in this class.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9d4af006258e2..c92a104b239d4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -78,7 +78,8 @@ interface IWindowManager
void addWindowToken(IBinder token, int type);
void removeWindowToken(IBinder token);
void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
- int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId);
+ int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
+ int configChanges);
void setAppGroupId(IBinder token, int groupId);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
@@ -211,7 +212,7 @@ interface IWindowManager
/**
* Called by the status bar to notify Views of changes to System UI visiblity.
*/
- void statusBarVisibilityChanged(int visibility);
+ oneway void statusBarVisibilityChanged(int visibility);
/**
* Block until the given window has been drawn to the screen.
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index f5ee7edca50ae..25972e7737a85 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -48,7 +48,7 @@ public abstract class InputEventReceiver {
InputChannel inputChannel, MessageQueue messageQueue);
private static native void nativeDispose(int receiverPtr);
private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
- private static native void nativeConsumeBatchedInputEvents(int receiverPtr,
+ private static native boolean nativeConsumeBatchedInputEvents(int receiverPtr,
long frameTimeNanos);
/**
@@ -165,14 +165,17 @@ public abstract class InputEventReceiver {
*
* @param frameTimeNanos The time in the {@link System#nanoTime()} time base
* when the current display frame started rendering, or -1 if unknown.
+ *
+ * @return Whether a batch was consumed
*/
- public final void consumeBatchedInputEvents(long frameTimeNanos) {
+ public final boolean consumeBatchedInputEvents(long frameTimeNanos) {
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to consume batched input events but the input event "
+ "receiver has already been disposed.");
} else {
- nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
+ return nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
}
+ return false;
}
// Called from native code.
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index f36c78fd48078..42a58a8efc222 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -323,6 +323,10 @@ public class ScaleGestureDetector {
mInProgress = false;
mInitialSpan = 0;
mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+ } else if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS && streamComplete) {
+ mInProgress = false;
+ mInitialSpan = 0;
+ mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
}
if (streamComplete) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e2d98edafc49a..b0bae463112dc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,7 +18,6 @@ package android.view;
import android.content.ClipData;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -3102,6 +3101,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
+ /**
+ * Cache if a left padding has been defined
+ */
+ private boolean mLeftPaddingDefined = false;
+
+ /**
+ * Cache if a right padding has been defined
+ */
+ private boolean mRightPaddingDefined = false;
+
/**
* @hide
*/
@@ -3530,10 +3539,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
int overScrollMode = mOverScrollMode;
boolean initializeScrollbars = false;
- boolean leftPaddingDefined = false;
- boolean rightPaddingDefined = false;
boolean startPaddingDefined = false;
boolean endPaddingDefined = false;
+ boolean leftPaddingDefined = false;
+ boolean rightPaddingDefined = false;
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -3865,6 +3874,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setBackground(background);
}
+ // setBackground above will record that padding is currently provided by the background.
+ // If we have padding specified via xml, record that here instead and use it.
+ mLeftPaddingDefined = leftPaddingDefined;
+ mRightPaddingDefined = rightPaddingDefined;
+
if (padding >= 0) {
leftPadding = padding;
topPadding = padding;
@@ -3882,11 +3896,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
// and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
// defined.
- if (!leftPaddingDefined && startPaddingDefined) {
+ if (!mLeftPaddingDefined && startPaddingDefined) {
leftPadding = startPadding;
}
mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial;
- if (!rightPaddingDefined && endPaddingDefined) {
+ if (!mRightPaddingDefined && endPaddingDefined) {
rightPadding = endPadding;
}
mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial;
@@ -3898,10 +3912,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// defined.
final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
- if (leftPaddingDefined && !hasRelativePadding) {
+ if (mLeftPaddingDefined && !hasRelativePadding) {
mUserPaddingLeftInitial = leftPadding;
}
- if (rightPaddingDefined && !hasRelativePadding) {
+ if (mRightPaddingDefined && !hasRelativePadding) {
mUserPaddingRightInitial = rightPadding;
}
}
@@ -5900,6 +5914,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
sThreadLocal.set(localInsets);
}
boolean res = computeFitSystemWindows(insets, localInsets);
+ mUserPaddingLeftInitial = localInsets.left;
+ mUserPaddingRightInitial = localInsets.right;
internalSetPadding(localInsets.left, localInsets.top,
localInsets.right, localInsets.bottom);
return res;
@@ -9044,9 +9060,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public interface OnLayoutChangeListener {
/**
- * Called when the focus state of a view has changed.
+ * Called when the layout bounds of a view changes due to layout processing.
*
- * @param v The view whose state has changed.
+ * @param v The view whose bounds have changed.
* @param left The new value of the view's left property.
* @param top The new value of the view's top property.
* @param right The new value of the view's right property.
@@ -10287,7 +10303,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * The horizontal location of this view relative to its {@link #getTop() top} position.
+ * The vertical location of this view relative to its {@link #getTop() top} position.
* This position is post-layout, in addition to wherever the object's
* layout placed it.
*
@@ -12133,12 +12149,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (!isTextAlignmentResolved()) {
resolveTextAlignment();
}
- if (!isPaddingResolved()) {
- resolvePadding();
- }
+ // Should resolve Drawables before Padding because we need the layout direction of the
+ // Drawable to correctly resolve Padding.
if (!isDrawablesResolved()) {
resolveDrawables();
}
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
onRtlPropertiesChanged(getLayoutDirection());
return true;
}
@@ -12341,6 +12359,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// If start / end padding are defined, they will be resolved (hence overriding) to
// left / right or right / left depending on the resolved layout direction.
// If start / end padding are not defined, use the left / right ones.
+ if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) {
+ Rect padding = sThreadLocal.get();
+ if (padding == null) {
+ padding = new Rect();
+ sThreadLocal.set(padding);
+ }
+ mBackground.getPadding(padding);
+ if (!mLeftPaddingDefined) {
+ mUserPaddingLeftInitial = padding.left;
+ }
+ if (!mRightPaddingDefined) {
+ mUserPaddingRightInitial = padding.right;
+ }
+ }
switch (resolvedLayoutDirection) {
case LAYOUT_DIRECTION_RTL:
if (mUserPaddingStart != UNDEFINED_PADDING) {
@@ -15336,6 +15368,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mUserPaddingRightInitial = padding.right;
internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
}
+ mLeftPaddingDefined = false;
+ mRightPaddingDefined = false;
}
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
@@ -15432,6 +15466,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mUserPaddingLeftInitial = left;
mUserPaddingRightInitial = right;
+ mLeftPaddingDefined = true;
+ mRightPaddingDefined = true;
+
internalSetPadding(left, top, right, bottom);
}
@@ -15517,6 +15554,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mUserPaddingStart = start;
mUserPaddingEnd = end;
+ mLeftPaddingDefined = true;
+ mRightPaddingDefined = true;
switch(getLayoutDirection()) {
case LAYOUT_DIRECTION_RTL:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 946106868d57c..bc0d7e3c806be 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -77,8 +77,10 @@ import com.android.internal.policy.PolicyManager;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
@@ -3391,16 +3393,7 @@ public final class ViewRootImpl implements ViewParent,
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
- } else if (mView == null || !mAdded) {
- Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
- finish(q, false);
- } else if (!mAttachInfo.mHasWindowFocus &&
- !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
- !isTerminalInputEvent(q.mEvent)) {
- // If this is a focused event and the window doesn't currently have input focus,
- // then drop this event. This could be an event that came back from the previous
- // stage but the window has lost focus in the meantime.
- Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
+ } else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
@@ -3458,6 +3451,28 @@ public final class ViewRootImpl implements ViewParent,
finishInputEvent(q);
}
}
+
+ protected boolean shouldDropInputEvent(QueuedInputEvent q) {
+ if (mView == null || !mAdded) {
+ Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
+ return true;
+ } else if (!mAttachInfo.mHasWindowFocus &&
+ !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
+ !isTerminalInputEvent(q.mEvent)) {
+ // If this is a focused event and the window doesn't currently have input focus,
+ // then drop this event. This could be an event that came back from the previous
+ // stage but the window has lost focus in the meantime.
+ Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
+ return true;
+ }
+ return false;
+ }
+
+ void dump(String prefix, PrintWriter writer) {
+ if (mNext != null) {
+ mNext.dump(prefix, writer);
+ }
+ }
}
/**
@@ -3595,6 +3610,16 @@ public final class ViewRootImpl implements ViewParent,
mQueueLength -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
}
+
+ @Override
+ void dump(String prefix, PrintWriter writer) {
+ writer.print(prefix);
+ writer.print(getClass().getName());
+ writer.print(": mQueueLength=");
+ writer.println(mQueueLength);
+
+ super.dump(prefix, writer);
+ }
}
/**
@@ -3828,6 +3853,10 @@ public final class ViewRootImpl implements ViewParent,
return FINISH_HANDLED;
}
+ if (shouldDropInputEvent(q)) {
+ return FINISH_NOT_HANDLED;
+ }
+
// If the Control modifier is held, try to interpret the key as a shortcut.
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.isCtrlPressed()
@@ -3836,12 +3865,18 @@ public final class ViewRootImpl implements ViewParent,
if (mView.dispatchKeyShortcutEvent(event)) {
return FINISH_HANDLED;
}
+ if (shouldDropInputEvent(q)) {
+ return FINISH_NOT_HANDLED;
+ }
}
// Apply the fallback event policy.
if (mFallbackEventHandler.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
}
+ if (shouldDropInputEvent(q)) {
+ return FINISH_NOT_HANDLED;
+ }
// Handle automatic focus changes.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -5201,6 +5236,53 @@ public final class ViewRootImpl implements ViewParent,
mView.debug();
}
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ String innerPrefix = prefix + " ";
+ writer.print(prefix); writer.println("ViewRoot:");
+ writer.print(innerPrefix); writer.print("mAdded="); writer.print(mAdded);
+ writer.print(" mRemoved="); writer.println(mRemoved);
+ writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
+ writer.println(mConsumeBatchedInputScheduled);
+ writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
+ writer.println(mPendingInputEventCount);
+ writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
+ writer.println(mProcessInputEventsScheduled);
+ writer.print(innerPrefix); writer.print("mTraversalScheduled=");
+ writer.print(mTraversalScheduled);
+ if (mTraversalScheduled) {
+ writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
+ } else {
+ writer.println();
+ }
+ mFirstInputStage.dump(innerPrefix, writer);
+
+ mChoreographer.dump(prefix, writer);
+
+ writer.print(prefix); writer.println("View Hierarchy:");
+ dumpViewHierarchy(innerPrefix, writer, mView);
+ }
+
+ private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
+ writer.print(prefix);
+ if (view == null) {
+ writer.println("null");
+ return;
+ }
+ writer.println(view.toString());
+ if (!(view instanceof ViewGroup)) {
+ return;
+ }
+ ViewGroup grp = (ViewGroup)view;
+ final int N = grp.getChildCount();
+ if (N <= 0) {
+ return;
+ }
+ prefix = prefix + " ";
+ for (int i=0; i
It should be defined in an XML resource file with an {@code <input-method>} element. + * For more information, see the guide to + * + * Creating an Input Method.
+ * + * @see InputMethodSubtype + * + * @attr ref android.R.styleable#InputMethod_settingsActivity + * @attr ref android.R.styleable#InputMethod_isDefault + * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod */ public final class InputMethodInfo implements Parcelable { static final String TAG = "InputMethodInfo"; diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java index 88b29776fa0f6..2ab30246662ca 100644 --- a/core/java/android/view/inputmethod/InputMethodSubtype.java +++ b/core/java/android/view/inputmethod/InputMethodSubtype.java @@ -38,9 +38,22 @@ import java.util.Locale; * the specified subtype of the designated IME directly. * *It should be defined in an XML resource file of the input method with the
- * <subtype> element. For more information, see the guide to
- *
+ * <subtype> element, which resides within an {@code <input-method>} element.
+ * For more information, see the guide to
+ *
* Creating an Input Method.
+ * + * Note: VideoView does not retain its full state when going into the + * background. In particular, it does not restore the current play state, + * play position, selected tracks, or any subtitle tracks added via + * {@link #addSubtitleSource addSubtitleSource()}. Applications should + * save and restore these on their own in + * {@link android.app.Activity#onSaveInstanceState} and + * {@link android.app.Activity#onRestoreInstanceState}.
+ * Also note that the audio session id (from {@link #getAudioSessionId}) may + * change from its previously returned value when the VideoView is restored. */ public class VideoView extends SurfaceView implements MediaPlayerControl, SubtitleController.Anchor { diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java index 061bb00cfd530..b152297275a81 100644 --- a/core/java/android/widget/ViewFlipper.java +++ b/core/java/android/widget/ViewFlipper.java @@ -90,7 +90,7 @@ public class ViewFlipper extends ViewAnimator { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); - getContext().registerReceiver(mReceiver, filter); + getContext().registerReceiver(mReceiver, filter, null, mHandler); if (mAutoStart) { // Automatically start when requested diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 525517c00eb50..43c4b49ce946a 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -68,6 +68,8 @@ interface IBatteryStats { void noteFullWifiLockReleasedFromSource(in WorkSource ws); void noteWifiScanStartedFromSource(in WorkSource ws); void noteWifiScanStoppedFromSource(in WorkSource ws); + void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph); + void noteWifiBatchedScanStoppedFromSource(in WorkSource ws); void noteWifiMulticastEnabledFromSource(in WorkSource ws); void noteWifiMulticastDisabledFromSource(in WorkSource ws); void noteNetworkInterfaceType(String iface, int type); diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java new file mode 100644 index 0000000000000..47d2a9c3468d6 --- /dev/null +++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import com.android.internal.R; + +import android.app.Dialog; +import android.content.Context; +import android.media.MediaRouter; +import android.media.MediaRouter.RouteInfo; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.Comparator; + +/** + * This class implements the route chooser dialog for {@link MediaRouter}. + *
+ * This dialog allows the user to choose a route that matches a given selector. + *
+ * + * @see MediaRouteButton + * @see MediaRouteActionProvider + * + * TODO: Move this back into the API, as in the support library media router. + */ +public class MediaRouteChooserDialog extends Dialog { + private final MediaRouter mRouter; + private final MediaRouterCallback mCallback; + + private int mRouteTypes; + private View.OnClickListener mExtendedSettingsClickListener; + private RouteAdapter mAdapter; + private ListView mListView; + private Button mExtendedSettingsButton; + private boolean mAttachedToWindow; + + public MediaRouteChooserDialog(Context context, int theme) { + super(context, theme); + + mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); + mCallback = new MediaRouterCallback(); + } + + /** + * Gets the media route types for filtering the routes that the user can + * select using the media route chooser dialog. + * + * @return The route types. + */ + public int getRouteTypes() { + return mRouteTypes; + } + + /** + * Sets the types of routes that will be shown in the media route chooser dialog + * launched by this button. + * + * @param types The route types to match. + */ + public void setRouteTypes(int types) { + if (mRouteTypes != types) { + mRouteTypes = types; + + if (mAttachedToWindow) { + mRouter.removeCallback(mCallback); + mRouter.addCallback(types, mCallback, + MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); + } + + refreshRoutes(); + } + } + + public void setExtendedSettingsClickListener(View.OnClickListener listener) { + if (listener != mExtendedSettingsClickListener) { + mExtendedSettingsClickListener = listener; + updateExtendedSettingsButton(); + } + } + + /** + * Returns true if the route should be included in the list. + *+ * The default implementation returns true for enabled non-default routes that + * match the route types. Subclasses can override this method to filter routes + * differently. + *
+ * + * @param route The route to consider, never null. + * @return True if the route should be included in the chooser dialog. + */ + public boolean onFilterRoute(MediaRouter.RouteInfo route) { + return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getWindow().requestFeature(Window.FEATURE_LEFT_ICON); + + setContentView(R.layout.media_route_chooser_dialog); + setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY + ? R.string.media_route_chooser_title_for_remote_display + : R.string.media_route_chooser_title); + + // Must be called after setContentView. + getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, + R.drawable.ic_media_route_off_holo_dark); + + mAdapter = new RouteAdapter(getContext()); + mListView = (ListView)findViewById(R.id.media_route_list); + mListView.setAdapter(mAdapter); + mListView.setOnItemClickListener(mAdapter); + mListView.setEmptyView(findViewById(android.R.id.empty)); + + mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button); + updateExtendedSettingsButton(); + } + + private void updateExtendedSettingsButton() { + if (mExtendedSettingsButton != null) { + mExtendedSettingsButton.setOnClickListener(mExtendedSettingsClickListener); + mExtendedSettingsButton.setVisibility( + mExtendedSettingsClickListener != null ? View.VISIBLE : View.GONE); + } + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + mAttachedToWindow = true; + mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); + refreshRoutes(); + } + + @Override + public void onDetachedFromWindow() { + mAttachedToWindow = false; + mRouter.removeCallback(mCallback); + + super.onDetachedFromWindow(); + } + + /** + * Refreshes the list of routes that are shown in the chooser dialog. + */ + public void refreshRoutes() { + if (mAttachedToWindow) { + mAdapter.update(); + } + } + + private final class RouteAdapter extends ArrayAdapter+ * Creates a {@link MediaRouteChooserDialog}. The application may subclass + * this dialog fragment to customize the media route chooser dialog. + *
* - * @see MediaRouteButton - * @see MediaRouteActionProvider + * TODO: Move this back into the API, as in the support library media router. */ public class MediaRouteChooserDialogFragment extends DialogFragment { - private static final String TAG = "MediaRouteChooserDialogFragment"; - public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment"; + private final String ARGUMENT_ROUTE_TYPES = "routeTypes"; - private static final int[] ITEM_LAYOUTS = new int[] { - R.layout.media_route_list_item_top_header, - R.layout.media_route_list_item_section_header, - R.layout.media_route_list_item, - R.layout.media_route_list_item_checkable, - R.layout.media_route_list_item_collapse_group - }; - - MediaRouter mRouter; - private int mRouteTypes; - - private LayoutInflater mInflater; - private LauncherListener mLauncherListener; - private View.OnClickListener mExtendedSettingsListener; - private RouteAdapter mAdapter; - private ListView mListView; - private SeekBar mVolumeSlider; - private ImageView mVolumeIcon; - - final RouteComparator mComparator = new RouteComparator(); - final MediaRouterCallback mCallback = new MediaRouterCallback(); - private boolean mIgnoreSliderVolumeChanges; - private boolean mIgnoreCallbackVolumeChanges; + private View.OnClickListener mExtendedSettingsClickListener; + /** + * Creates a media route chooser dialog fragment. + *+ * All subclasses of this class must also possess a default constructor. + *
+ */ public MediaRouteChooserDialogFragment() { - setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog); + setCancelable(true); + setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Dialog); } - public void setLauncherListener(LauncherListener listener) { - mLauncherListener = listener; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE); - mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); - } - - @Override - public void onDetach() { - super.onDetach(); - if (mLauncherListener != null) { - mLauncherListener.onDetached(this); - } - if (mAdapter != null) { - mAdapter = null; - } - mInflater = null; - mRouter.removeCallback(mCallback); - mRouter = null; - } - - public void setExtendedSettingsClickListener(View.OnClickListener listener) { - mExtendedSettingsListener = listener; + public int getRouteTypes() { + Bundle args = getArguments(); + return args != null ? args.getInt(ARGUMENT_ROUTE_TYPES) : 0; } public void setRouteTypes(int types) { - mRouteTypes = types; - } - - void updateVolume() { - if (mRouter == null) return; - - final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); - mVolumeIcon.setImageResource(selectedRoute == null || - selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ? - R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark); - - mIgnoreSliderVolumeChanges = true; - - if (selectedRoute == null || - selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) { - // Disable the slider and show it at max volume. - mVolumeSlider.setMax(1); - mVolumeSlider.setProgress(1); - mVolumeSlider.setEnabled(false); - } else { - mVolumeSlider.setEnabled(true); - mVolumeSlider.setMax(selectedRoute.getVolumeMax()); - mVolumeSlider.setProgress(selectedRoute.getVolume()); - } - - mIgnoreSliderVolumeChanges = false; - } - - void changeVolume(int newValue) { - if (mIgnoreSliderVolumeChanges) return; - - final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes); - if (selectedRoute != null && - selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) { - final int maxVolume = selectedRoute.getVolumeMax(); - newValue = Math.max(0, Math.min(newValue, maxVolume)); - selectedRoute.requestSetVolume(newValue); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - mInflater = inflater; - final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false); - - mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon); - mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider); - updateVolume(); - mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener()); - - if (mExtendedSettingsListener != null) { - final View extendedSettingsButton = layout.findViewById(R.id.extended_settings); - extendedSettingsButton.setVisibility(View.VISIBLE); - extendedSettingsButton.setOnClickListener(mExtendedSettingsListener); - } - - final ListView list = (ListView) layout.findViewById(R.id.list); - list.setItemsCanFocus(true); - list.setAdapter(mAdapter = new RouteAdapter()); - list.setOnItemClickListener(mAdapter); - - mListView = list; - - mAdapter.scrollToSelectedItem(); - - return layout; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new RouteChooserDialog(getActivity(), getTheme()); - } - - private static class ViewHolder { - public TextView text1; - public TextView text2; - public ImageView icon; - public ImageButton expandGroupButton; - public RouteAdapter.ExpandGroupListener expandGroupListener; - public int position; - public CheckBox check; - } - - private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener { - private static final int VIEW_TOP_HEADER = 0; - private static final int VIEW_SECTION_HEADER = 1; - private static final int VIEW_ROUTE = 2; - private static final int VIEW_GROUPING_ROUTE = 3; - private static final int VIEW_GROUPING_DONE = 4; - - private int mSelectedItemPosition = -1; - private final ArrayList