summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java15
-rw-r--r--core/java/android/app/ApplicationPackageManager.java13
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/content/Intent.java52
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java19
-rw-r--r--core/java/android/content/pm/PackageManager.java5
-rw-r--r--core/java/android/content/res/Configuration.java4
-rw-r--r--core/java/android/content/res/Resources.java9
-rw-r--r--core/java/android/hardware/Sensor.java67
-rw-r--r--core/java/android/hardware/SensorEventListener2.java13
-rw-r--r--core/java/android/hardware/SensorManager.java251
-rw-r--r--core/java/android/hardware/hdmi/HdmiClient.java10
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java29
-rw-r--r--core/java/android/hardware/hdmi/HdmiRecordSources.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiTvClient.java18
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl1
-rw-r--r--core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl3
-rw-r--r--core/java/android/os/Build.java5
-rw-r--r--core/java/android/os/Debug.java10
-rw-r--r--core/java/android/preference/ListPreference.java4
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java38
-rw-r--r--core/java/android/preference/VolumePreference.java3
-rw-r--r--core/java/android/provider/Settings.java21
-rw-r--r--core/java/android/util/PathParser.java50
-rw-r--r--core/java/android/view/Surface.java123
-rw-r--r--core/java/android/view/View.java23
-rw-r--r--core/java/android/view/ViewDebug.java35
-rw-r--r--core/java/android/view/ViewGroup.java45
-rw-r--r--core/java/android/view/WindowManager.java9
-rw-r--r--core/java/android/widget/AppSecurityPermissions.java4
-rw-r--r--core/java/android/widget/CalendarView.java19
-rw-r--r--core/java/android/widget/ListPopupWindow.java14
-rw-r--r--core/java/android/widget/PopupMenu.java57
-rw-r--r--core/java/android/widget/ProgressBar.java3
-rw-r--r--core/java/android/widget/RadialTimePickerView.java269
-rw-r--r--core/java/android/widget/RemoteViews.java50
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java2
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java227
-rw-r--r--core/java/android/widget/Toolbar.java9
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java26
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java17
-rw-r--r--core/java/com/android/internal/util/MemInfoReader.java49
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java13
-rw-r--r--core/java/com/android/internal/widget/ExploreByTouchHelper.java7
44 files changed, 1034 insertions, 620 deletions
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 540376e..d611058 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -222,8 +222,15 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
if (mListener != null) {
mListener.onMapSharedElements(mAllSharedElementNames, sharedElements);
}
- mSharedElementNames.addAll(sharedElements.keySet());
- mSharedElements.addAll(sharedElements.values());
+ int numSharedElements = sharedElements.size();
+ for (int i = 0; i < numSharedElements; i++) {
+ View sharedElement = sharedElements.valueAt(i);
+ String name = sharedElements.keyAt(i);
+ if (sharedElement != null && sharedElement.isAttachedToWindow() && name != null) {
+ mSharedElements.add(sharedElement);
+ mSharedElementNames.add(name);
+ }
+ }
if (getViewsTransition() != null && mTransitioningViews != null) {
ViewGroup decorView = getDecor();
if (decorView != null) {
@@ -536,10 +543,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
int numSharedElements = names.size();
+ ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
if (numSharedElements == 0) {
- return null;
+ return snapshots;
}
- ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
Context context = getWindow().getContext();
int[] decorLoc = new int[2];
ViewGroup decorView = getDecor();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1e1a613..854719d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1664,6 +1664,17 @@ final class ApplicationPackageManager extends PackageManager {
* @hide
*/
public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
+ Drawable dr = loadUnbadgedItemIcon(itemInfo, appInfo);
+ if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
+ return dr;
+ }
+ return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
+ }
+
+ /**
+ * @hide
+ */
+ public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
Bitmap bitmap = getUserManager().getUserIcon(itemInfo.showUserIcon);
if (bitmap == null) {
@@ -1678,7 +1689,7 @@ final class ApplicationPackageManager extends PackageManager {
if (dr == null) {
dr = itemInfo.loadDefaultIcon(this);
}
- return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId()));
+ return dr;
}
private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fb10e17..9849c51 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
@@ -2773,6 +2774,14 @@ public class Notification implements Parcelable
contentView.setViewVisibility(R.id.progress, View.VISIBLE);
contentView.setProgressBar(
R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
+ contentView.setProgressBackgroundTintList(
+ R.id.progress, ColorStateList.valueOf(mContext.getResources().getColor(
+ R.color.notification_progress_background_color)));
+ if (mColor != COLOR_DEFAULT) {
+ ColorStateList colorStateList = ColorStateList.valueOf(mColor);
+ contentView.setProgressTintList(R.id.progress, colorStateList);
+ contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
+ }
showLine2 = true;
} else {
contentView.setViewVisibility(R.id.progress, View.GONE);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af6f181..7676e4b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -876,12 +876,44 @@ public class Intent implements Parcelable, Cloneable {
* related methods.
*/
public static Intent createChooser(Intent target, CharSequence title) {
+ return createChooser(target, title, null);
+ }
+
+ /**
+ * Convenience function for creating a {@link #ACTION_CHOOSER} Intent.
+ *
+ * <p>Builds a new {@link #ACTION_CHOOSER} Intent that wraps the given
+ * target intent, also optionally supplying a title. If the target
+ * intent has specified {@link #FLAG_GRANT_READ_URI_PERMISSION} or
+ * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be
+ * set in the returned chooser intent, with its ClipData set appropriately:
+ * either a direct reflection of {@link #getClipData()} if that is non-null,
+ * or a new ClipData built from {@link #getData()}.</p>
+ *
+ * <p>The caller may optionally supply an {@link IntentSender} to receive a callback
+ * when the user makes a choice. This can be useful if the calling application wants
+ * to remember the last chosen target and surface it as a more prominent or one-touch
+ * affordance elsewhere in the UI for next time.</p>
+ *
+ * @param target The Intent that the user will be selecting an activity
+ * to perform.
+ * @param title Optional title that will be displayed in the chooser.
+ * @param sender Optional IntentSender to be called when a choice is made.
+ * @return Return a new Intent object that you can hand to
+ * {@link Context#startActivity(Intent) Context.startActivity()} and
+ * related methods.
+ */
+ public static Intent createChooser(Intent target, CharSequence title, IntentSender sender) {
Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_INTENT, target);
if (title != null) {
intent.putExtra(EXTRA_TITLE, title);
}
+ if (sender != null) {
+ intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
+ }
+
// Migrate any clip data and flags from target.
int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
| FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
@@ -3140,6 +3172,26 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.REPLACEMENT_EXTRAS";
/**
+ * An {@link IntentSender} that will be notified if a user successfully chooses a target
+ * component to handle an action in an {@link #ACTION_CHOOSER} activity. The IntentSender
+ * will have the extra {@link #EXTRA_CHOSEN_COMPONENT} appended to it containing the
+ * {@link ComponentName} of the chosen component.
+ *
+ * <p>In some situations this callback may never come, for example if the user abandons
+ * the chooser, switches to another task or any number of other reasons. Apps should not
+ * be written assuming that this callback will always occur.</p>
+ */
+ public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER =
+ "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
+
+ /**
+ * The {@link ComponentName} chosen by the user to complete an action.
+ *
+ * @see #EXTRA_CHOSEN_COMPONENT_INTENT_SENDER
+ */
+ public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
+
+ /**
* A {@link android.view.KeyEvent} object containing the event that
* triggered the creation of the Intent it is in.
*/
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index cacdf8e..22a899c 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -138,7 +138,7 @@ public class PackageItemInfo {
}
return packageName;
}
-
+
/**
* Retrieve the current graphical icon associated with this item. This
* will call back on the given PackageManager to load the icon from
@@ -156,6 +156,23 @@ public class PackageItemInfo {
}
/**
+ * Retrieve the current graphical icon associated with this item without
+ * the addition of a work badge if applicable.
+ * This will call back on the given PackageManager to load the icon from
+ * the application.
+ *
+ * @param pm A PackageManager from which the icon can be loaded; usually
+ * the PackageManager from which you originally retrieved this item.
+ *
+ * @return Returns a Drawable containing the item's icon. If the
+ * item does not have an icon, the item's default icon is returned
+ * such as the default activity icon.
+ */
+ public Drawable loadUnbadgedIcon(PackageManager pm) {
+ return pm.loadUnbadgedItemIcon(this, getApplicationInfo());
+ }
+
+ /**
* Retrieve the current graphical banner associated with this item. This
* will call back on the given PackageManager to load the banner from
* the application.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e519163..ab90b66 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3911,6 +3911,11 @@ public abstract class PackageManager {
*/
public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+ /**
+ * @hide
+ */
+ public abstract Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+
/** {@hide} */
public abstract boolean isPackageAvailable(String packageName);
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 27bbb24..acdd87e 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1365,9 +1365,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration
ArrayList<String> parts = new ArrayList<String>();
if (config.mcc != 0) {
- parts.add(config.mcc + "mcc");
+ parts.add("mcc" + config.mcc);
if (config.mnc != 0) {
- parts.add(config.mnc + "mnc");
+ parts.add("mnc" + config.mnc);
}
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7f276c2..e34ce3e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2323,7 +2323,14 @@ public class Resources {
final Drawable dr;
if (cs != null) {
- dr = cs.newDrawable(this, theme);
+ final Drawable clonedDr = cs.newDrawable(this);
+ if (theme != null) {
+ dr = clonedDr.mutate();
+ dr.applyTheme(theme);
+ dr.clearMutated();
+ } else {
+ dr = clonedDr;
+ }
} else if (isColorDrawable) {
dr = new ColorDrawable(value.data);
} else {
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index f514e42..cf6a779 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -329,7 +329,11 @@ public final class Sensor {
* A sensor of this type triggers an event each time a step is taken by the user. The only
* allowed value to return is 1.0 and an event is generated for each step. Like with any other
* event, the timestamp indicates when the event (here the step) occurred, this corresponds to
- * when the foot hit the ground, generating a high variation in acceleration.
+ * when the foot hit the ground, generating a high variation in acceleration. This sensor is
+ * only for detecting every individual step as soon as it is taken, for example to perform dead
+ * reckoning. If you only need aggregate number of steps taken over a period of time, register
+ * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a
+ * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor.
* <p>
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
@@ -349,7 +353,12 @@ public final class Sensor {
* while activated. The value is returned as a float (with the fractional part set to zero) and
* is reset to zero only on a system reboot. The timestamp of the event is set to the time when
* the last step for that event was taken. This sensor is implemented in hardware and is
- * expected to be low power.
+ * expected to be low power. If you want to continuously track the number of steps over a long
+ * period of time, do NOT unregister for this sensor, so that it keeps counting steps in the
+ * background even when the AP is in suspend mode and report the aggregate count when the AP
+ * is awake. Application needs to stay registered for this sensor because step counter does not
+ * count steps if it is not activated. This sensor is ideal for fitness tracking applications.
+ * It is defined as an {@link Sensor#REPORTING_MODE_ON_CHANGE} sensor.
* <p>
* See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
*/
@@ -750,31 +759,41 @@ public final class Sensor {
}
/**
- * Returns whether this sensor is a wake-up sensor.
+ * Returns true if the sensor is a wake-up sensor.
* <p>
- * Wake up sensors wake the application processor up when they have events to deliver. When a
- * wake up sensor is registered to without batching enabled, each event will wake the
- * application processor up.
- * <p>
- * When a wake up sensor is registered to with batching enabled, it
- * wakes the application processor up when maxReportingLatency has elapsed or when the hardware
- * FIFO storing the events from wake up sensors is getting full.
- * <p>
- * Non-wake up sensors never wake the application processor up. Their events are only reported
- * when the application processor is awake, for example because the application holds a wake
- * lock, or another source woke the application processor up.
+ * <b>Application Processor Power modes</b> <p>
+ * Application Processor(AP), is the processor on which applications run. When no wake lock is held
+ * and the user is not interacting with the device, this processor can enter a “Suspend” mode,
+ * reducing the power consumption by 10 times or more.
+ * </p>
* <p>
- * When a non-wake up sensor is registered to without batching enabled, the measurements made
- * while the application processor is asleep might be lost and never returned.
+ * <b>Non-wake-up sensors</b> <p>
+ * Non-wake-up sensors are sensors that do not wake the AP out of suspend to report data. While
+ * the AP is in suspend mode, the sensors continue to function and generate events, which are
+ * put in a hardware FIFO. The events in the FIFO are delivered to the application when the AP
+ * wakes up. If the FIFO was too small to store all events generated while the AP was in
+ * suspend mode, the older events are lost: the oldest data is dropped to accommodate the newer
+ * data. In the extreme case where the FIFO is non-existent {@code maxFifoEventCount() == 0},
+ * all events generated while the AP was in suspend mode are lost. Applications using
+ * non-wake-up sensors should usually:
+ * <ul>
+ * <li>Either unregister from the sensors when they do not need them, usually in the activity’s
+ * {@code onPause} method. This is the most common case.
+ * <li>Or realize that the sensors are consuming some power while the AP is in suspend mode and
+ * that even then, some events might be lost.
+ * </ul>
+ * </p>
* <p>
- * When a non-wake up sensor is registered to with batching enabled, the measurements made while
- * the application processor is asleep are stored in the hardware FIFO for non-wake up sensors.
- * When this FIFO gets full, new events start overwriting older events. When the application
- * then wakes up, the latest events are returned, and some old events might be lost. The number
- * of events actually returned depends on the hardware FIFO size, as well as on what other
- * sensors are activated. If losing sensor events is not acceptable during batching, you must
- * use the wake-up version of the sensor.
- * @return true if this is a wake up sensor, false otherwise.
+ * <b>Wake-up sensors</b> <p>
+ * In opposition to non-wake-up sensors, wake-up sensors ensure that their data is delivered
+ * independently of the state of the AP. While the AP is awake, the wake-up sensors behave
+ * like non-wake-up-sensors. When the AP is asleep, wake-up sensors wake up the AP to deliver
+ * events. That is, the AP will wake up and the sensor will deliver the events before the
+ * maximum reporting latency is elapsed or the hardware FIFO gets full. See {@link
+ * SensorManager#registerListener(SensorEventListener, Sensor, int, int)} for more details.
+ * </p>
+ *
+ * @return <code>true</code> if this is a wake-up sensor, <code>false</code> otherwise.
*/
public boolean isWakeUpSensor() {
return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
diff --git a/core/java/android/hardware/SensorEventListener2.java b/core/java/android/hardware/SensorEventListener2.java
index 70eff08..fd3e62b 100644
--- a/core/java/android/hardware/SensorEventListener2.java
+++ b/core/java/android/hardware/SensorEventListener2.java
@@ -21,15 +21,16 @@ package android.hardware;
*/
public interface SensorEventListener2 extends SensorEventListener {
/**
- * Called after flush() is completed. All the events in the batch at the point when
- * the flush was called have been delivered to the applications registered for those
- * sensor events. Flush Complete Events are sent ONLY to the application that has
- * explicitly called flush(). If the hardware FIFO is flushed due to some other
- * application calling flush(), flush complete event is not delivered to this application.
+ * Called after flush() is completed. All the events in the batch at the point when the flush
+ * was called have been delivered to the applications registered for those sensor events. In
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, applications may receive flush complete events
+ * even if some other application has called flush() on the same sensor. Starting with
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP}, flush Complete events are sent ONLY to the
+ * application that has explicitly called flush(). If the hardware FIFO is flushed due to some
+ * other application calling flush(), flush complete event is not delivered to this application.
* <p>
*
* @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called.
- *
* @see android.hardware.SensorManager#flush(SensorEventListener)
*/
public void onFlushCompleted(Sensor sensor);
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index cccd624..e4e5a8c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -626,73 +626,90 @@ public abstract class SensorManager {
protected abstract void unregisterListenerImpl(SensorEventListener listener, Sensor sensor);
/**
- * Registers a {@link android.hardware.SensorEventListener
- * SensorEventListener} for the given sensor.
- *
- * <p class="note"></p>
- * Note: Don't use this method with a one shot trigger sensor such as
- * {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
- * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead.
+ * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+ * sensor at the given sampling frequency.
+ * <p>
+ * The events will be delivered to the provided {@code SensorEventListener} as soon as they are
+ * available. To reduce the power consumption, applications can use
+ * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a
+ * positive non-zero maximum reporting latency.
+ * </p>
+ * <p>
+ * In the case of non-wake-up sensors, the events are only delivered while the Application
+ * Processor (AP) is not in suspend mode. See {@link Sensor#isWakeUpSensor()} for more details.
+ * To ensure delivery of events from non-wake-up sensors even when the screen is OFF, the
+ * application registering to the sensor must hold a partial wake-lock to keep the AP awake,
+ * otherwise some events might be lost while the AP is asleep. Note that although events might
+ * be lost while the AP is asleep, the sensor will still consume power if it is not explicitly
+ * deactivated by the application. Applications must unregister their {@code
+ * SensorEventListener}s in their activity's {@code onPause()} method to avoid consuming power
+ * while the device is inactive. See {@link #registerListener(SensorEventListener, Sensor, int,
+ * int)} for more details on hardware FIFO (queueing) capabilities and when some sensor events
+ * might be lost.
+ * </p>
+ * <p>
+ * In the case of wake-up sensors, each event generated by the sensor will cause the AP to
+ * wake-up, ensuring that each event can be delivered. Because of this, registering to a wake-up
+ * sensor has very significant power implications. Call {@link Sensor#isWakeUpSensor()} to check
+ * whether a sensor is a wake-up sensor. See
+ * {@link #registerListener(SensorEventListener, Sensor, int, int)} for information on how to
+ * reduce the power impact of registering to wake-up sensors.
+ * </p>
+ * <p class="note">
+ * Note: Don't use this method with one-shot trigger sensors such as
+ * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+ * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. Use
+ * {@link Sensor#getReportingMode()} to obtain the reporting mode of a given sensor.
* </p>
*
- * @param listener
- * A {@link android.hardware.SensorEventListener SensorEventListener}
- * object.
- *
- * @param sensor
- * The {@link android.hardware.Sensor Sensor} to register to.
- *
- * @param rateUs
- * The rate {@link android.hardware.SensorEvent sensor events} are
- * delivered at. This is only a hint to the system. Events may be
- * received faster or slower than the specified rate. Usually events
- * are received faster. The value must be one of
- * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
- * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
- * or, the desired delay between events in microseconds.
- * Specifying the delay in microseconds only works from Android
- * 2.3 (API level 9) onwards. For earlier releases, you must use
- * one of the {@code SENSOR_DELAY_*} constants.
- *
- * @return <code>true</code> if the sensor is supported and successfully
- * enabled.
- *
+ * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+ * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+ * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are
+ * delivered at. This is only a hint to the system. Events may be received faster or
+ * slower than the specified rate. Usually events are received faster. The value must
+ * be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+ * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired delay
+ * between events in microseconds. Specifying the delay in microseconds only works
+ * from Android 2.3 (API level 9) onwards. For earlier releases, you must use one of
+ * the {@code SENSOR_DELAY_*} constants.
+ * @return <code>true</code> if the sensor is supported and successfully enabled.
* @see #registerListener(SensorEventListener, Sensor, int, Handler)
* @see #unregisterListener(SensorEventListener)
* @see #unregisterListener(SensorEventListener, Sensor)
- *
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) {
- return registerListener(listener, sensor, rateUs, null);
+ public boolean registerListener(SensorEventListener listener, Sensor sensor,
+ int samplingPeriodUs) {
+ return registerListener(listener, sensor, samplingPeriodUs, null);
}
/**
- * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the
- * underlying hardware does not support batch mode, this defaults to
- * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are
- * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected.
- * While in batch mode, sensor events do not need to be reported as soon as they are detected.
- * They can be temporarily stored in batches and reported in batches, as long as no event is
- * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the
- * previous batch are recorded and returned all at once. This allows to reduce the amount of
- * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while
- * the sensor is capturing and batching data.
- * <p>
- * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In
- * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the
- * FIFO gets full before the AP wakes up again, some events will be lost, as the older events
- * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake
- * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events
- * will be lost, as the events will be reported before the FIFO gets full.
- * </p>
+ * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+ * sensor at the given sampling frequency and the given maximum reporting latency.
* <p>
- * Batching is always best effort. If a different application requests updates in continuous
- * mode, this application will also get events in continuous mode. Batch mode updates can be
- * unregistered by calling {@link #unregisterListener(SensorEventListener)}.
+ * This function is similar to {@link #registerListener(SensorEventListener, Sensor, int)} but
+ * it allows events to stay temporarily in the hardware FIFO (queue) before being delivered. The
+ * events can be stored in the hardware FIFO up to {@code maxReportLatencyUs} microseconds. Once
+ * one of the events in the FIFO needs to be reported, all of the events in the FIFO are
+ * reported sequentially. This means that some events will be reported before the maximum
+ * reporting latency has elapsed.
+ * </p><p>
+ * When {@code maxReportLatencyUs} is 0, the call is equivalent to a call to
+ * {@link #registerListener(SensorEventListener, Sensor, int)}, as it requires the events to be
+ * delivered as soon as possible.
+ * </p><p>
+ * When {@code sensor.maxFifoEventCount()} is 0, the sensor does not use a FIFO, so the call
+ * will also be equivalent to {@link #registerListener(SensorEventListener, Sensor, int)}.
+ * </p><p>
+ * Setting {@code maxReportLatencyUs} to a positive value allows to reduce the number of
+ * interrupts the AP (Application Processor) receives, hence reducing power consumption, as the
+ * AP can switch to a lower power state while the sensor is capturing the data. This is
+ * especially important when registering to wake-up sensors, for which each interrupt causes the
+ * AP to wake up if it was in suspend mode. See {@link Sensor#isWakeUpSensor()} for more
+ * information on wake-up sensors.
* </p>
* <p class="note">
* </p>
- * Note: Don't use this method with a one shot trigger sensor such as
+ * Note: Don't use this method with one-shot trigger sensors such as
* {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
* {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
*
@@ -701,118 +718,104 @@ public abstract class SensorManager {
* flush complete notifications, it should register with
* {@link android.hardware.SensorEventListener SensorEventListener2} instead.
* @param sensor The {@link android.hardware.Sensor Sensor} to register to.
- * @param rateUs The desired delay between two consecutive events in microseconds. This is only
- * a hint to the system. Events may be received faster or slower than the specified
- * rate. Usually events are received faster. Can be one of
+ * @param samplingPeriodUs The desired delay between two consecutive events in microseconds.
+ * This is only a hint to the system. Events may be received faster or slower than
+ * the specified rate. Usually events are received faster. Can be one of
* {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
* {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
* microseconds.
- * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
- * maxBatchReportLatency microseconds. More events can be batched if this value is
- * large. If this is set to zero, batch mode is disabled and events are delivered in
- * continuous mode as soon as they are available which is equivalent to calling
+ * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before
+ * being reported to the application. A large value allows reducing the power
+ * consumption associated with the sensor. If maxReportLatencyUs is set to zero,
+ * events are delivered as soon as they are available, which is equivalent to calling
* {@link #registerListener(SensorEventListener, Sensor, int)}.
- * @return <code>true</code> if batch mode is successfully enabled for this sensor,
- * <code>false</code> otherwise.
+ * @return <code>true</code> if the sensor is supported and successfully enabled.
* @see #registerListener(SensorEventListener, Sensor, int)
* @see #unregisterListener(SensorEventListener)
* @see #flush(SensorEventListener)
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
- int maxBatchReportLatencyUs) {
- int delay = getDelay(rateUs);
- return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, 0);
+ public boolean registerListener(SensorEventListener listener, Sensor sensor,
+ int samplingPeriodUs, int maxReportLatencyUs) {
+ int delay = getDelay(samplingPeriodUs);
+ return registerListenerImpl(listener, sensor, delay, null, maxReportLatencyUs, 0);
}
/**
* Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
* sensor. Events are delivered in continuous mode as soon as they are available. To reduce the
- * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int)} which
- * enables batch mode for the sensor.
- *
- * <p class="note"></p>
- * Note: Don't use this method with a one shot trigger sensor such as
- * {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
- * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead.
+ * power consumption, applications can use
+ * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a
+ * positive non-zero maximum reporting latency.
+ * <p class="note">
* </p>
+ * Note: Don't use this method with a one shot trigger sensor such as
+ * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+ * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
*
- * @param listener
- * A {@link android.hardware.SensorEventListener SensorEventListener}
- * object.
- *
- * @param sensor
- * The {@link android.hardware.Sensor Sensor} to register to.
- *
- * @param rateUs
- * The rate {@link android.hardware.SensorEvent sensor events} are
- * delivered at. This is only a hint to the system. Events may be
- * received faster or slower than the specified rate. Usually events
- * are received faster. The value must be one of
- * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
- * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
- * or, the desired delay between events in microseconds.
- * Specifying the delay in microseconds only works from Android
- * 2.3 (API level 9) onwards. For earlier releases, you must use
- * one of the {@code SENSOR_DELAY_*} constants.
- *
- * @param handler
- * The {@link android.os.Handler Handler} the
- * {@link android.hardware.SensorEvent sensor events} will be
- * delivered to.
- *
+ * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
+ * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+ * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are
+ * delivered at. This is only a hint to the system. Events may be received faster or
+ * slower than the specified rate. Usually events are received faster. The value must
+ * be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+ * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired
+ * delay between events in microseconds. Specifying the delay in microseconds only
+ * works from Android 2.3 (API level 9) onwards. For earlier releases, you must use
+ * one of the {@code SENSOR_DELAY_*} constants.
+ * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent
+ * sensor events} will be delivered to.
* @return <code>true</code> if the sensor is supported and successfully enabled.
- *
* @see #registerListener(SensorEventListener, Sensor, int)
* @see #unregisterListener(SensorEventListener)
* @see #unregisterListener(SensorEventListener, Sensor)
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
- Handler handler) {
- int delay = getDelay(rateUs);
+ public boolean registerListener(SensorEventListener listener, Sensor sensor,
+ int samplingPeriodUs, Handler handler) {
+ int delay = getDelay(samplingPeriodUs);
return registerListenerImpl(listener, sensor, delay, handler, 0, 0);
}
/**
- * Enables batch mode for a sensor with the given rate and maxBatchReportLatency.
+ * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+ * sensor at the given sampling frequency and the given maximum reporting latency.
+ *
* @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
* that will receive the sensor events. If the application is interested in receiving
* flush complete notifications, it should register with
* {@link android.hardware.SensorEventListener SensorEventListener2} instead.
* @param sensor The {@link android.hardware.Sensor Sensor} to register to.
- * @param rateUs The desired delay between two consecutive events in microseconds. This is only
- * a hint to the system. Events may be received faster or slower than the specified
- * rate. Usually events are received faster. Can be one of
+ * @param samplingPeriodUs The desired delay between two consecutive events in microseconds.
+ * This is only a hint to the system. Events may be received faster or slower than
+ * the specified rate. Usually events are received faster. Can be one of
* {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
* {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
* microseconds.
- * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
- * maxBatchReportLatency microseconds. More events can be batched if this value is
- * large. If this is set to zero, batch mode is disabled and events are delivered in
- * continuous mode as soon as they are available which is equivalent to calling
+ * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before
+ * being reported to the application. A large value allows reducing the power
+ * consumption associated with the sensor. If maxReportLatencyUs is set to zero,
+ * events are delivered as soon as they are available, which is equivalent to calling
* {@link #registerListener(SensorEventListener, Sensor, int)}.
- * @param handler The {@link android.os.Handler Handler} the
- * {@link android.hardware.SensorEvent sensor events} will be delivered to.
- *
- * @return <code>true</code> if batch mode is successfully enabled for this sensor,
- * <code>false</code> otherwise.
+ * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent
+ * sensor events} will be delivered to.
+ * @return <code>true</code> if the sensor is supported and successfully enabled.
* @see #registerListener(SensorEventListener, Sensor, int, int)
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
- int maxBatchReportLatencyUs, Handler handler) {
- int delayUs = getDelay(rateUs);
- return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, 0);
+ public boolean registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs,
+ int maxReportLatencyUs, Handler handler) {
+ int delayUs = getDelay(samplingPeriodUs);
+ return registerListenerImpl(listener, sensor, delayUs, handler, maxReportLatencyUs, 0);
}
/** @hide */
protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
- int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags);
+ int delayUs, Handler handler, int maxReportLatencyUs, int reservedFlags);
/**
- * Flushes the batch FIFO of all the sensors registered for this listener. If there are events
- * in the FIFO of the sensor, they are returned as if the batch timeout in the FIFO of the
- * sensors had expired. Events are returned in the usual way through the SensorEventListener.
- * This call doesn't affect the batch timeout for this sensor. This call is asynchronous and
+ * Flushes the FIFO of all the sensors registered for this listener. If there are events
+ * in the FIFO of the sensor, they are returned as if the maxReportLantecy of the FIFO has
+ * expired. Events are returned in the usual way through the SensorEventListener.
+ * This call doesn't affect the maxReportLantecy for this sensor. This call is asynchronous and
* returns immediately.
* {@link android.hardware.SensorEventListener2#onFlushCompleted onFlushCompleted} is called
* after all the events in the batch at the time of calling this method have been delivered
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index aba90e4..c2b9846 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -3,7 +3,6 @@ package android.hardware.hdmi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
-import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.os.RemoteException;
import android.util.Log;
@@ -91,8 +90,13 @@ public abstract class HdmiClient {
final VendorCommandListener listener) {
return new IHdmiVendorCommandListener.Stub() {
@Override
- public void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
- listener.onReceived(srcAddress, params, hasVendorId);
+ public void onReceived(int srcAddress, int destAddress, byte[] params,
+ boolean hasVendorId) {
+ listener.onReceived(srcAddress, destAddress, params, hasVendorId);
+ }
+ @Override
+ public void onControlStateChanged(boolean enabled, int reason) {
+ listener.onControlStateChanged(enabled, reason);
}
};
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 30f3576..ff2ba1e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -236,6 +236,15 @@ public final class HdmiControlManager {
/** Clear timer error - CEC is disabled. */
public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
+ /** The HdmiControlService is started. */
+ public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
+ /** The state of HdmiControlService is changed by changing of settings. */
+ public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
+ /** The HdmiControlService is enabled to wake up. */
+ public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
+ /** The HdmiControlService will be disabled to standby. */
+ public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
+
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.
@@ -339,11 +348,29 @@ public final class HdmiControlManager {
* Called when a vendor command is received.
*
* @param srcAddress source logical address
+ * @param destAddress destination logical address
* @param params vendor-specific parameters
* @param hasVendorId {@code true} if the command is &lt;Vendor Command
* With ID&gt;. The first 3 bytes of params is vendor id.
*/
- void onReceived(int srcAddress, byte[] params, boolean hasVendorId);
+ void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
+
+ /**
+ * The callback is called:
+ * <ul>
+ * <li> before HdmiControlService is disabled.
+ * <li> after HdmiControlService is enabled and the local address is assigned.
+ * </ul>
+ * The client shouldn't hold the thread too long since this is a blocking call.
+ *
+ * @param enabled {@code true} if HdmiControlService is enabled.
+ * @param reason the reason code why the state of HdmiControlService is changed.
+ * @see #CONTROL_STATE_CHANGED_REASON_START
+ * @see #CONTROL_STATE_CHANGED_REASON_SETTING
+ * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
+ * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
+ */
+ void onControlStateChanged(boolean enabled, int reason);
}
/**
diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java
index dcc41fa..c294f72 100644
--- a/core/java/android/hardware/hdmi/HdmiRecordSources.java
+++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java
@@ -55,8 +55,10 @@ public final class HdmiRecordSources {
/**
* Base class for each record source.
+ * @hide
*/
- static abstract class RecordSource {
+ @SystemApi
+ public static abstract class RecordSource {
protected final int mSourceType;
protected final int mExtraDataSize;
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 9d92fd9..683d04b 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -22,6 +22,9 @@ import android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
import android.os.RemoteException;
import android.util.Log;
+import java.util.Collections;
+import java.util.List;
+
import libcore.util.EmptyArray;
/**
@@ -150,6 +153,21 @@ public final class HdmiTvClient extends HdmiClient {
}
/**
+ * Returns all the CEC devices connected to TV.
+ *
+ * @return list of {@link HdmiDeviceInfo} for connected CEC devices.
+ * Empty list is returned if there is none.
+ */
+ public List<HdmiDeviceInfo> getDeviceList() {
+ try {
+ return mService.getDeviceList();
+ } catch (RemoteException e) {
+ Log.e("TAG", "Failed to call getDeviceList():", e);
+ return Collections.<HdmiDeviceInfo>emptyList();
+ }
+ }
+
+ /**
* Set system audio volume
*
* @param oldIndex current volume index
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 4866a9a..c1e924e 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -59,6 +59,7 @@ interface IHdmiControlService {
void setSystemAudioMute(boolean mute);
void setInputChangeListener(IHdmiInputChangeListener listener);
List<HdmiDeviceInfo> getInputDevices();
+ List<HdmiDeviceInfo> getDeviceList();
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
boolean hasVendorId);
void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
index 55cc925..a16e878 100644
--- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
@@ -23,5 +23,6 @@ package android.hardware.hdmi;
* @hide
*/
oneway interface IHdmiVendorCommandListener {
- void onReceived(int logicalAddress, in byte[] operands, boolean hasVendorId);
+ void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId);
+ void onControlStateChanged(boolean enabled, int reason);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 24cdd77..f361695b 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -588,6 +588,11 @@ public class Build {
* </ul>
*/
public static final int LOLLIPOP = 21;
+
+ /**
+ * Lollipop with an extra sugar coating on the outside!
+ */
+ public static final int LOLLIPOP_MR1 = 22;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 18730b6..084ca30 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1093,7 +1093,15 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/** @hide */
public static final int MEMINFO_ZRAM_TOTAL = 8;
/** @hide */
- public static final int MEMINFO_COUNT = 9;
+ public static final int MEMINFO_MAPPED = 9;
+ /** @hide */
+ public static final int MEMINFO_VM_ALLOC_USED = 10;
+ /** @hide */
+ public static final int MEMINFO_PAGE_TABLES = 11;
+ /** @hide */
+ public static final int MEMINFO_KERNEL_STACK = 12;
+ /** @hide */
+ public static final int MEMINFO_COUNT = 13;
/**
* Retrieves /proc/meminfo. outSizes is filled with fields
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 8081a54..9482a72 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -162,10 +162,10 @@ public class ListPreference extends DialogPreference {
@Override
public CharSequence getSummary() {
final CharSequence entry = getEntry();
- if (mSummary == null || entry == null) {
+ if (mSummary == null) {
return super.getSummary();
} else {
- return String.format(mSummary, entry);
+ return String.format(mSummary, entry == null ? "" : entry);
}
}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 671f722..3130b64 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -47,7 +47,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
private final Context mContext;
- private final Handler mHandler;
private final H mUiHandler = new H();
private final Callback mCallback;
private final Uri mDefaultUri;
@@ -55,8 +54,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
private final int mStreamType;
private final int mMaxStreamVolume;
private final Receiver mReceiver = new Receiver();
- private final Observer mVolumeObserver;
+ private Handler mHandler;
+ private Observer mVolumeObserver;
private int mOriginalStreamVolume;
private Ringtone mRingtone;
private int mLastProgress = -1;
@@ -75,16 +75,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mStreamType = streamType;
mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
- HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
- thread.start();
- mHandler = new Handler(thread.getLooper(), this);
mCallback = callback;
mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
- mVolumeObserver = new Observer(mHandler);
- mContext.getContentResolver().registerContentObserver(
- System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
- false, mVolumeObserver);
- mReceiver.setListening(true);
if (defaultUri == null) {
if (mStreamType == AudioManager.STREAM_RING) {
defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
@@ -95,7 +87,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
}
mDefaultUri = defaultUri;
- mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
}
public void setSeekBar(SeekBar seekBar) {
@@ -139,6 +130,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
private void postStartSample() {
+ if (mHandler == null) return;
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
@@ -159,7 +151,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
}
- void postStopSample() {
+ private void postStopSample() {
+ if (mHandler == null) return;
// remove pending delayed start messages
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.removeMessages(MSG_STOP_SAMPLE);
@@ -173,11 +166,27 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
public void stop() {
+ if (mHandler == null) return; // already stopped
postStopSample();
mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
- mSeekBar.setOnSeekBarChangeListener(null);
mReceiver.setListening(false);
+ mSeekBar.setOnSeekBarChangeListener(null);
mHandler.getLooper().quitSafely();
+ mHandler = null;
+ mVolumeObserver = null;
+ }
+
+ public void start() {
+ if (mHandler != null) return; // already started
+ HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+ thread.start();
+ mHandler = new Handler(thread.getLooper(), this);
+ mHandler.sendEmptyMessage(MSG_INIT_SAMPLE);
+ mVolumeObserver = new Observer(mHandler);
+ mContext.getContentResolver().registerContentObserver(
+ System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
+ false, mVolumeObserver);
+ mReceiver.setListening(true);
}
public void revertVolume() {
@@ -193,7 +202,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
postSetVolume(progress);
}
- void postSetVolume(int progress) {
+ private void postSetVolume(int progress) {
+ if (mHandler == null) return;
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index df9e10e..0d4c0b6 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -67,6 +67,7 @@ public class VolumePreference extends SeekBarDialogPreference implements
final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this);
+ mSeekBarVolumizer.start();
mSeekBarVolumizer.setSeekBar(seekBar);
getPreferenceManager().registerOnActivityStopListener(this);
@@ -116,7 +117,7 @@ public class VolumePreference extends SeekBarDialogPreference implements
public void onActivityStop() {
if (mSeekBarVolumizer != null) {
- mSeekBarVolumizer.postStopSample();
+ mSeekBarVolumizer.stopSample();
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 79e84d9..75c435e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5013,10 +5013,19 @@ public final class Settings {
default:
throw new IllegalArgumentException("Invalid location mode: " + mode);
}
- boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
- cr, LocationManager.GPS_PROVIDER, gps, userId);
+ // Note it's important that we set the NLP mode first. The Google implementation
+ // of NLP clears its NLP consent setting any time it receives a
+ // LocationManager.PROVIDERS_CHANGED_ACTION broadcast and NLP is disabled. Also,
+ // it shows an NLP consent dialog any time it receives the broadcast, NLP is
+ // enabled, and the NLP consent is not set. If 1) we were to enable GPS first,
+ // 2) a setup wizard has its own NLP consent UI that sets the NLP consent setting,
+ // and 3) the receiver happened to complete before we enabled NLP, then the Google
+ // NLP would detect the attempt to enable NLP and show a redundant NLP consent
+ // dialog. Then the people who wrote the setup wizard would be sad.
boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser(
cr, LocationManager.NETWORK_PROVIDER, network, userId);
+ boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser(
+ cr, LocationManager.GPS_PROVIDER, gps, userId);
return gpsSuccess && nlpSuccess;
}
}
@@ -6579,6 +6588,14 @@ public final class Settings {
public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
/**
+ * Whether the Volte/VT is enabled
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ * @hide
+ */
+ public static final String VOLTE_VT_ENABLED = "volte_vt_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 6820f77..e5f3b2c 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -34,7 +34,11 @@ public class PathParser {
Path path = new Path();
PathDataNode[] nodes = createNodesFromPathData(pathData);
if (nodes != null) {
- PathDataNode.nodesToPath(nodes, path);
+ try {
+ PathDataNode.nodesToPath(nodes, path);
+ } catch (RuntimeException e) {
+ throw new RuntimeException("Error in parsing " + pathData, e);
+ }
return path;
}
return null;
@@ -128,7 +132,12 @@ public class PathParser {
while (end < s.length()) {
c = s.charAt(end);
- if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
+ // Note that 'e' or 'E' are not valid path commands, but could be
+ // used for floating point numbers' scientific notation.
+ // Therefore, when searching for next command, we should ignore 'e'
+ // and 'E'.
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
+ && c != 'e' && c != 'E') {
return end;
}
end++;
@@ -142,9 +151,9 @@ public class PathParser {
private static class ExtractFloatResult {
// We need to return the position of the next separator and whether the
- // next float starts with a '-'.
+ // next float starts with a '-' or a '.'.
int mEndPosition;
- boolean mEndWithNegSign;
+ boolean mEndWithNegOrDot;
}
/**
@@ -179,8 +188,8 @@ public class PathParser {
s.substring(startPosition, endPosition));
}
- if (result.mEndWithNegSign) {
- // Keep the '-' sign with next number.
+ if (result.mEndWithNegOrDot) {
+ // Keep the '-' or '.' sign with next number.
startPosition = endPosition;
} else {
startPosition = endPosition + 1;
@@ -188,8 +197,7 @@ public class PathParser {
}
return Arrays.copyOf(results, count);
} catch (NumberFormatException e) {
- Log.e(LOGTAG, "error in parsing \"" + s + "\"");
- throw e;
+ throw new RuntimeException("error in parsing \"" + s + "\"", e);
}
}
@@ -201,11 +209,15 @@ public class PathParser {
* the starting position of next number, whether it is ending with a '-'.
*/
private static void extract(String s, int start, ExtractFloatResult result) {
- // Now looking for ' ', ',' or '-' from the start.
+ // Now looking for ' ', ',', '.' or '-' from the start.
int currentIndex = start;
boolean foundSeparator = false;
- result.mEndWithNegSign = false;
+ result.mEndWithNegOrDot = false;
+ boolean secondDot = false;
+ boolean isExponential = false;
for (; currentIndex < s.length(); currentIndex++) {
+ boolean isPrevExponential = isExponential;
+ isExponential = false;
char currentChar = s.charAt(currentIndex);
switch (currentChar) {
case ' ':
@@ -213,11 +225,25 @@ public class PathParser {
foundSeparator = true;
break;
case '-':
- if (currentIndex != start) {
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
foundSeparator = true;
- result.mEndWithNegSign = true;
+ result.mEndWithNegOrDot = true;
}
break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
}
if (foundSeparator) {
break;
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 3770b8a..132e25c 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -87,6 +87,8 @@ public class Surface implements Parcelable {
// non compatibility mode.
private Matrix mCompatibleMatrix;
+ private HwuiContext mHwuiContext;
+
/** @hide */
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
@@ -171,6 +173,10 @@ public class Surface implements Parcelable {
nativeRelease(mNativeObject);
setNativeObjectLocked(0);
}
+ if (mHwuiContext != null) {
+ mHwuiContext.destroy();
+ mHwuiContext = null;
+ }
}
}
@@ -264,27 +270,60 @@ public class Surface implements Parcelable {
* @param canvas The canvas previously obtained from {@link #lockCanvas}.
*/
public void unlockCanvasAndPost(Canvas canvas) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+
+ if (mHwuiContext != null) {
+ mHwuiContext.unlockAndPost(canvas);
+ } else {
+ unlockSwCanvasAndPost(canvas);
+ }
+ }
+ }
+
+ private void unlockSwCanvasAndPost(Canvas canvas) {
if (canvas != mCanvas) {
throw new IllegalArgumentException("canvas object must be the same instance that "
+ "was previously returned by lockCanvas");
}
+ if (mNativeObject != mLockedObject) {
+ Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
+ Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
+ Long.toHexString(mLockedObject) +")");
+ }
+ if (mLockedObject == 0) {
+ throw new IllegalStateException("Surface was not locked");
+ }
+ try {
+ nativeUnlockCanvasAndPost(mLockedObject, canvas);
+ } finally {
+ nativeRelease(mLockedObject);
+ mLockedObject = 0;
+ }
+ }
+ /**
+ * Gets a {@link Canvas} for drawing into this surface.
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
+ * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+ * unsupported drawing operations</a> for a list of what is and isn't
+ * supported in a hardware-accelerated canvas.
+ *
+ * @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalStateException If the canvas cannot be locked.
+ */
+ public Canvas lockHardwareCanvas() {
synchronized (mLock) {
checkNotReleasedLocked();
- if (mNativeObject != mLockedObject) {
- Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
- Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
- Long.toHexString(mLockedObject) +")");
- }
- if (mLockedObject == 0) {
- throw new IllegalStateException("Surface was not locked");
- }
- try {
- nativeUnlockCanvasAndPost(mLockedObject, canvas);
- } finally {
- nativeRelease(mLockedObject);
- mLockedObject = 0;
+ if (mHwuiContext == null) {
+ mHwuiContext = new HwuiContext();
}
+ return mHwuiContext.lockCanvas();
}
}
@@ -415,6 +454,9 @@ public class Surface implements Parcelable {
}
mNativeObject = ptr;
mGenerationId += 1;
+ if (mHwuiContext != null) {
+ mHwuiContext.updateSurface();
+ }
}
}
@@ -518,4 +560,59 @@ public class Surface implements Parcelable {
mOrigMatrix.set(m);
}
}
+
+ private final class HwuiContext {
+ private final RenderNode mRenderNode;
+ private long mHwuiRenderer;
+ private HardwareCanvas mCanvas;
+
+ HwuiContext() {
+ mRenderNode = RenderNode.create("HwuiCanvas", null);
+ mRenderNode.setClipToBounds(false);
+ mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
+ }
+
+ Canvas lockCanvas() {
+ if (mCanvas != null) {
+ throw new IllegalStateException("Surface was already locked!");
+ }
+ mCanvas = mRenderNode.start(0, 0);
+ return mCanvas;
+ }
+
+ void unlockAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ mRenderNode.end(mCanvas);
+ mCanvas = null;
+ nHwuiDraw(mHwuiRenderer);
+ }
+
+ void updateSurface() {
+ nHwuiSetSurface(mHwuiRenderer, mNativeObject);
+ }
+
+ void destroy() {
+ if (mHwuiRenderer != 0) {
+ nHwuiDestroy(mHwuiRenderer);
+ mHwuiRenderer = 0;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ private static native long nHwuiCreate(long rootNode, long surface);
+ private static native void nHwuiSetSurface(long renderer, long surface);
+ private static native void nHwuiDraw(long renderer);
+ private static native void nHwuiDestroy(long renderer);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1ecc8d9..8e58cd6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16617,8 +16617,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
invalidate(true);
refreshDrawableState();
dispatchSetSelected(selected);
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ if (selected) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ } else {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
}
}
@@ -17414,17 +17418,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
- if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
- widthMeasureSpec != mOldWidthMeasureSpec ||
- heightMeasureSpec != mOldHeightMeasureSpec) {
+ final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
+ final boolean isExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&
+ MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
+ final boolean matchingSize = isExactly &&
+ getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) &&
+ getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
+ if (forceLayout || !matchingSize &&
+ (widthMeasureSpec != mOldWidthMeasureSpec ||
+ heightMeasureSpec != mOldHeightMeasureSpec)) {
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
resolveRtlPropertiesIfNeeded();
- int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
- mMeasureCache.indexOfKey(key);
+ int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 12a49d5..50e64c6 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1005,12 +1005,21 @@ public class ViewDebug {
return fields;
}
- final ArrayList<Field> foundFields = new ArrayList<Field>();
- fields = klass.getDeclaredFields();
+ final ArrayList<Field> declaredFields = new ArrayList();
+ klass.getDeclaredFieldsUnchecked(false, declaredFields);
- int count = fields.length;
+ final ArrayList<Field> foundFields = new ArrayList<Field>();
+ final int count = declaredFields.size();
for (int i = 0; i < count; i++) {
- final Field field = fields[i];
+ final Field field = declaredFields.get(i);
+
+ // Ensure the field type can be resolved.
+ try {
+ field.getType();
+ } catch (NoClassDefFoundError e) {
+ continue;
+ }
+
if (field.isAnnotationPresent(ExportedProperty.class)) {
field.setAccessible(true);
foundFields.add(field);
@@ -1039,12 +1048,22 @@ public class ViewDebug {
return methods;
}
- final ArrayList<Method> foundMethods = new ArrayList<Method>();
- methods = klass.getDeclaredMethods();
+ final ArrayList<Method> declaredMethods = new ArrayList();
+ klass.getDeclaredMethodsUnchecked(false, declaredMethods);
- int count = methods.length;
+ final ArrayList<Method> foundMethods = new ArrayList<Method>();
+ final int count = declaredMethods.size();
for (int i = 0; i < count; i++) {
- final Method method = methods[i];
+ final Method method = declaredMethods.get(i);
+
+ // Ensure the method return and parameter types can be resolved.
+ try {
+ method.getReturnType();
+ method.getParameterTypes();
+ } catch (NoClassDefFoundError e) {
+ continue;
+ }
+
if (method.getParameterTypes().length == 0 &&
method.isAnnotationPresent(ExportedProperty.class) &&
method.getReturnType() != Void.class) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4116b6b..134171a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -864,6 +864,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (siblingBounds.intersect(bounds)) {
// If an interactive sibling completely covers the child, done.
if (siblingBounds.equals(bounds)) {
+ if (orderedList != null) orderedList.clear();
return false;
}
// Keep track of the intersection rectangle.
@@ -871,6 +872,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
intersections.add(intersection);
}
}
+ if (orderedList != null) orderedList.clear();
if (mParent instanceof ViewGroup) {
ViewGroup parentGroup = (ViewGroup) mParent;
@@ -3293,7 +3295,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
- * sorted first by Z, then by child drawing order (if applicable).
+ * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
+ * after use to avoid leaking child Views.
*
* Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
* children.
@@ -3668,6 +3671,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @see #generateDefaultLayoutParams()
*/
public void addView(View child, int index) {
+ if (child == null) {
+ throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+ }
LayoutParams params = child.getLayoutParams();
if (params == null) {
params = generateDefaultLayoutParams();
@@ -3725,6 +3731,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
System.out.println(this + " addView");
}
+ if (child == null) {
+ throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+ }
+
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
@@ -3852,6 +3862,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
protected boolean addViewInLayout(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
+ if (child == null) {
+ throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
+ }
child.mParent = null;
addViewInner(child, index, params, preventRequestLayout);
child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
@@ -4065,9 +4078,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
*/
public void removeView(View view) {
- removeViewInternal(view);
- requestLayout();
- invalidate(true);
+ if (removeViewInternal(view)) {
+ requestLayout();
+ invalidate(true);
+ }
}
/**
@@ -4130,11 +4144,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
invalidate(true);
}
- private void removeViewInternal(View view) {
+ private boolean removeViewInternal(View view) {
final int index = indexOfChild(view);
if (index >= 0) {
removeViewInternal(index, view);
+ return true;
}
+ return false;
}
private void removeViewInternal(int index, View view) {
@@ -6488,7 +6504,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
/**
- * The left margin in pixels of the child.
+ * The left margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6496,7 +6512,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
public int leftMargin;
/**
- * The top margin in pixels of the child.
+ * The top margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6504,7 +6520,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
public int topMargin;
/**
- * The right margin in pixels of the child.
+ * The right margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6512,7 +6528,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
public int rightMargin;
/**
- * The bottom margin in pixels of the child.
+ * The bottom margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6520,7 +6536,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
public int bottomMargin;
/**
- * The start margin in pixels of the child.
+ * The start margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6528,7 +6544,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private int startMargin = DEFAULT_MARGIN_RELATIVE;
/**
- * The end margin in pixels of the child.
+ * The end margin in pixels of the child. Margin values should be positive.
* Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
* to this field.
*/
@@ -6709,6 +6725,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
* to be done so that the new margins are taken into account. Left and right margins may be
* overriden by {@link android.view.View#requestLayout()} depending on layout direction.
+ * Margin values should be positive.
*
* @param left the left margin size
* @param top the top margin size
@@ -6738,7 +6755,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
* needs to be done so that the new relative margins are taken into account. Left and right
* margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
- * direction.
+ * direction. Margin values should be positive.
*
* @param start the start margin size
* @param top the top margin size
@@ -6761,7 +6778,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
- * Sets the relative start margin.
+ * Sets the relative start margin. Margin values should be positive.
*
* @param start the start margin size
*
@@ -6794,7 +6811,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
- * Sets the relative end margin.
+ * Sets the relative end margin. Margin values should be positive.
*
* @param end the end margin size
*
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 47ee52e..75c9ebd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -523,15 +523,6 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
/**
- * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on
- * one user's screen.
- * In multiuser systems shows on all users' windows.
- * @hide
- */
- public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
-
-
- /**
* Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
* In multiuser systems shows on all users' windows.
* @hide
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 10e56c7..5c05b5a 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -99,12 +99,12 @@ public class AppSecurityPermissions {
public Drawable loadGroupIcon(PackageManager pm) {
if (icon != 0) {
- return loadIcon(pm);
+ return loadUnbadgedIcon(pm);
} else {
ApplicationInfo appInfo;
try {
appInfo = pm.getApplicationInfo(packageName, 0);
- return appInfo.loadIcon(pm);
+ return appInfo.loadUnbadgedIcon(pm);
} catch (NameNotFoundException e) {
}
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index ea60abb..f380d68 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -775,9 +775,14 @@ public class CalendarView extends FrameLayout {
private ViewGroup mDayNamesHeader;
/**
- * Cached labels for the week names header.
+ * Cached abbreviations for day of week names.
*/
- private String[] mDayLabels;
+ private String[] mDayNamesShort;
+
+ /**
+ * Cached full-length day of week names.
+ */
+ private String[] mDayNamesLong;
/**
* The first day of the week.
@@ -1306,11 +1311,14 @@ public class CalendarView extends FrameLayout {
* Sets up the strings to be used by the header.
*/
private void setUpHeader() {
- mDayLabels = new String[mDaysPerWeek];
+ mDayNamesShort = new String[mDaysPerWeek];
+ mDayNamesLong = new String[mDaysPerWeek];
for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) {
int calendarDay = (i > Calendar.SATURDAY) ? i - Calendar.SATURDAY : i;
- mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+ mDayNamesShort[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
DateUtils.LENGTH_SHORTEST);
+ mDayNamesLong[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay,
+ DateUtils.LENGTH_LONG);
}
TextView label = (TextView) mDayNamesHeader.getChildAt(0);
@@ -1325,7 +1333,8 @@ public class CalendarView extends FrameLayout {
label.setTextAppearance(mContext, mWeekDayTextAppearanceResId);
}
if (i < mDaysPerWeek + 1) {
- label.setText(mDayLabels[i - 1]);
+ label.setText(mDayNamesShort[i - 1]);
+ label.setContentDescription(mDayNamesLong[i - 1]);
label.setVisibility(View.VISIBLE);
} else {
label.setVisibility(View.GONE);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3c186e3..9f540c0 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1639,6 +1639,11 @@ public class ListPopupWindow {
setPressed(false);
updateSelectorState();
+ final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+ if (motionView != null) {
+ motionView.setPressed(false);
+ }
+
if (mClickAnimation != null) {
mClickAnimation.cancel();
mClickAnimation = null;
@@ -1653,6 +1658,15 @@ public class ListPopupWindow {
setPressed(true);
layoutChildren();
+ // Manage the pressed view based on motion position. This allows us to
+ // play nicely with actual touch and scroll events.
+ final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+ if (motionView != null) {
+ motionView.setPressed(false);
+ }
+ mMotionPosition = position;
+ child.setPressed(true);
+
// Ensure that keyboard focus starts from the last touched position.
setSelectedPositionInt(position);
positionSelectorLikeTouch(position, child, x, y);
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 111dadc..2708398 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -16,6 +16,7 @@
package android.widget;
+import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuPresenter;
@@ -37,10 +38,11 @@ import android.widget.ListPopupWindow.ForwardingListener;
* of the popup will dismiss it.
*/
public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
- private Context mContext;
- private MenuBuilder mMenu;
- private View mAnchor;
- private MenuPopupHelper mPopup;
+ private final Context mContext;
+ private final MenuBuilder mMenu;
+ private final View mAnchor;
+ private final MenuPopupHelper mPopup;
+
private OnMenuItemClickListener mMenuItemClickListener;
private OnDismissListener mDismissListener;
private OnTouchListener mDragListener;
@@ -58,31 +60,56 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
}
/**
- * Construct a new PopupMenu.
+ * Constructor to create a new popup menu with an anchor view.
*
- * @param context Context for the PopupMenu.
- * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
- * is room, or above it if there is not.
+ * @param context Context the popup menu is running in, through which it
+ * can access the current theme, resources, etc.
+ * @param anchor Anchor view for this popup. The popup will appear below
+ * the anchor if there is room, or above it if there is not.
*/
public PopupMenu(Context context, View anchor) {
this(context, anchor, Gravity.NO_GRAVITY);
}
/**
- * Construct a new PopupMenu.
+ * Constructor to create a new popup menu with an anchor view and alignment
+ * gravity.
*
- * @param context Context for the PopupMenu.
- * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
- * is room, or above it if there is not.
- * @param gravity The {@link Gravity} value for aligning the popup with its anchor
+ * @param context Context the popup menu is running in, through which it
+ * can access the current theme, resources, etc.
+ * @param anchor Anchor view for this popup. The popup will appear below
+ * the anchor if there is room, or above it if there is not.
+ * @param gravity The {@link Gravity} value for aligning the popup with its
+ * anchor.
*/
public PopupMenu(Context context, View anchor, int gravity) {
- // TODO Theme?
+ this(context, anchor, gravity, R.attr.popupMenuStyle, 0);
+ }
+
+ /**
+ * Constructor a create a new popup menu with a specific style.
+ *
+ * @param context Context the popup menu is running in, through which it
+ * can access the current theme, resources, etc.
+ * @param anchor Anchor view for this popup. The popup will appear below
+ * the anchor if there is room, or above it if there is not.
+ * @param gravity The {@link Gravity} value for aligning the popup with its
+ * anchor.
+ * @param popupStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default values for
+ * the popup window. Can be 0 to not look for defaults.
+ * @param popupStyleRes A resource identifier of a style resource that
+ * supplies default values for the popup window, used only if
+ * popupStyleAttr is 0 or can not be found in the theme. Can be 0
+ * to not look for defaults.
+ */
+ public PopupMenu(Context context, View anchor, int gravity, int popupStyleAttr,
+ int popupStyleRes) {
mContext = context;
mMenu = new MenuBuilder(context);
mMenu.setCallback(this);
mAnchor = anchor;
- mPopup = new MenuPopupHelper(context, mMenu, anchor);
+ mPopup = new MenuPopupHelper(context, mMenu, anchor, false, popupStyleAttr, popupStyleRes);
mPopup.setGravity(gravity);
mPopup.setCallback(this);
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9298c2..1c190c3 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -604,6 +604,7 @@ public class ProgressBar extends View {
* @see #getIndeterminateTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setIndeterminateTintList(@Nullable ColorStateList tint) {
if (mProgressTintInfo == null) {
mProgressTintInfo = new ProgressTintInfo();
@@ -842,6 +843,7 @@ public class ProgressBar extends View {
* @see #getProgressTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setProgressTintList(@Nullable ColorStateList tint) {
if (mProgressTintInfo == null) {
mProgressTintInfo = new ProgressTintInfo();
@@ -923,6 +925,7 @@ public class ProgressBar extends View {
* @see #getProgressBackgroundTintList()
* @see Drawable#setTintList(ColorStateList)
*/
+ @RemotableViewMethod
public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
if (mProgressTintInfo == null) {
mProgressTintInfo = new ProgressTintInfo();
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 56f126c..d15f2d6 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -22,9 +22,7 @@ import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -47,7 +45,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
-import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
@@ -69,7 +66,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private static final int HOURS = 0;
private static final int MINUTES = 1;
private static final int HOURS_INNER = 2;
- private static final int AMPM = 3;
private static final int SELECTOR_CIRCLE = 0;
private static final int SELECTOR_DOT = 1;
@@ -87,12 +83,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
// Alpha level of color for selector.
private static final int ALPHA_SELECTOR = 60; // was 51
- // Alpha level of color for selected circle.
- private static final int ALPHA_AMPM_SELECTED = ALPHA_SELECTOR;
-
- // Alpha level of color for pressed circle.
- private static final int ALPHA_AMPM_PRESSED = 255; // was 175
-
private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f;
private static final float SINE_30_DEGREES = 0.5f;
@@ -105,8 +95,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private static final int CENTER_RADIUS = 2;
- private static final int[] STATE_SET_SELECTED = new int[] {R.attr.state_selected};
-
private static int[] sSnapPrefer30sMap = new int[361];
private final String[] mHours12Texts = new String[12];
@@ -114,8 +102,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private final String[] mInnerHours24Texts = new String[12];
private final String[] mMinutesTexts = new String[12];
- private final String[] mAmPmText = new String[2];
-
private final Paint[] mPaint = new Paint[2];
private final int[] mColor = new int[2];
private final IntHolder[] mAlpha = new IntHolder[2];
@@ -126,11 +112,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private final int[][] mColorSelector = new int[2][3];
private final IntHolder[][] mAlphaSelector = new IntHolder[2][3];
- private final Paint mPaintAmPmText = new Paint();
- private final Paint[] mPaintAmPmCircle = new Paint[2];
-
private final Paint mPaintBackground = new Paint();
- private final Paint mPaintDisabled = new Paint();
private final Paint mPaintDebug = new Paint();
private Typeface mTypeface;
@@ -184,21 +166,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
private float mSelectionRadiusMultiplier;
private int[] mSelectionDegrees = new int[3];
- private int mAmPmCircleRadius;
- private float mAmPmYCenter;
-
- private float mAmPmCircleRadiusMultiplier;
- private int mAmPmTextColor;
-
- private float mLeftIndicatorXCenter;
- private float mRightIndicatorXCenter;
-
- private int mAmPmUnselectedColor;
- private int mAmPmSelectedColor;
-
private int mAmOrPm;
- private int mAmOrPmPressed;
-
private int mDisabledAlpha;
private RectF mRectF = new RectF();
@@ -331,27 +299,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker,
defStyle, 0);
- ColorStateList amPmBackgroundColor = a.getColorStateList(
- R.styleable.TimePicker_amPmBackgroundColor);
- if (amPmBackgroundColor == null) {
- amPmBackgroundColor = res.getColorStateList(
- R.color.timepicker_default_ampm_unselected_background_color_material);
- }
-
- // Obtain the backup selected color. If the background color state
- // list doesn't have a state for selected, we'll use this color.
- final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
- res.getColor(R.color.timepicker_default_ampm_selected_background_color_material));
- amPmBackgroundColor = ColorStateList.addFirstIfMissing(
- amPmBackgroundColor, R.attr.state_selected, amPmSelectedColor);
-
- mAmPmSelectedColor = amPmBackgroundColor.getColorForState(
- STATE_SET_SELECTED, amPmSelectedColor);
- mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor();
-
- mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor,
- res.getColor(R.color.timepicker_default_text_color_material));
-
mTypeface = Typeface.create("sans-serif", Typeface.NORMAL);
// Initialize all alpha values to opaque.
@@ -419,16 +366,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
R.styleable.TimePicker_numbersSelectorColor,
R.color.timepicker_default_selector_color_material);
- mPaintAmPmText.setColor(mAmPmTextColor);
- mPaintAmPmText.setTypeface(mTypeface);
- mPaintAmPmText.setAntiAlias(true);
- mPaintAmPmText.setTextAlign(Paint.Align.CENTER);
-
- mPaintAmPmCircle[AM] = new Paint();
- mPaintAmPmCircle[AM].setAntiAlias(true);
- mPaintAmPmCircle[PM] = new Paint();
- mPaintAmPmCircle[PM].setAntiAlias(true);
-
mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
res.getColor(R.color.timepicker_default_numbers_background_color_material)));
mPaintBackground.setAntiAlias(true);
@@ -444,7 +381,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mShowHours = true;
mIs24HourMode = false;
mAmOrPm = AM;
- mAmOrPmPressed = -1;
initHoursAndMinutesText();
initData();
@@ -530,13 +466,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
// 0 is 12 AM (midnight) and 12 is 12 PM (noon).
mAmOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM;
-
- if (mIs24HourMode) {
- // Inner circle is 1 through 12.
- mIsOnInnerCircle = hour >= 1 && hour <= 12;
- } else {
- mIsOnInnerCircle = false;
- }
+ mIsOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12;
initData();
updateLayoutData();
@@ -586,11 +516,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
return mAmOrPm;
}
- public void swapAmPm() {
- mAmOrPm = (mAmOrPm == AM) ? PM : AM;
- invalidate();
- }
-
public void showHours(boolean animate) {
if (mShowHours) return;
mShowHours = true;
@@ -621,10 +546,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mInnerHours24Texts[i] = String.format("%d", HOURS_NUMBERS[i]);
mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]);
}
-
- String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext);
- mAmPmText[AM] = amPmStrings[0];
- mAmPmText[PM] = amPmStrings[1];
}
private void initData() {
@@ -674,9 +595,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mAnimationRadiusMultiplier[HOURS_INNER] = 1;
mAnimationRadiusMultiplier[MINUTES] = 1;
- mAmPmCircleRadiusMultiplier = Float.parseFloat(
- res.getString(R.string.timepicker_ampm_circle_radius_multiplier));
-
mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT);
mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE);
@@ -710,14 +628,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS];
mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES];
- if (!mIs24HourMode) {
- // We'll need to draw the AM/PM circles, so the main circle will need to have
- // a slightly higher center. To keep the entire view centered vertically, we'll
- // have to push it up by half the radius of the AM/PM circles.
- int amPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier);
- mYCenter -= amPmCircleRadius / 2;
- }
-
mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS]
* mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS];
mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS]
@@ -738,17 +648,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mSelectionRadius[HOURS] = (int) (mCircleRadius[HOURS] * mSelectionRadiusMultiplier);
mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS];
mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier);
-
- mAmPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier);
- mPaintAmPmText.setTextSize(mAmPmCircleRadius * 3 / 4);
-
- // Line up the vertical center of the AM/PM circles with the bottom of the main circle.
- mAmPmYCenter = mYCenter + mCircleRadius[HOURS];
-
- // Line up the horizontal edges of the AM/PM circles with the horizontal edges
- // of the main circle
- mLeftIndicatorXCenter = mXCenter - mCircleRadius[HOURS] + mAmPmCircleRadius;
- mRightIndicatorXCenter = mXCenter + mCircleRadius[HOURS] - mAmPmCircleRadius;
}
@Override
@@ -780,9 +679,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
mColor[MINUTES], mAlpha[MINUTES].getValue());
drawCenter(canvas);
- if (!mIs24HourMode) {
- drawAmPm(canvas);
- }
if (DEBUG) {
drawDebug(canvas);
@@ -804,50 +700,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
drawSelector(canvas, MINUTES);
}
- private void drawAmPm(Canvas canvas) {
- final boolean isLayoutRtl = isLayoutRtl();
-
- int amColor = mAmPmUnselectedColor;
- int amAlpha = ALPHA_OPAQUE;
- int pmColor = mAmPmUnselectedColor;
- int pmAlpha = ALPHA_OPAQUE;
- if (mAmOrPm == AM) {
- amColor = mAmPmSelectedColor;
- amAlpha = ALPHA_AMPM_SELECTED;
- } else if (mAmOrPm == PM) {
- pmColor = mAmPmSelectedColor;
- pmAlpha = ALPHA_AMPM_SELECTED;
- }
- if (mAmOrPmPressed == AM) {
- amColor = mAmPmSelectedColor;
- amAlpha = ALPHA_AMPM_PRESSED;
- } else if (mAmOrPmPressed == PM) {
- pmColor = mAmPmSelectedColor;
- pmAlpha = ALPHA_AMPM_PRESSED;
- }
-
- // Draw the two circles
- mPaintAmPmCircle[AM].setColor(amColor);
- mPaintAmPmCircle[AM].setAlpha(getMultipliedAlpha(amColor, amAlpha));
- canvas.drawCircle(isLayoutRtl ? mRightIndicatorXCenter : mLeftIndicatorXCenter,
- mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[AM]);
-
- mPaintAmPmCircle[PM].setColor(pmColor);
- mPaintAmPmCircle[PM].setAlpha(getMultipliedAlpha(pmColor, pmAlpha));
- canvas.drawCircle(isLayoutRtl ? mLeftIndicatorXCenter : mRightIndicatorXCenter,
- mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[PM]);
-
- // Draw the AM/PM texts on top
- mPaintAmPmText.setColor(mAmPmTextColor);
- float textYCenter = mAmPmYCenter -
- (int) (mPaintAmPmText.descent() + mPaintAmPmText.ascent()) / 2;
-
- canvas.drawText(isLayoutRtl ? mAmPmText[PM] : mAmPmText[AM], mLeftIndicatorXCenter,
- textYCenter, mPaintAmPmText);
- canvas.drawText(isLayoutRtl ? mAmPmText[AM] : mAmPmText[PM], mRightIndicatorXCenter,
- textYCenter, mPaintAmPmText);
- }
-
private int getMultipliedAlpha(int argb, int alpha) {
return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5);
}
@@ -950,7 +802,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
float x = mXCenter - width / 2;
float y = mYCenter + 1.5f * height;
- canvas.drawText(selected.toString(), x, y, paint);
+ canvas.drawText(selected, x, y, paint);
}
private void calculateGridSizesHours() {
@@ -1259,26 +1111,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
return (int) degrees;
}
- private int getIsTouchingAmOrPm(float x, float y) {
- final boolean isLayoutRtl = isLayoutRtl();
- int squaredYDistance = (int) ((y - mAmPmYCenter) * (y - mAmPmYCenter));
-
- int distanceToAmCenter = (int) Math.sqrt(
- (x - mLeftIndicatorXCenter) * (x - mLeftIndicatorXCenter) + squaredYDistance);
- if (distanceToAmCenter <= mAmPmCircleRadius) {
- return (isLayoutRtl ? PM : AM);
- }
-
- int distanceToPmCenter = (int) Math.sqrt(
- (x - mRightIndicatorXCenter) * (x - mRightIndicatorXCenter) + squaredYDistance);
- if (distanceToPmCenter <= mAmPmCircleRadius) {
- return (isLayoutRtl ? AM : PM);
- }
-
- // Neither was close enough.
- return -1;
- }
-
@Override
public boolean onTouch(View v, MotionEvent event) {
if(!mInputEnabled) {
@@ -1295,75 +1127,53 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
- mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY);
- if (mAmOrPmPressed != -1) {
- result = true;
- } else {
- degrees = getDegreesFromXY(eventX, eventY);
- if (degrees != -1) {
- snapDegrees = (mShowHours ?
- snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
+ degrees = getDegreesFromXY(eventX, eventY);
+ if (degrees != -1) {
+ snapDegrees = (mShowHours ?
+ snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
+ if (mShowHours) {
+ mSelectionDegrees[HOURS] = snapDegrees;
+ mSelectionDegrees[HOURS_INNER] = snapDegrees;
+ } else {
+ mSelectionDegrees[MINUTES] = snapDegrees;
+ }
+ performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ if (mListener != null) {
if (mShowHours) {
- mSelectionDegrees[HOURS] = snapDegrees;
- mSelectionDegrees[HOURS_INNER] = snapDegrees;
- } else {
- mSelectionDegrees[MINUTES] = snapDegrees;
- }
- performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
- if (mListener != null) {
- if (mShowHours) {
- mListener.onValueSelected(HOURS, getCurrentHour(), false);
- } else {
- mListener.onValueSelected(MINUTES, getCurrentMinute(), false);
- }
+ mListener.onValueSelected(HOURS, getCurrentHour(), false);
+ } else {
+ mListener.onValueSelected(MINUTES, getCurrentMinute(), false);
}
- result = true;
}
+ result = true;
+ invalidate();
}
- invalidate();
- return result;
+ break;
case MotionEvent.ACTION_UP:
- mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY);
- if (mAmOrPmPressed != -1) {
- if (mAmOrPm != mAmOrPmPressed) {
- swapAmPm();
+ degrees = getDegreesFromXY(eventX, eventY);
+ if (degrees != -1) {
+ snapDegrees = (mShowHours ?
+ snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
+ if (mShowHours) {
+ mSelectionDegrees[HOURS] = snapDegrees;
+ mSelectionDegrees[HOURS_INNER] = snapDegrees;
+ } else {
+ mSelectionDegrees[MINUTES] = snapDegrees;
}
- mAmOrPmPressed = -1;
if (mListener != null) {
- mListener.onValueSelected(AMPM, getCurrentHour(), true);
- }
- result = true;
- } else {
- degrees = getDegreesFromXY(eventX, eventY);
- if (degrees != -1) {
- snapDegrees = (mShowHours ?
- snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360;
if (mShowHours) {
- mSelectionDegrees[HOURS] = snapDegrees;
- mSelectionDegrees[HOURS_INNER] = snapDegrees;
- } else {
- mSelectionDegrees[MINUTES] = snapDegrees;
+ mListener.onValueSelected(HOURS, getCurrentHour(), true);
+ } else {
+ mListener.onValueSelected(MINUTES, getCurrentMinute(), true);
}
- if (mListener != null) {
- if (mShowHours) {
- mListener.onValueSelected(HOURS, getCurrentHour(), true);
- } else {
- mListener.onValueSelected(MINUTES, getCurrentMinute(), true);
- }
- }
- result = true;
}
- }
- if (result) {
invalidate();
+ result = true;
}
- return result;
-
- default:
break;
}
- return false;
+ return result;
}
/**
@@ -1373,8 +1183,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
}
/**
@@ -1404,7 +1214,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
* When scroll forward/backward events are received, jump the time to the higher/lower
* discrete, visible value on the circle.
*/
- @SuppressLint("NewApi")
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (super.performAccessibilityAction(action, arguments)) {
@@ -1418,8 +1227,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
changeMultiplier = -1;
}
if (changeMultiplier != 0) {
- int value = 0;
- int stepSize = 0;
+ int value;
+ final int stepSize;
if (mShowHours) {
stepSize = DEGREES_FOR_ONE_HOUR;
value = getCurrentHour() % 12;
@@ -1431,7 +1240,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
int degrees = value * stepSize;
degrees = snapOnly30s(degrees, changeMultiplier);
value = degrees / stepSize;
- int maxValue = 0;
+ final int maxValue;
int minValue = 0;
if (mShowHours) {
if (mIs24HourMode) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7cb3c37..80f364b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -27,6 +27,7 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -1069,6 +1070,7 @@ public class RemoteViews implements Parcelable, Filter {
static final int BITMAP = 12;
static final int BUNDLE = 13;
static final int INTENT = 14;
+ static final int COLOR_STATE_LIST = 15;
String methodName;
int type;
@@ -1142,6 +1144,11 @@ public class RemoteViews implements Parcelable, Filter {
this.value = Intent.CREATOR.createFromParcel(in);
}
break;
+ case COLOR_STATE_LIST:
+ if (in.readInt() != 0) {
+ this.value = ColorStateList.CREATOR.createFromParcel(in);
+ }
+ break;
default:
break;
}
@@ -1212,6 +1219,11 @@ public class RemoteViews implements Parcelable, Filter {
((Intent)this.value).writeToParcel(out, flags);
}
break;
+ case COLOR_STATE_LIST:
+ out.writeInt(this.value != null ? 1 : 0);
+ if (this.value != null) {
+ ((ColorStateList)this.value).writeToParcel(out, flags);
+ }
default:
break;
}
@@ -1247,6 +1259,8 @@ public class RemoteViews implements Parcelable, Filter {
return Bundle.class;
case INTENT:
return Intent.class;
+ case COLOR_STATE_LIST:
+ return ColorStateList.class;
default:
return null;
}
@@ -2207,6 +2221,42 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * @hide
+ * Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}.
+ *
+ * @param viewId The id of the view whose tint should change
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ */
+ public void setProgressTintList(int viewId, ColorStateList tint) {
+ addAction(new ReflectionAction(viewId, "setProgressTintList",
+ ReflectionAction.COLOR_STATE_LIST, tint));
+ }
+
+ /**
+ * @hide
+ * Equivalent to calling {@link android.widget.ProgressBar#setProgressBackgroundTintList}.
+ *
+ * @param viewId The id of the view whose tint should change
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ */
+ public void setProgressBackgroundTintList(int viewId, ColorStateList tint) {
+ addAction(new ReflectionAction(viewId, "setProgressBackgroundTintList",
+ ReflectionAction.COLOR_STATE_LIST, tint));
+ }
+
+ /**
+ * @hide
+ * Equivalent to calling {@link android.widget.ProgressBar#setIndeterminateTintList}.
+ *
+ * @param viewId The id of the view whose tint should change
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ */
+ public void setProgressIndeterminateTintList(int viewId, ColorStateList tint) {
+ addAction(new ReflectionAction(viewId, "setIndeterminateTintList",
+ ReflectionAction.COLOR_STATE_LIST, tint));
+ }
+
+ /**
* Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
*
* @param viewId The id of the view whose text color should change
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 8917f39..6dfea92 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -43,7 +43,7 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
/**
- * A delegate implementing the basic TimePicker
+ * A delegate implementing the basic spinner-based TimePicker.
*/
class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private static final boolean DEFAULT_ENABLED_STATE = true;
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 73e05e8..d9c4114 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -28,6 +28,7 @@ import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -44,7 +45,7 @@ import java.util.Calendar;
import java.util.Locale;
/**
- * A view for selecting the time of day, in either 24 hour or AM/PM mode.
+ * A delegate implementing the radial clock-based TimePicker.
*/
class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements
RadialTimePickerView.OnValueSelectedListener {
@@ -61,23 +62,27 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
// Also NOT a real index, just used for keyboard mode.
private static final int ENABLE_PICKER_INDEX = 3;
- private static final int AM = 0;
- private static final int PM = 1;
+ static final int AM = 0;
+ static final int PM = 1;
private static final boolean DEFAULT_ENABLED_STATE = true;
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
private static final int HOURS_IN_HALF_DAY = 12;
- private View mHeaderView;
- private TextView mHourView;
- private TextView mMinuteView;
- private TextView mAmPmTextView;
- private RadialTimePickerView mRadialTimePickerView;
- private TextView mSeparatorView;
+ private final View mHeaderView;
+ private final TextView mHourView;
+ private final TextView mMinuteView;
+ private final View mAmPmLayout;
+ private final CheckedTextView mAmLabel;
+ private final CheckedTextView mPmLabel;
+ private final RadialTimePickerView mRadialTimePickerView;
+ private final TextView mSeparatorView;
- private String mAmText;
- private String mPmText;
+ private final String mAmText;
+ private final String mPmText;
+
+ private final float mDisabledAlpha;
private boolean mAllowAutoAdvance;
private int mInitialHourOfDay;
@@ -100,6 +105,10 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private String mMinutePickerDescription;
private String mSelectMinutes;
+ // Most recent time announcement values for accessibility.
+ private CharSequence mLastAnnouncedText;
+ private boolean mLastAnnouncedIsHour;
+
private Calendar mTempCalendar;
public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
@@ -124,15 +133,18 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_holo);
- final View mainView = inflater.inflate(layoutResourceId, null);
- mDelegator.addView(mainView);
+ final View mainView = inflater.inflate(layoutResourceId, delegator);
+
+ mHeaderView = mainView.findViewById(R.id.time_header);
+ mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
- mHourView = (TextView) mainView.findViewById(R.id.hours);
- mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
- mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
- mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label);
+ // Set up hour/minute labels.
+ mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
+ mHourView.setOnClickListener(mClickListener);
+ mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
+ mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
+ mMinuteView.setOnClickListener(mClickListener);
- // Set up text appearances from style.
final int headerTimeTextAppearance = a.getResourceId(
R.styleable.TimePicker_headerTimeTextAppearance, 0);
if (headerTimeTextAppearance != 0) {
@@ -141,6 +153,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mMinuteView.setTextAppearance(context, headerTimeTextAppearance);
}
+ // TODO: This can be removed once we support themed color state lists.
final int headerSelectedTextColor = a.getColor(
R.styleable.TimePicker_headerSelectedTextColor,
res.getColor(R.color.timepicker_default_selector_color_material));
@@ -149,17 +162,29 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
R.attr.state_selected, headerSelectedTextColor));
+ // Set up AM/PM labels.
+ mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
+ mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
+ mAmLabel.setText(amPmStrings[0]);
+ mAmLabel.setOnClickListener(mClickListener);
+ mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
+ mPmLabel.setText(amPmStrings[1]);
+ mPmLabel.setOnClickListener(mClickListener);
+
final int headerAmPmTextAppearance = a.getResourceId(
R.styleable.TimePicker_headerAmPmTextAppearance, 0);
if (headerAmPmTextAppearance != 0) {
- mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance);
+ mAmLabel.setTextAppearance(context, headerAmPmTextAppearance);
+ mPmLabel.setTextAppearance(context, headerAmPmTextAppearance);
}
- mHeaderView = mainView.findViewById(R.id.time_header);
- mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
-
a.recycle();
+ // Pull disabled alpha from theme.
+ final TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
+ mDisabledAlpha = outValue.getFloat();
+
mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
R.id.radial_picker);
@@ -195,21 +220,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mHeaderView.setFocusable(true);
mRadialTimePickerView.setOnValueSelectedListener(this);
-
- mHourView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setCurrentItemShowing(HOUR_INDEX, true, true);
- tryVibrate();
- }
- });
- mMinuteView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setCurrentItemShowing(MINUTE_INDEX, true, true);
- tryVibrate();
- }
- });
}
private void updateUI(int index) {
@@ -218,11 +228,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
// Enable or disable the AM/PM view.
updateHeaderAmPm();
// Update Hour and Minutes
- updateHeaderHour(mInitialHourOfDay, true);
+ updateHeaderHour(mInitialHourOfDay, false);
// Update time separator
updateHeaderSeparator();
// Update Minutes
- updateHeaderMinute(mInitialMinute);
+ updateHeaderMinute(mInitialMinute, false);
// Invalidate everything
mDelegator.invalidate();
}
@@ -250,46 +260,31 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private void updateHeaderAmPm() {
if (mIs24HourView) {
- mAmPmTextView.setVisibility(View.GONE);
+ mAmPmLayout.setVisibility(View.GONE);
} else {
- mAmPmTextView.setVisibility(View.VISIBLE);
- final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
- "hm");
-
+ final String bestDateTimePattern = DateFormat.getBestDateTimePattern(
+ mCurrentLocale, "hm");
boolean amPmOnLeft = bestDateTimePattern.startsWith("a");
if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) ==
View.LAYOUT_DIRECTION_RTL) {
amPmOnLeft = !amPmOnLeft;
}
- RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
- mAmPmTextView.getLayoutParams();
+ final ViewGroup.MarginLayoutParams params =
+ (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams();
if (amPmOnLeft) {
- layoutParams.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
- layoutParams.removeRule(RelativeLayout.RIGHT_OF);
- layoutParams.addRule(RelativeLayout.LEFT_OF, R.id.separator);
+ params.leftMargin = 0;
+ params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */);
} else {
- layoutParams.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
- layoutParams.removeRule(RelativeLayout.LEFT_OF);
- layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.separator);
+ params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */);
+ params.rightMargin = 0;
}
- updateAmPmDisplay(mInitialHourOfDay < 12 ? AM : PM);
- mAmPmTextView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- tryVibrate();
- int amOrPm = mRadialTimePickerView.getAmOrPm();
- if (amOrPm == AM) {
- amOrPm = PM;
- } else if (amOrPm == PM){
- amOrPm = AM;
- }
- updateAmPmDisplay(amOrPm);
- mRadialTimePickerView.setAmOrPm(amOrPm);
- }
- });
+ mAmPmLayout.setLayoutParams(params);
+ mAmPmLayout.setVisibility(View.VISIBLE);
+
+ updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
}
}
@@ -302,7 +297,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return;
}
mInitialHourOfDay = currentHour;
- updateHeaderHour(currentHour, true /* accessibility announce */);
+ updateHeaderHour(currentHour, true);
updateHeaderAmPm();
mRadialTimePickerView.setCurrentHour(currentHour);
mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
@@ -338,7 +333,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return;
}
mInitialMinute = currentMinute;
- updateHeaderMinute(currentMinute);
+ updateHeaderMinute(currentMinute, true);
mRadialTimePickerView.setCurrentMinute(currentMinute);
mDelegator.invalidate();
onTimeChanged();
@@ -366,7 +361,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
generateLegalTimesTree();
int hour = mRadialTimePickerView.getCurrentHour();
mInitialHourOfDay = hour;
- updateHeaderHour(hour, false /* no accessibility announce */);
+ updateHeaderHour(hour, false);
updateHeaderAmPm();
updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
mDelegator.invalidate();
@@ -389,7 +384,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
public void setEnabled(boolean enabled) {
mHourView.setEnabled(enabled);
mMinuteView.setEnabled(enabled);
- mAmPmTextView.setEnabled(enabled);
+ mAmLabel.setEnabled(enabled);
+ mPmLabel.setEnabled(enabled);
mRadialTimePickerView.setEnabled(enabled);
mIsEnabled = enabled;
}
@@ -596,16 +592,14 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
}
- private void updateAmPmDisplay(int amOrPm) {
- if (amOrPm == AM) {
- mAmPmTextView.setText(mAmText);
- mRadialTimePickerView.announceForAccessibility(mAmText);
- } else if (amOrPm == PM){
- mAmPmTextView.setText(mPmText);
- mRadialTimePickerView.announceForAccessibility(mPmText);
- } else {
- mAmPmTextView.setText(mDoublePlaceholderText);
- }
+ private void updateAmPmLabelStates(int amOrPm) {
+ final boolean isAm = amOrPm == AM;
+ mAmLabel.setChecked(isAm);
+ mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
+
+ final boolean isPm = amOrPm == PM;
+ mPmLabel.setChecked(isPm);
+ mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
}
/**
@@ -614,22 +608,20 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
@Override
public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
if (pickerIndex == HOUR_INDEX) {
- updateHeaderHour(newValue, false);
- String announcement = String.format("%d", newValue);
if (mAllowAutoAdvance && autoAdvance) {
+ updateHeaderHour(newValue, false);
setCurrentItemShowing(MINUTE_INDEX, true, false);
- announcement += ". " + mSelectMinutes;
+ mRadialTimePickerView.announceForAccessibility(newValue + ". " + mSelectMinutes);
} else {
+ updateHeaderHour(newValue, true);
mRadialTimePickerView.setContentDescription(
mHourPickerDescription + ": " + newValue);
}
-
- mRadialTimePickerView.announceForAccessibility(announcement);
} else if (pickerIndex == MINUTE_INDEX){
- updateHeaderMinute(newValue);
+ updateHeaderMinute(newValue, true);
mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
} else if (pickerIndex == AMPM_INDEX) {
- updateAmPmDisplay(newValue);
+ updateAmPmLabelStates(newValue);
} else if (pickerIndex == ENABLE_PICKER_INDEX) {
if (!isTypedTimeFullyLegal()) {
mTypedTimes.clear();
@@ -674,7 +666,16 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
CharSequence text = String.format(format, value);
mHourView.setText(text);
if (announce) {
- mRadialTimePickerView.announceForAccessibility(text);
+ tryAnnounceForAccessibility(text, true);
+ }
+ }
+
+ private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
+ if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
+ // TODO: Find a better solution, potentially live regions?
+ mDelegator.announceForAccessibility(text);
+ mLastAnnouncedText = text;
+ mLastAnnouncedIsHour = isHour;
}
}
@@ -725,13 +726,15 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return -1;
}
- private void updateHeaderMinute(int value) {
+ private void updateHeaderMinute(int value, boolean announceForAccessibility) {
if (value == 60) {
value = 0;
}
- CharSequence text = String.format(mCurrentLocale, "%02d", value);
- mRadialTimePickerView.announceForAccessibility(text);
+ final CharSequence text = String.format(mCurrentLocale, "%02d", value);
mMinuteView.setText(text);
+ if (announceForAccessibility) {
+ tryAnnounceForAccessibility(text, false);
+ }
}
/**
@@ -761,6 +764,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mMinuteView.setSelected(index == MINUTE_INDEX);
}
+ private void setAmOrPm(int amOrPm) {
+ updateAmPmLabelStates(amOrPm);
+ mRadialTimePickerView.setAmOrPm(amOrPm);
+ }
+
/**
* For keyboard mode, processes key events.
*
@@ -926,10 +934,10 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
int hour = mRadialTimePickerView.getCurrentHour();
int minute = mRadialTimePickerView.getCurrentMinute();
- updateHeaderHour(hour, true);
- updateHeaderMinute(minute);
+ updateHeaderHour(hour, false);
+ updateHeaderMinute(minute, false);
if (!mIs24HourView) {
- updateAmPmDisplay(hour < 12 ? AM : PM);
+ updateAmPmLabelStates(hour < 12 ? AM : PM);
}
setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
onValidationChanged(true);
@@ -947,7 +955,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mMinuteView.setText(minuteStr);
mMinuteView.setSelected(false);
if (!mIs24HourView) {
- updateAmPmDisplay(values[2]);
+ updateAmPmLabelStates(values[2]);
}
}
}
@@ -1231,6 +1239,33 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
}
}
+ private final View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ final int amOrPm;
+ switch (v.getId()) {
+ case R.id.am_label:
+ setAmOrPm(AM);
+ break;
+ case R.id.pm_label:
+ setAmOrPm(PM);
+ break;
+ case R.id.hours:
+ setCurrentItemShowing(HOUR_INDEX, true, true);
+ break;
+ case R.id.minutes:
+ setCurrentItemShowing(MINUTE_INDEX, true, true);
+ break;
+ default:
+ // Failed to handle this click, don't vibrate.
+ return;
+ }
+
+ tryVibrate();
+ }
+ };
+
private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 1ce19ce..d8e39e3 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -66,7 +66,9 @@ import java.util.List;
* <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
* collapse, done or another glyph of the app's choosing. This button should always be used
* to access other navigational destinations within the container of the Toolbar and
- * its signified content or otherwise leave the current context signified by the Toolbar.</li>
+ * its signified content or otherwise leave the current context signified by the Toolbar.
+ * The navigation button is vertically aligned within the Toolbar's
+ * {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
* <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
* arbitrarily wide.</li>
* <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
@@ -82,8 +84,9 @@ import java.util.List;
* <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
* end of the Toolbar offering a few
* <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
- * frequent, important or typical</a> actions along with an optional overflow menu for
- * additional actions.</li>
+ * frequent, important or typical</a> actions along with an optional overflow menu for
+ * additional actions. Action buttons are vertically aligned within the Toolbar's
+ * {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
* </ul>
* </p>
*
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5267811..0bc1a8d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,13 +16,20 @@
package com.android.internal.app;
+import android.app.Activity;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
+import android.util.Slog;
public class ChooserActivity extends ResolverActivity {
+ private static final String TAG = "ChooserActivity";
+
private Bundle mReplacementExtras;
+ private IntentSender mChosenComponentSender;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -60,11 +67,14 @@ public class ChooserActivity extends ResolverActivity {
initialIntents[i] = in;
}
}
+ mChosenComponentSender = intent.getParcelableExtra(
+ Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
setSafeForwardingMode(true);
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
}
+ @Override
public Intent getReplacementIntent(String packageName, Intent defIntent) {
if (mReplacementExtras != null) {
final Bundle replExtras = mReplacementExtras.getBundle(packageName);
@@ -77,6 +87,22 @@ public class ChooserActivity extends ResolverActivity {
return defIntent;
}
+ @Override
+ public void onActivityStarted(Intent intent) {
+ if (mChosenComponentSender != null) {
+ final ComponentName target = intent.getComponent();
+ if (target != null) {
+ final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target);
+ try {
+ mChosenComponentSender.sendIntent(this, Activity.RESULT_OK, fillIn, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.e(TAG, "Unable to launch supplied IntentSender to report "
+ + "the chosen component: " + e);
+ }
+ }
+ }
+ }
+
private void modifyTargetIntent(Intent in) {
final String action = in.getAction();
if (Intent.ACTION_SEND.equals(action) ||
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0062e2d..ccffa19 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -74,6 +74,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+
/**
* This activity is displayed when the system attempts to start an Intent for
* which there is more than one matching activity, allowing the user to decide
@@ -269,6 +272,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mListView = (ListView) findViewById(R.id.resolver_list);
mListView.setVisibility(View.GONE);
}
+ // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
+ // control of the system bars.
+ getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
@@ -638,10 +644,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
public void safelyStartActivity(Intent intent) {
if (!mSafeForwardingMode) {
startActivity(intent);
+ onActivityStarted(intent);
return;
}
try {
startActivityAsCaller(intent, null, UserHandle.USER_NULL);
+ onActivityStarted(intent);
} catch (RuntimeException e) {
String launchedFromPackage;
try {
@@ -656,6 +664,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
+ public void onActivityStarted(Intent intent) {
+ // Do nothing
+ }
+
void showAppDetails(ResolveInfo ri) {
Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
@@ -819,6 +831,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
+ UserManager userManager =
+ (UserManager) getSystemService(Context.USER_SERVICE);
+ if (userManager.isManagedProfile()) {
+ ri.noResourceId = true;
+ }
if (ii instanceof LabeledIntent) {
LabeledIntent li = (LabeledIntent)ii;
ri.resolvePackageName = li.getSourcePackage();
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 5f240f7..1dd9464 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -34,40 +34,65 @@ public final class MemInfoReader {
}
}
+ /**
+ * Total amount of RAM available to the kernel.
+ */
public long getTotalSize() {
return mInfos[Debug.MEMINFO_TOTAL] * 1024;
}
+ /**
+ * Amount of RAM that is not being used for anything.
+ */
public long getFreeSize() {
return mInfos[Debug.MEMINFO_FREE] * 1024;
}
+ /**
+ * Amount of RAM that the kernel is being used for caches, not counting caches
+ * that are mapped in to processes.
+ */
public long getCachedSize() {
- return mInfos[Debug.MEMINFO_CACHED] * 1024;
+ return getCachedSizeKb() * 1024;
}
+ /**
+ * Amount of RAM that is in use by the kernel for actual allocations.
+ */
+ public long getKernelUsedSize() {
+ return getKernelUsedSizeKb() * 1024;
+ }
+
+ /**
+ * Total amount of RAM available to the kernel.
+ */
public long getTotalSizeKb() {
return mInfos[Debug.MEMINFO_TOTAL];
}
+ /**
+ * Amount of RAM that is not being used for anything.
+ */
public long getFreeSizeKb() {
return mInfos[Debug.MEMINFO_FREE];
}
+ /**
+ * Amount of RAM that the kernel is being used for caches, not counting caches
+ * that are mapped in to processes.
+ */
public long getCachedSizeKb() {
- return mInfos[Debug.MEMINFO_CACHED];
- }
-
- public long getBuffersSizeKb() {
- return mInfos[Debug.MEMINFO_BUFFERS];
- }
-
- public long getShmemSizeKb() {
- return mInfos[Debug.MEMINFO_SHMEM];
+ return mInfos[Debug.MEMINFO_BUFFERS]
+ + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
}
- public long getSlabSizeKb() {
- return mInfos[Debug.MEMINFO_SLAB];
+ /**
+ * Amount of RAM that is in use by the kernel for actual allocations.
+ */
+ public long getKernelUsedSizeKb() {
+ return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]
+ + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
+ + mInfos[Debug.MEMINFO_KERNEL_STACK];
}
public long getSwapTotalSizeKb() {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 40f58e9..99bb1ac 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -54,6 +54,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private final boolean mOverflowOnly;
private final int mPopupMaxWidth;
private final int mPopupStyleAttr;
+ private final int mPopupStyleRes;
private View mAnchorView;
private ListPopupWindow mPopup;
@@ -73,21 +74,27 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private int mDropDownGravity = Gravity.NO_GRAVITY;
public MenuPopupHelper(Context context, MenuBuilder menu) {
- this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
+ this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
}
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
- this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
+ this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle, 0);
}
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly, int popupStyleAttr) {
+ this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0);
+ }
+
+ public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+ boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
mContext = context;
mInflater = LayoutInflater.from(context);
mMenu = menu;
mAdapter = new MenuAdapter(mMenu);
mOverflowOnly = overflowOnly;
mPopupStyleAttr = popupStyleAttr;
+ mPopupStyleRes = popupStyleRes;
final Resources res = context.getResources();
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -122,7 +129,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
}
public boolean tryShow() {
- mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
+ mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
mPopup.setOnDismissListener(this);
mPopup.setOnItemClickListener(this);
mPopup.setAdapter(mAdapter);
diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
index 11c4ca1..4689179 100644
--- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java
+++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
@@ -54,6 +54,10 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
/** Default class name used for virtual views. */
private static final String DEFAULT_CLASS_NAME = View.class.getName();
+ /** Default bounds used to determine if the client didn't set any. */
+ private static final Rect INVALID_PARENT_BOUNDS = new Rect(
+ Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
+
// Temporary, reusable data structures.
private final Rect mTempScreenRect = new Rect();
private final Rect mTempParentRect = new Rect();
@@ -372,6 +376,7 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
+ node.setBoundsInParent(INVALID_PARENT_BOUNDS);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
@@ -383,7 +388,7 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
}
node.getBoundsInParent(mTempParentRect);
- if (mTempParentRect.isEmpty()) {
+ if (mTempParentRect.equals(INVALID_PARENT_BOUNDS)) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}